Почему psycopg2 не выполняет ни одну из моих функций SQL? (IndexError: индекс кортежа вне диапазона) - PullRequest
16 голосов
/ 14 ноября 2009

В качестве примера я возьму простейшую из функций SQL:

CREATE OR REPLACE FUNCTION skater_name_match(INTEGER,VARCHAR)
RETURNS BOOL AS
$$
    SELECT $1 IN (SELECT skaters_skater.competitor_ptr_id FROM skaters_skater
    WHERE name||' '||surname ILIKE '%'||$2||'%' 
    OR surname||' '||name ILIKE '%'||$2||'%');
$$ LANGUAGE SQL;

Если я скопирую и вставлю это в psql (оболочка PostgreSQL), то он выполнится без проблем.

Если я напишу фрагмент кода Python, подобный этому (с реальным именем базы данных и пользователем, конечно):

import psycopg2

sql_function_above = '''CREATE OR REPLACE FUNCTION skater_name_match(INTEGER,VARCHAR)
RETURNS BOOL AS
$$
    SELECT $1 IN (SELECT skaters_skater.competitor_ptr_id FROM skaters_skater
    WHERE name||' '||surname ILIKE '%'||$2||'%' 
    OR surname||' '||name ILIKE '%'||$2||'%');
$$ LANGUAGE SQL;'''

try:
    connection = psycopg2.connect("dbname='x' user='x' host='localhost' password='x'");
except:
    print "I am unable to connect to the database"

cursor = connection.cursor()
cursor.execute(sql_function_above)

Это кажется выполненным (это не дает мне ошибки), но когда я просматриваю базу данных, функции там нет.

Когда я пытаюсь выполнить код в Django, поместив его в файл app / sql / model.sql, я получаю следующую ошибку во время syncdb:

IndexError: tuple index out of range

Когда я пытаюсь написать собственную команду manage.py, которая будет выполнять sql, я получаю ту же ошибку.

Что здесь происходит? Был бы очень признателен всем, кто мог бы пролить свет на это :) Я все еще новичок, когда дело доходит до Python и Django, поэтому, возможно, я упустил что-то очевидное.

Ответы [ 3 ]

29 голосов
/ 15 ноября 2009

По умолчанию psycopg2 идентифицирует заполнители аргументов, используя символ % (обычно в строке будет %s).

Итак, если вы используете cursor.execute('... %s, %s ...', (arg1, arg2)), то эти %s превращаются в значения arg1 и arg2 соответственно.

Но так как вы вызываете: cursor.execute(sql_function_above), без дополнительных аргументов, и ваш SQL включает % признаков, библиотека пытается найти 2-й аргумент, переданный в функцию - который находится вне диапазона, следовательно, IndexError.

Решение: Вместо использования % напишите %% в своей переменной SQL. Это переводится в литерал % перед отправкой в ​​PostgreSQL.

3 голосов
/ 14 ноября 2009

Похоже, вы не совершаете транзакцию:

Попробуйте поставить:

cursor.execute("COMMIT")

После последней строки и посмотрите, работает ли это.

Вы также можете установить уровень изоляции для автоматической фиксации, например:

connection.set_isolation_level(0)

Подробнее об этом в этом ответе

1 голос
/ 14 ноября 2009

Индекс вне диапазона означает, что вы пытались получить доступ (например) к третьему элементу кортежа, который имеет только два элемента. Обратите внимание, что индексы Python начинаются с 0, поэтому двухэлементный кортеж с именем myTuple будет иметь элементы myTuple [0] и myTuple [1], но без элемента myTuple [2].

...