11# -*- coding: utf-8 -*-
22import os
33
4+ import psycopg2
45import pytest
56
67from elasticapm .instrumentation import control
78from elasticapm .instrumentation .packages .psycopg2 import (PGCursorProxy ,
89 extract_signature )
910
1011try :
11- import psycopg2
12- has_psycopg2 = True
12+ from psycopg2 import sql
13+ has_sql_module = True
1314except ImportError :
14- has_psycopg2 = False
15+ # as of Jan 2018, psycopg2cffi doesn't have this module
16+ has_sql_module = False
17+
1518
1619has_postgres_configured = 'POSTGRES_DB' in os .environ
1720
@@ -37,100 +40,100 @@ def postgres_connection(request):
3740
3841
3942def test_insert ():
40- sql = """INSERT INTO mytable (id, name) VALUE ('2323', 'Ron')"""
41- actual = extract_signature (sql )
43+ sql_statement = """INSERT INTO mytable (id, name) VALUE ('2323', 'Ron')"""
44+ actual = extract_signature (sql_statement )
4245
4346 assert "INSERT INTO mytable" == actual
4447
4548
4649def test_update_with_quotes ():
47- sql = """UPDATE "my table" set name='Ron' WHERE id = 2323"""
48- actual = extract_signature (sql )
50+ sql_statement = """UPDATE "my table" set name='Ron' WHERE id = 2323"""
51+ actual = extract_signature (sql_statement )
4952
5053 assert "UPDATE my table" == actual
5154
5255
5356def test_update ():
54- sql = """update mytable set name = 'Ron where id = 'a'"""
55- actual = extract_signature (sql )
57+ sql_statement = """update mytable set name = 'Ron where id = 'a'"""
58+ actual = extract_signature (sql_statement )
5659
5760 assert "UPDATE mytable" == actual
5861
5962
6063def test_delete_simple ():
61- sql = 'DELETE FROM "mytable"'
62- actual = extract_signature (sql )
64+ sql_statement = 'DELETE FROM "mytable"'
65+ actual = extract_signature (sql_statement )
6366
6467 assert "DELETE FROM mytable" == actual
6568
6669
6770def test_delete ():
68- sql = """DELETE FROM "my table" WHERE id = 2323"""
69- actual = extract_signature (sql )
71+ sql_statement = """DELETE FROM "my table" WHERE id = 2323"""
72+ actual = extract_signature (sql_statement )
7073
7174 assert "DELETE FROM my table" == actual
7275
7376
7477def test_select_simple ():
75- sql = """SELECT id, name FROM my_table WHERE id = 2323"""
76- actual = extract_signature (sql )
78+ sql_statement = """SELECT id, name FROM my_table WHERE id = 2323"""
79+ actual = extract_signature (sql_statement )
7780
7881 assert "SELECT FROM my_table" == actual
7982
8083
8184def test_select_with_entity_quotes ():
82- sql = """SELECT id, name FROM "mytable" WHERE id = 2323"""
83- actual = extract_signature (sql )
85+ sql_statement = """SELECT id, name FROM "mytable" WHERE id = 2323"""
86+ actual = extract_signature (sql_statement )
8487
8588 assert "SELECT FROM mytable" == actual
8689
8790
8891def test_select_with_difficult_values ():
89- sql = """SELECT id, 'some name' + '" from Denmark' FROM "mytable" WHERE id = 2323"""
90- actual = extract_signature (sql )
92+ sql_statement = """SELECT id, 'some name' + '" from Denmark' FROM "mytable" WHERE id = 2323"""
93+ actual = extract_signature (sql_statement )
9194
9295 assert "SELECT FROM mytable" == actual
9396
9497
9598def test_select_with_dollar_quotes ():
96- sql = """SELECT id, $$some single doubles ' $$ + '" from Denmark' FROM "mytable" WHERE id = 2323"""
97- actual = extract_signature (sql )
99+ sql_statement = """SELECT id, $$some single doubles ' $$ + '" from Denmark' FROM "mytable" WHERE id = 2323"""
100+ actual = extract_signature (sql_statement )
98101
99102 assert "SELECT FROM mytable" == actual
100103
101104
102105def test_select_with_invalid_dollar_quotes ():
103- sql = """SELECT id, $fish$some single doubles ' $$ + '" from Denmark' FROM "mytable" WHERE id = 2323"""
104- actual = extract_signature (sql )
106+ sql_statement = """SELECT id, $fish$some single doubles ' $$ + '" from Denmark' FROM "mytable" WHERE id = 2323"""
107+ actual = extract_signature (sql_statement )
105108
106109 assert "SELECT FROM" == actual
107110
108111
109112def test_select_with_dollar_quotes_custom_token ():
110- sql = """SELECT id, $token $FROM $ FROM $ FROM single doubles ' $token $ + '" from Denmark' FROM "mytable" WHERE id = 2323"""
111- actual = extract_signature (sql )
113+ sql_statement = """SELECT id, $token $FROM $ FROM $ FROM single doubles ' $token $ + '" from Denmark' FROM "mytable" WHERE id = 2323"""
114+ actual = extract_signature (sql_statement )
112115
113116 assert "SELECT FROM mytable" == actual
114117
115118
116119def test_select_with_difficult_table_name ():
117- sql = "SELECT id FROM \" myta\n -æøåble\" WHERE id = 2323" ""
118- actual = extract_signature (sql )
120+ sql_statement = "SELECT id FROM \" myta\n -æøåble\" WHERE id = 2323" ""
121+ actual = extract_signature (sql_statement )
119122
120123 assert "SELECT FROM myta\n -æøåble" == actual
121124
122125
123126def test_select_subselect ():
124- sql = """SELECT id, name FROM (
127+ sql_statement = """SELECT id, name FROM (
125128 SELECT id, 'not a FROM ''value' FROM mytable WHERE id = 2323
126129 ) LIMIT 20"""
127- actual = extract_signature (sql )
130+ actual = extract_signature (sql_statement )
128131
129132 assert "SELECT FROM mytable" == actual
130133
131134
132135def test_select_subselect_with_alias ():
133- sql = """
136+ sql_statement = """
134137 SELECT count(*)
135138 FROM (
136139 SELECT count(id) AS some_alias, some_column
@@ -139,75 +142,76 @@ def test_select_subselect_with_alias():
139142 HAVING count(id) > 1
140143 ) AS foo
141144 """
142- actual = extract_signature (sql )
145+ actual = extract_signature (sql_statement )
143146
144147 assert "SELECT FROM mytable" == actual
145148
146149
147150def test_select_with_multiple_tables ():
148- sql = """SELECT count(table2.id)
151+ sql_statement = """SELECT count(table2.id)
149152 FROM table1, table2, table2
150153 WHERE table2.id = table1.table2_id
151154 """
152- actual = extract_signature (sql )
155+ actual = extract_signature (sql_statement )
153156 assert "SELECT FROM table1" == actual
154157
155158
156159def test_select_with_invalid_subselect ():
157- sql = "SELECT id FROM (SELECT * " ""
158- actual = extract_signature (sql )
160+ sql_statement = "SELECT id FROM (SELECT * " ""
161+ actual = extract_signature (sql_statement )
159162
160163 assert "SELECT FROM" == actual
161164
162165
163166def test_select_with_invalid_literal ():
164- sql = "SELECT 'neverending literal FROM (SELECT * FROM ..." ""
165- actual = extract_signature (sql )
167+ sql_statement = "SELECT 'neverending literal FROM (SELECT * FROM ..." ""
168+ actual = extract_signature (sql_statement )
166169
167170 assert "SELECT FROM" == actual
168171
169172
170173def test_savepoint ():
171- sql = """SAVEPOINT x_asd1234"""
172- actual = extract_signature (sql )
174+ sql_statement = """SAVEPOINT x_asd1234"""
175+ actual = extract_signature (sql_statement )
173176
174177 assert "SAVEPOINT" == actual
175178
176179
177180def test_begin ():
178- sql = """BEGIN"""
179- actual = extract_signature (sql )
181+ sql_statement = """BEGIN"""
182+ actual = extract_signature (sql_statement )
180183
181184 assert "BEGIN" == actual
182185
183186
184187def test_create_index_with_name ():
185- sql = """CREATE INDEX myindex ON mytable"""
186- actual = extract_signature (sql )
188+ sql_statement = """CREATE INDEX myindex ON mytable"""
189+ actual = extract_signature (sql_statement )
187190
188191 assert "CREATE INDEX" == actual
189192
190193
191194def test_create_index_without_name ():
192- sql = """CREATE INDEX ON mytable"""
193- actual = extract_signature (sql )
195+ sql_statement = """CREATE INDEX ON mytable"""
196+ actual = extract_signature (sql_statement )
194197
195198 assert "CREATE INDEX" == actual
196199
197200
198201def test_drop_table ():
199- sql = """DROP TABLE mytable"""
200- actual = extract_signature (sql )
202+ sql_statement = """DROP TABLE mytable"""
203+ actual = extract_signature (sql_statement )
201204
202205 assert "DROP TABLE" == actual
203206
204207
205208def test_multi_statement_sql ():
206- sql = """CREATE TABLE mytable; SELECT * FROM mytable; DROP TABLE mytable"""
207- actual = extract_signature (sql )
209+ sql_statement = """CREATE TABLE mytable; SELECT * FROM mytable; DROP TABLE mytable"""
210+ actual = extract_signature (sql_statement )
208211
209212 assert "CREATE TABLE" == actual
210213
214+
211215@pytest .mark .integrationtest
212216@pytest .mark .skipif (not has_postgres_configured , reason = "PostgresSQL not configured" )
213217def test_psycopg2_register_type (postgres_connection , elasticapm_client ):
@@ -289,3 +293,35 @@ def test_psycopg2_select_LIKE(postgres_connection, elasticapm_client):
289293 assert 'db' in span ['context' ]
290294 assert span ['context' ]['db' ]['type' ] == 'sql'
291295 assert span ['context' ]['db' ]['statement' ] == query
296+
297+
298+ @pytest .mark .integrationtest
299+ @pytest .mark .skipif (not has_postgres_configured , reason = "PostgresSQL not configured" )
300+ @pytest .mark .skipif (not has_sql_module , reason = "psycopg2.sql module missing" )
301+ def test_psycopg2_composable_query_works (postgres_connection , elasticapm_client ):
302+ """
303+ Check that we parse queries that are psycopg2.sql.Composable correctly
304+ """
305+ control .instrument ()
306+ cursor = postgres_connection .cursor ()
307+ query = sql .SQL ("SELECT * FROM {table} WHERE {row} LIKE 't%' ORDER BY {row} DESC" ).format (
308+ table = sql .Identifier ('test' ),
309+ row = sql .Identifier ('name' ),
310+ )
311+ baked_query = query .as_string (cursor .__wrapped__ )
312+ result = None
313+ try :
314+ elasticapm_client .begin_transaction ("web.django" )
315+ cursor .execute (query )
316+ result = cursor .fetchall ()
317+ elasticapm_client .end_transaction (None , "test-transaction" )
318+ finally :
319+ # make sure we've cleared out the spans for the other tests.
320+ assert [(2 , 'two' ), (3 , 'three' )] == result
321+ transactions = elasticapm_client .instrumentation_store .get_all ()
322+ spans = transactions [0 ]['spans' ]
323+ span = spans [0 ]
324+ assert span ['name' ] == 'SELECT FROM test'
325+ assert 'db' in span ['context' ]
326+ assert span ['context' ]['db' ]['type' ] == 'sql'
327+ assert span ['context' ]['db' ]['statement' ] == baked_query
0 commit comments