2009-05-12 6 views
3

J'utilise Python avec adodbapi de pywin32 pour écrire un script pour créer une base de données SQL Server et toutes ses tables associées, des vues et des procédures. Le problème est que DBAPI de Python nécessite que cursor.execute() soit enveloppé dans une transaction qui est uniquement validée par cursor.commit(), et vous ne pouvez pas exécuter une instruction drop ou create database dans une transaction utilisateur. Des idées sur la façon de contourner cela?Création d'une base de données SQL Server à partir de Python

EDIT:

Il ne semble pas être quelque chose d'analogue à un paramètre autocommit soit la méthode connect() de adodbapi ou la méthode du curseur(). Je serais heureux d'utiliser pymssql au lieu d'adodbapi, sauf qu'il tronque les types de données char et varchar à 255 caractères. J'ai essayé cela avant de poster; voici le retraçage.

Traceback (most recent call last): 
    File "demo.py", line 39, in <module> 
    cur.execute("create database dummydatabase") 
    File "C:\Python26\lib\site-packages\adodbapi\adodbapi.py", line 713, in execute 
    self._executeHelper(operation,False,parameters) 
    File "C:\Python26\lib\site-packages\adodbapi\adodbapi.py", line 664, in _executeHelper 
    self._raiseCursorError(DatabaseError,tracebackhistory) 
    File "C:\Python26\lib\site-packages\adodbapi\adodbapi.py", line 474, in _raiseCursorError 
    eh(self.conn,self,errorclass,errorvalue) 
    File "C:\Python26\lib\site-packages\adodbapi\adodbapi.py", line 60, in standardErrorHandler 
    raise errorclass(errorvalue) 
adodbapi.adodbapi.DatabaseError: 
--ADODBAPI 
Traceback (most recent call last): 
    File "C:\Python26\lib\site-packages\adodbapi\adodbapi.py", line 650, in _executeHelper 
    adoRetVal=self.cmd.Execute() 
    File "<COMObject ADODB.Command>", line 3, in Execute 
    File "C:\Python26\lib\site-packages\win32com\client\dynamic.py", line 258, in _ApplyTypes_ 
    result = self._oleobj_.InvokeTypes(*(dispid, LCID, wFlags, retType, argTypes) + args) 
com_error: (-2147352567, 'Exception occurred.', (0, u'Microsoft SQL Native Client', u'CREATE DATABASE statement not allowed within multi-statement transaction.', None, 0, -2147217900), None) 
-- on command: "create database dummydatabase" 
-- with parameters: None 

Répondre

1

L'objet connexion adodbapi conn ne démarre pas automatiquement une nouvelle transaction après chaque commettras si la base de données prend en charge les transactions. DB-API nécessite que la validation automatique soit désactivée par défaut, ce qui permet à une méthode API de la réactiver, mais je n'en vois aucune dans adodbapi.

Vous pouvez peut-être utiliser la propriété conn.adoConn pour contourner ce problème, en utilisant l'API ADO au lieu de DB-API pour vous retirer de toute transaction. Faites-moi savoir si cela fonctionne:

conn.adoConn.CommitTrans() 
cursor.execute('CREATE DATABASE ...') 
conn.adoConn.BeginTrans() 

est ici la source pour le adodbapi commit() method.

+1

C'est proche. Qu'est-ce qui a finalement travaillé était: conn.adoConn.Execute ("créer une base de données dummydatabase") Merci! Je n'aurais peut-être jamais compris ça. – JasonFruit

0

créer la base de données réelle en dehors de la transaction. Je ne suis pas familier avec python, mais il doit y avoir un moyen d'exécuter une chaîne donnée par l'utilisateur sur une base de données, utilisez-le avec la commande create db réelle. Ensuite, utilisez l'adodbapi pour faire toutes les tables, etc. et validez cette transaction.

+0

Oui, c'est une bonne reformulation de la question. Avez-vous une idée de comment accomplir cela? Adodbapi est en grande partie non documenté, mais j'ai creusé à travers ses tests unitaires, et il n'y a pas de test qui traite l'exécution d'une commande SQL en dehors d'une transaction. – JasonFruit

+0

essayez autre chose qu'adodbapi pour lancer la commande create –

1

« Le problème est que la DBAPI Python exige que cursor.execute() être enveloppé dans une transaction qui ne commise par cursor.commit() »

« et vous ne pouvez pas exécuter une goutte ou créer la base de données déclaration dans une transaction utilisateur. "

Je ne suis pas sûr que tout cela soit vrai pour toutes les interfaces DBAPI.

Puisque vous ne présentez pas les messages d'erreur, il peut se que ce n'est pas vrai pour l'interface ADODBAPI. Avez-vous réellement essayé? Si oui, quel message d'erreur obtenez-vous?

Une connexion ne peut pas toujours à créer une « transaction utilisateur ». Vous pouvez souvent ouvrir des connexions avec autocommit=True pour obtenir un autocommit de style DDL.

En outre, vous pouvez envisager d'utiliser une connexion différente pour exécuter DDL.

http://pymssql.sourceforge.net/ par exemple, en cours d'exécution montre DDL comme celui-ci.

import pymssql 
conn = pymssql.connect(host='SQL01', user='user', password='password', database='mydatabase') 
cur = conn.cursor() 
cur.execute('CREATE TABLE persons(id INT, name VARCHAR(100))') 
+0

Vous avez raison - ce n'est pas le cas de * toutes * les interfaces DBAPI, mais c'est l'approche préférée lorsque le fournisseur le permet. J'ai mis à jour ma question avec plus d'informations pertinentes à votre réponse. Merci pour les idées! – JasonFruit

0

J'ai eu ce même problème en essayant d'exécuter des commandes sur adodbapi (par exemple DBCC CHECKDB ...) et les conseils de joeforker aidé un peu. Le problème que j'avais toujours était qu'adodbapi commençait automatiquement une transaction, donc il n'y avait aucun moyen d'exécuter quelque chose en dehors d'une transaction.

En fin de compte, je fini par désactiver adodbapi de commettre un tel comportement:

self.conn = adodbapi.connect(conn_str) 
# rollback the transaction that was started in Connection.__init__() 
self.conn.adoConn.RollbackTrans() 
# prevent adodbapi from trying to rollback a transaction in Connection.close() 
self.conn.supportsTransactions = False 

Pour autant que je peux dire, ce va réactiver la norme SQL Server fonctionnalité d'auto-validation, à savoir chaque instruction SQL est automatiquement engagé. L'inconvénient est qu'il n'y a aucun moyen pour moi de réactiver les transactions (pour le moment) si je ne veux pas exécuter quelque chose dans une transaction, car Connection.commit() ne fera rien quand supportsTransactions == False.

Questions connexes