Skip to content

Commit 261c32a

Browse files
authored
Log query result as a table (#217)
* Log query results as a table (fix #147) * Formatting * Consistent naming of internal functions
1 parent d1f5b40 commit 261c32a

2 files changed

Lines changed: 50 additions & 11 deletions

File tree

src/DatabaseLibrary/query.py

Lines changed: 50 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -83,10 +83,11 @@ def query(
8383
try:
8484
cur = db_connection.client.cursor()
8585
logger.info(f"Executing : Query | {selectStatement} ")
86-
self.__execute_sql(cur, selectStatement, parameters=parameters)
86+
self._execute_sql(cur, selectStatement, parameters=parameters)
8787
all_rows = cur.fetchall()
88+
col_names = [c[0] for c in cur.description]
89+
self._log_query_result(col_names, all_rows)
8890
if returnAsDict:
89-
col_names = [c[0] for c in cur.description]
9091
return [dict(zip(col_names, row)) for row in all_rows]
9192
return all_rows
9293
finally:
@@ -123,13 +124,15 @@ def row_count(
123124
try:
124125
cur = db_connection.client.cursor()
125126
logger.info(f"Executing : Row Count | {selectStatement}")
126-
self.__execute_sql(cur, selectStatement, parameters=parameters)
127+
self._execute_sql(cur, selectStatement, parameters=parameters)
127128
data = cur.fetchall()
129+
col_names = [c[0] for c in cur.description]
128130
if db_connection.module_name in ["sqlite3", "ibm_db", "ibm_db_dbi", "pyodbc"]:
129131
current_row_count = len(data)
130132
else:
131133
current_row_count = cur.rowcount
132134
logger.info(f"Retrieved {current_row_count} rows")
135+
self._log_query_result(col_names, data)
133136
return current_row_count
134137
finally:
135138
if cur and not sansTran:
@@ -175,7 +178,7 @@ def description(
175178
try:
176179
cur = db_connection.client.cursor()
177180
logger.info("Executing : Description | {selectStatement}")
178-
self.__execute_sql(cur, selectStatement, parameters=parameters)
181+
self._execute_sql(cur, selectStatement, parameters=parameters)
179182
description = list(cur.description)
180183
if sys.version_info[0] < 3:
181184
for row in range(0, len(description)):
@@ -205,7 +208,7 @@ def delete_all_rows_from_table(self, tableName: str, sansTran: bool = False, ali
205208
try:
206209
cur = db_connection.client.cursor()
207210
logger.info(f"Executing : Delete All Rows From Table | {query}")
208-
result = self.__execute_sql(cur, query)
211+
result = self._execute_sql(cur, query)
209212
if result is not None:
210213
if not sansTran:
211214
db_connection.client.commit()
@@ -289,7 +292,7 @@ def execute_sql_script(
289292
logger.info(f"Executing : Execute SQL Script | {sqlScriptFileName}")
290293
if not split:
291294
logger.info("Statements splitting disabled - pass entire script content to the database module")
292-
self.__execute_sql(cur, sql_file.read())
295+
self._execute_sql(cur, sql_file.read())
293296
else:
294297
logger.info("Splitting script file into statements...")
295298
statements_to_execute = []
@@ -355,7 +358,7 @@ def execute_sql_script(
355358
logger.info(f"Executing statement from script file: {statement}")
356359
line_ends_with_proc_end = re.compile(r"(\s|;)" + proc_end_pattern.pattern + "$")
357360
omit_semicolon = not line_ends_with_proc_end.search(statement.lower())
358-
self.__execute_sql(cur, statement, omit_semicolon)
361+
self._execute_sql(cur, statement, omit_semicolon)
359362
if not sansTran:
360363
db_connection.client.commit()
361364
finally:
@@ -400,7 +403,7 @@ def execute_sql_string(
400403
try:
401404
cur = db_connection.client.cursor()
402405
logger.info(f"Executing : Execute SQL String | {sqlString}")
403-
self.__execute_sql(cur, sqlString, omit_trailing_semicolon=omitTrailingSemicolon, parameters=parameters)
406+
self._execute_sql(cur, sqlString, omit_trailing_semicolon=omitTrailingSemicolon, parameters=parameters)
404407
if not sansTran:
405408
db_connection.client.commit()
406409
finally:
@@ -549,7 +552,7 @@ def call_stored_procedure(
549552
if cur and not sansTran:
550553
db_connection.client.rollback()
551554

552-
def __execute_sql(
555+
def _execute_sql(
553556
self,
554557
cur,
555558
sql_statement: str,
@@ -573,3 +576,41 @@ def __execute_sql(
573576
else:
574577
logger.debug(f"Executing sql '{sql_statement}' with parameters: {parameters}")
575578
return cur.execute(sql_statement, parameters)
579+
580+
def _log_query_result(self, col_names, result_rows, log_head=50):
581+
"""
582+
Logs the `result_rows` of a query in RF log as a HTML table.
583+
The `col_names` are needed for the table header.
584+
Max. `log_head` rows are logged (`0` disables the limit).
585+
"""
586+
cell_border_and_align = "border: 1px solid rgb(160 160 160);padding: 8px 10px;text-align: center;"
587+
table_border = "2px solid rgb(140 140 140)"
588+
row_index_color = "#d6ecd4"
589+
msg = f'<div style="max-width: 100%; overflow-x: auto;">'
590+
msg += f'<table style="width: auto; border-collapse: collapse; border: {table_border}">'
591+
msg += f'<caption style="text-align: left; font-weight: bold; padding: 5px;">Query returned {len(result_rows)} rows</caption>'
592+
msg += "<tr>"
593+
msg += f'<th scope="col" style="background-color: {row_index_color}; {cell_border_and_align}">Row</th>'
594+
for col in col_names:
595+
msg += f'<th scope="col" style="background-color: #505050; color: #fff;{cell_border_and_align}">{col}</th>'
596+
msg += "</tr>"
597+
table_truncated = False
598+
for i, row in enumerate(result_rows):
599+
if log_head and i >= log_head:
600+
table_truncated = True
601+
break
602+
row_style = ""
603+
if i % 2 == 0:
604+
row_style = ' style="background-color: #eee;"'
605+
msg += f"<tr{row_style}>"
606+
msg += f'<th scope="row" style="background-color: {row_index_color};{cell_border_and_align}">{i}</th>'
607+
for cell in row:
608+
msg += f'<td style="{cell_border_and_align}">{cell}</td>'
609+
msg += "</tr>"
610+
msg += "</table>"
611+
if table_truncated:
612+
msg += (
613+
f'<p style="font-weight: bold;">Log limit of {log_head} rows was reached, the table was truncated</p>'
614+
)
615+
msg += "</div>"
616+
logger.info(msg, html=True)

test/tests/common_tests/assertion_retry.robot

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,6 @@ ${Tolerance} ${0.5}
1313
${Request} SELECT first_name FROM person
1414

1515
*** Test Cases ***
16-
17-
1816
Check Query Results With Timeout - Fast If DB Ready
1917
Check Query Result ${Request} contains Allan retry_timeout=${Timeout} seconds
2018
${End time}= Get Current Date

0 commit comments

Comments
 (0)