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
This commit is contained in:
Lauri Tulmin 2022-03-29 10:48:51 +03:00 committed by GitHub
parent da036f0b50
commit b85696b1a3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 49 additions and 17 deletions

View File

@ -16,18 +16,19 @@ package io.opentelemetry.instrumentation.api.db;
%unicode
%ignorecase
COMMA = ","
OPEN_PAREN = "("
CLOSE_PAREN = ")"
OPEN_COMMENT = "/*"
CLOSE_COMMENT = "*/"
IDENTIFIER = ([:letter:] | "_") ([:letter:] | [0-9] | [_.])*
BASIC_NUM = [.+-]* [0-9] ([0-9] | [eE.+-])*
HEX_NUM = "0x" ([a-f] | [A-F] | [0-9])+
QUOTED_STR = "'" ("''" | [^'])* "'"
DOUBLE_QUOTED_STR = "\"" ("\"\"" | [^\"])* "\""
DOLLAR_QUOTED_STR = "$$" [^$]* "$$"
WHITESPACE = [ \t\r\n]+
COMMA = ","
OPEN_PAREN = "("
CLOSE_PAREN = ")"
OPEN_COMMENT = "/*"
CLOSE_COMMENT = "*/"
IDENTIFIER = ([:letter:] | "_") ([:letter:] | [0-9] | [_.])*
BASIC_NUM = [.+-]* [0-9] ([0-9] | [eE.+-])*
HEX_NUM = "0x" ([a-f] | [A-F] | [0-9])+
QUOTED_STR = "'" ("''" | [^'])* "'"
DOUBLE_QUOTED_STR = "\"" ("\"\"" | [^\"])* "\""
DOLLAR_QUOTED_STR = "$$" [^$]* "$$"
BACKTICK_QUOTED_STR = "`" [^`]* "`"
WHITESPACE = [ \t\r\n]+
%{
static SqlStatementInfo sanitize(String statement, SqlDialect dialect) {
@ -61,6 +62,16 @@ WHITESPACE = [ \t\r\n]+
return builder.length() > LIMIT;
}
/** @return text matched by current token without enclosing double quotes or backticks */
private String readTableName() {
String tableName = yytext();
if (tableName != null && ((tableName.startsWith("\"") && tableName.endsWith("\""))
|| (tableName.startsWith("`") && tableName.endsWith("`")))) {
tableName = tableName.substring(1, tableName.length() - 1);
}
return tableName;
}
// you can reference a table in the FROM clause in one of the following ways:
// table
// table t
@ -172,7 +183,7 @@ WHITESPACE = [ \t\r\n]+
return true;
}
mainTable = yytext();
mainTable = readTableName();
mainTableSetAlready = true;
expectingTableName = false;
// start counting identifiers after encountering main from clause
@ -208,7 +219,7 @@ WHITESPACE = [ \t\r\n]+
return false;
}
mainTable = yytext();
mainTable = readTableName();
return true;
}
}
@ -226,21 +237,21 @@ WHITESPACE = [ \t\r\n]+
return false;
}
mainTable = yytext();
mainTable = readTableName();
return true;
}
}
private class Update extends Operation {
boolean handleIdentifier() {
mainTable = yytext();
mainTable = readTableName();
return true;
}
}
private class Merge extends Operation {
boolean handleIdentifier() {
mainTable = yytext();
mainTable = readTableName();
return true;
}
}
@ -372,11 +383,22 @@ WHITESPACE = [ \t\r\n]+
if (dialect == SqlDialect.COUCHBASE) {
builder.append('?');
} else {
if (!insideComment && !extractionDone) {
extractionDone = operation.handleIdentifier();
}
appendCurrentFragment();
}
if (isOverLimit()) return YYEOF;
}
{BACKTICK_QUOTED_STR} {
if (!insideComment && !extractionDone) {
extractionDone = operation.handleIdentifier();
}
appendCurrentFragment();
if (isOverLimit()) return YYEOF;
}
{WHITESPACE} {
builder.append(' ');
if (isOverLimit()) return YYEOF;

View File

@ -105,6 +105,8 @@ class SqlStatementSanitizerTest extends Specification {
sql | expected
// Select
'SELECT x, y, z FROM schema.table' | SqlStatementInfo.create(sql, 'SELECT', 'schema.table')
'SELECT x, y, z FROM `schema table`' | SqlStatementInfo.create(sql, 'SELECT', 'schema table')
'SELECT x, y, z FROM "schema table"' | SqlStatementInfo.create(sql, 'SELECT', 'schema table')
'WITH subquery as (select a from b) SELECT x, y, z FROM table' | SqlStatementInfo.create(sql, 'SELECT', null)
'SELECT x, y, (select a from b) as z FROM table' | SqlStatementInfo.create(sql, 'SELECT', null)
'select delete, insert into, merge, update from table' | SqlStatementInfo.create(sql, 'SELECT', 'table')
@ -131,16 +133,24 @@ class SqlStatementSanitizerTest extends Specification {
' insert into table where lalala' | SqlStatementInfo.create(sql, 'INSERT', 'table')
'insert insert into table where lalala' | SqlStatementInfo.create(sql, 'INSERT', 'table')
'insert into db.table where lalala' | SqlStatementInfo.create(sql, 'INSERT', 'db.table')
'insert into `db table` where lalala' | SqlStatementInfo.create(sql, 'INSERT', 'db table')
'insert into "db table" where lalala' | SqlStatementInfo.create(sql, 'INSERT', 'db table')
'insert without i-n-t-o' | SqlStatementInfo.create(sql, 'INSERT', null)
// Delete
'delete from table where something something' | SqlStatementInfo.create(sql, 'DELETE', 'table')
'delete from `my table` where something something' | SqlStatementInfo.create(sql, 'DELETE', 'my table')
'delete from "my table" where something something' | SqlStatementInfo.create(sql, 'DELETE', 'my table')
'delete from 12345678' | SqlStatementInfo.create('delete from ?', 'DELETE', null)
'delete (((' | SqlStatementInfo.create('delete (((', 'DELETE', null)
// Update
'update table set answer=42' | SqlStatementInfo.create('update table set answer=?', 'UPDATE', 'table')
'update `my table` set answer=42' | SqlStatementInfo.create('update `my table` set answer=?', 'UPDATE', 'my table')
'update "my table" set answer=42' | SqlStatementInfo.create('update "my table" set answer=?', 'UPDATE', 'my table')
'update /*table' | SqlStatementInfo.create(sql, 'UPDATE', null)
// Merge
'merge into table' | SqlStatementInfo.create(sql, 'MERGE', 'table')
'merge into `my table`' | SqlStatementInfo.create(sql, 'MERGE', 'my table')
'merge into "my table"' | SqlStatementInfo.create(sql, 'MERGE', 'my table')
'merge table (into is optional in some dbs)' | SqlStatementInfo.create(sql, 'MERGE', 'table')
'merge (into )))' | SqlStatementInfo.create(sql, 'MERGE', null)
// Unknown operation