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:
parent
da036f0b50
commit
b85696b1a3
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue