Repository navigation
refactor(jdbc): split SqlTableReference parser into focused units - #225
Merged
Merged
Conversation
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #206
Splits the 789-line
SqlTableReference.Parserinner class into focused units with no parse-rule, call-order, or error-type changes.SqlTableReferenceremains the public entry point; the split commit does not touch tests,pom.xml, orSqlTokenizer. A follow-up commit adds characterization tests for the AS-onlyRETURNINGtarget-alias rule.Unit split
SqlTableReference.javaWITH,SELECT,RETURNING,targetTable, shared records, result builderSqlCursor.javaisWordAt/isSymbolAt/identifierAt/wordAt,indexOf*,matchingParen,identifiersFromClauseParser.javaINDEXED,USING, star list,parseSourceSelectItemParser.javaTableBinding.javaSourceconstruction, including the view cycle guardResolutionBuilderreplaces the parallellabels/tableslists in the select list and the star list. Every mutation goes throughadd(label, table)oraddAll(labels, tables), which rejects a size mismatch; the star list uses the same builder, soUSING/NATURALdeletion removes a pair.Preserved invariants
Schema.definitionis still called once per source occurrence, in source order;SQLExceptionpropagates. Verified by a differential probe that logs every call (below).schema + "." + lower(table),addbefore recursion,removeinfinally.CREATE VIEWis still tokenized twice (isViewDefinitionplusresolveView), which keeps the explicit column list behaviour.(carries pre-increment depth,)post-decrement.SqlCursorcompares token depth exactly.resolve(sql, schema, columnCount)width guard is unchanged and still follows the cache-warmingresolve(sql, schema)call.parseSelectstill takes only the leftmost set-operator branch; theFROMsearch still stops atFROM_END.targetTableis still AS-only and still accepts a third dotted part; quoted identifiers still qualify as aliases. The AS-only rule is pinned by the follow-up tests below.git diff --name-only HEAD~1lists only the five parser files.Proof: normalized diff
Each moved method was compared with its old body after whitespace collapsing and these mechanical substitutions: cursor rebinding (
SqlTokenizer.nav(tokens, …, depth, …)->cursor.nav(…)orcursor.at(depth).nav(…),tokens.get(i)->cursor.token(i)),new Parser(...)->parser.onTokens(...),SourceList(List.of(new Source(...)), index)-> aTableBindingcall, andlabels.add/tables.add->ResolutionBuilder.add. 31 methods/fragments were compared;findSourceandexpressionLabelare identical after normalization, and every remaining hunk is one of those substitutions or delegations. Representative hunks per unit:SqlCursor
TableBinding (
sourcefragment moved out ofparseSource)FromClauseParser
SelectItemParser
Differential probe
A scratch probe (not committed) ran 109 statements against classes built from
origin/mainand from this branch, printingResolution.labels(),Resolution.tables(), the exactSchema.definitioncall sequence, and any thrownSQLException. The corpus covers everySqlTableReferenceTeststatement plus view chains, explicit view column lists, cyclic views, CTEs with and without column lists,USING/NATURAL, subqueries, compound selects,RETURNINGforms, malformed input, and a definition that throws. Output was byte-identical (diffempty), including the definition call order and the propagatedSQLException.RETURNING target alias coverage
Commit
test(jdbc): pin the AS-only RETURNING target alias ruleadds four tests toSqlTableReferenceTest(no production change). They assert what a caller sees: column label, table reference, and the table reference used as the nullability path.DELETE FROM w RETURNING w.aawUPDATE w x RETURNING x.aanullxis not bound;UPDATE w x RETURNING w.astill resolves towINSERT INTO w t SELECT 1 RETURNING t.aanulltis not bound;INSERT INTO w t SELECT 1 RETURNING w.astill resolves towUPDATE w AS x RETURNING x.aawASalias still binds (positive case)Probes
Probe A (depth convention) — killed. In
SqlCursor.isSymbolAtI changedtoken.depth() == depthtotoken.depth() == depth - 1, an off-by-one against the(/)convention.SqlTableReferenceTest: 34 run, 8 failures, 4 errors. Reverted and re-ran: 34/34 green.Probe B (implicit alias in
targetTable) — killed by the new tests. I addedelse { alias = cursor.identifierAt(index); }after the AS-only branch, sotargetTableaccepts an implicit alias.SqlTableReferenceTest: 38 run, 3 failures — exactlyresolvesReturningThroughTheTableNameWhenTheTargetHasNoAlias,doesNotBindAnImplicitUpdateAliasToTheReturningSource, anddoesNotBindAnImplicitInsertAliasToTheReturningSource. The explicitASpositive case and the other 34 tests in the class stayed green. The mutation was live:DELETE FROM w RETURNING w.aresolved to[null]with it and[w]without it. Reverted;git statusclean; the full suite is green at 396.Gates
./mvnw -pl libsql-jdbc -am test./mvnw spotless:applythen./mvnw spotless:check./mvnw -pl libsql-conformance -am verifyThe first JDBC run in this session raced a concurrent conformance build on the same
target/directory and reported a spurious failure; the serial reruns above are the results of record.