Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
40 commits
Select commit Hold shift + click to select a range
42663a6
for loop initial version
dusantism-db Nov 1, 2024
e7492cf
first time working
dusantism-db Nov 4, 2024
63289c7
drop local variable at end of execution
dusantism-db Nov 4, 2024
7de3e76
refactor to drop var after every iteration
dusantism-db Nov 4, 2024
91fb9ee
cleanup code
dusantism-db Nov 5, 2024
5154a48
support for FOR without variable
dusantism-db Nov 5, 2024
4ca1ed2
adding tests
dusantism-db Nov 5, 2024
130d0d1
add more tests
dusantism-db Nov 6, 2024
3335e22
add support for map
dusantism-db Nov 7, 2024
85f99e9
add support for struct, seems to work
dusantism-db Nov 7, 2024
f1e1268
clean up
dusantism-db Nov 7, 2024
e41fa94
fix comments and clean up code
dusantism-db Nov 7, 2024
57ec14b
formatting
dusantism-db Nov 7, 2024
f3e8a9c
change iterator to seq
dusantism-db Nov 7, 2024
18788c9
improve iteration logic for map args
dusantism-db Nov 7, 2024
b3c7145
add parser test
dusantism-db Nov 8, 2024
0eb6184
identation
dusantism-db Nov 8, 2024
338bb81
execution node tests
dusantism-db Nov 8, 2024
4910fc2
execution node tests - iterate and elave
dusantism-db Nov 8, 2024
9c01b57
start interpreter tests
dusantism-db Nov 8, 2024
616c94c
refactor to support column access without qualifying
dusantism-db Nov 12, 2024
78eb903
update execution node test
dusantism-db Nov 12, 2024
f498a50
add drop variables
dusantism-db Nov 13, 2024
755ebe4
fix for nested arrays, and change drop variable logic to work with le…
dusantism-db Nov 14, 2024
49017e4
add nested tests
dusantism-db Nov 18, 2024
9a2f5fa
add tests for no variables variant of for
dusantism-db Nov 19, 2024
cc632c3
clean up
dusantism-db Nov 19, 2024
d444751
update labels and tests
dusantism-db Nov 20, 2024
f78e1fc
nit
dusantism-db Nov 20, 2024
055a1b2
add unique label tests
dusantism-db Nov 20, 2024
955e79c
fix formatting and improve tests
dusantism-db Nov 21, 2024
c46750a
implement daneils suggestions
dusantism-db Nov 21, 2024
e485c99
move isExecuted out of buildDataframe
dusantism-db Nov 21, 2024
112b860
fix scalastyle
dusantism-db Nov 21, 2024
54271d0
formatting
dusantism-db Nov 21, 2024
223612e
refactor collect() to toLocalIterator()
dusantism-db Nov 22, 2024
9bf0b7a
fix scalastyle
dusantism-db Nov 25, 2024
9d1cf29
add sum test
dusantism-db Nov 26, 2024
d4de13a
Merge remote-tracking branch 'upstream/master' into scripting-for-loop
dusantism-db Nov 27, 2024
3b3aebe
fix exec node test
dusantism-db Nov 27, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ compoundStatement
| leaveStatement
| iterateStatement
| loopStatement
| forStatement
;

setStatementWithOptionalVarKeyword
Expand Down Expand Up @@ -111,6 +112,10 @@ loopStatement
: beginLabel? LOOP compoundBody END LOOP endLabel?
;

forStatement
: beginLabel? FOR (multipartIdentifier AS)? query DO compoundBody END FOR endLabel?
;

singleStatement
: (statement|setResetStatement) SEMICOLON* EOF
;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -226,6 +226,8 @@ class AstBuilder extends DataTypeAstBuilder
visitSearchedCaseStatementImpl(searchedCaseContext, labelCtx)
case simpleCaseContext: SimpleCaseStatementContext =>
visitSimpleCaseStatementImpl(simpleCaseContext, labelCtx)
case forStatementContext: ForStatementContext =>
visitForStatementImpl(forStatementContext, labelCtx)
case stmt => visit(stmt).asInstanceOf[CompoundPlanStatement]
}
} else {
Expand Down Expand Up @@ -347,28 +349,48 @@ class AstBuilder extends DataTypeAstBuilder
RepeatStatement(condition, body, Some(labelText))
}

