Skip to content

Commit

Permalink
Adds syntactical support for CREATE FUNCTION
Browse files Browse the repository at this point in the history
  • Loading branch information
johnedquinn committed Aug 16, 2023
1 parent eb0b72e commit 8b30752
Show file tree
Hide file tree
Showing 117 changed files with 1,312 additions and 0 deletions.
60 changes: 60 additions & 0 deletions partiql-ast/src/main/resources/partiql_ast.ion
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,33 @@ statement::[
definition: optional::table_definition,
},

// CREATE FUNCTION
create_function::{
specification: specification,
body: routine_body,
_: [
specification::{
name: '.identifier.qualified',
parameters: list::[parameter_declaration],
returns: returns,
characteristics: list::[routine_characteristic],
},
parameter_declaration::{
name: optional::'.identifier.symbol',
type: '.type'
},
// SQL:1999
// <returns clause> ::= RETURNS <returns data type> [ <result cast> ]
// <returns data type> ::= <data type> [ <locator indication> ]
// <result cast> ::= CAST FROM <result cast from type>
// <result cast from type> ::= <data type> [ <locator indication> ]
// TODO: Eventually add other grammatical rules here
returns::{
type: '.type'
}
]
},

// CREATE INDEX [<identifier>] ON <identifier> (<path> [, <path>]...)
create_index::{
index: optional::identifier,
Expand All @@ -133,6 +160,19 @@ statement::[
},
],

// SQL:1999
// <SQL control statement> ::=
// <call statement>
// | <return statement>
// <return statement> ::=
// RETURN <return value>
// <return value> ::=
// <value expression>
// | NULL
return::{
value: expr
},

// EXEC <symbol> [<expr>.*]
exec::{
procedure: string,
Expand All @@ -149,6 +189,26 @@ statement::[
},
],
},

_::[
// SQL:1999
// <routine body> ::=
// <SQL routine body> <-- nicknaming this `internal`
// | <external body reference> <-- nicknaming this `external`
routine_body::[
// SQL:1999
// <SQL routine body> (nicknamed `internal`) ::= <SQL procedure statement>
// Note: Semantic pass should ensure the statement is a procedure statement.
internal::{
procedure_statement: statement
}
],
routine_characteristic::[
specific::{
name: '.identifier.qualified'
}
]
]
]

// PartiQL Type AST nodes
Expand Down
145 changes: 145 additions & 0 deletions partiql-parser/src/main/antlr/PartiQL.g4
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,153 @@ statement
| dml COLON_SEMI? EOF # QueryDml
| ddl COLON_SEMI? EOF # QueryDdl
| execCommand COLON_SEMI? EOF # QueryExec
| sqlInvokedRoutine # CreateRoutineStatement
;

// SQL:1999
// <SQL-invoked routine> ::= <schema routine>
sqlInvokedRoutine
: schemaRoutine
;

// SQL:1999
// <schema routine> ::=
// <schema procedure>
// | <schema function>
schemaRoutine
: schemaFunction
;

// SQL:1999
// <schema function> ::=
// CREATE <SQL-invoked function>
schemaFunction
: CREATE sqlInvokedFunction
;

// SQL:1999
// <SQL-invoked function> ::=
// { <function specification> | <method specification designator> }
// <routine body>
sqlInvokedFunction
:
(
functionSpecification
) routineBody
;

// SQL:1999
// <function specification> ::=
// FUNCTION <schema qualified routine name>
// <SQL parameter declaration list>
// <returns clause>
// <routine characteristics>
// [ <dispatch clause> ]
functionSpecification
: FUNCTION name=symbolPrimitive // FIXME: Should be schemaQualifiedRoutineName
sqlParameterDeclarationList
returnsClause
routineCharacteristic*
;

// SQL:1999
// <routine characteristic> ::=
// SPECIFIC <specific name>
// | and many more...
routineCharacteristic
: SPECIFIC specificName
;

// SQL:1999
// <specific name> ::= <schema qualified name>
specificName
: name=symbolPrimitive // FIXME: should be ```schemaQualifiedName```
;

