-
Notifications
You must be signed in to change notification settings - Fork 27
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
[RFC] Report an error when binding a column name in an ORDER BY clause #216
[RFC] Report an error when binding a column name in an ORDER BY clause #216
Conversation
DialectPreset.SQLITE_3_18 to arrayOf("src/test/fixtures", "src/test/fixtures_upsert_not_supported"), | ||
DialectPreset.SQLITE_3_24 to arrayOf("src/test/fixtures", "src/test/fixtures_sqlite_3_24"), | ||
DialectPreset.SQLITE_3_25 to arrayOf("src/test/fixtures", "src/test/fixtures_sqlite_3_24", "src/test/fixtures_sqlite_3_25"), | ||
DialectPreset.MYSQL to arrayOf("src/test/fixtures_mysql"), | ||
DialectPreset.HSQL to arrayOf("src/test/fixtures_hsql"), | ||
DialectPreset.POSTGRESQL to arrayOf("src/test/fixtures_postgresql") | ||
DialectPreset.SQLITE_3_18 to arrayOf("src/test/fixtures") | ||
) | ||
|
||
@Suppress("unused") // Used by Parameterized JUnit runner reflectively. | ||
@Parameters(name = "{0}: {1}") | ||
@JvmStatic fun parameters() = dialects.flatMap { (dialect, fixtureFolders) -> | ||
fixtureFolders.flatMap { fixtureFolder -> | ||
File(fixtureFolder).listFiles() | ||
.filter { it.isDirectory } | ||
.filter { it.isDirectory && it.name == "bind-failures" } |
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.
Pardon my harness, i.e. is there a better way to do this?
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.
to run a single test what i usually do is run all tests, and then right click the specific one I want from the intellij run panel and run just the one test. It's not a great flow, this works too
34878e4
to
21290e7
Compare
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 is perfect! just the one comment and harness revert but looks great to me
val childBindExpr = node.psi.children.find { it is SqlBindExpr } | ||
if (childBindExpr != null) { | ||
annotationHolder.createErrorAnnotation(childBindExpr, "Cannot bind the name of a column in an ORDER BY clause") | ||
} |
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.
i think you might be able to be more explicit here
val childBindExpr = node.psi.children.find { it is SqlBindExpr } | |
if (childBindExpr != null) { | |
annotationHolder.createErrorAnnotation(childBindExpr, "Cannot bind the name of a column in an ORDER BY clause") | |
} | |
if (expr is SqlBindExpr) { | |
annotationHolder.createErrorAnnotation(expr, "Cannot bind the name of a column in an ORDER BY clause") | |
} |
DialectPreset.MYSQL to arrayOf("src/test/fixtures_mysql"), | ||
DialectPreset.HSQL to arrayOf("src/test/fixtures_hsql"), | ||
DialectPreset.POSTGRESQL to arrayOf("src/test/fixtures_postgresql") | ||
DialectPreset.SQLITE_3_18 to arrayOf("src/test/fixtures") |
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.
revert
DialectPreset.SQLITE_3_18 to arrayOf("src/test/fixtures", "src/test/fixtures_upsert_not_supported"), | ||
DialectPreset.SQLITE_3_24 to arrayOf("src/test/fixtures", "src/test/fixtures_sqlite_3_24"), | ||
DialectPreset.SQLITE_3_25 to arrayOf("src/test/fixtures", "src/test/fixtures_sqlite_3_24", "src/test/fixtures_sqlite_3_25"), | ||
DialectPreset.MYSQL to arrayOf("src/test/fixtures_mysql"), | ||
DialectPreset.HSQL to arrayOf("src/test/fixtures_hsql"), | ||
DialectPreset.POSTGRESQL to arrayOf("src/test/fixtures_postgresql") | ||
DialectPreset.SQLITE_3_18 to arrayOf("src/test/fixtures") | ||
) | ||
|
||
@Suppress("unused") // Used by Parameterized JUnit runner reflectively. | ||
@Parameters(name = "{0}: {1}") | ||
@JvmStatic fun parameters() = dialects.flatMap { (dialect, fixtureFolders) -> | ||
fixtureFolders.flatMap { fixtureFolder -> | ||
File(fixtureFolder).listFiles() | ||
.filter { it.isDirectory } | ||
.filter { it.isDirectory && it.name == "bind-failures" } |
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.
to run a single test what i usually do is run all tests, and then right click the specific one I want from the intellij run panel and run just the one test. It's not a great flow, this works too
21290e7
to
7ccaa2f
Compare
val bindExpr = expr as? SqlBindExpr | ||
if (bindExpr != null) { | ||
annotationHolder.createErrorAnnotation(bindExpr, "Cannot bind the name of a column in a SELECT result-column") | ||
} |
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.
I did it like this because smartcast can't be used on expr. I can do it as a let if you think that would look better.
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.
i think this is good 👍
@@ -46,6 +50,25 @@ internal abstract class SelectStmtMixin( | |||
override fun annotate(annotationHolder: SqlAnnotationHolder) { | |||
super.annotate(annotationHolder) | |||
|
|||
val invalidBinaryEqualityBindExpr = exprList.find { child -> |
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.
its still valid to do WHERE ? = some_column
so I wouldn't want to fail here
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.
I was thinking about that. What if the failure only occurs if the RHS is also a SqlBindExpr
?
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.
I also updated to test for all binary expressions
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.
yep im cool with LHS and RHS cant both be a bind expr. I'd recommend just doing that in a new mixin for binary expressions then instead of having it live in SelectStmtMixin
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.
I can add a mixin to all the binary comparison expressions, but is there a way to add something that includes all the different types of expressions in a synthetic one?
Something like:
binary_comparison_expr ::= [ binary_boolean_expr | binary_equality_expr | binary_like_expr | is_expr | between_expr | in_expr ]
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.
that would need a ton of changes downstream so probably not ideal. you could have a single mixin kotlin class like
abstract class BinaryMixin : SqlCompositeElement(node) {
abstract fun getExprList(): List<SqlExpr>
fun annotate() {
...
}
}
and then you just have to repeat yourself in the bnf but i think thats fine
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.
Just pushed that update
val bindExpr = expr as? SqlBindExpr | ||
if (bindExpr != null) { | ||
annotationHolder.createErrorAnnotation(bindExpr, "Cannot bind the name of a column in a SELECT result-column") | ||
} |
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.
i think this is good 👍
34707a1
to
24e11af
Compare
@@ -259,12 +261,18 @@ collate_expr ::= expr COLLATE collation_name | |||
binary_like_operator ::= ( LIKE | GLOB | REGEXP | MATCH ) | |||
binary_like_expr ::= expr [ NOT ] ( binary_like_operator ) expr [ ESCAPE expr ] { | |||
mixin = "com.alecstrong.sql.psi.core.psi.mixins.BinaryLikeExprMixin" | |||
mixin = "com.alecstrong.sql.psi.core.psi.mixins.BinaryComparisonExprMixin" |
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.
Is it OK to specify two mixins like this?
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.
Looks like it's not. Pushed some changes to address that.
…r in a GROUP BY clause
24e11af
to
bafdb9b
Compare
awesome, thanks! |
reverting the result_column part: sqldelight/sqldelight#631 |
Is it possible to suppress the error just for that scenario? |
probably, i'm working on getting a release out so will wait till thats stable before working more on it in general |
also no idea why but i think this is causing memory leaks downstream: https://github.com/cashapp/sqldelight/pull/2038/checks?check_run_id=1227010895 going to revert for now to derisk the release but yea we can come back to it after |
nevermind that looks like it might be unrelated |
Attempting to address sqldelight/sqldelight#1187
@AlecStrong Is this the right approach, and does it need to be broadened to other areas besides ORDER BY?