2009-05-12 9 views
3

Ich verwende Python mit adodbapi von pywin32, um ein Skript zum Erstellen einer SQL Server-Datenbank mit allen zugehörigen Tabellen, Sichten und Prozeduren zu schreiben. Das Problem besteht darin, dass Pythons DBAPI erfordert, dass cursor.execute() in eine Transaktion eingeschlossen wird, die nur von cursor.commit() übergeben wird, und Sie können keine drop- oder create database-Anweisung in einer Benutzertransaktion ausführen. Irgendwelche Ideen, wie man das schafft?Erstellen einer SQL Server-Datenbank aus Python

EDIT:

Es scheint nicht der connect() -Methode von adodbapi oder dessen Cursor() -Methode, um etwas analog zu einem autocommit Parameter zu sein. Ich würde glücklich sein, Pymssql anstelle von Adodbapi zu verwenden, außer dass es char und varchar Datentypen bei 255 Zeichen abschneidet.

Ich habe dies vor dem Posten versucht; Hier ist die Rückverfolgung.

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 

Antwort

1

Die adodbapi Verbindungsobjekt conn startet automatisch eine neue Transaktion nach jedem Commit, wenn die Datenbank Transaktionen unterstützt. DB-API erfordert, dass Autocommit standardmäßig deaktiviert wird und eine API-Methode es wieder aktiviert, aber ich sehe keine in adodbapi.

Sie können möglicherweise die conn.adoConn-Eigenschaft verwenden, um dies zu hacken, mit der ADO API anstelle von DB-API, um Sie aus einer Transaktion zu nehmen. Lassen Sie mich wissen, ob das funktioniert:

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

Hier ist die Quelle für die adodbapi commit() method.

+1

Das ist nah dran. Was zuletzt funktioniert hat, war: conn.adoConn.Execute ("create database dummydatabase") Danke! Ich hätte das vielleicht nie herausgefunden. – JasonFruit

0

Erstellen Sie die tatsächliche DB außerhalb der Transaktion. Ich bin nicht vertraut mit Python, aber es muss eine Möglichkeit geben, einen Benutzer angegebene Zeichenfolge in einer Datenbank auszuführen, verwenden Sie diese mit dem tatsächlichen create db -Befehl. Verwenden Sie dann die Adodbapi, um alle Tabellen usw. auszuführen und diese Transaktion zu übernehmen.

+0

Ja, das ist eine gute Neuerung der Frage. Hast du eine Idee, wie das geht? Adodbapi ist weitgehend undokumentiert, aber ich habe seine Unit-Tests durchforstet, und es gibt keinen Test, der das Ausführen eines SQL-Befehls außerhalb einer Transaktion anspricht. – JasonFruit

+0

versuchen Sie etwas anderes als adodbapi, um den Befehl create auszugeben –

1

„Das Problem ist, dass Python DBAPI erfordert, dass cursor.execute() in einer Transaktion eingewickelt werden, die nur durch cursor.commit() begangen wird“

„und Sie können keinen Tropfen oder erstellen Datenbank ausführen Anweisung in einer Benutzertransaktion. "

Ich bin nicht sicher, dass das alles tatsächlich für alle DBAPI-Schnittstellen gilt.

Da Sie die Fehlermeldungen nicht anzeigen, kann es sich herausstellen, dass dies nicht für die ADODBAPI-Schnittstelle gilt. Hast du es tatsächlich versucht? Wenn ja, welche Fehlermeldung erhalten Sie?

Eine Verbindung darf nicht immer eine "Benutzertransaktion" erstellen. Sie können häufig Verbindungen mit autocommit=True öffnen, um DDL-style autocommit zu erhalten.

Sie können auch eine andere Verbindung verwenden, um DDL auszuführen.

http://pymssql.sourceforge.net/ zum Beispiel, zeigt DDL wie diese ausgeführt wird.

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

Sie haben Recht - das gilt nicht für * alle * DBAPI-Schnittstellen, aber es ist der bevorzugte Ansatz, wenn der Provider es erlaubt. Ich habe meine Frage mit weiteren relevanten Informationen aktualisiert. Danke für die Ideen! – JasonFruit

0

Ich hatte das gleiche Problem beim Versuch, Befehle über Adodbapi (z. B. DBCC CHECKDB ...) und Joeforker Tipps half ein wenig. Das Problem, das ich immer noch hatte, war, dass Adodbapi automatisch eine Transaktion startet, also gab es keine Möglichkeit, etwas außerhalb einer Transaktion auszuführen.

Am Ende landete ich adodbapi commit Verhalten wie folgt deaktivieren:

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 

Soweit ich sagen kann, diese wieder aktiviert die Standard-SQL-Server-Funktionalität autocommit, dh jede SQL-Anweisung wird automatisch engagiert sein. Der Nachteil ist, dass es für mich keine Möglichkeit gibt, Transaktionen (im Moment) wieder zu aktivieren, wenn ich etwas innerhalb einer Transaktion ausführen möchte, da Connection.commit() nichts tut, wenn supportsTransactions == False.