// SQL:1999
// <returns clause> ::= RETURNS <returns data type> [ <result cast> ]
returnsClause
: RETURNS returnsDataType
;

// SQL:1999
// <returns data type> ::= <data type> [ <locator indication> ]
returnsDataType
: type
;

// SQL:1999
// <routine body> ::=
// <SQL routine body>
// | <external body reference>
routineBody
: sqlRoutineBody
;

// SQL:1999
// <SQL parameter declaration list> ::=
// <left paren>
// [ <SQL parameter declaration> [ { <comma> <SQL parameter declaration> }... ] ]
// <right paren>
sqlParameterDeclarationList
: PAREN_LEFT (sqlParameterDeclaration (COMMA sqlParameterDeclaration)* )? PAREN_RIGHT
;

// SQL:1999
// <SQL parameter declaration> ::=
// [ <parameter mode> ] [ <SQL parameter name> ]
// <parameter type>
// [ RESULT ]
sqlParameterDeclaration
: sqlParameterName? parameterType
;

// SQL:1999
// <SQL parameter name> ::= <identifier>
sqlParameterName
: symbolPrimitive
;

// SQL:1999
// <parameter type> ::=
// <data type> [ <locator indication> ]
parameterType
: type
;

// SQL:1999
// <SQL routine body> ::= <SQL procedure statement>
sqlRoutineBody: sqlProcedureStatement;

// SQL:1999
// <SQL procedure statement> ::= <SQL executable statement>
sqlProcedureStatement: sqlExecutableStatement;

// SQL:1999
// <SQL executable statement> ::=
// <SQL control statement>
// | many more alternatives...
sqlExecutableStatement
: sqlControlStatement
;

// SQL:1999
// <SQL control statement> ::=
// <call statement>
// | <return statement>
sqlControlStatement
: returnStatement
;

// SQL:1999
// <return statement> ::=
// RETURN <return value>
// <return value> ::=
// <value expression>
// | NULL
returnStatement
: RETURN expr;

