Skip to content

Commit b85696b

Browse files
authored
Sql sanitizer: handle double quoted table names (#5699)
* Sql sanitizer: handle double quoted table names * handle backtick * strip double quotes and backtick from table name in a separate method
1 parent da036f0 commit b85696b

File tree

2 files changed

+49
-17
lines changed

2 files changed

+49
-17
lines changed

instrumentation-api/src/main/jflex/SqlSanitizer.jflex

Lines changed: 39 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -16,18 +16,19 @@ package io.opentelemetry.instrumentation.api.db;
1616
%unicode
1717
%ignorecase
1818

19-
COMMA = ","
20-
OPEN_PAREN = "("
21-
CLOSE_PAREN = ")"
22-
OPEN_COMMENT = "/*"
23-
CLOSE_COMMENT = "*/"
24-
IDENTIFIER = ([:letter:] | "_") ([:letter:] | [0-9] | [_.])*
25-
BASIC_NUM = [.+-]* [0-9] ([0-9] | [eE.+-])*
26-
HEX_NUM = "0x" ([a-f] | [A-F] | [0-9])+
27-
QUOTED_STR = "'" ("''" | [^'])* "'"
28-
DOUBLE_QUOTED_STR = "\"" ("\"\"" | [^\"])* "\""
29-
DOLLAR_QUOTED_STR = "$$" [^$]* "$$"
30-
WHITESPACE = [ \t\r\n]+
19+
COMMA = ","
20+
OPEN_PAREN = "("
21+
CLOSE_PAREN = ")"
22+
OPEN_COMMENT = "/*"
23+
CLOSE_COMMENT = "*/"
24+
IDENTIFIER = ([:letter:] | "_") ([:letter:] | [0-9] | [_.])*
25+
BASIC_NUM = [.+-]* [0-9] ([0-9] | [eE.+-])*
26+
HEX_NUM = "0x" ([a-f] | [A-F] | [0-9])+
27+
QUOTED_STR = "'" ("''" | [^'])* "'"
28+
DOUBLE_QUOTED_STR = "\"" ("\"\"" | [^\"])* "\""
29+
DOLLAR_QUOTED_STR = "$$" [^$]* "$$"
30+
BACKTICK_QUOTED_STR = "`" [^`]* "`"
31+
WHITESPACE = [ \t\r\n]+
3132

3233
%{
3334
static SqlStatementInfo sanitize(String statement, SqlDialect dialect) {
@@ -61,6 +62,16 @@ WHITESPACE = [ \t\r\n]+
6162
return builder.length() > LIMIT;
6263
}
6364

65+
/** @return text matched by current token without enclosing double quotes or backticks */
66+
private String readTableName() {
67+
String tableName = yytext();
68+
if (tableName != null && ((tableName.startsWith("\"") && tableName.endsWith("\""))
69+
|| (tableName.startsWith("`") && tableName.endsWith("`")))) {
70+
tableName = tableName.substring(1, tableName.length() - 1);
71+
}
72+
return tableName;
73+
}
74+
6475
// you can reference a table in the FROM clause in one of the following ways:
6576
// table
6677
// table t
@@ -172,7 +183,7 @@ WHITESPACE = [ \t\r\n]+
172183
return true;
173184
}
174185

175-
mainTable = yytext();
186+
mainTable = readTableName();
176187
mainTableSetAlready = true;
177188
expectingTableName = false;
178189
// start counting identifiers after encountering main from clause
@@ -208,7 +219,7 @@ WHITESPACE = [ \t\r\n]+
208219
return false;
209220
}
210221

211-
mainTable = yytext();
222+
mainTable = readTableName();
212223
return true;
213224
}
214225
}
@@ -226,21 +237,21 @@ WHITESPACE = [ \t\r\n]+
226237
return false;
227238
}
228239

229-
mainTable = yytext();
240+
mainTable = readTableName();
230241
return true;
231242
}
232243
}
233244

234245
private class Update extends Operation {
235246
boolean handleIdentifier() {
236-
mainTable = yytext();
247+
mainTable = readTableName();
237248
return true;
238249
}
239250
}
240251

241252
private class Merge extends Operation {
242253
boolean handleIdentifier() {
243-
mainTable = yytext();
254+
mainTable = readTableName();
244255
return true;
245256
}
246257
}
@@ -372,11 +383,22 @@ WHITESPACE = [ \t\r\n]+
372383
if (dialect == SqlDialect.COUCHBASE) {
373384
builder.append('?');
374385
} else {
386+
if (!insideComment && !extractionDone) {
387+
extractionDone = operation.handleIdentifier();
388+
}
375389
appendCurrentFragment();
376390
}
377391
if (isOverLimit()) return YYEOF;
378392
}
379393

394+
{BACKTICK_QUOTED_STR} {
395+
if (!insideComment && !extractionDone) {
396+
extractionDone = operation.handleIdentifier();
397+
}
398+
appendCurrentFragment();
399+
if (isOverLimit()) return YYEOF;
400+
}
401+
380402
{WHITESPACE} {
381403
builder.append(' ');
382404
if (isOverLimit()) return YYEOF;

instrumentation-api/src/test/groovy/io/opentelemetry/instrumentation/api/db/SqlStatementSanitizerTest.groovy

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,8 @@ class SqlStatementSanitizerTest extends Specification {
105105
sql | expected
106106
// Select
107107
'SELECT x, y, z FROM schema.table' | SqlStatementInfo.create(sql, 'SELECT', 'schema.table')
108+
'SELECT x, y, z FROM `schema table`' | SqlStatementInfo.create(sql, 'SELECT', 'schema table')
109+
'SELECT x, y, z FROM "schema table"' | SqlStatementInfo.create(sql, 'SELECT', 'schema table')
108110
'WITH subquery as (select a from b) SELECT x, y, z FROM table' | SqlStatementInfo.create(sql, 'SELECT', null)
109111
'SELECT x, y, (select a from b) as z FROM table' | SqlStatementInfo.create(sql, 'SELECT', null)
110112
'select delete, insert into, merge, update from table' | SqlStatementInfo.create(sql, 'SELECT', 'table')
@@ -131,16 +133,24 @@ class SqlStatementSanitizerTest extends Specification {
131133
' insert into table where lalala' | SqlStatementInfo.create(sql, 'INSERT', 'table')
132134
'insert insert into table where lalala' | SqlStatementInfo.create(sql, 'INSERT', 'table')
133135
'insert into db.table where lalala' | SqlStatementInfo.create(sql, 'INSERT', 'db.table')
136+
'insert into `db table` where lalala' | SqlStatementInfo.create(sql, 'INSERT', 'db table')
137+
'insert into "db table" where lalala' | SqlStatementInfo.create(sql, 'INSERT', 'db table')
134138
'insert without i-n-t-o' | SqlStatementInfo.create(sql, 'INSERT', null)
135139
// Delete
136140
'delete from table where something something' | SqlStatementInfo.create(sql, 'DELETE', 'table')
141+
'delete from `my table` where something something' | SqlStatementInfo.create(sql, 'DELETE', 'my table')
142+
'delete from "my table" where something something' | SqlStatementInfo.create(sql, 'DELETE', 'my table')
137143
'delete from 12345678' | SqlStatementInfo.create('delete from ?', 'DELETE', null)
138144
'delete (((' | SqlStatementInfo.create('delete (((', 'DELETE', null)
139145
// Update
140146
'update table set answer=42' | SqlStatementInfo.create('update table set answer=?', 'UPDATE', 'table')
147+
'update `my table` set answer=42' | SqlStatementInfo.create('update `my table` set answer=?', 'UPDATE', 'my table')
148+
'update "my table" set answer=42' | SqlStatementInfo.create('update "my table" set answer=?', 'UPDATE', 'my table')
141149
'update /*table' | SqlStatementInfo.create(sql, 'UPDATE', null)
142150
// Merge
143151
'merge into table' | SqlStatementInfo.create(sql, 'MERGE', 'table')
152+
'merge into `my table`' | SqlStatementInfo.create(sql, 'MERGE', 'my table')
153+
'merge into "my table"' | SqlStatementInfo.create(sql, 'MERGE', 'my table')
144154
'merge table (into is optional in some dbs)' | SqlStatementInfo.create(sql, 'MERGE', 'table')
145155
'merge (into )))' | SqlStatementInfo.create(sql, 'MERGE', null)
146156
// Unknown operation

0 commit comments

Comments
 (0)