private def visitForStatementImpl(
ctx: ForStatementContext,
labelCtx: SqlScriptingLabelContext): ForStatement = {
val labelText = labelCtx.enterLabeledScope(Option(ctx.beginLabel()), Option(ctx.endLabel()))

val queryCtx = ctx.query()
val query = withOrigin(queryCtx) {
SingleStatement(visitQuery(queryCtx))
}
val varName = Option(ctx.multipartIdentifier()).map(_.getText)
val body = visitCompoundBodyImpl(ctx.compoundBody(), None, allowVarDeclare = false, labelCtx)
labelCtx.exitLabeledScope(Option(ctx.beginLabel()))

ForStatement(query, varName, body, Some(labelText))
}

private def leaveOrIterateContextHasLabel(
ctx: RuleContext, label: String, isIterate: Boolean): Boolean = {
ctx match {
case c: BeginEndCompoundBlockContext
if Option(c.beginLabel()).isDefined &&
c.beginLabel().multipartIdentifier().getText.toLowerCase(Locale.ROOT).equals(label) =>
if (isIterate) {
if Option(c.beginLabel()).exists { b =>
b.multipartIdentifier().getText.toLowerCase(Locale.ROOT).equals(label)
} => if (isIterate) {
throw SqlScriptingErrors.invalidIterateLabelUsageForCompound(CurrentOrigin.get, label)
}
true
case c: WhileStatementContext
if Option(c.beginLabel()).isDefined &&
c.beginLabel().multipartIdentifier().getText.toLowerCase(Locale.ROOT).equals(label)
=> true
if Option(c.beginLabel()).exists { b =>
b.multipartIdentifier().getText.toLowerCase(Locale.ROOT).equals(label)
} => true
case c: RepeatStatementContext
if Option(c.beginLabel()).isDefined &&
c.beginLabel().multipartIdentifier().getText.toLowerCase(Locale.ROOT).equals(label)
=> true
if Option(c.beginLabel()).exists { b =>
b.multipartIdentifier().getText.toLowerCase(Locale.ROOT).equals(label)
} => true
case c: LoopStatementContext
if Option(c.beginLabel()).isDefined &&
c.beginLabel().multipartIdentifier().getText.toLowerCase(Locale.ROOT).equals(label)
=> true
if Option(c.beginLabel()).exists { b =>
b.multipartIdentifier().getText.toLowerCase(Locale.ROOT).equals(label)
} => true
case c: ForStatementContext
if Option(c.beginLabel()).exists { b =>
b.multipartIdentifier().getText.toLowerCase(Locale.ROOT).equals(label)
} => true
case _ => false
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -267,3 +267,31 @@ case class LoopStatement(
LoopStatement(newChildren(0).asInstanceOf[CompoundBody], label)
}
}

/**
* Logical operator for FOR statement.
* @param query Query which is executed once, then it's result set is iterated on, row by row.
* @param variableName Name of variable which is used to access the current row during iteration.
* @param body Compound body is a collection of statements that are executed for each row in
* the result set of the query.
* @param label An optional label for the loop which is unique amongst all labels for statements
* within which the FOR statement is contained.
* If an end label is specified it must match the beginning label.
* The label can be used to LEAVE or ITERATE the loop.
*/
case class ForStatement(
query: SingleStatement,
variableName: Option[String],
body: CompoundBody,
label: Option[String]) extends CompoundPlanStatement {

override def output: Seq[Attribute] = Seq.empty

override def children: Seq[LogicalPlan] = Seq(query, body)

override protected def withNewChildrenInternal(
newChildren: IndexedSeq[LogicalPlan]): LogicalPlan = newChildren match {
case IndexedSeq(query: SingleStatement, body: CompoundBody) =>
ForStatement(query, variableName, body, label)
}
}
Loading