/**
*
* COMMON STRUCTURES
Expand Down
4 changes: 4 additions & 0 deletions partiql-parser/src/main/antlr/PartiQLTokens.g4
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,7 @@ FOREIGN: 'FOREIGN';
FOUND: 'FOUND';
FROM: 'FROM';
FULL: 'FULL';
FUNCTION: 'FUNCTION';
GET: 'GET';
GLOBAL: 'GLOBAL';
GO: 'GO';
Expand Down Expand Up @@ -197,6 +198,8 @@ REFERENCES: 'REFERENCES';
RELATIVE: 'RELATIVE';
REPLACE: 'REPLACE';
RESTRICT: 'RESTRICT';
RETURN: 'RETURN';
RETURNS: 'RETURNS';
REVOKE: 'REVOKE';
RIGHT: 'RIGHT';
ROLLBACK: 'ROLLBACK';
Expand All @@ -213,6 +216,7 @@ SIZE: 'SIZE';
SMALLINT: 'SMALLINT';
SOME: 'SOME';
SPACE: 'SPACE';
SPECIFIC: 'SPECIFIC';
SQL: 'SQL';
SQLCODE: 'SQLCODE';
SQLERROR: 'SQLERROR';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -508,6 +508,82 @@ internal class PartiQLParserDefault : PartiQLParser {
statementExec(procedure, args)
}

// FUNCTION

override fun visitSqlInvokedRoutine(ctx: org.partiql.parser.antlr.PartiQLParser.SqlInvokedRoutineContext?): AstNode {
return super.visitSqlInvokedRoutine(ctx)
}

override fun visitSchemaRoutine(ctx: org.partiql.parser.antlr.PartiQLParser.SchemaRoutineContext?): AstNode {
return super.visitSchemaRoutine(ctx)
}

override fun visitSchemaFunction(ctx: org.partiql.parser.antlr.PartiQLParser.SchemaFunctionContext?): AstNode {
return super.visitSchemaFunction(ctx)
}

override fun visitSqlInvokedFunction(ctx: org.partiql.parser.antlr.PartiQLParser.SqlInvokedFunctionContext) = translate(ctx) {
val specification = visitFunctionSpecification(ctx.functionSpecification())
val body = visitRoutineBody(ctx.routineBody())
statementDDLCreateFunction(specification, body)
}

override fun visitFunctionSpecification(ctx: org.partiql.parser.antlr.PartiQLParser.FunctionSpecificationContext) = translate(ctx) {
val root = visitSymbolPrimitive(ctx.name)
val name = identifierQualified(root, emptyList())
val parameters = ctx.sqlParameterDeclarationList().sqlParameterDeclaration().map { decl ->
visitSqlParameterDeclaration(decl)
}
val returns = visitReturnsClause(ctx.returnsClause())
val characteristics = ctx.routineCharacteristic().map { characteristic ->
visitRoutineCharacteristic(characteristic)
}
statementDDLCreateFunctionSpecification(name, parameters, returns, characteristics)
}

override fun visitSqlParameterDeclaration(ctx: org.partiql.parser.antlr.PartiQLParser.SqlParameterDeclarationContext) = translate(ctx) {
val name = ctx.sqlParameterName()?.let { visitSymbolPrimitive(it.symbolPrimitive()) }
val type = visit(ctx.parameterType().type()) as Type
statementDDLCreateFunctionParameterDeclaration(name, type)
}

override fun visitReturnsClause(ctx: org.partiql.parser.antlr.PartiQLParser.ReturnsClauseContext) = translate(ctx) {
val type = visit(ctx.returnsDataType().type()) as Type
statementDDLCreateFunctionReturns(type)
}

override fun visitRoutineCharacteristic(ctx: org.partiql.parser.antlr.PartiQLParser.RoutineCharacteristicContext) = translate(ctx) {
val name = visitSymbolPrimitive(ctx.specificName().name)
val specificName = identifierQualified(name, emptyList())
statementRoutineCharacteristicSpecific(specificName)
}

override fun visitReturnStatement(ctx: org.partiql.parser.antlr.PartiQLParser.ReturnStatementContext) = translate(ctx) {
val expr = visitExpr(ctx.expr())
statementReturn(expr)
}

override fun visitSqlProcedureStatement(ctx: org.partiql.parser.antlr.PartiQLParser.SqlProcedureStatementContext?): AstNode {
return super.visitSqlProcedureStatement(ctx)
}

override fun visitSqlExecutableStatement(ctx: org.partiql.parser.antlr.PartiQLParser.SqlExecutableStatementContext?): AstNode {
return super.visitSqlExecutableStatement(ctx)
}

override fun visitRoutineBody(ctx: org.partiql.parser.antlr.PartiQLParser.RoutineBodyContext) = translate(ctx) {
visitSqlRoutineBody(ctx.sqlRoutineBody())
}

override fun visitSqlRoutineBody(ctx: org.partiql.parser.antlr.PartiQLParser.SqlRoutineBodyContext) = translate(ctx) {
val stmt = visitSqlProcedureStatement(ctx.sqlProcedureStatement()) as Statement
statementRoutineBodyInternal(stmt)
}

override fun visitSqlControlStatement(ctx: org.partiql.parser.antlr.PartiQLParser.SqlControlStatementContext?): AstNode {
return super.visitSqlControlStatement(ctx)
}

/**
*
* DATA MANIPULATION LANGUAGE (DML)
Expand Down Expand Up @@ -1835,6 +1911,7 @@ internal class PartiQLParserDefault : PartiQLParser {
val n = ctx.arg0?.text?.toInt()
when (ctx.datatype.type) {
GeneratedParser.FLOAT -> when (n) {
null -> typeFloat64()
32 -> typeFloat32()
64 -> typeFloat64()
else -> throw error(ctx.datatype, "Invalid FLOAT precision. Expected 32 or 64")
Expand Down
Loading

0 comments on commit 8b30752

Please sign in to comment.