-
Notifications
You must be signed in to change notification settings - Fork 1k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat: support variable substitution in SQL statements #6504
Conversation
9ce2885
to
9d64a3d
Compare
throw new ParseFailedException( | ||
"Illegal argument at " + location.map(NodeLocation::toString).orElse("?") | ||
+ ". Identifier names may only contain alphanumeric values, '_' " | ||
+ "or not starting with '@'. Got: '" + value + "'", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The text is a bit confusing. You mean: "Identifier names cannot start with '@' and may only contain alphanumeric values and '_'. "
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks. That sounds much better.
Done
} | ||
|
||
@Test | ||
public void shouldThrowOnSQLInjection() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This works (identifying sql injection) because variable names must not contain spaces, etc? Basically, only alphanumeric and '_'?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Variable names do not contain spaces, but values can. However, it all depends on how to reference the values in the statement. All values must be enclosed into single-quotes, but single-quotes are not part of the value in the statement.
For instance:
// This should throw an error because ${id} has spaces.
ksql> define id = '5 and id != 5';
ksql> SELECT * FROM s1 WHERE id = ${id};
// This is a valid statement. The query will print | 5 and id != 5 | in column 1 because it is referenced inside the single-quotes, which defines the column as String.
ksql> define id = '5 and id != 5';
ksql> SELECT '${id}' FROM ...
Where is the |
87ae813
to
739bf26
Compare
@vpapavas which |
Ah ok, I got confused. I thought there are reserved words. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM
Thanks @vpapavas for the review |
Description
This is part of KLIP-38 - Variable Substitution
It implements variable substitution on SQL statements, both the Server-side and CLI-side. Variables are referenced in statements with the
${}
characters. For instance:For the CLI-side, the scope is per-session. The following example will create the
s1
stream that reads from topict1
.For the server-side, the variable scope is seen per-request. The following example will create the
s1
stream that reads from topict1
.Request 1 will create stream
s1
from topict1
:Request 2 will FAIL because
${topicName}
is not a valid topic nameVariable substitution can be enabled or disabled with the
ksql.variable.substitution.enable
configuration. It can be set in theksql-server.properties
or can be overridden from the CLI. By default istrue
.Implementation:
A new
VariableSubstitutor
class is created that replaces variables wrapped in${}
from a parsed statement (ParsedStatement
). ThisVarialbeSubstitutor
is called from the CLI to replace variables before sending to the Server; and from theKsqlEngine.prepare()
too in case there are variables defined in the KSQL request.During the CLI session, variables are substituted before sending the request to the Server. I initially thought of sending the
DEFINE
statements, but it was more work to identify the variables and create a new request with them. Doing it in the CLI saves some time on parsing.I didn't do the substitution in the
AstBuilder
because there were several places I needed to change to provide substitution. If a new syntax was added in the future, the developer would have to know about variables and call the rightvisit
orParserUtil
methods to get the variables substituted. Also, I needed to rewrite the statement text, which required more work in the builder for doing that. Having a simpleVariableSubstitutor
that returns the replaced statement text was simple.Because substitution happens by replacing text, I had to make sure of escape the single-quote characters to avoid using variables for SQL injection. The escape is done in the
ParserUtil
when called by theVariableSubstitutor
.Testing done
Added unit tests
Verified manually
Server side
Reviewer checklist