@@ -117,7 +117,7 @@ def fetchall(self):
117117 logger .log (logging .WARN if conf .dbmsHandler else logging .DEBUG , "(remote) %s" % getSafeExString (ex ))
118118 return None
119119
120- def execute (self , query ):
120+ def execute (self , query , commit = True ):
121121 retVal = False
122122
123123 # Reference: https://stackoverflow.com/a/69491015
@@ -126,10 +126,14 @@ def execute(self, query):
126126
127127 try :
128128 self .cursor = self .connector .execute (query )
129- if hasattr (self .connector , "commit" ): # Note: SQLAlchemy 2.0+ dropped implicit autocommit (otherwise DML changes - e.g. via --sql-query - would be silently lost)
129+ # Note: SQLAlchemy 2.0+ dropped implicit autocommit (otherwise DML changes - e.g. via --sql-query -
130+ # would be silently lost). SELECT goes through select() with commit=False so the result set is
131+ # fetched BEFORE committing: on some drivers (e.g. pymssql) commit() discards the open cursor, which
132+ # otherwise made every MSSQL '-d' query silently return empty (banner/is-dba/dump all blank).
133+ if commit and hasattr (self .connector , "commit" ):
130134 self .connector .commit ()
131135 retVal = True
132- except (_sqlalchemy .exc .OperationalError , _sqlalchemy .exc .ProgrammingError ) as ex :
136+ except (_sqlalchemy .exc .OperationalError , _sqlalchemy .exc .ProgrammingError , _sqlalchemy . exc . DataError , _sqlalchemy . exc . IntegrityError ) as ex :
133137 logger .log (logging .WARN if conf .dbmsHandler else logging .DEBUG , "(remote) %s" % getSafeExString (ex ))
134138 # Roll back the failed statement's transaction so it does not poison every following query with
135139 # 'InFailedSqlTransaction' (SQLAlchemy 2.0+ keeps the transaction open after an error). Without this
@@ -148,7 +152,14 @@ def execute(self, query):
148152 def select (self , query ):
149153 retVal = None
150154
151- if self .execute (query ):
155+ # Fetch BEFORE committing (commit=False): committing can discard the open result cursor on some drivers
156+ # (e.g. pymssql), which silently emptied every MSSQL '-d' result. No DML is persisted by a SELECT anyway.
157+ if self .execute (query , commit = False ):
152158 retVal = self .fetchall ()
159+ if hasattr (self .connector , "commit" ):
160+ try :
161+ self .connector .commit ()
162+ except Exception :
163+ pass
153164
154165 return retVal
0 commit comments