Skip to content

Adds qualifiers to function call expressions #1337

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

Merged
merged 1 commit into from
Jan 16, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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 @@ -36,7 +36,6 @@ import com.amazon.ionelement.api.loadSingleElement
import org.antlr.v4.runtime.ParserRuleContext
import org.antlr.v4.runtime.Token
import org.antlr.v4.runtime.tree.TerminalNode
import org.partiql.ast.Identifier
import org.partiql.errors.ErrorCode
import org.partiql.errors.Property
import org.partiql.errors.PropertyValueMap
Expand Down Expand Up @@ -118,7 +117,7 @@ import java.time.format.DateTimeParseException
*/
internal class PartiQLPigVisitor(
val customTypes: List<CustomType> = listOf(),
private val parameterIndexes: Map<Int, Int> = mapOf()
private val parameterIndexes: Map<Int, Int> = mapOf(),
) :
PartiQLBaseVisitor<PartiqlAst.PartiqlAstNode>() {

Expand Down Expand Up @@ -648,19 +647,22 @@ internal class PartiQLPigVisitor(
excludeTupleAttr(identifier(attr, caseSensitivity))
}

override fun visitExcludeExprCollectionIndex(ctx: PartiQLParser.ExcludeExprCollectionIndexContext) = PartiqlAst.build {
val index = ctx.index.text.toInteger().toLong()
excludeCollectionIndex(index)
}
override fun visitExcludeExprCollectionIndex(ctx: PartiQLParser.ExcludeExprCollectionIndexContext) =
PartiqlAst.build {
val index = ctx.index.text.toInteger().toLong()
excludeCollectionIndex(index)
}

override fun visitExcludeExprCollectionAttr(ctx: PartiQLParser.ExcludeExprCollectionAttrContext) = PartiqlAst.build {
val attr = ctx.attr.getStringValue()
excludeTupleAttr(identifier(attr, caseSensitive()))
}
override fun visitExcludeExprCollectionAttr(ctx: PartiQLParser.ExcludeExprCollectionAttrContext) =
PartiqlAst.build {
val attr = ctx.attr.getStringValue()
excludeTupleAttr(identifier(attr, caseSensitive()))
}

override fun visitExcludeExprCollectionWildcard(ctx: PartiQLParser.ExcludeExprCollectionWildcardContext) = PartiqlAst.build {
excludeCollectionWildcard()
}
override fun visitExcludeExprCollectionWildcard(ctx: PartiQLParser.ExcludeExprCollectionWildcardContext) =
PartiqlAst.build {
excludeCollectionWildcard()
}

override fun visitExcludeExprTupleWildcard(ctx: PartiQLParser.ExcludeExprTupleWildcardContext) = PartiqlAst.build {
excludeTupleWildcard()
Expand Down Expand Up @@ -1292,17 +1294,20 @@ internal class PartiQLPigVisitor(
canLosslessCast(expr, type, metas)
}

override fun visitFunctionCallIdent(ctx: PartiQLParser.FunctionCallIdentContext) = PartiqlAst.build {
val name = ctx.name.getString().lowercase()
val args = ctx.expr().map { visitExpr(it) }
val metas = ctx.name.getSourceMetaContainer()
call(name, args = args, metas = metas)
}

override fun visitFunctionCallReserved(ctx: PartiQLParser.FunctionCallReservedContext) = PartiqlAst.build {
val name = ctx.name.text.lowercase()
override fun visitFunctionCall(ctx: PartiQLParser.FunctionCallContext) = PartiqlAst.build {
val name = when (val nameCtx = ctx.functionName()) {
is PartiQLParser.FunctionNameReservedContext -> {
if (nameCtx.qualifier.isNotEmpty()) error("Legacy AST does not support qualified function names")
nameCtx.name.text.lowercase()
}
is PartiQLParser.FunctionNameSymbolContext -> {
if (nameCtx.qualifier.isNotEmpty()) error("Legacy AST does not support qualified function names")
nameCtx.name.getString().lowercase()
}
else -> error("Expected context FunctionNameReserved or FunctionNameSymbol")
}
val args = ctx.expr().map { visitExpr(it) }
val metas = ctx.name.getSourceMetaContainer()
val metas = ctx.start.getSourceMetaContainer()
call(name, args = args, metas = metas)
}

Expand Down Expand Up @@ -1693,7 +1698,7 @@ internal class PartiQLPigVisitor(
lhs: ParserRuleContext?,
rhs: ParserRuleContext?,
op: Token?,
parent: ParserRuleContext? = null
parent: ParserRuleContext? = null,
) = PartiqlAst.build {
if (parent != null) return@build visit(parent) as PartiqlAst.Expr
val args = listOf(lhs!!, rhs!!).map { visit(it) as PartiqlAst.Expr }
Expand Down Expand Up @@ -1847,7 +1852,7 @@ internal class PartiQLPigVisitor(
withTimeZone: Boolean,
precision: Long,
stringNode: TerminalNode,
timeNode: TerminalNode
timeNode: TerminalNode,
) = PartiqlAst.build {
val time: LocalTime
val formatter = when (withTimeZone) {
Expand All @@ -1871,7 +1876,7 @@ internal class PartiQLPigVisitor(

private fun getTimestampStringAndPrecision(
stringNode: TerminalNode,
integerNode: TerminalNode?
integerNode: TerminalNode?,
): Pair<String, Long?> {
val timestampString = stringNode.getStringValue()
val precision = when (integerNode) {
Expand All @@ -1890,7 +1895,7 @@ internal class PartiQLPigVisitor(
private fun getTimestampDynamic(
timestampString: String,
precision: Long?,
node: TerminalNode
node: TerminalNode,
) = PartiqlAst.build {
val timestamp =
try {
Expand All @@ -1901,17 +1906,22 @@ internal class PartiQLPigVisitor(
val timeZone = timestamp.timeZone?.let { getTimeZone(it) }
timestamp(
timestampValue(
timestamp.year.toLong(), timestamp.month.toLong(), timestamp.day.toLong(),
timestamp.hour.toLong(), timestamp.minute.toLong(), ionDecimal(Decimal.valueOf(timestamp.decimalSecond)),
timeZone, precision
timestamp.year.toLong(),
timestamp.month.toLong(),
timestamp.day.toLong(),
timestamp.hour.toLong(),
timestamp.minute.toLong(),
ionDecimal(Decimal.valueOf(timestamp.decimalSecond)),
timeZone,
precision
)
)
}

private fun getTimestampWithTimezone(
timestampString: String,
precision: Long?,
node: TerminalNode
node: TerminalNode,
) = PartiqlAst.build {
val timestamp = try {
DateTimeUtils.parseTimestamp(timestampString)
Expand All @@ -1926,9 +1936,14 @@ internal class PartiQLPigVisitor(
val timeZone = timestamp.timeZone?.let { getTimeZone(it) }
timestamp(
timestampValue(
timestamp.year.toLong(), timestamp.month.toLong(), timestamp.day.toLong(),
timestamp.hour.toLong(), timestamp.minute.toLong(), ionDecimal(Decimal.valueOf(timestamp.decimalSecond)),
timeZone, precision
timestamp.year.toLong(),
timestamp.month.toLong(),
timestamp.day.toLong(),
timestamp.hour.toLong(),
timestamp.minute.toLong(),
ionDecimal(Decimal.valueOf(timestamp.decimalSecond)),
timeZone,
precision
)
)
}
Expand Down Expand Up @@ -2124,13 +2139,13 @@ internal class PartiQLPigVisitor(
msg: String,
code: ErrorCode,
ctx: PropertyValueMap = PropertyValueMap(),
cause: Throwable? = null
cause: Throwable? = null,
) = this.error(msg, code, ctx, cause)

private fun Token?.err(
msg: String,
code: ErrorCode,
ctx: PropertyValueMap = PropertyValueMap(),
cause: Throwable? = null
cause: Throwable? = null,
) = this.error(msg, code, ctx, cause)
}
12 changes: 8 additions & 4 deletions partiql-parser/src/main/antlr/PartiQL.g4
Original file line number Diff line number Diff line change
Expand Up @@ -709,11 +709,15 @@ trimFunction
dateFunction
: func=(DATE_ADD|DATE_DIFF) PAREN_LEFT dt=IDENTIFIER COMMA expr COMMA expr PAREN_RIGHT;

// SQL-99 10.4 — <routine invocation> ::= <routine name> <SQL argument list>
functionCall
: name=( CHAR_LENGTH | CHARACTER_LENGTH | OCTET_LENGTH |
BIT_LENGTH | UPPER | LOWER | SIZE | EXISTS | COUNT )
PAREN_LEFT ( expr ( COMMA expr )* )? PAREN_RIGHT # FunctionCallReserved
| name=symbolPrimitive PAREN_LEFT ( expr ( COMMA expr )* )? PAREN_RIGHT # FunctionCallIdent
: functionName PAREN_LEFT ( expr ( COMMA expr )* )? PAREN_RIGHT
;

// SQL-99 10.4 — <routine name> ::= [ <schema name> <period> ] <qualified identifier>
functionName
: (qualifier+=symbolPrimitive PERIOD)* name=( CHAR_LENGTH | CHARACTER_LENGTH | OCTET_LENGTH | BIT_LENGTH | UPPER | LOWER | SIZE | EXISTS | COUNT ) # FunctionNameReserved
| (qualifier+=symbolPrimitive PERIOD)* name=symbolPrimitive # FunctionNameSymbol
;

pathStep
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
package org.partiql.parser

import org.partiql.ast.Statement
import org.partiql.parser.impl.PartiQLParserDefault
import org.partiql.parser.internal.PartiQLParserDefault

public interface PartiQLParser {

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@

package org.partiql.parser

import org.partiql.parser.impl.PartiQLParserDefault
import org.partiql.parser.internal.PartiQLParserDefault

/**
* A builder class to instantiate a [PartiQLParser].
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
* language governing permissions and limitations under the License.
*/

package org.partiql.parser.impl
package org.partiql.parser.internal

import com.amazon.ionelement.api.IntElement
import com.amazon.ionelement.api.IntElementSize
Expand Down Expand Up @@ -118,6 +118,7 @@ import org.partiql.ast.graphMatchSelectorShortestK
import org.partiql.ast.graphMatchSelectorShortestKGroup
import org.partiql.ast.groupBy
import org.partiql.ast.groupByKey
import org.partiql.ast.identifierQualified
import org.partiql.ast.identifierSymbol
import org.partiql.ast.let
import org.partiql.ast.letBinding
Expand Down Expand Up @@ -208,7 +209,7 @@ import org.partiql.parser.PartiQLSyntaxException
import org.partiql.parser.SourceLocation
import org.partiql.parser.SourceLocations
import org.partiql.parser.antlr.PartiQLBaseVisitor
import org.partiql.parser.impl.util.DateTimeUtils
import org.partiql.parser.internal.util.DateTimeUtils
import org.partiql.value.NumericValue
import org.partiql.value.PartiQLValueExperimental
import org.partiql.value.StringValue
Expand Down Expand Up @@ -1723,16 +1724,34 @@ internal class PartiQLParserDefault : PartiQLParser {
exprCanLosslessCast(expr, type)
}

override fun visitFunctionCallIdent(ctx: GeneratedParser.FunctionCallIdentContext) = translate(ctx) {
val function = visitSymbolPrimitive(ctx.name)
override fun visitFunctionCall(ctx: GeneratedParser.FunctionCallContext) = translate(ctx) {
val function = visit(ctx.functionName()) as Identifier
val args = visitOrEmpty<Expr>(ctx.expr())
exprCall(function, args)
}

override fun visitFunctionCallReserved(ctx: GeneratedParser.FunctionCallReservedContext) = translate(ctx) {
val function = ctx.name.text.toIdentifier()
val args = visitOrEmpty<Expr>(ctx.expr())
exprCall(function, args)
override fun visitFunctionNameReserved(ctx: GeneratedParser.FunctionNameReservedContext): Identifier {
val path = ctx.qualifier.map { visitSymbolPrimitive(it) }
val name = identifierSymbol(ctx.name.text, Identifier.CaseSensitivity.INSENSITIVE)
return if (path.isEmpty()) {
name
} else {
val root = path.first()
val steps = path.drop(1) + listOf(name)
identifierQualified(root, steps)
}
}

override fun visitFunctionNameSymbol(ctx: GeneratedParser.FunctionNameSymbolContext): Identifier {
val path = ctx.qualifier.map { visitSymbolPrimitive(it) }
val name = visitSymbolPrimitive(ctx.name)
return if (path.isEmpty()) {
name
} else {
val root = path.first()
val steps = path.drop(1) + listOf(name)
identifierQualified(root, steps)
}
}

/**
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package org.partiql.parser.impl.util
package org.partiql.parser.internal.util

import org.partiql.value.datetime.Date
import org.partiql.value.datetime.DateTimeException
Expand Down
Loading