Skip to content

Commit 3f40bee

Browse files
authored
Merge pull request #250 from MarketSquare/resolve_robot_vars
Resolve robot vars
2 parents b415c99 + e8c8a32 commit 3f40bee

File tree

6 files changed

+138
-9
lines changed

6 files changed

+138
-9
lines changed

src/DatabaseLibrary/assertion.py

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -278,6 +278,7 @@ def check_row_count(
278278
retry_timeout="0 seconds",
279279
retry_pause="0.5 seconds",
280280
*,
281+
replace_robot_variables=False,
281282
selectStatement: Optional[str] = None,
282283
sansTran: Optional[bool] = None,
283284
):
@@ -298,6 +299,8 @@ def check_row_count(
298299
Use ``retry_timeout`` and ``retry_pause`` parameters to enable waiting for assertion to pass.
299300
See `Retry mechanism` for more details.
300301
302+
Set ``replace_robot_variables`` to resolve RF variables (like ${MY_VAR}) before executing the SQL.
303+
301304
=== Some parameters were renamed in version 2.0 ===
302305
The old parameters ``selectStatement`` and ``sansTran`` are *deprecated*,
303306
please use new parameters ``select_statement`` and ``no_transaction`` instead.
@@ -317,7 +320,11 @@ def check_row_count(
317320
while not check_ok:
318321
try:
319322
num_rows = self.row_count(
320-
select_statement, no_transaction=no_transaction, alias=alias, parameters=parameters
323+
select_statement,
324+
no_transaction=no_transaction,
325+
alias=alias,
326+
parameters=parameters,
327+
replace_robot_variables=replace_robot_variables,
321328
)
322329
verify_assertion(num_rows, assertion_operator, expected_value, "Wrong row count:", assertion_message)
323330
check_ok = True
@@ -343,6 +350,7 @@ def check_query_result(
343350
retry_timeout="0 seconds",
344351
retry_pause="0.5 seconds",
345352
*,
353+
replace_robot_variables=False,
346354
selectStatement: Optional[str] = None,
347355
sansTran: Optional[bool] = None,
348356
):
@@ -368,6 +376,8 @@ def check_query_result(
368376
Use ``retry_timeout`` and ``retry_pause`` parameters to enable waiting for assertion to pass.
369377
See `Retry mechanism` for more details.
370378
379+
Set ``replace_robot_variables`` to resolve RF variables (like ${MY_VAR}) before executing the SQL.
380+
371381
=== Some parameters were renamed in version 2.0 ===
372382
The old parameters ``selectStatement`` and ``sansTran`` are *deprecated*,
373383
please use new parameters ``select_statement`` and ``no_transaction`` instead.
@@ -390,7 +400,11 @@ def check_query_result(
390400
while not check_ok:
391401
try:
392402
query_results = self.query(
393-
select_statement, no_transaction=no_transaction, alias=alias, parameters=parameters
403+
select_statement,
404+
no_transaction=no_transaction,
405+
alias=alias,
406+
parameters=parameters,
407+
replace_robot_variables=replace_robot_variables,
394408
)
395409
row_count = len(query_results)
396410
assert (

src/DatabaseLibrary/query.py

Lines changed: 34 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020

2121
import sqlparse
2222
from robot.api import logger
23+
from robot.libraries.BuiltIn import BuiltIn
2324
from robot.utils.dotdict import DotDict
2425

2526
from .connection_manager import Connection
@@ -46,6 +47,7 @@ def query(
4647
alias: Optional[str] = None,
4748
parameters: Optional[Tuple] = None,
4849
*,
50+
replace_robot_variables=False,
4951
selectStatement: Optional[str] = None,
5052
sansTran: Optional[bool] = None,
5153
returnAsDict: Optional[bool] = None,
@@ -65,6 +67,8 @@ def query(
6567
Use ``parameters`` for query variable substitution (variable substitution syntax may be different
6668
depending on the database client).
6769
70+
Set ``replace_robot_variables`` to resolve RF variables (like ${MY_VAR}) before executing the SQL.
71+
6872
=== Some parameters were renamed in version 2.0 ===
6973
The old parameters ``selectStatement``, ``sansTran`` and ``returnAsDict`` are *deprecated*,
7074
please use new parameters ``select_statement``, ``no_transaction`` and ``return_dict`` instead.
@@ -88,6 +92,7 @@ def query(
8892
select_statement,
8993
parameters=parameters,
9094
omit_trailing_semicolon=db_connection.omit_trailing_semicolon,
95+
replace_robot_variables=replace_robot_variables,
9196
)
9297
all_rows = cur.fetchall()
9398
if all_rows is None:
@@ -109,6 +114,7 @@ def row_count(
109114
alias: Optional[str] = None,
110115
parameters: Optional[Tuple] = None,
111116
*,
117+
replace_robot_variables=False,
112118
selectStatement: Optional[str] = None,
113119
sansTran: Optional[bool] = None,
114120
):
@@ -123,6 +129,8 @@ def row_count(
123129
Use ``parameters`` for query variable substitution (variable substitution syntax may be different
124130
depending on the database client).
125131
132+
Set ``replace_robot_variables`` to resolve RF variables (like ${MY_VAR}) before executing the SQL.
133+
126134
=== Some parameters were renamed in version 2.0 ===
127135
The old parameters ``selectStatement`` and ``sansTran`` are *deprecated*,
128136
please use new parameters ``select_statement`` and ``no_transaction`` instead.
@@ -145,6 +153,7 @@ def row_count(
145153
select_statement,
146154
parameters=parameters,
147155
omit_trailing_semicolon=db_connection.omit_trailing_semicolon,
156+
replace_robot_variables=replace_robot_variables,
148157
)
149158
data = cur.fetchall()
150159
if data is None:
@@ -169,6 +178,7 @@ def description(
169178
alias: Optional[str] = None,
170179
parameters: Optional[Tuple] = None,
171180
*,
181+
replace_robot_variables=False,
172182
selectStatement: Optional[str] = None,
173183
sansTran: Optional[bool] = None,
174184
):
@@ -183,6 +193,8 @@ def description(
183193
Use ``parameters`` for query variable substitution (variable substitution syntax may be different
184194
depending on the database client).
185195
196+
Set ``replace_robot_variables`` to resolve RF variables (like ${MY_VAR}) before executing the SQL.
197+
186198
=== Some parameters were renamed in version 2.0 ===
187199
The old parameters ``selectStatement`` and ``sansTran`` are *deprecated*,
188200
please use new parameters ``select_statement`` and ``no_transaction`` instead.
@@ -205,6 +217,7 @@ def description(
205217
select_statement,
206218
parameters=parameters,
207219
omit_trailing_semicolon=db_connection.omit_trailing_semicolon,
220+
replace_robot_variables=replace_robot_variables,
208221
)
209222
self._commit_if_needed(db_connection, no_transaction)
210223
description = list(cur.description)
@@ -264,8 +277,9 @@ def execute_sql_script(
264277
no_transaction: bool = False,
265278
alias: Optional[str] = None,
266279
split: bool = True,
267-
external_parser=False,
268280
*,
281+
external_parser=False,
282+
replace_robot_variables=False,
269283
sqlScriptFileName: Optional[str] = None,
270284
sansTran: Optional[bool] = None,
271285
):
@@ -284,6 +298,8 @@ def execute_sql_script(
284298
285299
Use ``alias`` to specify what connection should be used if `Handling multiple database connections`.
286300
301+
Set ``replace_robot_variables`` to resolve RF variables (like ${MY_VAR}) before executing the SQL.
302+
287303
=== Some parameters were renamed in version 2.0 ===
288304
The old parameters ``sqlScriptFileName`` and ``sansTran`` are *deprecated*,
289305
please use new parameters ``script_path`` and ``no_transaction`` instead.
@@ -307,14 +323,15 @@ def execute_sql_script(
307323
cur,
308324
sql_file.read(),
309325
omit_trailing_semicolon=db_connection.omit_trailing_semicolon,
326+
replace_robot_variables=replace_robot_variables,
310327
)
311328
else:
312329
statements_to_execute = self.split_sql_script(script_path, external_parser=external_parser)
313330
for statement in statements_to_execute:
314331
proc_end_pattern = re.compile("end(?!( if;| loop;| case;| while;| repeat;)).*;()?")
315332
line_ends_with_proc_end = re.compile(r"(\s|;)" + proc_end_pattern.pattern + "$")
316333
omit_semicolon = not line_ends_with_proc_end.search(statement.lower())
317-
self._execute_sql(cur, statement, omit_semicolon)
334+
self._execute_sql(cur, statement, omit_semicolon, replace_robot_variables=replace_robot_variables)
318335
self._commit_if_needed(db_connection, no_transaction)
319336
except Exception as e:
320337
self._rollback_and_raise(db_connection, no_transaction, e)
@@ -411,6 +428,7 @@ def execute_sql_string(
411428
parameters: Optional[Tuple] = None,
412429
omit_trailing_semicolon: Optional[bool] = None,
413430
*,
431+
replace_robot_variables=False,
414432
sqlString: Optional[str] = None,
415433
sansTran: Optional[bool] = None,
416434
omitTrailingSemicolon: Optional[bool] = None,
@@ -427,7 +445,9 @@ def execute_sql_string(
427445
Use ``parameters`` for query variable substitution (variable substitution syntax may be different
428446
depending on the database client).
429447
430-
Set the ``omit_trailing_semicolon`` to explicitly control the `Omitting trailing semicolon behavior` for the command.
448+
Set ``omit_trailing_semicolon`` to explicitly control the `Omitting trailing semicolon behavior` for the command.
449+
450+
Set ``replace_robot_variables`` to resolve RF variables (like ${MY_VAR}) before executing the SQL.
431451
432452
=== Some parameters were renamed in version 2.0 ===
433453
The old parameters ``sqlString``, ``sansTran`` and ``omitTrailingSemicolon`` are *deprecated*,
@@ -449,7 +469,13 @@ def execute_sql_string(
449469
cur = db_connection.client.cursor()
450470
if omit_trailing_semicolon is None:
451471
omit_trailing_semicolon = db_connection.omit_trailing_semicolon
452-
self._execute_sql(cur, sql_string, omit_trailing_semicolon=omit_trailing_semicolon, parameters=parameters)
472+
self._execute_sql(
473+
cur,
474+
sql_string,
475+
omit_trailing_semicolon=omit_trailing_semicolon,
476+
parameters=parameters,
477+
replace_robot_variables=replace_robot_variables,
478+
)
453479
self._commit_if_needed(db_connection, no_transaction)
454480
except Exception as e:
455481
self._rollback_and_raise(db_connection, no_transaction, e)
@@ -784,16 +810,20 @@ def _execute_sql(
784810
sql_statement: str,
785811
omit_trailing_semicolon: Optional[bool] = False,
786812
parameters: Optional[Tuple] = None,
813+
replace_robot_variables=False,
787814
):
788815
"""
789816
Runs the `sql_statement` using `cur` as Cursor object.
817+
790818
Use `omit_trailing_semicolon` parameter (bool) for explicit instruction,
791819
if the trailing semicolon (;) should be removed - otherwise the statement
792820
won't be executed by some databases (e.g. Oracle).
793821
Otherwise, it's decided based on the current database module in use.
794822
"""
795823
if omit_trailing_semicolon:
796824
sql_statement = sql_statement.rstrip(";")
825+
if replace_robot_variables:
826+
sql_statement = BuiltIn().replace_variables(sql_statement)
797827
if parameters is None:
798828
logger.info(f'Executing sql:<br><code style="font-weight: bold;">{sql_statement}</code>', html=True)
799829
return cur.execute(sql_statement)

test/resources/common.resource

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ ${DB_NAME} db
1717
${DB_PASS} pass
1818
${DB_PORT} 5432
1919
${DB_USER} db_user
20+
${Script files dir} ${CURDIR}/script_file_tests
2021

2122
# used for MySQL via PyODBC only
2223
${DB_DRIVER} ODBC Driver 18 for SQL Server
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
SELECT * FROM ${PERSON_TABLE}
Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
*** Settings ***
2+
Documentation Tests which work with the same input params across all databases.
3+
4+
Resource ../../resources/common.resource
5+
6+
Suite Setup Connect To DB
7+
Suite Teardown Disconnect From Database
8+
Test Setup Create Table And Set Test Variable
9+
Test Teardown Drop Tables Person And Foobar
10+
11+
12+
*** Variables ***
13+
${Query with vars} SELECT * FROM \${PERSON_TABLE}
14+
${Script with vars} ${Script files dir}/select_with_robot_variables.sql
15+
16+
&{Error}
17+
... psycopg2=*syntax error*$*
18+
... oracledb=*$*invalid character*
19+
... pymssql=*Incorrect syntax*$*
20+
... pymysql=*error*syntax*
21+
... pyodbc=*error*syntax*
22+
... ibm_db_dbi=*Invalid SQL syntax*
23+
... sqlite3=*unrecognized token*$*
24+
25+
26+
*** Test Cases ***
27+
Query
28+
${results}= Run Keyword And Expect Error ${Error}[${DB_MODULE}]
29+
... Query ${Query with vars}
30+
${results}= Run Keyword And Expect Error ${Error}[${DB_MODULE}]
31+
... Query ${Query with vars} replace_robot_variables=False
32+
Query ${Query with vars} replace_robot_variables=True
33+
34+
SQL String
35+
Run Keyword And Expect Error ${Error}[${DB_MODULE}]
36+
... Execute Sql String ${Query with vars}
37+
Run Keyword And Expect Error ${Error}[${DB_MODULE}]
38+
... Execute Sql String ${Query with vars} replace_robot_variables=False
39+
Execute Sql String ${Query with vars} replace_robot_variables=True
40+
41+
SQL Script
42+
Run Keyword And Expect Error ${Error}[${DB_MODULE}]
43+
... Execute Sql Script ${Script with vars}
44+
Run Keyword And Expect Error ${Error}[${DB_MODULE}]
45+
... Execute Sql Script ${Script with vars} replace_robot_variables=False
46+
Execute Sql Script ${Script with vars} replace_robot_variables=True
47+
48+
Row Count
49+
${result}= Run Keyword And Expect Error ${Error}[${DB_MODULE}]
50+
... Row Count ${Query with vars}
51+
${result}= Run Keyword And Expect Error ${Error}[${DB_MODULE}]
52+
... Row Count ${Query with vars} replace_robot_variables=False
53+
${result}= Row Count ${Query with vars} replace_robot_variables=True
54+
55+
Description
56+
${result}= Run Keyword And Expect Error ${Error}[${DB_MODULE}]
57+
... Description ${Query with vars}
58+
${result}= Run Keyword And Expect Error ${Error}[${DB_MODULE}]
59+
... Description ${Query with vars} replace_robot_variables=False
60+
${result}= Description ${Query with vars} replace_robot_variables=True
61+
62+
Check Query Result
63+
Run Keyword And Expect Error ${Error}[${DB_MODULE}]
64+
... Check Query Result ${Query with vars} contains Franz Allan col=1
65+
Run Keyword And Expect Error
66+
... ${Error}[${DB_MODULE}]
67+
... Check Query Result
68+
... ${Query with vars}
69+
... contains
70+
... Franz Allan
71+
... col=1
72+
... replace_robot_variables=False
73+
Check Query Result ${Query with vars} contains Franz Allan col=1 replace_robot_variables=True
74+
75+
Check Row Count
76+
Run Keyword And Expect Error ${Error}[${DB_MODULE}]
77+
... Check Row Count ${Query with vars} == 2
78+
Run Keyword And Expect Error ${Error}[${DB_MODULE}]
79+
... Check Row Count ${Query with vars} == 2 replace_robot_variables=False
80+
Check Row Count ${Query with vars} == 2 replace_robot_variables=True
81+
82+
83+
*** Keywords ***
84+
Create Table And Set Test Variable
85+
Create Person Table And Insert Data
86+
Set Test Variable ${PERSON_TABLE} person

test/tests/common_tests/script_files.robot

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,6 @@ Suite Teardown Disconnect From Database
66
Test Setup Create Person Table
77
Test Teardown Drop Tables Person And Foobar
88

9-
*** Variables ***
10-
${Script files dir} ${CURDIR}/../../resources/script_file_tests
11-
129

1310
*** Test Cases ***
1411
Semicolons As Statement Separators In One Line

0 commit comments

Comments
 (0)