diff --git a/instrumentation-api/src/main/jflex/SqlSanitizer.jflex b/instrumentation-api/src/main/jflex/SqlSanitizer.jflex index 3c3767498f..e4a8a664af 100644 --- a/instrumentation-api/src/main/jflex/SqlSanitizer.jflex +++ b/instrumentation-api/src/main/jflex/SqlSanitizer.jflex @@ -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; diff --git a/instrumentation-api/src/test/groovy/io/opentelemetry/instrumentation/api/db/SqlStatementSanitizerTest.groovy b/instrumentation-api/src/test/groovy/io/opentelemetry/instrumentation/api/db/SqlStatementSanitizerTest.groovy index 13f58f5db9..a126b2a312 100644 --- a/instrumentation-api/src/test/groovy/io/opentelemetry/instrumentation/api/db/SqlStatementSanitizerTest.groovy +++ b/instrumentation-api/src/test/groovy/io/opentelemetry/instrumentation/api/db/SqlStatementSanitizerTest.groovy @@ -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