Skip to content

Commit a3d28f2

Browse files
clslgrnctux-00
authored andcommitted
Parameter binding for client's query() method (influxdata#678)
* add bind_params to query * tutorial for bind_params
1 parent 170d47e commit a3d28f2

File tree

6 files changed

+46
-5
lines changed

6 files changed

+46
-5
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
77
## [Unreleased]
88

99
### Added
10+
- query() now accepts a bind_params argument for parameter binding (#678 thx @clslgrnc)
1011

1112
### Changed
1213
- Update test suite to add support for Python 3.7 and InfluxDB v1.6.4 and 1.7.4 (#692 thx @clslgrnc)

examples/tutorial.py

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,9 @@ def main(host='localhost', port=8086):
1313
dbname = 'example'
1414
dbuser = 'smly'
1515
dbuser_password = 'my_secret_password'
16-
query = 'select value from cpu_load_short;'
16+
query = 'select Float_value from cpu_load_short;'
17+
query_where = 'select Int_value from cpu_load_short where host=$host;'
18+
bind_params = {'host': 'server01'}
1719
json_body = [
1820
{
1921
"measurement": "cpu_load_short",
@@ -50,6 +52,11 @@ def main(host='localhost', port=8086):
5052

5153
print("Result: {0}".format(result))
5254

55+
print("Querying data: " + query_where)
56+
result = client.query(query_where, bind_params=bind_params)
57+
58+
print("Result: {0}".format(result))
59+
5360
print("Switch user: " + user)
5461
client.switch_user(user, password)
5562

influxdb/_dataframe_client.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -142,6 +142,7 @@ def write_points(self,
142142
def query(self,
143143
query,
144144
params=None,
145+
bind_params=None,
145146
epoch=None,
146147
expected_response_code=200,
147148
database=None,
@@ -153,8 +154,18 @@ def query(self,
153154
"""
154155
Query data into a DataFrame.
155156
157+
.. danger::
158+
In order to avoid injection vulnerabilities (similar to `SQL
159+
injection <https://www.owasp.org/index.php/SQL_Injection>`_
160+
vulnerabilities), do not directly include untrusted data into the
161+
``query`` parameter, use ``bind_params`` instead.
162+
156163
:param query: the actual query string
157164
:param params: additional parameters for the request, defaults to {}
165+
:param bind_params: bind parameters for the query:
166+
any variable in the query written as ``'$var_name'`` will be
167+
replaced with ``bind_params['var_name']``. Only works in the
168+
``WHERE`` clause and takes precedence over ``params['params']``
158169
:param epoch: response timestamps to be in epoch format either 'h',
159170
'm', 's', 'ms', 'u', or 'ns',defaults to `None` which is
160171
RFC3339 UTC format with nanosecond precision
@@ -172,6 +183,7 @@ def query(self,
172183
:rtype: :class:`~.ResultSet`
173184
"""
174185
query_args = dict(params=params,
186+
bind_params=bind_params,
175187
epoch=epoch,
176188
expected_response_code=expected_response_code,
177189
raise_errors=raise_errors,

influxdb/client.py

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -345,6 +345,7 @@ def _read_chunked_response(response, raise_errors=True):
345345
def query(self,
346346
query,
347347
params=None,
348+
bind_params=None,
348349
epoch=None,
349350
expected_response_code=200,
350351
database=None,
@@ -354,13 +355,25 @@ def query(self,
354355
method="GET"):
355356
"""Send a query to InfluxDB.
356357
358+
.. danger::
359+
In order to avoid injection vulnerabilities (similar to `SQL
360+
injection <https://www.owasp.org/index.php/SQL_Injection>`_
361+
vulnerabilities), do not directly include untrusted data into the
362+
``query`` parameter, use ``bind_params`` instead.
363+
357364
:param query: the actual query string
358365
:type query: str
359366
360367
:param params: additional parameters for the request,
361368
defaults to {}
362369
:type params: dict
363370
371+
:param bind_params: bind parameters for the query:
372+
any variable in the query written as ``'$var_name'`` will be
373+
replaced with ``bind_params['var_name']``. Only works in the
374+
``WHERE`` clause and takes precedence over ``params['params']``
375+
:type bind_params: dict
376+
364377
:param epoch: response timestamps to be in epoch format either 'h',
365378
'm', 's', 'ms', 'u', or 'ns',defaults to `None` which is
366379
RFC3339 UTC format with nanosecond precision
@@ -394,6 +407,11 @@ def query(self,
394407
if params is None:
395408
params = {}
396409

410+
if bind_params is not None:
411+
params_dict = json.loads(params.get('params', '{}'))
412+
params_dict.update(bind_params)
413+
params['params'] = json.dumps(params_dict)
414+
397415
params['q'] = query
398416
params['db'] = database or self._database
399417

influxdb/tests/dataframe_client_test.py

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -923,10 +923,11 @@ def test_multiquery_into_dataframe(self):
923923
expected = [{'cpu_load_short': pd1}, {'cpu_load_short': pd2}]
924924

925925
cli = DataFrameClient('host', 8086, 'username', 'password', 'db')
926-
iql = "SELECT value FROM cpu_load_short WHERE region='us-west';"\
927-
"SELECT count(value) FROM cpu_load_short WHERE region='us-west'"
926+
iql = "SELECT value FROM cpu_load_short WHERE region=$region;"\
927+
"SELECT count(value) FROM cpu_load_short WHERE region=$region"
928+
bind_params = {'region': 'us-west'}
928929
with _mocked_session(cli, 'GET', 200, data):
929-
result = cli.query(iql)
930+
result = cli.query(iql, bind_params=bind_params)
930931
for r, e in zip(result, expected):
931932
for k in e:
932933
assert_frame_equal(e[k], r[k])

influxdb/tests/server_tests/client_test_with_server.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -440,7 +440,9 @@ def test_write_points_batch(self):
440440
batch_size=2)
441441
time.sleep(5)
442442
net_in = self.cli.query("SELECT value FROM network "
443-
"WHERE direction='in'").raw
443+
"WHERE direction=$dir",
444+
bind_params={'dir': 'in'}
445+
).raw
444446
net_out = self.cli.query("SELECT value FROM network "
445447
"WHERE direction='out'").raw
446448
cpu = self.cli.query("SELECT value FROM cpu_usage").raw

0 commit comments

Comments
 (0)