2009-11-14 4 views
16

Je vais prendre le plus simple des fonctions SQL comme exemple:Pourquoi psycopg2 n'exécute-t-il aucune de mes fonctions SQL? (IndexError: indice de tuple hors de portée)

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; 

Si je copier et coller dans psql (le shell de PostgreSQL), il exécute sans aucun problème .

Si j'écris un morceau de code Python comme celui-ci (avec un vrai nom de base de données et l'utilisateur bien sûr):

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) 

Il semble d'exécuter (il ne me donne pas une erreur), mais quand je regarde dans la base de données, la fonction n'est pas là.

Lorsque je tente d'exécuter le code de Django en le mettant dans une application/sql/fichier model.sql Je reçois l'erreur suivante lors de syncdb:

IndexError: tuple index out of range 

Lorsque je tente d'écrire mon propre gérer. commande py qui exécuterait le sql, je reçois la même erreur.

Que se passe-t-il ici? Je serais très reconnaissant à tous ceux qui pourraient faire la lumière sur ce sujet :) Je suis toujours un novice quand il s'agit de Python et Django, donc j'ai peut-être oublié quelque chose d'évident.

+1

Seriez-vous en mesure d'ajouter l'instruction réelle que vous exécutez dans "curseur.execute (sql_function_above) "(ou montre où vous définissez 'sql_function_above' si vous voulez littéralement utiliser cet identifiant) –

+1

Dites-nous comment vous avez défini sql_function_above 'dans votre code python – nos

+0

Désolé, c'était une simplification de ma part. J'ai essayé d'écrire la variable de différentes façons, j'ai aussi essayé de lire le texte depuis un fichier sql, tous ont produit la même erreur, l'une des nombreuses façons dont j'ai écrit la variable éditée dans la question originale. réponses - c'est la première fois que j'utilise stackoverflow.com et l'utilité et la rapidité des réponses de votre part est incroyable :) –

Répondre

28

Par psycopg2 par défaut identifie des espaces réservés argument en utilisant le symbole % (en général, vous auriez %s dans la chaîne). Par conséquent, si vous utilisez cursor.execute('... %s, %s ...', (arg1, arg2)), les valeurs %s sont converties respectivement en valeurs arg1 et arg2.

Mais puisque vous appelez: cursor.execute(sql_function_above), sans arguments supplémentaires, et votre SQL comprend % signes la bibliothèque tente de trouver le 2ème argument passé dans la fonction - qui est hors de portée, d'où une erreur IndexError.

Solution: Au lieu d'utiliser %, écrivez %% dans votre variable SQL. Ceci est traduit en littéral % avant d'être envoyé à PostgreSQL.

1

L'index hors limites implique que vous avez essayé d'accéder (par exemple) au troisième élément d'un tuple qui n'a que deux éléments. Notez que les index de Python commencent à 0, donc un tuple de deux éléments nommé myTuple aurait les éléments myTuple [0] et myTuple [1], mais aucun élément myTuple [2].

+0

Oui ... c'est ce qui m'embrouille d'autant plus que ça ressemble à un tuple dans la bibliothèque psycopg2 qui est le coupable et cela signifierait qu'il y a un bug dans la bibliothèque psycopg2 (ou est-ce que je saute aux mauvaises conclusions?) .Mais si oui, quel est si spécial au sujet de mon SQL qui casse une bibliothèque dont la plupart pe ople trouve parfaitement stable? Une partie du problème ici est que je ne peux même pas isoler où exactement les choses vont mal parce que quand j'essaie d'exécuter le SQL en dehors de Django, je n'obtiens aucun message d'erreur et pourtant le SQL ne s'exécute pas. –

+0

Votre code inclut les littéraux tels que $ 2 et%. Certaines bibliothèques de bases de données peuvent interpréter ces espaces comme des espaces réservés aux paramètres. Dans le cas de python, vous n'avez probablement pas engagé la transaction. – nos

3

On dirait que vous ne commettez pas la transaction:

Essayez de mettre:

 
cursor.execute("COMMIT") 

Après la dernière ligne et voir si cela fonctionne.

Vous pouvez également définir le niveau d'isolement autocommit comme:

 
connection.set_isolation_level(0) 

Plus d'informations à ce sujet dans cette answer

+0

Bien que l'erreur de tuple n'ait rien à voir avec les transactions, une fois le problème de signe% supprimé, la fonction sql ne se chargeait toujours pas et c'était naturellement la raison, alors merci beaucoup pour cette réponse :) –

+0

PS: Vous devriez utiliser 'connection.commit()' au lieu d'exécuter manuellement "COMMIT" - de cette façon, psycopg2 connaît l'état actuel de la transaction. – intgr

Questions connexes