Skip to content

Commit 1c26783

Browse files
Support multiple result sets (#130)
* Add multiple result set support to mssqlcliclient * Add multi result set support * Add tests for multi statement and multi result sets
1 parent 91cbf58 commit 1c26783

File tree

3 files changed

+121
-70
lines changed

3 files changed

+121
-70
lines changed

mssqlcli/mssqlcliclient.py

Lines changed: 59 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -121,7 +121,8 @@ def execute_multi_statement_single_batch(self, query):
121121
if not sql:
122122
yield None, None, None, sql, False
123123
continue
124-
yield self.execute_single_batch_query(sql)
124+
for rows, columns, status, sql, is_error in self.execute_single_batch_query(sql):
125+
yield rows, columns, status, sql, is_error
125126

126127
def execute_single_batch_query(self, query):
127128
if not self.is_connected:
@@ -134,22 +135,22 @@ def execute_single_batch_query(self, query):
134135
query_request = self.sql_tools_client.create_request(u'query_execute_string_request',
135136
{u'OwnerUri': self.owner_uri, u'Query': query})
136137
query_request.execute()
137-
query_message = None
138+
query_messages = []
138139
while not query_request.completed():
139140
query_response = query_request.get_response()
140141
if query_response:
141142
if isinstance(query_response, queryservice.QueryExecuteErrorResponseEvent):
142-
return self.tabular_results_generator(column_info=None, result_rows=None,
143+
yield self.tabular_results_generator(column_info=None, result_rows=None,
143144
query=query, message=query_response.error_message,
144145
is_error=True)
145146
elif isinstance(query_response, queryservice.QueryMessageEvent):
146-
query_message = query_response
147+
query_messages.append(query_response)
147148
else:
148149
sleep(time_wait_if_no_response)
149150

150151
if query_response.exception_message:
151152
logger.error(u'Query response had an exception')
152-
return self.tabular_results_generator(
153+
yield self.tabular_results_generator(
153154
column_info=None,
154155
result_rows=None,
155156
query=query,
@@ -158,42 +159,43 @@ def execute_single_batch_query(self, query):
158159

159160
if (not query_response.batch_summaries[0].result_set_summaries) or \
160161
(query_response.batch_summaries[0].result_set_summaries[0].row_count == 0):
161-
return self.tabular_results_generator(
162+
yield self.tabular_results_generator(
162163
column_info=None,
163164
result_rows=None,
164165
query=query,
165-
message=query_message.message if query_message else u'',
166-
is_error=query_message.is_error if query_message else query_response.batch_summaries[0].has_error)
166+
message=query_messages[0].message if query_messages else u'',
167+
is_error=query_messages[0].is_error if query_messages else query_response.batch_summaries[0].has_error)
167168

168169
else:
169-
query_subset_request = self.sql_tools_client.create_request(u'query_subset_request',
170-
{u'OwnerUri': query_response.owner_uri,
171-
u'BatchIndex': query_response.batch_summaries[0].result_set_summaries[0].batch_id,
172-
u'ResultSetIndex': query_response.batch_summaries[0].result_set_summaries[0].id,
173-
u'RowsStartIndex': 0,
174-
u'RowCount': query_response.batch_summaries[0].result_set_summaries[0].row_count})
175-
176-
query_subset_request.execute()
177-
while not query_subset_request.completed():
178-
subset_response = query_subset_request.get_response()
179-
if not subset_response:
180-
sleep(time_wait_if_no_response)
181-
182-
if subset_response.error_message:
183-
logger.error(u'Error obtaining result sets for query response')
184-
return self.tabular_results_generator(
185-
column_info=None,
186-
result_rows=None,
170+
for result_set_summary in query_response.batch_summaries[0].result_set_summaries:
171+
query_subset_request = self.sql_tools_client.create_request(u'query_subset_request',
172+
{u'OwnerUri': query_response.owner_uri,
173+
u'BatchIndex': result_set_summary.batch_id,
174+
u'ResultSetIndex': result_set_summary.id,
175+
u'RowsStartIndex': 0,
176+
u'RowCount': result_set_summary.row_count})
177+
178+
query_subset_request.execute()
179+
while not query_subset_request.completed():
180+
subset_response = query_subset_request.get_response()
181+
if not subset_response:
182+
sleep(time_wait_if_no_response)
183+
184+
if subset_response.error_message:
185+
logger.error(u'Error obtaining result sets for query response')
186+
yield self.tabular_results_generator(
187+
column_info=None,
188+
result_rows=None,
189+
query=query,
190+
message=subset_response.error_message,
191+
is_error=True)
192+
193+
logger.info(u'Obtained result set for query')
194+
yield self.tabular_results_generator(
195+
column_info=result_set_summary.column_info,
196+
result_rows=subset_response.rows,
187197
query=query,
188-
message=subset_response.error_message,
189-
is_error=True)
190-
191-
logger.info(u'Obtained result set for query')
192-
return self.tabular_results_generator(
193-
column_info=query_response.batch_summaries[0].result_set_summaries[0].column_info,
194-
result_rows=subset_response.rows,
195-
query=query,
196-
message=query_message.message if query_message else u'')
198+
message=query_messages[result_set_summary.id].message if query_messages else u'')
197199

198200
def tabular_results_generator(
199201
self, column_info, result_rows, query, message, is_error=False):
@@ -213,55 +215,63 @@ def schemas(self):
213215
""" Returns a list of schema names"""
214216
query = mssqlqueries.get_schemas()
215217
logger.info(u'Schemas query: {0}'.format(query))
216-
return [x[0] for x in self.execute_single_batch_query(query)[0]]
218+
for tabular_result in self.execute_single_batch_query(query):
219+
return [x[0] for x in tabular_result[0]]
217220

218221
def databases(self):
219222
""" Returns a list of database names"""
220223
query = mssqlqueries.get_databases()
221224
logger.info(u'Databases query: {0}'.format(query))
222-
return [x[0] for x in self.execute_single_batch_query(query)[0]]
225+
for tabular_result in self.execute_single_batch_query(query):
226+
return [x[0] for x in tabular_result[0]]
223227

224228
def tables(self):
225229
""" Yields (schema_name, table_name) tuples"""
226230
query = mssqlqueries.get_tables()
227231
logger.info(u'Tables query: {0}'.format(query))
228-
for row in self.execute_single_batch_query(query)[0]:
229-
yield (row[0], row[1])
232+
for tabular_result in self.execute_single_batch_query(query):
233+
for row in tabular_result[0]:
234+
yield (row[0], row[1])
230235

231236
def table_columns(self):
232237
""" Yields (schema_name, table_name, column_name, data_type, column_default) tuples"""
233238
query = mssqlqueries.get_table_columns()
234239
logger.info(u'Table columns query: {0}'.format(query))
235-
for row in self.execute_single_batch_query(query)[0]:
236-
yield (row[0], row[1], row[2], row[3], row[4])
240+
for tabular_result in self.execute_single_batch_query(query):
241+
for row in tabular_result[0]:
242+
yield (row[0], row[1], row[2], row[3], row[4])
237243

238244
def views(self):
239245
""" Yields (schema_name, table_name) tuples"""
240246
query = mssqlqueries.get_views()
241247
logger.info(u'Views query: {0}'.format(query))
242-
for row in self.execute_single_batch_query(query)[0]:
243-
yield (row[0], row[1])
248+
for tabular_result in self.execute_single_batch_query(query):
249+
for row in tabular_result[0]:
250+
yield (row[0], row[1])
244251

245252
def view_columns(self):
246253
""" Yields (schema_name, table_name, column_name, data_type, column_default) tuples"""
247254
query = mssqlqueries.get_view_columns()
248255
logger.info(u'View columns query: {0}'.format(query))
249-
for row in self.execute_single_batch_query(query)[0]:
250-
yield (row[0], row[1], row[2], row[3], row[4])
256+
for tabular_result in self.execute_single_batch_query(query):
257+
for row in tabular_result[0]:
258+
yield (row[0], row[1], row[2], row[3], row[4])
251259

252260
def user_defined_types(self):
253261
""" Yields (schema_name, type_name) tuples"""
254262
query = mssqlqueries.get_user_defined_types()
255263
logger.info(u'UDTs query: {0}'.format(query))
256-
for row in self.execute_single_batch_query(query)[0]:
257-
yield (row[0], row[1])
264+
for tabular_result in self.execute_single_batch_query(query):
265+
for row in tabular_result[0]:
266+
yield (row[0], row[1])
258267

259268
def foreignkeys(self):
260269
""" Yields (parent_schema, parent_table, parent_column, child_schema, child_table, child_column) typles"""
261270
query = mssqlqueries.get_foreignkeys()
262271
logger.info(u'Foreign keys query: {0}'.format(query))
263-
for row in self.execute_single_batch_query(query)[0]:
264-
yield ForeignKey(*row)
272+
for tabular_result in self.execute_single_batch_query(query):
273+
for row in tabular_result[0]:
274+
yield ForeignKey(*row)
265275

266276
def shutdown(self):
267277
self.sql_tools_client.shutdown()

tests/mssqlutils.py

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -51,14 +51,14 @@ def run_and_return_string_from_formatter(client, sql, join=False, expanded=False
5151
:return:
5252
"""
5353

54-
rows, col, message, query, is_error = client.execute_single_batch_query(sql)
55-
settings = OutputSettings(table_format='psql', dcmlfmt='d', floatfmt='g',
56-
expanded=expanded)
57-
formatted = format_output(None, rows, col, message, settings)
58-
if join:
59-
formatted = '\n'.join(formatted)
54+
for rows, col, message, query, is_error in client.execute_single_batch_query(sql):
55+
settings = OutputSettings(table_format='psql', dcmlfmt='d', floatfmt='g',
56+
expanded=expanded)
57+
formatted = format_output(None, rows, col, message, settings)
58+
if join:
59+
formatted = '\n'.join(formatted)
6060

61-
return formatted
61+
return formatted
6262

6363

6464
def shutdown(connection):

tests/test_mssqlcliclient.py

Lines changed: 55 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -88,10 +88,9 @@ def test_get_query_results(self):
8888
select 3, 'Night'
8989
"""
9090

91-
rows, col, message, query, is_error = client.execute_single_batch_query(test_query)
92-
93-
self.assertTrue(len(rows), 3)
94-
self.assertTrue(query, test_query)
91+
for rows, col, message, query, is_error in client.execute_single_batch_query(test_query):
92+
self.assertTrue(len(rows), 3)
93+
self.assertTrue(query, test_query)
9594
finally:
9695
shutdown(client)
9796

@@ -118,11 +117,11 @@ def test_schema_table_views_and_columns_query(self):
118117
"""
119118
try:
120119
client = create_mssql_cli_client()
121-
client.execute_single_batch_query('CREATE TABLE tabletest1 (a int, b varchar(25));')
122-
client.execute_single_batch_query('CREATE TABLE tabletest2 (x int, y varchar(25), z bit);')
123-
client.execute_single_batch_query('CREATE VIEW viewtest as SELECT a from tabletest1;')
124-
client.execute_single_batch_query('CREATE SCHEMA schematest;')
125-
client.execute_single_batch_query('CREATE TABLE schematest.tabletest1 (a int);')
120+
list(client.execute_single_batch_query('CREATE TABLE tabletest1 (a int, b varchar(25));'))
121+
list(client.execute_single_batch_query('CREATE TABLE tabletest2 (x int, y varchar(25), z bit);'))
122+
list(client.execute_single_batch_query('CREATE VIEW viewtest as SELECT a from tabletest1;'))
123+
list(client.execute_single_batch_query('CREATE SCHEMA schematest;'))
124+
list(client.execute_single_batch_query('CREATE TABLE schematest.tabletest1 (a int);'))
126125

127126
assert ('schematest', 'tabletest1') in set(client.tables())
128127
assert ('dbo', 'viewtest') in set(client.views())
@@ -131,11 +130,11 @@ def test_schema_table_views_and_columns_query(self):
131130
assert 'schematest' in client.schemas()
132131

133132
finally:
134-
client.execute_single_batch_query('DROP TABLE tabletest1;')
135-
client.execute_single_batch_query('DROP TABLE tabletest2;')
136-
client.execute_single_batch_query('DROP VIEW viewtest IF EXISTS;')
137-
client.execute_single_batch_query('DROP TABLE schematest.tabletest1;')
138-
client.execute_single_batch_query('DROP SCHEMA schematest;')
133+
list(client.execute_single_batch_query('DROP TABLE tabletest1;'))
134+
list(client.execute_single_batch_query('DROP TABLE tabletest2;'))
135+
list(client.execute_single_batch_query('DROP VIEW viewtest IF EXISTS;'))
136+
list(client.execute_single_batch_query('DROP TABLE schematest.tabletest1;'))
137+
list(client.execute_single_batch_query('DROP SCHEMA schematest;'))
139138
shutdown(client)
140139

141140
def test_mssqlcliclient_reset_connection(self):
@@ -155,12 +154,54 @@ def test_mssqlcliclient_multiple_statement(self):
155154
try:
156155
client = create_mssql_cli_client()
157156
multi_statement_query = u"select 'Morning' as [Name] UNION ALL select 'Evening'; select 1;"
157+
multi_statement_query2 = u"select 1; select 'foo' from teapot;"
158+
multi_statement_query3 = u"select 'foo' from teapot; select 2;"
158159
for rows, col, message, query, is_error in \
159160
client.execute_multi_statement_single_batch(multi_statement_query):
160161
if query == u"select 'Morning' as [Name] UNION ALL select 'Evening'":
161162
self.assertTrue(len(rows), 2)
162163
else:
163164
self.assertTrue(len(rows), 1)
165+
166+
for rows, col, message, query, is_error in \
167+
client.execute_multi_statement_single_batch(multi_statement_query2):
168+
if query == u"select 1":
169+
self.assertTrue(len(rows) == 1)
170+
else:
171+
self.assertTrue(is_error)
172+
173+
for rows, col, message, query, is_error in \
174+
client.execute_multi_statement_single_batch(multi_statement_query3):
175+
if query == u"select 2":
176+
self.assertTrue(len(rows) == 1)
177+
else:
178+
self.assertTrue(is_error)
179+
180+
finally:
181+
shutdown(client)
182+
183+
def test_stored_proc_multiple_result_sets(self):
184+
"""
185+
Verify the results of running a stored proc with multiple result sets
186+
"""
187+
try:
188+
client = create_mssql_cli_client()
189+
create_stored_proc = u"CREATE PROC sp_mssqlcli_multiple_results " \
190+
u"AS " \
191+
u"BEGIN " \
192+
u"SELECT 'Morning' as [Name] UNION ALL select 'Evening' " \
193+
u"SELECT 'Dawn' as [Name] UNION ALL select 'Dusk' UNION ALL select 'Midnight' " \
194+
u"END"
195+
exec_stored_proc = u"EXEC sp_mssqlcli_multiple_results"
196+
del_stored_proc = u"DROP PROCEDURE sp_mssqlcli_multiple_results"
197+
198+
list(client.execute_single_batch_query(create_stored_proc))
199+
row_counts = []
200+
for rows, columns, message, query, is_error in client.execute_single_batch_query(exec_stored_proc):
201+
row_counts.append(len(rows))
202+
self.assertTrue(row_counts[0] == 2)
203+
self.assertTrue(row_counts[1] == 3)
204+
list(client.execute_single_batch_query(del_stored_proc))
164205
finally:
165206
shutdown(client)
166207

0 commit comments

Comments
 (0)