diff --git a/cloud/docker-image/src/main/docker/assembly.xml b/cloud/docker-image/src/main/docker/assembly.xml
index eaf132aa3e..7e0d989f1a 100644
--- a/cloud/docker-image/src/main/docker/assembly.xml
+++ b/cloud/docker-image/src/main/docker/assembly.xml
@@ -66,7 +66,6 @@
org/junit/**
com/google/**
org/checkerframework/**
- com/github/jsqlparser/**
diff --git a/incubator/binding-pgsql-kafka/NOTICE b/incubator/binding-pgsql-kafka/NOTICE
index c6b7d9c015..3913dbbc71 100644
--- a/incubator/binding-pgsql-kafka/NOTICE
+++ b/incubator/binding-pgsql-kafka/NOTICE
@@ -10,5 +10,5 @@ WARRANTIES OF ANY KIND, either express or implied. See the License for the
specific language governing permissions and limitations under the License.
This project includes:
- JSQLParser library under GNU Library or Lesser General Public License (LGPL) V2.1 or The Apache Software License, Version 2.0
+ zilla::incubator::binding-pgsql under Aklivity Community License Agreement
diff --git a/incubator/binding-pgsql-kafka/pom.xml b/incubator/binding-pgsql-kafka/pom.xml
index 5779c09cb9..c3bcc8b6ab 100644
--- a/incubator/binding-pgsql-kafka/pom.xml
+++ b/incubator/binding-pgsql-kafka/pom.xml
@@ -24,7 +24,7 @@
- 0.82
+ 0.86
0
@@ -42,8 +42,8 @@
provided
- com.github.jsqlparser
- jsqlparser
+ io.aklivity.zilla
+ binding-pgsql
${project.groupId}
@@ -195,7 +195,6 @@
io/aklivity/zilla/runtime/binding/pgsql/kafka/internal/types/**/*.class
- net/sf/jsqlparser/parser/*
diff --git a/incubator/binding-pgsql-kafka/src/main/java/io/aklivity/zilla/runtime/binding/pgsql/kafka/internal/schema/PgsqlKafkaKeyAvroSchemaTemplate.java b/incubator/binding-pgsql-kafka/src/main/java/io/aklivity/zilla/runtime/binding/pgsql/kafka/internal/schema/PgsqlKafkaKeyAvroSchemaTemplate.java
index cecef1e11f..6885f5ee94 100644
--- a/incubator/binding-pgsql-kafka/src/main/java/io/aklivity/zilla/runtime/binding/pgsql/kafka/internal/schema/PgsqlKafkaKeyAvroSchemaTemplate.java
+++ b/incubator/binding-pgsql-kafka/src/main/java/io/aklivity/zilla/runtime/binding/pgsql/kafka/internal/schema/PgsqlKafkaKeyAvroSchemaTemplate.java
@@ -14,11 +14,9 @@
*/
package io.aklivity.zilla.runtime.binding.pgsql.kafka.internal.schema;
-import java.util.List;
+import java.util.Map;
-import net.sf.jsqlparser.statement.create.table.ColumnDefinition;
-import net.sf.jsqlparser.statement.create.table.CreateTable;
-import net.sf.jsqlparser.statement.create.table.Index;
+import io.aklivity.zilla.runtime.binding.pgsql.parser.model.TableInfo;
public class PgsqlKafkaKeyAvroSchemaTemplate extends PgsqlKafkaAvroSchemaTemplate
{
@@ -35,12 +33,12 @@ public PgsqlKafkaKeyAvroSchemaTemplate(
public String generateSchema(
String database,
- CreateTable createTable)
+ TableInfo createTable)
{
schemaBuilder.setLength(0);
final String newNamespace = namespace.replace(DATABASE_PLACEHOLDER, database);
- final String recordName = String.format("%s_key", createTable.getTable().getName());
+ final String recordName = String.format("%s_key", createTable.name());
schemaBuilder.append("{\n");
schemaBuilder.append("\"schemaType\": \"AVRO\",\n");
@@ -52,10 +50,10 @@ public String generateSchema(
schemaBuilder.append(" \\\"namespace\\\": \\\"").append(newNamespace).append("\\\",");
schemaBuilder.append(" \\\"fields\\\": [");
- for (ColumnDefinition column : createTable.getColumnDefinitions())
+ for (Map.Entry column : createTable.columns().entrySet())
{
- String fieldName = column.getColumnName();
- String pgsqlType = column.getColDataType().getDataType();
+ String fieldName = column.getKey();
+ String pgsqlType = column.getValue();
String avroType = convertPgsqlTypeToAvro(pgsqlType);
@@ -72,28 +70,4 @@ public String generateSchema(
return schemaBuilder.toString();
}
-
- public String primaryKey(
- CreateTable statement)
- {
- String primaryKey = null;
-
- final List indexes = statement.getIndexes();
-
- if (indexes != null && !indexes.isEmpty())
- {
- match:
- for (Index index : indexes)
- {
- if ("PRIMARY KEY".equalsIgnoreCase(index.getType()))
- {
- final List primaryKeyColumns = index.getColumns();
- primaryKey = primaryKeyColumns.get(0).columnName;
- break match;
- }
- }
- }
-
- return primaryKey;
- }
}
diff --git a/incubator/binding-pgsql-kafka/src/main/java/io/aklivity/zilla/runtime/binding/pgsql/kafka/internal/schema/PgsqlKafkaValueAvroSchemaTemplate.java b/incubator/binding-pgsql-kafka/src/main/java/io/aklivity/zilla/runtime/binding/pgsql/kafka/internal/schema/PgsqlKafkaValueAvroSchemaTemplate.java
index fe53279963..ebfaea7915 100644
--- a/incubator/binding-pgsql-kafka/src/main/java/io/aklivity/zilla/runtime/binding/pgsql/kafka/internal/schema/PgsqlKafkaValueAvroSchemaTemplate.java
+++ b/incubator/binding-pgsql-kafka/src/main/java/io/aklivity/zilla/runtime/binding/pgsql/kafka/internal/schema/PgsqlKafkaValueAvroSchemaTemplate.java
@@ -14,11 +14,9 @@
*/
package io.aklivity.zilla.runtime.binding.pgsql.kafka.internal.schema;
-import java.util.List;
+import java.util.Map;
-import net.sf.jsqlparser.statement.create.table.ColumnDefinition;
-import net.sf.jsqlparser.statement.create.table.CreateTable;
-import net.sf.jsqlparser.statement.create.table.Index;
+import io.aklivity.zilla.runtime.binding.pgsql.parser.model.TableInfo;
public class PgsqlKafkaValueAvroSchemaTemplate extends PgsqlKafkaAvroSchemaTemplate
{
@@ -35,27 +33,26 @@ public PgsqlKafkaValueAvroSchemaTemplate(
public String generateSchema(
String database,
- CreateTable createTable)
+ TableInfo createTable)
{
schemaBuilder.setLength(0);
final String newNamespace = namespace.replace(DATABASE_PLACEHOLDER, database);
- final String recordName = createTable.getTable().getName();
+ final String recordName = createTable.name();
schemaBuilder.append("{\n");
schemaBuilder.append("\"schemaType\": \"AVRO\",\n");
- schemaBuilder.append("\"schema\": \""); // Begin the schema field
+ schemaBuilder.append("\"schema\": \"");
- // Building the actual Avro schema
schemaBuilder.append("{\\\"type\\\": \\\"record\\\",");
schemaBuilder.append(" \\\"name\\\": \\\"").append(recordName).append("\\\",");
schemaBuilder.append(" \\\"namespace\\\": \\\"").append(newNamespace).append("\\\",");
schemaBuilder.append(" \\\"fields\\\": [");
- for (ColumnDefinition column : createTable.getColumnDefinitions())
+ for (Map.Entry column : createTable.columns().entrySet())
{
- String fieldName = column.getColumnName();
- String pgsqlType = column.getColDataType().getDataType();
+ String fieldName = column.getKey();
+ String pgsqlType = column.getValue();
String avroType = convertPgsqlTypeToAvro(pgsqlType);
@@ -63,60 +60,11 @@ public String generateSchema(
schemaBuilder.append(" \\\"type\\\": ").append(avroType).append("},");
}
- // Remove the last comma and close the fields array
schemaBuilder.setLength(schemaBuilder.length() - 1);
schemaBuilder.append("]");
- // Closing the Avro schema
schemaBuilder.append("}\"\n}");
return schemaBuilder.toString();
}
-
- public String primaryKey(
- CreateTable statement)
- {
- String primaryKey = null;
-
- final List indexes = statement.getIndexes();
-
- if (indexes != null && !indexes.isEmpty())
- {
- match:
- for (Index index : indexes)
- {
- if ("PRIMARY KEY".equalsIgnoreCase(index.getType()))
- {
- final List primaryKeyColumns = index.getColumns();
- primaryKey = primaryKeyColumns.get(0).columnName;
- break match;
- }
- }
- }
-
- return primaryKey;
- }
-
- public int primaryKeyCount(
- CreateTable statement)
- {
- int primaryKeyCount = 0;
-
- final List indexes = statement.getIndexes();
-
- if (indexes != null && !indexes.isEmpty())
- {
- match:
- for (Index index : indexes)
- {
- if ("PRIMARY KEY".equalsIgnoreCase(index.getType()))
- {
- primaryKeyCount = index.getColumns().size();
- break match;
- }
- }
- }
-
- return primaryKeyCount;
- }
}
diff --git a/incubator/binding-pgsql-kafka/src/main/java/io/aklivity/zilla/runtime/binding/pgsql/kafka/internal/stream/PgsqlKafkaProxyFactory.java b/incubator/binding-pgsql-kafka/src/main/java/io/aklivity/zilla/runtime/binding/pgsql/kafka/internal/stream/PgsqlKafkaProxyFactory.java
index 6461b89336..5c4e740d83 100644
--- a/incubator/binding-pgsql-kafka/src/main/java/io/aklivity/zilla/runtime/binding/pgsql/kafka/internal/stream/PgsqlKafkaProxyFactory.java
+++ b/incubator/binding-pgsql-kafka/src/main/java/io/aklivity/zilla/runtime/binding/pgsql/kafka/internal/stream/PgsqlKafkaProxyFactory.java
@@ -19,13 +19,11 @@
import static java.nio.charset.StandardCharsets.UTF_8;
import static java.util.Objects.requireNonNull;
-import java.io.InputStreamReader;
-import java.io.Reader;
-import java.io.StringReader;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
+import java.util.Set;
import java.util.function.Consumer;
import java.util.function.LongFunction;
import java.util.function.LongUnaryOperator;
@@ -36,7 +34,6 @@
import org.agrona.collections.Long2ObjectHashMap;
import org.agrona.collections.Object2ObjectHashMap;
import org.agrona.concurrent.UnsafeBuffer;
-import org.agrona.io.DirectBufferInputStream;
import io.aklivity.zilla.runtime.binding.pgsql.kafka.internal.PgsqlKafkaConfiguration;
import io.aklivity.zilla.runtime.binding.pgsql.kafka.internal.config.PgsqlKafkaBindingConfig;
@@ -56,16 +53,14 @@
import io.aklivity.zilla.runtime.binding.pgsql.kafka.internal.types.stream.ResetFW;
import io.aklivity.zilla.runtime.binding.pgsql.kafka.internal.types.stream.SignalFW;
import io.aklivity.zilla.runtime.binding.pgsql.kafka.internal.types.stream.WindowFW;
+import io.aklivity.zilla.runtime.binding.pgsql.parser.PgsqlParser;
+import io.aklivity.zilla.runtime.binding.pgsql.parser.model.TableInfo;
import io.aklivity.zilla.runtime.engine.EngineContext;
import io.aklivity.zilla.runtime.engine.binding.BindingHandler;
import io.aklivity.zilla.runtime.engine.binding.function.MessageConsumer;
import io.aklivity.zilla.runtime.engine.buffer.BufferPool;
import io.aklivity.zilla.runtime.engine.catalog.CatalogHandler;
import io.aklivity.zilla.runtime.engine.config.BindingConfig;
-import net.sf.jsqlparser.parser.CCJSqlParserManager;
-import net.sf.jsqlparser.statement.Statement;
-import net.sf.jsqlparser.statement.create.table.CreateTable;
-import net.sf.jsqlparser.statement.drop.Drop;
public final class PgsqlKafkaProxyFactory implements PgsqlKafkaStreamFactory
{
@@ -75,8 +70,7 @@ public final class PgsqlKafkaProxyFactory implements PgsqlKafkaStreamFactory
"schema": "{\\"type\\": \\"string\\"}"
}""";
-
- private static final Byte STATEMENT_SEMICOLON = ';';
+ private static final String SPLIT_STATEMENTS = "\"(?<=;)(?!\\x00)\"";
private static final int END_OF_FIELD = 0x00;
private static final int NO_ERROR_SCHEMA_VERSION_ID = -1;
@@ -87,11 +81,8 @@ public final class PgsqlKafkaProxyFactory implements PgsqlKafkaStreamFactory
private static final DirectBuffer EMPTY_BUFFER = new UnsafeBuffer(new byte[0]);
private static final OctetsFW EMPTY_OCTETS = new OctetsFW().wrap(EMPTY_BUFFER, 0, 0);
- private static final Consumer EMPTY_EXTENSION = ex -> {};
- private final CCJSqlParserManager parserManager = new CCJSqlParserManager();
- private final DirectBufferInputStream inputStream = new DirectBufferInputStream(EMPTY_BUFFER);
- private final Reader reader = new InputStreamReader(inputStream);
+ private final PgsqlParser parser = new PgsqlParser();
private final BeginFW beginRO = new BeginFW();
private final DataFW dataRO = new DataFW();
@@ -657,26 +648,16 @@ private void doParseQuery(
{
final MutableDirectBuffer parserBuffer = bufferPool.buffer(parserSlot);
- int statementOffset = 0;
- int progress = 0;
+ String sql = parserBuffer.getStringWithoutLengthAscii(0, parserSlotOffset);
+ String[] statements = sql.split(SPLIT_STATEMENTS);
- parse:
- while (progress <= parserSlotOffset)
+ int length = statements.length;
+ if (length > 0)
{
- if (parserBuffer.getByte(progress) == STATEMENT_SEMICOLON)
- {
- int length = progress - statementOffset + Byte.BYTES;
- if (parserBuffer.getByte(progress + Byte.BYTES) == END_OF_FIELD)
- {
- length += Byte.BYTES;
- }
- final PgsqlKafkaCommandType command = decodeCommandType(parserBuffer, statementOffset, length);
- final PgsqlDecoder decoder = pgsqlDecoder.get(command);
- decoder.decode(this, traceId, authorizationId, parserBuffer, statementOffset, length);
- break parse;
- }
-
- progress++;
+ String statement = statements[0];
+ String command = parser.parseCommand(statement);
+ final PgsqlDecoder decoder = pgsqlDecoder.get(PgsqlKafkaCommandType.valueOf(command.getBytes()));
+ decoder.decode(this, traceId, authorizationId, statement);
}
}
}
@@ -1317,33 +1298,32 @@ private void decodeCreateTopicCommand(
PgsqlProxy server,
long traceId,
long authorization,
- DirectBuffer buffer,
- int offset,
- int length)
+ String statement)
{
if (server.commandsProcessed == 1)
{
+ final int length = statement.length();
server.onCommandCompleted(traceId, authorization, length, PgsqlKafkaCompletionCommand.CREATE_TOPIC_COMMAND);
}
else if (server.commandsProcessed == 0)
{
- final CreateTable createTable = (CreateTable) parseStatement(buffer, offset, length);
- final String topic = createTable.getTable().getName();
+ final TableInfo createTable = parser.parseCreateTable(statement);
+ final String topic = createTable.name();
topics.clear();
topics.add(String.format("%s.%s", server.database, topic));
final PgsqlKafkaBindingConfig binding = server.binding;
- final String primaryKey = binding.avroValueSchema.primaryKey(createTable);
- final int primaryKeyCount = binding.avroValueSchema.primaryKeyCount(createTable);
+
int versionId = NO_ERROR_SCHEMA_VERSION_ID;
- if (primaryKey != null)
+ Set primaryKeys = createTable.primaryKeys();
+ if (!primaryKeys.isEmpty())
{
//TODO: assign versionId to avoid test failure
final String subjectKey = String.format("%s.%s-key", server.database, topic);
- String keySchema = primaryKeyCount > 1
+ String keySchema = primaryKeys.size() > 1
? binding.avroKeySchema.generateSchema(server.database, createTable)
: AVRO_KEY_SCHEMA;
binding.catalog.register(subjectKey, keySchema);
@@ -1357,7 +1337,7 @@ else if (server.commandsProcessed == 0)
if (versionId != NO_VERSION_ID)
{
- final String policy = primaryKey != null && primaryKeyCount == 1
+ final String policy = primaryKeys.size() == 1
? "compact"
: "delete";
@@ -1375,28 +1355,28 @@ private void decodeDropTopicCommand(
PgsqlProxy server,
long traceId,
long authorization,
- DirectBuffer buffer,
- int offset,
- int length)
+ String statement)
{
if (server.commandsProcessed == 1)
{
+ final int length = statement.length();
server.onCommandCompleted(traceId, authorization, length, PgsqlKafkaCompletionCommand.DROP_TOPIC_COMMAND);
}
else if (server.commandsProcessed == 0)
{
- final Drop drop = (Drop) parseStatement(buffer, offset, length);
- final String topic = drop.getName().getName();
-
- final PgsqlKafkaBindingConfig binding = server.binding;
- final String subjectKey = String.format("%s.%s-key", server.database, topic);
- final String subjectValue = String.format("%s.%s-value", server.database, topic);
+ List drops = parser.parseDrop(statement);
+ drops.stream().findFirst().ifPresent(d ->
+ {
+ final PgsqlKafkaBindingConfig binding = server.binding;
+ final String subjectKey = String.format("%s.%s-key", server.database, d);
+ final String subjectValue = String.format("%s.%s-value", server.database, d);
- binding.catalog.unregister(subjectKey);
- binding.catalog.unregister(subjectValue);
+ binding.catalog.unregister(subjectKey);
+ binding.catalog.unregister(subjectValue);
- final KafkaDeleteTopicsProxy deleteTopicsProxy = server.deleteTopicsProxy;
- deleteTopicsProxy.doKafkaBegin(traceId, authorization, List.of("%s.%s".formatted(server.database, topic)));
+ final KafkaDeleteTopicsProxy deleteTopicsProxy = server.deleteTopicsProxy;
+ deleteTopicsProxy.doKafkaBegin(traceId, authorization, List.of("%s.%s".formatted(server.database, d)));
+ });
}
}
@@ -1404,82 +1384,11 @@ private void decodeUnknownCommand(
PgsqlProxy server,
long traceId,
long authorization,
- DirectBuffer buffer,
- int offset,
- int length)
+ String statement)
{
server.cleanup(traceId, authorization);
}
- private PgsqlKafkaCommandType decodeCommandType(
- DirectBuffer buffer,
- int offset,
- int length)
- {
- PgsqlKafkaCommandType matchingCommand = PgsqlKafkaCommandType.UNKNOWN_COMMAND;
-
- command:
- for (PgsqlKafkaCommandType command : PgsqlKafkaCommandType.values())
- {
- int progressOffset = offset;
-
- boolean match = true;
- for (byte b : command.value())
- {
- if (buffer.getByte(progressOffset) != b)
- {
- match = false;
- break;
- }
- progressOffset++;
- }
-
- if (match)
- {
- matchingCommand = command;
- break command;
- }
- }
-
- return matchingCommand;
- }
-
- private Statement parseStatement(
- DirectBuffer buffer,
- int offset,
- int length)
- {
- Statement statement = null;
- try
- {
- if (decodeCommandType(buffer, offset, length).
- equals(PgsqlKafkaCommandType.CREATE_TOPIC_COMMAND))
- {
- String sql = buffer.getStringWithoutLengthUtf8(offset, length);
- sql = sql.replace("CREATE TOPIC", "CREATE TABLE");
- statement = parserManager.parse(new StringReader(sql));
- }
- if (decodeCommandType(buffer, offset, length).
- equals(PgsqlKafkaCommandType.DROP_TOPIC_COMMAND))
- {
- String sql = buffer.getStringWithoutLengthUtf8(offset, length);
- sql = sql.replace("DROP TOPIC", "DROP TABLE");
- statement = parserManager.parse(new StringReader(sql));
- }
- else
- {
- inputStream.wrap(buffer, offset, length);
- statement = parserManager.parse(reader);
- }
- }
- catch (Exception ignored)
- {
- //NOOP
- }
-
- return statement;
- }
-
@FunctionalInterface
private interface PgsqlDecoder
{
@@ -1487,8 +1396,6 @@ void decode(
PgsqlProxy server,
long traceId,
long authorization,
- DirectBuffer writeBuffer,
- int offset,
- int length);
+ String statement);
}
}
diff --git a/incubator/binding-pgsql-kafka/src/main/moditect/module-info.java b/incubator/binding-pgsql-kafka/src/main/moditect/module-info.java
index ca4d84298d..e4c6b9efab 100644
--- a/incubator/binding-pgsql-kafka/src/main/moditect/module-info.java
+++ b/incubator/binding-pgsql-kafka/src/main/moditect/module-info.java
@@ -14,8 +14,8 @@
*/
module io.aklivity.zilla.runtime.binding.pgsql.kafka
{
- requires net.sf.jsqlparser;
requires io.aklivity.zilla.runtime.engine;
+ requires io.aklivity.zilla.runtime.binding.pgsql;
provides io.aklivity.zilla.runtime.engine.binding.BindingFactorySpi
with io.aklivity.zilla.runtime.binding.pgsql.kafka.internal.PgsqlKafkaBindingFactorySpi;
diff --git a/incubator/binding-pgsql/pom.xml b/incubator/binding-pgsql/pom.xml
index 73bf387b5f..4c0cd40a3d 100644
--- a/incubator/binding-pgsql/pom.xml
+++ b/incubator/binding-pgsql/pom.xml
@@ -24,7 +24,7 @@
- 0.89
+ 0.91
0
@@ -35,6 +35,11 @@
${project.version}
provided
+
+ org.antlr
+ antlr4-runtime
+ provided
+
${project.groupId}
engine
@@ -107,6 +112,10 @@
+
+ org.antlr
+ antlr4-maven-plugin
+
com.mycila
license-maven-plugin
@@ -191,6 +200,7 @@
io/aklivity/zilla/runtime/binding/pgsql/internal/types/**/*.class
+ io/aklivity/zilla/runtime/binding/pgsql/parser/**/*.class
diff --git a/incubator/binding-pgsql/src/main/antlr4/io/aklivity/zilla/runtime/binding/pgsql/parser/PostgreSqlLexer.g4 b/incubator/binding-pgsql/src/main/antlr4/io/aklivity/zilla/runtime/binding/pgsql/parser/PostgreSqlLexer.g4
new file mode 100644
index 0000000000..6c7dfef3cb
--- /dev/null
+++ b/incubator/binding-pgsql/src/main/antlr4/io/aklivity/zilla/runtime/binding/pgsql/parser/PostgreSqlLexer.g4
@@ -0,0 +1,1667 @@
+/*
+ * Copyright 2021-2023 Aklivity Inc
+ *
+ * Licensed under the Aklivity Community License (the "License"); you may not use
+ * this file except in compliance with the License. You may obtain a copy of the
+ * License at
+ *
+ * https://www.aklivity.io/aklivity-community-license/
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OF ANY KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations under the License.
+ */
+
+lexer grammar PostgreSqlLexer;
+/* Reference:
+ * http://www.postgresql.org/docs/9.3/static/sql-syntax-lexical.html
+ */
+
+options {
+ superClass = PostgreSqlLexerBase;
+ caseInsensitive = true;
+}
+
+@header {
+}
+@members {
+/* This field stores the tags which are used to detect the end of a dollar-quoted string literal.
+ */
+}
+//
+
+// SPECIAL CHARACTERS (4.1.4)
+
+//
+
+// Note that Asterisk is a valid operator, but does not have the type Operator due to its syntactic use in locations
+
+// that are not expressions.
+
+Dollar: '$';
+
+OPEN_PAREN: '(';
+
+CLOSE_PAREN: ')';
+
+OPEN_BRACKET: '[';
+
+CLOSE_BRACKET: ']';
+
+COMMA: ',';
+
+SEMI: ';';
+
+COLON: ':';
+
+STAR: '*';
+
+EQUAL: '=';
+
+DOT: '.';
+//NamedArgument : ':=';
+
+PLUS: '+';
+
+MINUS: '-';
+
+SLASH: '/';
+
+CARET: '^';
+
+LT: '<';
+
+GT: '>';
+
+LESS_LESS: '<<';
+
+GREATER_GREATER: '>>';
+
+COLON_EQUALS: ':=';
+
+LESS_EQUALS: '<=';
+
+EQUALS_GREATER: '=>';
+
+GREATER_EQUALS: '>=';
+
+DOT_DOT: '..';
+
+NOT_EQUALS: '<>';
+
+TYPECAST: '::';
+
+PERCENT: '%';
+
+PARAM: '$' ([0-9])+;
+//
+
+// OPERATORS (4.1.3)
+
+//
+
+// this rule does not allow + or - at the end of a multi-character operator
+
+Operator:
+ (
+ (
+ OperatorCharacter
+ | ('+' | '-' {checkLA('-')}?)+ (OperatorCharacter | '/' {checkLA('*')}?)
+ | '/' {checkLA('*')}?
+ )+
+ | // special handling for the single-character operators + and -
+ [+-]
+ )
+ //TODO somehow rewrite this part without using Actions
+ {
+ handleLessLessGreaterGreater();
+ }
+;
+/* This rule handles operators which end with + or -, and sets the token type to Operator. It is comprised of four
+ * parts, in order:
+ *
+ * 1. A prefix, which does not contain a character from the required set which allows + or - to appear at the end of
+ * the operator.
+ * 2. A character from the required set which allows + or - to appear at the end of the operator.
+ * 3. An optional sub-token which takes the form of an operator which does not include a + or - at the end of the
+ * sub-token.
+ * 4. A suffix sequence of + and - characters.
+ */
+
+OperatorEndingWithPlusMinus:
+ (OperatorCharacterNotAllowPlusMinusAtEnd | '-' {checkLA('-')}? | '/' {checkLA('*')}?)* OperatorCharacterAllowPlusMinusAtEnd Operator? (
+ '+'
+ | '-' {checkLA('-')}?
+ )+ -> type (Operator)
+;
+// Each of the following fragment rules omits the +, -, and / characters, which must always be handled in a special way
+
+// by the operator rules above.
+
+fragment OperatorCharacter: [*<>=~!@%^&|`?#];
+// these are the operator characters that don't count towards one ending with + or -
+
+fragment OperatorCharacterNotAllowPlusMinusAtEnd: [*<>=+];
+// an operator may end with + or - if it contains one of these characters
+
+fragment OperatorCharacterAllowPlusMinusAtEnd: [~!@%^&|`?#];
+//
+
+// KEYWORDS (Appendix C)
+
+//
+
+//
+
+// reserved keywords
+
+//
+
+ALL: 'ALL';
+
+ANALYSE: 'ANALYSE';
+
+ANALYZE: 'ANALYZE';
+
+AND: 'AND';
+
+ANY: 'ANY';
+
+ARRAY: 'ARRAY';
+
+AS: 'AS';
+
+ASC: 'ASC';
+
+ASYMMETRIC: 'ASYMMETRIC';
+
+BOTH: 'BOTH';
+
+CASE: 'CASE';
+
+CAST: 'CAST';
+
+CHECK: 'CHECK';
+
+COLLATE: 'COLLATE';
+
+COLUMN: 'COLUMN';
+
+CONSTRAINT: 'CONSTRAINT';
+
+CREATE: 'CREATE';
+
+CURRENT_CATALOG: 'CURRENT_CATALOG';
+
+CURRENT_DATE: 'CURRENT_DATE';
+
+CURRENT_ROLE: 'CURRENT_ROLE';
+
+CURRENT_TIME: 'CURRENT_TIME';
+
+CURRENT_TIMESTAMP: 'CURRENT_TIMESTAMP';
+
+CURRENT_USER: 'CURRENT_USER';
+
+DEFAULT: 'DEFAULT';
+
+DEFERRABLE: 'DEFERRABLE';
+
+DESC: 'DESC';
+
+DISTINCT: 'DISTINCT';
+
+DO: 'DO';
+
+ELSE: 'ELSE';
+
+EXCEPT: 'EXCEPT';
+
+FALSE_P: 'FALSE';
+
+FETCH: 'FETCH';
+
+FOR: 'FOR';
+
+FOREIGN: 'FOREIGN';
+
+FROM: 'FROM';
+
+GRANT: 'GRANT';
+
+GROUP_P: 'GROUP';
+
+HAVING: 'HAVING';
+
+IN_P: 'IN';
+
+INITIALLY: 'INITIALLY';
+
+INTERSECT: 'INTERSECT';
+
+INTO: 'INTO';
+
+LATERAL_P: 'LATERAL';
+
+LEADING: 'LEADING';
+
+LIMIT: 'LIMIT';
+
+LOCALTIME: 'LOCALTIME';
+
+LOCALTIMESTAMP: 'LOCALTIMESTAMP';
+
+NOT: 'NOT';
+
+NULL_P: 'NULL';
+
+OFFSET: 'OFFSET';
+
+ON: 'ON';
+
+ONLY: 'ONLY';
+
+OR: 'OR';
+
+ORDER: 'ORDER';
+
+PLACING: 'PLACING';
+
+PRIMARY: 'PRIMARY';
+
+REFERENCES: 'REFERENCES';
+
+RETURNING: 'RETURNING';
+
+SELECT: 'SELECT';
+
+SESSION_USER: 'SESSION_USER';
+
+SOME: 'SOME';
+
+SYMMETRIC: 'SYMMETRIC';
+
+TABLE: 'TABLE';
+
+THEN: 'THEN';
+
+TO: 'TO';
+
+TOPIC: 'TOPIC';
+
+STREAM: 'STREAM';
+
+TRAILING: 'TRAILING';
+
+TRUE_P: 'TRUE';
+
+UNION: 'UNION';
+
+UNIQUE: 'UNIQUE';
+
+USER: 'USER';
+
+USING: 'USING';
+
+VARIADIC: 'VARIADIC';
+
+WHEN: 'WHEN';
+
+WHERE: 'WHERE';
+
+WINDOW: 'WINDOW';
+
+WITH: 'WITH';
+
+//
+
+// reserved keywords (can be function or type)
+
+//
+
+AUTHORIZATION: 'AUTHORIZATION';
+
+BINARY: 'BINARY';
+
+COLLATION: 'COLLATION';
+
+CONCURRENTLY: 'CONCURRENTLY';
+
+CROSS: 'CROSS';
+
+CURRENT_SCHEMA: 'CURRENT_SCHEMA';
+
+FREEZE: 'FREEZE';
+
+FULL: 'FULL';
+
+ILIKE: 'ILIKE';
+
+INNER_P: 'INNER';
+
+IS: 'IS';
+
+ISNULL: 'ISNULL';
+
+JOIN: 'JOIN';
+
+LEFT: 'LEFT';
+
+LIKE: 'LIKE';
+
+NATURAL: 'NATURAL';
+
+NOTNULL: 'NOTNULL';
+
+OUTER_P: 'OUTER';
+
+OVER: 'OVER';
+
+OVERLAPS: 'OVERLAPS';
+
+RIGHT: 'RIGHT';
+
+SIMILAR: 'SIMILAR';
+
+VERBOSE: 'VERBOSE';
+//
+
+// non-reserved keywords
+
+//
+
+ABORT_P: 'ABORT';
+
+ABSOLUTE_P: 'ABSOLUTE';
+
+ACCESS: 'ACCESS';
+
+ACTION: 'ACTION';
+
+ADD_P: 'ADD';
+
+ADMIN: 'ADMIN';
+
+AFTER: 'AFTER';
+
+AGGREGATE: 'AGGREGATE';
+
+ALSO: 'ALSO';
+
+ALTER: 'ALTER';
+
+ALWAYS: 'ALWAYS';
+
+ASSERTION: 'ASSERTION';
+
+ASSIGNMENT: 'ASSIGNMENT';
+
+AT: 'AT';
+
+ATTRIBUTE: 'ATTRIBUTE';
+
+BACKWARD: 'BACKWARD';
+
+BEFORE: 'BEFORE';
+
+BEGIN_P: 'BEGIN';
+
+BY: 'BY';
+
+CACHE: 'CACHE';
+
+CALLED: 'CALLED';
+
+CASCADE: 'CASCADE';
+
+CASCADED: 'CASCADED';
+
+CATALOG: 'CATALOG';
+
+CHAIN: 'CHAIN';
+
+CHARACTERISTICS: 'CHARACTERISTICS';
+
+CHECKPOINT: 'CHECKPOINT';
+
+CLASS: 'CLASS';
+
+CLOSE: 'CLOSE';
+
+CLUSTER: 'CLUSTER';
+
+COMMENT: 'COMMENT';
+
+COMMENTS: 'COMMENTS';
+
+COMMIT: 'COMMIT';
+
+COMMITTED: 'COMMITTED';
+
+CONFIGURATION: 'CONFIGURATION';
+
+CONNECTION: 'CONNECTION';
+
+CONSTRAINTS: 'CONSTRAINTS';
+
+CONTENT_P: 'CONTENT';
+
+CONTINUE_P: 'CONTINUE';
+
+CONVERSION_P: 'CONVERSION';
+
+COPY: 'COPY';
+
+COST: 'COST';
+
+CSV: 'CSV';
+
+CURSOR: 'CURSOR';
+
+CYCLE: 'CYCLE';
+
+DATA_P: 'DATA';
+
+DATABASE: 'DATABASE';
+
+DAY_P: 'DAY';
+
+DEALLOCATE: 'DEALLOCATE';
+
+DECLARE: 'DECLARE';
+
+DEFAULTS: 'DEFAULTS';
+
+DEFERRED: 'DEFERRED';
+
+DEFINER: 'DEFINER';
+
+DELETE_P: 'DELETE';
+
+DELIMITER: 'DELIMITER';
+
+DELIMITERS: 'DELIMITERS';
+
+DICTIONARY: 'DICTIONARY';
+
+DISABLE_P: 'DISABLE';
+
+DISCARD: 'DISCARD';
+
+DOCUMENT_P: 'DOCUMENT';
+
+DOMAIN_P: 'DOMAIN';
+
+DOUBLE_P: 'DOUBLE';
+
+DROP: 'DROP';
+
+EACH: 'EACH';
+
+ENABLE_P: 'ENABLE';
+
+ENCODING: 'ENCODING';
+
+ENCRYPTED: 'ENCRYPTED';
+
+ENUM_P: 'ENUM';
+
+ESCAPE: 'ESCAPE';
+
+EVENT: 'EVENT';
+
+EXCLUDE: 'EXCLUDE';
+
+EXCLUDING: 'EXCLUDING';
+
+EXCLUSIVE: 'EXCLUSIVE';
+
+EXECUTE: 'EXECUTE';
+
+EXPLAIN: 'EXPLAIN';
+
+EXTENSION: 'EXTENSION';
+
+EXTERNAL: 'EXTERNAL';
+
+FAMILY: 'FAMILY';
+
+FIRST_P: 'FIRST';
+
+FOLLOWING: 'FOLLOWING';
+
+FORCE: 'FORCE';
+
+FORWARD: 'FORWARD';
+
+FUNCTION: 'FUNCTION';
+
+FUNCTIONS: 'FUNCTIONS';
+
+GLOBAL: 'GLOBAL';
+
+GRANTED: 'GRANTED';
+
+HANDLER: 'HANDLER';
+
+HEADER_P: 'HEADER';
+
+HOLD: 'HOLD';
+
+HOUR_P: 'HOUR';
+
+IDENTITY_P: 'IDENTITY';
+
+IF_P: 'IF';
+
+IMMEDIATE: 'IMMEDIATE';
+
+IMMUTABLE: 'IMMUTABLE';
+
+IMPLICIT_P: 'IMPLICIT';
+
+INCLUDING: 'INCLUDING';
+
+INCREMENT: 'INCREMENT';
+
+INDEX: 'INDEX';
+
+INDEXES: 'INDEXES';
+
+INHERIT: 'INHERIT';
+
+INHERITS: 'INHERITS';
+
+INLINE_P: 'INLINE';
+
+INSENSITIVE: 'INSENSITIVE';
+
+INSERT: 'INSERT';
+
+INSTEAD: 'INSTEAD';
+
+INVOKER: 'INVOKER';
+
+ISOLATION: 'ISOLATION';
+
+KEY: 'KEY';
+
+LABEL: 'LABEL';
+
+LANGUAGE: 'LANGUAGE';
+
+LARGE_P: 'LARGE';
+
+LAST_P: 'LAST';
+//LC_COLLATE : 'LC'_'COLLATE;
+
+//LC_CTYPE : 'LC'_'CTYPE;
+
+LEAKPROOF: 'LEAKPROOF';
+
+LEVEL: 'LEVEL';
+
+LISTEN: 'LISTEN';
+
+LOAD: 'LOAD';
+
+LOCAL: 'LOCAL';
+
+LOCATION: 'LOCATION';
+
+LOCK_P: 'LOCK';
+
+MAPPING: 'MAPPING';
+
+MATCH: 'MATCH';
+
+MATCHED: 'MATCHED';
+
+MATERIALIZED: 'MATERIALIZED';
+
+MAXVALUE: 'MAXVALUE';
+
+MERGE: 'MERGE';
+
+MINUTE_P: 'MINUTE';
+
+MINVALUE: 'MINVALUE';
+
+MODE: 'MODE';
+
+MONTH_P: 'MONTH';
+
+MOVE: 'MOVE';
+
+NAME_P: 'NAME';
+
+NAMES: 'NAMES';
+
+NEXT: 'NEXT';
+
+NO: 'NO';
+
+NOTHING: 'NOTHING';
+
+NOTIFY: 'NOTIFY';
+
+NOWAIT: 'NOWAIT';
+
+NULLS_P: 'NULLS';
+
+OBJECT_P: 'OBJECT';
+
+OF: 'OF';
+
+OFF: 'OFF';
+
+OIDS: 'OIDS';
+
+OPERATOR: 'OPERATOR';
+
+OPTION: 'OPTION';
+
+OPTIONS: 'OPTIONS';
+
+OWNED: 'OWNED';
+
+OWNER: 'OWNER';
+
+PARSER: 'PARSER';
+
+PARTIAL: 'PARTIAL';
+
+PARTITION: 'PARTITION';
+
+PASSING: 'PASSING';
+
+PASSWORD: 'PASSWORD';
+
+PLANS: 'PLANS';
+
+PRECEDING: 'PRECEDING';
+
+PREPARE: 'PREPARE';
+
+PREPARED: 'PREPARED';
+
+PRESERVE: 'PRESERVE';
+
+PRIOR: 'PRIOR';
+
+PRIVILEGES: 'PRIVILEGES';
+
+PROCEDURAL: 'PROCEDURAL';
+
+PROCEDURE: 'PROCEDURE';
+
+PROGRAM: 'PROGRAM';
+
+QUOTE: 'QUOTE';
+
+RANGE: 'RANGE';
+
+READ: 'READ';
+
+REASSIGN: 'REASSIGN';
+
+RECHECK: 'RECHECK';
+
+RECURSIVE: 'RECURSIVE';
+
+REF: 'REF';
+
+REFRESH: 'REFRESH';
+
+REINDEX: 'REINDEX';
+
+RELATIVE_P: 'RELATIVE';
+
+RELEASE: 'RELEASE';
+
+RENAME: 'RENAME';
+
+REPEATABLE: 'REPEATABLE';
+
+REPLACE: 'REPLACE';
+
+REPLICA: 'REPLICA';
+
+RESET: 'RESET';
+
+RESTART: 'RESTART';
+
+RESTRICT: 'RESTRICT';
+
+RETURNS: 'RETURNS';
+
+REVOKE: 'REVOKE';
+
+ROLE: 'ROLE';
+
+ROLLBACK: 'ROLLBACK';
+
+ROWS: 'ROWS';
+
+RULE: 'RULE';
+
+SAVEPOINT: 'SAVEPOINT';
+
+SCHEMA: 'SCHEMA';
+
+SCROLL: 'SCROLL';
+
+SEARCH: 'SEARCH';
+
+SECOND_P: 'SECOND';
+
+SECURITY: 'SECURITY';
+
+SEQUENCE: 'SEQUENCE';
+
+SEQUENCES: 'SEQUENCES';
+
+SERIALIZABLE: 'SERIALIZABLE';
+
+SERVER: 'SERVER';
+
+SESSION: 'SESSION';
+
+SET: 'SET';
+
+SHARE: 'SHARE';
+
+SHOW: 'SHOW';
+
+SIMPLE: 'SIMPLE';
+
+SNAPSHOT: 'SNAPSHOT';
+
+STABLE: 'STABLE';
+
+STANDALONE_P: 'STANDALONE';
+
+START: 'START';
+
+STATEMENT: 'STATEMENT';
+
+STATISTICS: 'STATISTICS';
+
+STDIN: 'STDIN';
+
+STDOUT: 'STDOUT';
+
+STORAGE: 'STORAGE';
+
+STRICT_P: 'STRICT';
+
+STRIP_P: 'STRIP';
+
+SYSID: 'SYSID';
+
+SYSTEM_P: 'SYSTEM';
+
+TABLES: 'TABLES';
+
+TABLESPACE: 'TABLESPACE';
+
+TEMP: 'TEMP';
+
+TEMPLATE: 'TEMPLATE';
+
+TEMPORARY: 'TEMPORARY';
+
+TEXT_P: 'TEXT';
+
+TRANSACTION: 'TRANSACTION';
+
+TRIGGER: 'TRIGGER';
+
+TRUNCATE: 'TRUNCATE';
+
+TRUSTED: 'TRUSTED';
+
+TYPE_P: 'TYPE';
+
+TYPES_P: 'TYPES';
+
+UNBOUNDED: 'UNBOUNDED';
+
+UNCOMMITTED: 'UNCOMMITTED';
+
+UNENCRYPTED: 'UNENCRYPTED';
+
+UNKNOWN: 'UNKNOWN';
+
+UNLISTEN: 'UNLISTEN';
+
+UNLOGGED: 'UNLOGGED';
+
+UNTIL: 'UNTIL';
+
+UPDATE: 'UPDATE';
+
+VACUUM: 'VACUUM';
+
+VALID: 'VALID';
+
+VALIDATE: 'VALIDATE';
+
+VALIDATOR: 'VALIDATOR';
+//VALUE : 'VALUE;
+
+VARYING: 'VARYING';
+
+VERSION_P: 'VERSION';
+
+VIEW: 'VIEW';
+
+VOLATILE: 'VOLATILE';
+
+WHITESPACE_P: 'WHITESPACE';
+
+WITHOUT: 'WITHOUT';
+
+WORK: 'WORK';
+
+WRAPPER: 'WRAPPER';
+
+WRITE: 'WRITE';
+
+XML_P: 'XML';
+
+YEAR_P: 'YEAR';
+
+YES_P: 'YES';
+
+ZONE: 'ZONE';
+//
+
+// non-reserved keywords (can not be function or type)
+
+//
+
+BETWEEN: 'BETWEEN';
+
+BIGINT: 'BIGINT';
+
+BIT: 'BIT';
+
+BOOLEAN_P: 'BOOLEAN';
+
+CHAR_P: 'CHAR';
+
+CHARACTER: 'CHARACTER';
+
+COALESCE: 'COALESCE';
+
+DEC: 'DEC';
+
+DECIMAL_P: 'DECIMAL';
+
+EXISTS: 'EXISTS';
+
+EXTRACT: 'EXTRACT';
+
+FLOAT_P: 'FLOAT';
+
+GREATEST: 'GREATEST';
+
+INOUT: 'INOUT';
+
+INT_P: 'INT';
+
+INTEGER: 'INTEGER';
+
+INTERVAL: 'INTERVAL';
+
+LEAST: 'LEAST';
+
+NATIONAL: 'NATIONAL';
+
+NCHAR: 'NCHAR';
+
+NONE: 'NONE';
+
+NULLIF: 'NULLIF';
+
+NUMERIC: 'NUMERIC';
+
+OVERLAY: 'OVERLAY';
+
+POSITION: 'POSITION';
+
+PRECISION: 'PRECISION';
+
+REAL: 'REAL';
+
+ROW: 'ROW';
+
+SETOF: 'SETOF';
+
+SMALLINT: 'SMALLINT';
+
+SUBSTRING: 'SUBSTRING';
+
+TIME: 'TIME';
+
+TIMESTAMP: 'TIMESTAMP';
+
+TREAT: 'TREAT';
+
+TRIM: 'TRIM';
+
+VALUES: 'VALUES';
+
+VARCHAR: 'VARCHAR';
+
+XMLATTRIBUTES: 'XMLATTRIBUTES';
+
+XMLCOMMENT: 'XMLCOMMENT';
+
+XMLAGG: 'XMLAGG';
+
+XML_IS_WELL_FORMED: 'XML_IS_WELL_FORMED';
+
+XML_IS_WELL_FORMED_DOCUMENT: 'XML_IS_WELL_FORMED_DOCUMENT';
+
+XML_IS_WELL_FORMED_CONTENT: 'XML_IS_WELL_FORMED_CONTENT';
+
+XPATH: 'XPATH';
+
+XPATH_EXISTS: 'XPATH_EXISTS';
+
+XMLCONCAT: 'XMLCONCAT';
+
+XMLELEMENT: 'XMLELEMENT';
+
+XMLEXISTS: 'XMLEXISTS';
+
+XMLFOREST: 'XMLFOREST';
+
+XMLPARSE: 'XMLPARSE';
+
+XMLPI: 'XMLPI';
+
+XMLROOT: 'XMLROOT';
+
+XMLSERIALIZE: 'XMLSERIALIZE';
+//MISSED
+
+CALL: 'CALL';
+
+CURRENT_P: 'CURRENT';
+
+ATTACH: 'ATTACH';
+
+DETACH: 'DETACH';
+
+EXPRESSION: 'EXPRESSION';
+
+GENERATED: 'GENERATED';
+
+LOGGED: 'LOGGED';
+
+STORED: 'STORED';
+
+INCLUDE: 'INCLUDE';
+
+ROUTINE: 'ROUTINE';
+
+TRANSFORM: 'TRANSFORM';
+
+IMPORT_P: 'IMPORT';
+
+POLICY: 'POLICY';
+
+METHOD: 'METHOD';
+
+REFERENCING: 'REFERENCING';
+
+NEW: 'NEW';
+
+OLD: 'OLD';
+
+VALUE_P: 'VALUE';
+
+SUBSCRIPTION: 'SUBSCRIPTION';
+
+PUBLICATION: 'PUBLICATION';
+
+OUT_P: 'OUT';
+
+END_P: 'END';
+
+ROUTINES: 'ROUTINES';
+
+SCHEMAS: 'SCHEMAS';
+
+PROCEDURES: 'PROCEDURES';
+
+INPUT_P: 'INPUT';
+
+SUPPORT: 'SUPPORT';
+
+PARALLEL: 'PARALLEL';
+
+SQL_P: 'SQL';
+
+DEPENDS: 'DEPENDS';
+
+OVERRIDING: 'OVERRIDING';
+
+CONFLICT: 'CONFLICT';
+
+SKIP_P: 'SKIP';
+
+LOCKED: 'LOCKED';
+
+TIES: 'TIES';
+
+ROLLUP: 'ROLLUP';
+
+CUBE: 'CUBE';
+
+GROUPING: 'GROUPING';
+
+SETS: 'SETS';
+
+TABLESAMPLE: 'TABLESAMPLE';
+
+ORDINALITY: 'ORDINALITY';
+
+XMLTABLE: 'XMLTABLE';
+
+COLUMNS: 'COLUMNS';
+
+XMLNAMESPACES: 'XMLNAMESPACES';
+
+ROWTYPE: 'ROWTYPE';
+
+NORMALIZED: 'NORMALIZED';
+
+WITHIN: 'WITHIN';
+
+FILTER: 'FILTER';
+
+GROUPS: 'GROUPS';
+
+OTHERS: 'OTHERS';
+
+NFC: 'NFC';
+
+NFD: 'NFD';
+
+NFKC: 'NFKC';
+
+NFKD: 'NFKD';
+
+UESCAPE: 'UESCAPE';
+
+VIEWS: 'VIEWS';
+
+NORMALIZE: 'NORMALIZE';
+
+DUMP: 'DUMP';
+
+PRINT_STRICT_PARAMS: 'PRINT_STRICT_PARAMS';
+
+VARIABLE_CONFLICT: 'VARIABLE_CONFLICT';
+
+ERROR: 'ERROR';
+
+USE_VARIABLE: 'USE_VARIABLE';
+
+USE_COLUMN: 'USE_COLUMN';
+
+ALIAS: 'ALIAS';
+
+CONSTANT: 'CONSTANT';
+
+PERFORM: 'PERFORM';
+
+GET: 'GET';
+
+DIAGNOSTICS: 'DIAGNOSTICS';
+
+STACKED: 'STACKED';
+
+ELSIF: 'ELSIF';
+
+WHILE: 'WHILE';
+
+REVERSE: 'REVERSE';
+
+FOREACH: 'FOREACH';
+
+SLICE: 'SLICE';
+
+EXIT: 'EXIT';
+
+RETURN: 'RETURN';
+
+QUERY: 'QUERY';
+
+RAISE: 'RAISE';
+
+SQLSTATE: 'SQLSTATE';
+
+DEBUG: 'DEBUG';
+
+LOG: 'LOG';
+
+INFO: 'INFO';
+
+NOTICE: 'NOTICE';
+
+WARNING: 'WARNING';
+
+EXCEPTION: 'EXCEPTION';
+
+ASSERT: 'ASSERT';
+
+LOOP: 'LOOP';
+
+OPEN: 'OPEN';
+//
+
+// IDENTIFIERS (4.1.1)
+
+//
+
+ABS: 'ABS';
+
+CBRT: 'CBRT';
+
+CEIL: 'CEIL';
+
+CEILING: 'CEILING';
+
+DEGREES: 'DEGREES';
+
+DIV: 'DIV';
+
+EXP: 'EXP';
+
+FACTORIAL: 'FACTORIAL';
+
+FLOOR: 'FLOOR';
+
+GCD: 'GCD';
+
+LCM: 'LCM';
+
+LN: 'LN';
+
+LOG10: 'LOG10';
+
+MIN_SCALE: 'MIN_SCALE';
+
+MOD: 'MOD';
+
+PI: 'PI';
+
+POWER: 'POWER';
+
+RADIANS: 'RADIANS';
+
+ROUND: 'ROUND';
+
+SCALE: 'SCALE';
+
+SIGN: 'SIGN';
+
+SQRT: 'SQRT';
+
+TRIM_SCALE: 'TRIM_SCALE';
+
+TRUNC: 'TRUNC';
+
+WIDTH_BUCKET: 'WIDTH_BUCKET';
+
+RANDOM: 'RANDOM';
+
+SETSEED: 'SETSEED';
+
+ACOS: 'ACOS';
+
+ACOSD: 'ACOSD';
+
+ASIN: 'ASIN';
+
+ASIND: 'ASIND';
+
+ATAN: 'ATAN';
+
+ATAND: 'ATAND';
+
+ATAN2: 'ATAN2';
+
+ATAN2D: 'ATAN2D';
+
+COS: 'COS';
+
+COSD: 'COSD';
+
+COT: 'COT';
+
+COTD: 'COTD';
+
+SIN: 'SIN';
+
+SIND: 'SIND';
+
+TAN: 'TAN';
+
+TAND: 'TAND';
+
+SINH: 'SINH';
+
+COSH: 'COSH';
+
+TANH: 'TANH';
+
+ASINH: 'ASINH';
+
+ACOSH: 'ACOSH';
+
+ATANH: 'ATANH';
+
+BIT_LENGTH: 'BIT_LENGTH';
+
+CHAR_LENGTH: 'CHAR_LENGTH';
+
+CHARACTER_LENGTH: 'CHARACTER_LENGTH';
+
+LOWER: 'LOWER';
+
+OCTET_LENGTH: 'OCTET_LENGTH';
+
+UPPER: 'UPPER';
+
+ASCII: 'ASCII';
+
+BTRIM: 'BTRIM';
+
+CHR: 'CHR';
+
+CONCAT: 'CONCAT';
+
+CONCAT_WS: 'CONCAT_WS';
+
+FORMAT: 'FORMAT';
+
+INITCAP: 'INITCAP';
+
+LENGTH: 'LENGTH';
+
+LPAD: 'LPAD';
+
+LTRIM: 'LTRIM';
+
+MD5: 'MD5';
+
+PARSE_IDENT: 'PARSE_IDENT';
+
+PG_CLIENT_ENCODING: 'PG_CLIENT_ENCODING';
+
+QUOTE_IDENT: 'QUOTE_IDENT';
+
+QUOTE_LITERAL: 'QUOTE_LITERAL';
+
+QUOTE_NULLABLE: 'QUOTE_NULLABLE';
+
+REGEXP_COUNT: 'REGEXP_COUNT';
+
+REGEXP_INSTR: 'REGEXP_INSTR';
+
+REGEXP_LIKE: 'REGEXP_LIKE';
+
+REGEXP_MATCH: 'REGEXP_MATCH';
+
+REGEXP_MATCHES: 'REGEXP_MATCHES';
+
+REGEXP_REPLACE: 'REGEXP_REPLACE';
+
+REGEXP_SPLIT_TO_ARRAY: 'REGEXP_SPLIT_TO_ARRAY';
+
+REGEXP_SPLIT_TO_TABLE: 'REGEXP_SPLIT_TO_TABLE';
+
+REGEXP_SUBSTR: 'REGEXP_SUBSTR';
+
+REPEAT: 'REPEAT';
+
+RPAD: 'RPAD';
+
+RTRIM: 'RTRIM';
+
+SPLIT_PART: 'SPLIT_PART';
+
+STARTS_WITH: 'STARTS_WITH';
+
+STRING_TO_ARRAY: 'STRING_TO_ARRAY';
+
+STRING_TO_TABLE: 'STRING_TO_TABLE';
+
+STRPOS: 'STRPOS';
+
+SUBSTR: 'SUBSTR';
+
+TO_ASCII: 'TO_ASCII';
+
+TO_HEX: 'TO_HEX';
+
+TRANSLATE: 'TRANSLATE';
+
+UNISTR: 'UNISTR';
+
+AGE: 'AGE';
+
+CLOCK_TIMESTAMP: 'CLOCK_TIMESTAMP';
+
+DATE_BIN: 'DATE_BIN';
+
+DATE_PART: 'DATE_PART';
+
+DATE_TRUNC: 'DATE_TRUNC';
+
+ISFINITE: 'ISFINITE';
+
+JUSTIFY_DAYS: 'JUSTIFY_DAYS';
+
+JUSTIFY_HOURS: 'JUSTIFY_HOURS';
+
+JUSTIFY_INTERVAL: 'JUSTIFY_INTERVAL';
+
+MAKE_DATE: 'MAKE_DATE';
+
+MAKE_INTERVAL: 'MAKE_INTERVAL';
+
+MAKE_TIME: 'MAKE_TIME';
+
+MAKE_TIMESTAMP: 'MAKE_TIMESTAMP';
+
+MAKE_TIMESTAMPTZ: 'MAKE_TIMESTAMPTZ';
+
+NOW: 'NOW';
+
+STATEMENT_TIMESTAMP: 'STATEMENT_TIMESTAMP';
+
+TIMEOFDAY: 'TIMEOFDAY';
+
+TRANSACTION_TIMESTAMP: 'TRANSACTION_TIMESTAMP';
+
+TO_TIMESTAMP: 'TO_TIMESTAMP';
+
+TO_CHAR: 'TO_CHAR';
+
+TO_DATE: 'TO_DATE';
+
+TO_NUMBER: 'TO_NUMBER';
+
+Identifier: IdentifierStartChar IdentifierChar*;
+
+fragment IdentifierStartChar options {
+ caseInsensitive = false;
+}: // these are the valid identifier start characters below 0x7F
+ [a-zA-Z_]
+ | // these are the valid characters from 0x80 to 0xFF
+ [\u00AA\u00B5\u00BA\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u00FF]
+ | // these are the letters above 0xFF which only need a single UTF-16 code unit
+ [\u0100-\uD7FF\uE000-\uFFFF] {charIsLetter()}?
+ | // letters which require multiple UTF-16 code units
+ [\uD800-\uDBFF] [\uDC00-\uDFFF] {
+ checkIfUtf32Letter()
+ }?
+;
+
+fragment IdentifierChar: StrictIdentifierChar | '$';
+
+fragment StrictIdentifierChar: IdentifierStartChar | [0-9];
+/* Quoted Identifiers
+ *
+ * These are divided into four separate tokens, allowing distinction of valid quoted identifiers from invalid quoted
+ * identifiers without sacrificing the ability of the lexer to reliably recover from lexical errors in the input.
+ */
+
+QuotedIdentifier: UnterminatedQuotedIdentifier '"';
+// This is a quoted identifier which only contains valid characters but is not terminated
+
+UnterminatedQuotedIdentifier: '"' ('""' | ~ [\u0000"])*;
+// This is a quoted identifier which is terminated but contains a \u0000 character
+
+InvalidQuotedIdentifier: InvalidUnterminatedQuotedIdentifier '"';
+// This is a quoted identifier which is unterminated and contains a \u0000 character
+
+InvalidUnterminatedQuotedIdentifier: '"' ('""' | ~ '"')*;
+/* Unicode Quoted Identifiers
+ *
+ * These are divided into four separate tokens, allowing distinction of valid Unicode quoted identifiers from invalid
+ * Unicode quoted identifiers without sacrificing the ability of the lexer to reliably recover from lexical errors in
+ * the input. Note that escape sequences are never checked as part of this determination due to the ability of users
+ * to change the escape character with a UESCAPE clause following the Unicode quoted identifier.
+ *
+ * TODO: these rules assume "" is still a valid escape sequence within a Unicode quoted identifier.
+ */
+
+UnicodeQuotedIdentifier: 'U' '&' QuotedIdentifier;
+// This is a Unicode quoted identifier which only contains valid characters but is not terminated
+
+UnterminatedUnicodeQuotedIdentifier: 'U' '&' UnterminatedQuotedIdentifier;
+// This is a Unicode quoted identifier which is terminated but contains a \u0000 character
+
+InvalidUnicodeQuotedIdentifier: 'U' '&' InvalidQuotedIdentifier;
+// This is a Unicode quoted identifier which is unterminated and contains a \u0000 character
+
+InvalidUnterminatedUnicodeQuotedIdentifier: 'U' '&' InvalidUnterminatedQuotedIdentifier;
+//
+
+// CONSTANTS (4.1.2)
+
+//
+
+// String Constants (4.1.2.1)
+
+StringConstant: UnterminatedStringConstant '\'';
+
+UnterminatedStringConstant: '\'' ('\'\'' | ~ '\'')*;
+// String Constants with C-style Escapes (4.1.2.2)
+
+BeginEscapeStringConstant: 'E' '\'' -> more, pushMode (EscapeStringConstantMode);
+// String Constants with Unicode Escapes (4.1.2.3)
+
+//
+
+// Note that escape sequences are never checked as part of this token due to the ability of users to change the escape
+
+// character with a UESCAPE clause following the Unicode string constant.
+
+//
+
+// TODO: these rules assume '' is still a valid escape sequence within a Unicode string constant.
+
+UnicodeEscapeStringConstant: UnterminatedUnicodeEscapeStringConstant '\'';
+
+UnterminatedUnicodeEscapeStringConstant: 'U' '&' UnterminatedStringConstant;
+// Dollar-quoted String Constants (4.1.2.4)
+
+BeginDollarStringConstant: '$' Tag? '$' {pushTag();} -> pushMode (DollarQuotedStringMode);
+/* "The tag, if any, of a dollar-quoted string follows the same rules as an
+ * unquoted identifier, except that it cannot contain a dollar sign."
+ */
+
+fragment Tag: IdentifierStartChar StrictIdentifierChar*;
+// Bit-strings Constants (4.1.2.5)
+
+BinaryStringConstant: UnterminatedBinaryStringConstant '\'';
+
+UnterminatedBinaryStringConstant: 'B' '\'' [01]*;
+
+InvalidBinaryStringConstant: InvalidUnterminatedBinaryStringConstant '\'';
+
+InvalidUnterminatedBinaryStringConstant: 'B' UnterminatedStringConstant;
+
+HexadecimalStringConstant: UnterminatedHexadecimalStringConstant '\'';
+
+UnterminatedHexadecimalStringConstant: 'X' '\'' [0-9A-F]*;
+
+InvalidHexadecimalStringConstant: InvalidUnterminatedHexadecimalStringConstant '\'';
+
+InvalidUnterminatedHexadecimalStringConstant: 'X' UnterminatedStringConstant;
+// Numeric Constants (4.1.2.6)
+
+Integral: Digits;
+
+NumericFail: Digits '..' {handleNumericFail();};
+
+Numeric:
+ Digits '.' Digits? /*? replaced with + to solve problem with DOT_DOT .. but this surely must be rewriten */ (
+ 'E' [+-]? Digits
+ )?
+ | '.' Digits ('E' [+-]? Digits)?
+ | Digits 'E' [+-]? Digits
+;
+
+fragment Digits: [0-9]+;
+
+PLSQLVARIABLENAME: ':' [A-Z_] [A-Z_0-9$]*;
+
+PLSQLIDENTIFIER: ':"' ('\\' . | '""' | ~ ('"' | '\\'))* '"';
+//
+
+// WHITESPACE (4.1)
+
+//
+
+Whitespace: [ \t]+ -> channel (HIDDEN);
+
+Newline: ('\r' '\n'? | '\n') -> channel (HIDDEN);
+//
+
+// COMMENTS (4.1.5)
+
+//
+
+LineComment: '--' ~ [\r\n]* -> channel (HIDDEN);
+
+BlockComment:
+ ('/*' ('/'* BlockComment | ~ [/*] | '/'+ ~ [/*] | '*'+ ~ [/*])* '*'* '*/') -> channel (HIDDEN)
+;
+
+UnterminatedBlockComment:
+ '/*' (
+ '/'* BlockComment
+ | // these characters are not part of special sequences in a block comment
+ ~ [/*]
+ | // handle / or * characters which are not part of /* or */ and do not appear at the end of the file
+ ('/'+ ~ [/*] | '*'+ ~ [/*])
+ )*
+ // Handle the case of / or * characters at the end of the file, or a nested unterminated block comment
+ ('/'+ | '*'+ | '/'* UnterminatedBlockComment)?
+ // Optional assertion to make sure this rule is working as intended
+ {
+ unterminatedBlockCommentDebugAssert();
+ }
+;
+//
+
+// META-COMMANDS
+
+//
+
+// http://www.postgresql.org/docs/9.3/static/app-psql.html
+
+MetaCommand: '\\' (~ [\r\n\\"] | '"' ~ [\r\n"]* '"')* ('"' ~ [\r\n"]*)?;
+
+EndMetaCommand: '\\\\';
+//
+
+// ERROR
+
+//
+
+// Any character which does not match one of the above rules will appear in the token stream as an ErrorCharacter token.
+
+// This ensures the lexer itself will never encounter a syntax error, so all error handling may be performed by the
+
+// parser.
+
+ErrorCharacter: .;
+
+mode EscapeStringConstantMode;
+EscapeStringConstant: EscapeStringText '\'' -> mode (AfterEscapeStringConstantMode);
+
+UnterminatedEscapeStringConstant:
+ EscapeStringText
+ // Handle a final unmatched \ character appearing at the end of the file
+ '\\'? EOF
+;
+
+fragment EscapeStringText options {
+ caseInsensitive = false;
+}:
+ (
+ '\'\''
+ | '\\' (
+ // two-digit hex escapes are still valid when treated as single-digit escapes
+ 'x' [0-9a-fA-F]
+ | 'u' [0-9a-fA-F] [0-9a-fA-F] [0-9a-fA-F] [0-9a-fA-F]
+ | 'U' [0-9a-fA-F] [0-9a-fA-F] [0-9a-fA-F] [0-9a-fA-F] [0-9a-fA-F] [0-9a-fA-F] [0-9a-fA-F] [0-9a-fA-F]
+ | // Any character other than the Unicode escapes can follow a backslash. Some have special meaning,
+ // but that doesn't affect the syntax.
+ ~ [xuU]
+ )
+ | ~ ['\\]
+ )*
+;
+
+InvalidEscapeStringConstant: InvalidEscapeStringText '\'' -> mode (AfterEscapeStringConstantMode);
+
+InvalidUnterminatedEscapeStringConstant:
+ InvalidEscapeStringText
+ // Handle a final unmatched \ character appearing at the end of the file
+ '\\'? EOF
+;
+
+fragment InvalidEscapeStringText: ('\'\'' | '\\' . | ~ ['\\])*;
+
+mode AfterEscapeStringConstantMode;
+AfterEscapeStringConstantMode_Whitespace: Whitespace -> type (Whitespace), channel (HIDDEN);
+
+AfterEscapeStringConstantMode_Newline:
+ Newline -> type (Newline), channel (HIDDEN), mode (AfterEscapeStringConstantWithNewlineMode)
+;
+
+AfterEscapeStringConstantMode_NotContinued:
+ {} // intentionally empty
+ -> skip, popMode
+;
+
+mode AfterEscapeStringConstantWithNewlineMode;
+AfterEscapeStringConstantWithNewlineMode_Whitespace:
+ Whitespace -> type (Whitespace), channel (HIDDEN)
+;
+
+AfterEscapeStringConstantWithNewlineMode_Newline: Newline -> type (Newline), channel (HIDDEN);
+
+AfterEscapeStringConstantWithNewlineMode_Continued:
+ '\'' -> more, mode (EscapeStringConstantMode)
+;
+
+AfterEscapeStringConstantWithNewlineMode_NotContinued:
+ {} // intentionally empty
+ -> skip, popMode
+;
+
+mode DollarQuotedStringMode;
+DollarText:
+ ~ '$'+
+ //| '$'([0-9])+
+ | // this alternative improves the efficiency of handling $ characters within a dollar-quoted string which are
+
+ // not part of the ending tag.
+ '$' ~ '$'*
+;
+
+EndDollarStringConstant: ('$' Tag? '$') {isTag()}? {popTag();} -> popMode;
diff --git a/incubator/binding-pgsql/src/main/antlr4/io/aklivity/zilla/runtime/binding/pgsql/parser/PostgreSqlParser.g4 b/incubator/binding-pgsql/src/main/antlr4/io/aklivity/zilla/runtime/binding/pgsql/parser/PostgreSqlParser.g4
new file mode 100644
index 0000000000..d2bf3dcbd2
--- /dev/null
+++ b/incubator/binding-pgsql/src/main/antlr4/io/aklivity/zilla/runtime/binding/pgsql/parser/PostgreSqlParser.g4
@@ -0,0 +1,5616 @@
+/*
+ * Copyright 2021-2023 Aklivity Inc
+ *
+ * Licensed under the Aklivity Community License (the "License"); you may not use
+ * this file except in compliance with the License. You may obtain a copy of the
+ * License at
+ *
+ * https://www.aklivity.io/aklivity-community-license/
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OF ANY KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations under the License.
+ */
+
+parser grammar PostgreSqlParser;
+
+options {
+ tokenVocab = PostgreSqlLexer;
+ superClass = PostgreSqlParserBase;
+}
+
+@header {
+}
+
+@members {
+}
+
+root
+ : stmtblock EOF
+ ;
+
+plsqlroot
+ : pl_function
+ ;
+
+stmtblock
+ : stmtmulti
+ ;
+
+stmtmulti
+ : (stmt SEMI?)*
+ ;
+
+stmt
+ : altereventtrigstmt
+ | altercollationstmt
+ | alterdatabasestmt
+ | alterdatabasesetstmt
+ | alterdefaultprivilegesstmt
+ | alterdomainstmt
+ | alterenumstmt
+ | alterextensionstmt
+ | alterextensioncontentsstmt
+ | alterfdwstmt
+ | alterforeignserverstmt
+ | alterfunctionstmt
+ | altergroupstmt
+ | alterobjectdependsstmt
+ | alterobjectschemastmt
+ | alterownerstmt
+ | alteroperatorstmt
+ | altertypestmt
+ | alterpolicystmt
+ | alterseqstmt
+ | altersystemstmt
+ | altertablestmt
+ | altertblspcstmt
+ | altercompositetypestmt
+ | alterpublicationstmt
+ | alterrolesetstmt
+ | alterrolestmt
+ | altersubscriptionstmt
+ | alterstatsstmt
+ | altertsconfigurationstmt
+ | altertsdictionarystmt
+ | alterusermappingstmt
+ | analyzestmt
+ | callstmt
+ | checkpointstmt
+ | closeportalstmt
+ | clusterstmt
+ | commentstmt
+ | constraintssetstmt
+ | copystmt
+ | createamstmt
+ | createasstmt
+ | createassertionstmt
+ | createcaststmt
+ | createconversionstmt
+ | createdomainstmt
+ | createextensionstmt
+ | createfdwstmt
+ | createforeignserverstmt
+ | createforeigntablestmt
+ | createfunctionstmt
+ | creategroupstmt
+ | creatematviewstmt
+ | createopclassstmt
+ | createopfamilystmt
+ | createpublicationstmt
+ | alteropfamilystmt
+ | createpolicystmt
+ | createplangstmt
+ | createschemastmt
+ | createseqstmt
+ | createstmt
+ | createstreamstmt
+ | createsubscriptionstmt
+ | createstatsstmt
+ | createtablespacestmt
+ | createtransformstmt
+ | createtrigstmt
+ | createeventtrigstmt
+ | createrolestmt
+ | createuserstmt
+ | createusermappingstmt
+ | createdbstmt
+ | deallocatestmt
+ | declarecursorstmt
+ | definestmt
+ | deletestmt
+ | discardstmt
+ | dostmt
+ | dropcaststmt
+ | dropopclassstmt
+ | dropopfamilystmt
+ | dropownedstmt
+ | dropstmt
+ | dropsubscriptionstmt
+ | droptablespacestmt
+ | droptransformstmt
+ | droprolestmt
+ | dropusermappingstmt
+ | dropdbstmt
+ | executestmt
+ | explainstmt
+ | fetchstmt
+ | grantstmt
+ | grantrolestmt
+ | importforeignschemastmt
+ | indexstmt
+ | insertstmt
+ | mergestmt
+ | listenstmt
+ | refreshmatviewstmt
+ | loadstmt
+ | lockstmt
+ | notifystmt
+ | preparestmt
+ | reassignownedstmt
+ | reindexstmt
+ | removeaggrstmt
+ | removefuncstmt
+ | removeoperstmt
+ | renamestmt
+ | revokestmt
+ | revokerolestmt
+ | rulestmt
+ | seclabelstmt
+ | selectstmt
+ | transactionstmt
+ | truncatestmt
+ | unlistenstmt
+ | updatestmt
+ | vacuumstmt
+ | variableresetstmt
+ | variablesetstmt
+ | variableshowstmt
+ | viewstmt
+ | plsqlconsolecommand
+ ;
+
+plsqlconsolecommand
+ : MetaCommand EndMetaCommand?
+ ;
+
+callstmt
+ : CALL func_application
+ ;
+
+createrolestmt
+ : CREATE ROLE roleid opt_with optrolelist
+ ;
+
+opt_with
+ : WITH
+ //| WITH_LA
+ |
+ ;
+
+optrolelist
+ : createoptroleelem*
+ ;
+
+alteroptrolelist
+ : alteroptroleelem*
+ ;
+
+alteroptroleelem
+ : PASSWORD (sconst | NULL_P)
+ | (ENCRYPTED | UNENCRYPTED) PASSWORD sconst
+ | INHERIT
+ | CONNECTION LIMIT signediconst
+ | VALID UNTIL sconst
+ | USER role_list
+ | identifier
+ ;
+
+createoptroleelem
+ : alteroptroleelem
+ | SYSID iconst
+ | ADMIN role_list
+ | ROLE role_list
+ | IN_P (ROLE | GROUP_P) role_list
+ ;
+
+createuserstmt
+ : CREATE USER roleid opt_with optrolelist
+ ;
+
+alterrolestmt
+ : ALTER (ROLE | USER) rolespec opt_with alteroptrolelist
+ ;
+
+opt_in_database
+ :
+ | IN_P DATABASE name
+ ;
+
+alterrolesetstmt
+ : ALTER (ROLE | USER) ALL? rolespec opt_in_database setresetclause
+ ;
+
+droprolestmt
+ : DROP (ROLE | USER | GROUP_P) (IF_P EXISTS)? role_list
+ ;
+
+creategroupstmt
+ : CREATE GROUP_P roleid opt_with optrolelist
+ ;
+
+altergroupstmt
+ : ALTER GROUP_P rolespec add_drop USER role_list
+ ;
+
+add_drop
+ : ADD_P
+ | DROP
+ ;
+
+createschemastmt
+ : CREATE SCHEMA (IF_P NOT EXISTS)? (optschemaname AUTHORIZATION rolespec | colid) optschemaeltlist
+ ;
+
+optschemaname
+ : colid
+ |
+ ;
+
+optschemaeltlist
+ : schema_stmt*
+ ;
+
+schema_stmt
+ : createstmt
+ | indexstmt
+ | createseqstmt
+ | createtrigstmt
+ | grantstmt
+ | viewstmt
+ ;
+
+variablesetstmt
+ : SET (LOCAL | SESSION)? set_rest
+ ;
+
+set_rest
+ : TRANSACTION transaction_mode_list
+ | SESSION CHARACTERISTICS AS TRANSACTION transaction_mode_list
+ | set_rest_more
+ ;
+
+generic_set
+ : var_name (TO | EQUAL) var_list
+ ;
+
+set_rest_more
+ : generic_set
+ | var_name FROM CURRENT_P
+ | TIME ZONE zone_value
+ | CATALOG sconst
+ | SCHEMA sconst
+ | NAMES opt_encoding
+ | ROLE nonreservedword_or_sconst
+ | SESSION AUTHORIZATION nonreservedword_or_sconst
+ | XML_P OPTION document_or_content
+ | TRANSACTION SNAPSHOT sconst
+ ;
+
+var_name
+ : colid (DOT colid)*
+ ;
+
+var_list
+ : var_value (COMMA var_value)*
+ ;
+
+var_value
+ : opt_boolean_or_string
+ | numericonly
+ ;
+
+iso_level
+ : READ (UNCOMMITTED | COMMITTED)
+ | REPEATABLE READ
+ | SERIALIZABLE
+ ;
+
+opt_boolean_or_string
+ : TRUE_P
+ | FALSE_P
+ | ON
+ | nonreservedword_or_sconst
+ ;
+
+zone_value
+ : sconst
+ | identifier
+ | constinterval sconst opt_interval
+ | constinterval OPEN_PAREN iconst CLOSE_PAREN sconst
+ | numericonly
+ | DEFAULT
+ | LOCAL
+ ;
+
+opt_encoding
+ : sconst
+ | DEFAULT
+ |
+ ;
+
+nonreservedword_or_sconst
+ : nonreservedword
+ | sconst
+ ;
+
+variableresetstmt
+ : RESET reset_rest
+ ;
+
+reset_rest
+ : generic_reset
+ | TIME ZONE
+ | TRANSACTION ISOLATION LEVEL
+ | SESSION AUTHORIZATION
+ ;
+
+generic_reset
+ : var_name
+ | ALL
+ ;
+
+setresetclause
+ : SET set_rest
+ | variableresetstmt
+ ;
+
+functionsetresetclause
+ : SET set_rest_more
+ | variableresetstmt
+ ;
+
+variableshowstmt
+ : SHOW (var_name | TIME ZONE | TRANSACTION ISOLATION LEVEL | SESSION AUTHORIZATION | ALL)
+ ;
+
+constraintssetstmt
+ : SET CONSTRAINTS constraints_set_list constraints_set_mode
+ ;
+
+constraints_set_list
+ : ALL
+ | qualified_name_list
+ ;
+
+constraints_set_mode
+ : DEFERRED
+ | IMMEDIATE
+ ;
+
+checkpointstmt
+ : CHECKPOINT
+ ;
+
+discardstmt
+ : DISCARD (ALL | TEMP | TEMPORARY | PLANS | SEQUENCES)
+ ;
+
+altertablestmt
+ : ALTER TABLE (IF_P EXISTS)? relation_expr (alter_table_cmds | partition_cmd)
+ | ALTER TABLE ALL IN_P TABLESPACE name (OWNED BY role_list)? SET TABLESPACE name opt_nowait
+ | ALTER INDEX (IF_P EXISTS)? qualified_name (alter_table_cmds | index_partition_cmd)
+ | ALTER INDEX ALL IN_P TABLESPACE name (OWNED BY role_list)? SET TABLESPACE name opt_nowait
+ | ALTER SEQUENCE (IF_P EXISTS)? qualified_name alter_table_cmds
+ | ALTER VIEW (IF_P EXISTS)? qualified_name alter_table_cmds
+ | ALTER MATERIALIZED VIEW (IF_P EXISTS)? qualified_name alter_table_cmds
+ | ALTER MATERIALIZED VIEW ALL IN_P TABLESPACE name (OWNED BY role_list)? SET TABLESPACE name opt_nowait
+ | ALTER FOREIGN TABLE (IF_P EXISTS)? relation_expr alter_table_cmds
+ ;
+
+alter_table_cmds
+ : alter_table_cmd (COMMA alter_table_cmd)*
+ ;
+
+partition_cmd
+ : ATTACH PARTITION qualified_name partitionboundspec
+ | DETACH PARTITION qualified_name
+ ;
+
+index_partition_cmd
+ : ATTACH PARTITION qualified_name
+ ;
+
+alter_table_cmd
+ : ADD_P columnDef
+ | ADD_P IF_P NOT EXISTS columnDef
+ | ADD_P COLUMN columnDef
+ | ADD_P COLUMN IF_P NOT EXISTS columnDef
+ | ALTER opt_column colid alter_column_default
+ | ALTER opt_column colid DROP NOT NULL_P
+ | ALTER opt_column colid SET NOT NULL_P
+ | ALTER opt_column colid DROP EXPRESSION
+ | ALTER opt_column colid DROP EXPRESSION IF_P EXISTS
+ | ALTER opt_column colid SET STATISTICS signediconst
+ | ALTER opt_column iconst SET STATISTICS signediconst
+ | ALTER opt_column colid SET reloptions
+ | ALTER opt_column colid RESET reloptions
+ | ALTER opt_column colid SET STORAGE colid
+ | ALTER opt_column colid ADD_P GENERATED generated_when AS IDENTITY_P optparenthesizedseqoptlist
+ | ALTER opt_column colid alter_identity_column_option_list
+ | ALTER opt_column colid DROP IDENTITY_P
+ | ALTER opt_column colid DROP IDENTITY_P IF_P EXISTS
+ | DROP opt_column IF_P EXISTS colid opt_drop_behavior
+ | DROP opt_column colid opt_drop_behavior
+ | ALTER opt_column colid opt_set_data TYPE_P typename opt_collate_clause alter_using
+ | ALTER opt_column colid alter_generic_options
+ | ADD_P tableconstraint
+ | ALTER CONSTRAINT name constraintattributespec
+ | VALIDATE CONSTRAINT name
+ | DROP CONSTRAINT IF_P EXISTS name opt_drop_behavior
+ | DROP CONSTRAINT name opt_drop_behavior
+ | SET WITHOUT OIDS
+ | CLUSTER ON name
+ | SET WITHOUT CLUSTER
+ | SET LOGGED
+ | SET UNLOGGED
+ | ENABLE_P TRIGGER name
+ | ENABLE_P ALWAYS TRIGGER name
+ | ENABLE_P REPLICA TRIGGER name
+ | ENABLE_P TRIGGER ALL
+ | ENABLE_P TRIGGER USER
+ | DISABLE_P TRIGGER name
+ | DISABLE_P TRIGGER ALL
+ | DISABLE_P TRIGGER USER
+ | ENABLE_P RULE name
+ | ENABLE_P ALWAYS RULE name
+ | ENABLE_P REPLICA RULE name
+ | DISABLE_P RULE name
+ | INHERIT qualified_name
+ | NO INHERIT qualified_name
+ | OF any_name
+ | NOT OF
+ | OWNER TO rolespec
+ | SET TABLESPACE name
+ | SET reloptions
+ | RESET reloptions
+ | REPLICA IDENTITY_P replica_identity
+ | ENABLE_P ROW LEVEL SECURITY
+ | DISABLE_P ROW LEVEL SECURITY
+ | FORCE ROW LEVEL SECURITY
+ | NO FORCE ROW LEVEL SECURITY
+ | alter_generic_options
+ ;
+
+alter_column_default
+ : SET DEFAULT a_expr
+ | DROP DEFAULT
+ ;
+
+opt_drop_behavior
+ : CASCADE
+ | RESTRICT
+ |
+ ;
+
+opt_collate_clause
+ : COLLATE any_name
+ |
+ ;
+
+alter_using
+ : USING a_expr
+ |
+ ;
+
+replica_identity
+ : NOTHING
+ | FULL
+ | DEFAULT
+ | USING INDEX name
+ ;
+
+reloptions
+ : OPEN_PAREN reloption_list CLOSE_PAREN
+ ;
+
+opt_reloptions
+ : WITH reloptions
+ |
+ ;
+
+reloption_list
+ : reloption_elem (COMMA reloption_elem)*
+ ;
+
+reloption_elem
+ : collabel (EQUAL def_arg | DOT collabel (EQUAL def_arg)?)?
+ ;
+
+alter_identity_column_option_list
+ : alter_identity_column_option+
+ ;
+
+alter_identity_column_option
+ : RESTART (opt_with numericonly)?
+ | SET (seqoptelem | GENERATED generated_when)
+ ;
+
+partitionboundspec
+ : FOR VALUES WITH OPEN_PAREN hash_partbound CLOSE_PAREN
+ | FOR VALUES IN_P OPEN_PAREN expr_list CLOSE_PAREN
+ | FOR VALUES FROM OPEN_PAREN expr_list CLOSE_PAREN TO OPEN_PAREN expr_list CLOSE_PAREN
+ | DEFAULT
+ ;
+
+hash_partbound_elem
+ : nonreservedword iconst
+ ;
+
+hash_partbound
+ : hash_partbound_elem (COMMA hash_partbound_elem)*
+ ;
+
+altercompositetypestmt
+ : ALTER TYPE_P any_name alter_type_cmds
+ ;
+
+alter_type_cmds
+ : alter_type_cmd (COMMA alter_type_cmd)*
+ ;
+
+alter_type_cmd
+ : ADD_P ATTRIBUTE tablefuncelement opt_drop_behavior
+ | DROP ATTRIBUTE (IF_P EXISTS)? colid opt_drop_behavior
+ | ALTER ATTRIBUTE colid opt_set_data TYPE_P typename opt_collate_clause opt_drop_behavior
+ ;
+
+closeportalstmt
+ : CLOSE (cursor_name | ALL)
+ ;
+
+copystmt
+ : COPY opt_binary qualified_name opt_column_list copy_from opt_program copy_file_name copy_delimiter opt_with copy_options where_clause
+ | COPY OPEN_PAREN preparablestmt CLOSE_PAREN TO opt_program copy_file_name opt_with copy_options
+ ;
+
+copy_from
+ : FROM
+ | TO
+ ;
+
+opt_program
+ : PROGRAM
+ |
+ ;
+
+copy_file_name
+ : sconst
+ | STDIN
+ | STDOUT
+ ;
+
+copy_options
+ : copy_opt_list
+ | OPEN_PAREN copy_generic_opt_list CLOSE_PAREN
+ ;
+
+copy_opt_list
+ : copy_opt_item*
+ ;
+
+copy_opt_item
+ : BINARY
+ | FREEZE
+ | DELIMITER opt_as sconst
+ | NULL_P opt_as sconst
+ | CSV
+ | HEADER_P
+ | QUOTE opt_as sconst
+ | ESCAPE opt_as sconst
+ | FORCE QUOTE columnlist
+ | FORCE QUOTE STAR
+ | FORCE NOT NULL_P columnlist
+ | FORCE NULL_P columnlist
+ | ENCODING sconst
+ ;
+
+opt_binary
+ : BINARY
+ |
+ ;
+
+copy_delimiter
+ : opt_using DELIMITERS sconst
+ |
+ ;
+
+opt_using
+ : USING
+ |
+ ;
+
+copy_generic_opt_list
+ : copy_generic_opt_elem (COMMA copy_generic_opt_elem)*
+ ;
+
+copy_generic_opt_elem
+ : collabel copy_generic_opt_arg
+ ;
+
+copy_generic_opt_arg
+ : opt_boolean_or_string
+ | numericonly
+ | STAR
+ | OPEN_PAREN copy_generic_opt_arg_list CLOSE_PAREN
+ |
+ ;
+
+copy_generic_opt_arg_list
+ : copy_generic_opt_arg_list_item (COMMA copy_generic_opt_arg_list_item)*
+ ;
+
+copy_generic_opt_arg_list_item
+ : opt_boolean_or_string
+ ;
+
+createstreamstmt
+ : CREATE STREAM (IF_P NOT EXISTS)? stream_name OPEN_PAREN stream_columns CLOSE_PAREN opt_with_stream
+ ;
+
+stream_name
+ : qualified_name
+ ;
+
+stream_columns
+ : stream_column (COMMA stream_column)*
+ ;
+
+stream_column
+ : colid typename
+ ;
+
+opt_with_stream
+ : WITH reloptions
+ |
+ ;
+
+createstmt
+ : CREATE opttemp opttable_type (IF_P NOT EXISTS)? qualified_name (
+ OPEN_PAREN opttableelementlist CLOSE_PAREN optinherit optpartitionspec table_access_method_clause optwith oncommitoption opttablespace
+ | OF any_name opttypedtableelementlist optpartitionspec table_access_method_clause optwith oncommitoption opttablespace
+ | PARTITION OF qualified_name opttypedtableelementlist partitionboundspec optpartitionspec table_access_method_clause optwith oncommitoption
+ opttablespace
+ )
+ ;
+
+opttable_type
+ : TABLE
+ | TOPIC
+ ;
+
+opttemp
+ : TEMPORARY
+ | TEMP
+ | LOCAL (TEMPORARY | TEMP)
+ | GLOBAL (TEMPORARY | TEMP)
+ | UNLOGGED
+ |
+ ;
+
+opttableelementlist
+ : tableelementlist
+ |
+ ;
+
+opttypedtableelementlist
+ : OPEN_PAREN typedtableelementlist CLOSE_PAREN
+ |
+ ;
+
+tableelementlist
+ : tableelement (COMMA tableelement)*
+ ;
+
+typedtableelementlist
+ : typedtableelement (COMMA typedtableelement)*
+ ;
+
+tableelement
+ : tableconstraint
+ | tablelikeclause
+ | columnDef
+ ;
+
+typedtableelement
+ : columnOptions
+ | tableconstraint
+ ;
+
+columnDef
+ : colid typename create_generic_options colquallist
+ ;
+
+columnOptions
+ : colid (WITH OPTIONS)? colquallist
+ ;
+
+colquallist
+ : colconstraint*
+ ;
+
+colconstraint
+ : CONSTRAINT name colconstraintelem
+ | colconstraintelem
+ | constraintattr
+ | COLLATE any_name
+ ;
+
+colconstraintelem
+ : NOT NULL_P
+ | NULL_P
+ | UNIQUE opt_definition optconstablespace
+ | PRIMARY KEY opt_definition optconstablespace
+ | CHECK OPEN_PAREN a_expr CLOSE_PAREN opt_no_inherit
+ | DEFAULT b_expr
+ | GENERATED generated_when AS (
+ IDENTITY_P optparenthesizedseqoptlist
+ | OPEN_PAREN a_expr CLOSE_PAREN STORED
+ )
+ | REFERENCES qualified_name opt_column_list key_match key_actions
+ ;
+
+generated_when
+ : ALWAYS
+ | BY DEFAULT
+ ;
+
+constraintattr
+ : DEFERRABLE
+ | NOT DEFERRABLE
+ | INITIALLY (DEFERRED | IMMEDIATE)
+ ;
+
+tablelikeclause
+ : LIKE qualified_name tablelikeoptionlist
+ ;
+
+tablelikeoptionlist
+ : ((INCLUDING | EXCLUDING) tablelikeoption)*
+ ;
+
+tablelikeoption
+ : COMMENTS
+ | CONSTRAINTS
+ | DEFAULTS
+ | IDENTITY_P
+ | GENERATED
+ | INDEXES
+ | STATISTICS
+ | STORAGE
+ | ALL
+ ;
+
+tableconstraint
+ : CONSTRAINT name constraintelem
+ | constraintelem
+ ;
+
+constraintelem
+ : CHECK OPEN_PAREN a_expr CLOSE_PAREN constraintattributespec
+ | UNIQUE (
+ OPEN_PAREN columnlist CLOSE_PAREN opt_c_include opt_definition optconstablespace constraintattributespec
+ | existingindex constraintattributespec
+ )
+ | PRIMARY KEY (
+ OPEN_PAREN columnlist CLOSE_PAREN opt_c_include opt_definition optconstablespace constraintattributespec
+ | existingindex constraintattributespec
+ )
+ | EXCLUDE access_method_clause OPEN_PAREN exclusionconstraintlist CLOSE_PAREN opt_c_include opt_definition optconstablespace exclusionwhereclause
+ constraintattributespec
+ | FOREIGN KEY OPEN_PAREN columnlist CLOSE_PAREN REFERENCES qualified_name opt_column_list key_match key_actions constraintattributespec
+ ;
+
+opt_no_inherit
+ : NO INHERIT
+ |
+ ;
+
+opt_column_list
+ : OPEN_PAREN columnlist CLOSE_PAREN
+ |
+ ;
+
+columnlist
+ : columnElem (COMMA columnElem)*
+ ;
+
+columnElem
+ : colid
+ ;
+
+opt_c_include
+ : INCLUDE OPEN_PAREN columnlist CLOSE_PAREN
+ |
+ ;
+
+key_match
+ : MATCH (FULL | PARTIAL | SIMPLE)
+ |
+ ;
+
+exclusionconstraintlist
+ : exclusionconstraintelem (COMMA exclusionconstraintelem)*
+ ;
+
+exclusionconstraintelem
+ : index_elem WITH (any_operator | OPERATOR OPEN_PAREN any_operator CLOSE_PAREN)
+ ;
+
+exclusionwhereclause
+ : WHERE OPEN_PAREN a_expr CLOSE_PAREN
+ |
+ ;
+
+key_actions
+ : key_update
+ | key_delete
+ | key_update key_delete
+ | key_delete key_update
+ |
+ ;
+
+key_update
+ : ON UPDATE key_action
+ ;
+
+key_delete
+ : ON DELETE_P key_action
+ ;
+
+key_action
+ : NO ACTION
+ | RESTRICT
+ | CASCADE
+ | SET (NULL_P | DEFAULT)
+ ;
+
+optinherit
+ : INHERITS OPEN_PAREN qualified_name_list CLOSE_PAREN
+ |
+ ;
+
+optpartitionspec
+ : partitionspec
+ |
+ ;
+
+partitionspec
+ : PARTITION BY colid OPEN_PAREN part_params CLOSE_PAREN
+ ;
+
+part_params
+ : part_elem (COMMA part_elem)*
+ ;
+
+part_elem
+ : colid opt_collate opt_class
+ | func_expr_windowless opt_collate opt_class
+ | OPEN_PAREN a_expr CLOSE_PAREN opt_collate opt_class
+ ;
+
+table_access_method_clause
+ : USING name
+ |
+ ;
+
+optwith
+ : WITH reloptions
+ | WITHOUT OIDS
+ |
+ ;
+
+oncommitoption
+ : ON COMMIT (DROP | DELETE_P ROWS | PRESERVE ROWS)
+ |
+ ;
+
+opttablespace
+ : TABLESPACE name
+ |
+ ;
+
+optconstablespace
+ : USING INDEX TABLESPACE name
+ |
+ ;
+
+existingindex
+ : USING INDEX name
+ ;
+
+createstatsstmt
+ : CREATE STATISTICS (IF_P NOT EXISTS)? any_name opt_name_list ON expr_list FROM from_list
+ ;
+
+alterstatsstmt
+ : ALTER STATISTICS (IF_P EXISTS)? any_name SET STATISTICS signediconst
+ ;
+
+createasstmt
+ : CREATE opttemp TABLE (IF_P NOT EXISTS)? create_as_target AS selectstmt opt_with_data
+ ;
+
+create_as_target
+ : qualified_name opt_column_list table_access_method_clause optwith oncommitoption opttablespace
+ ;
+
+opt_with_data
+ : WITH (DATA_P | NO DATA_P)
+ |
+ ;
+
+creatematviewstmt
+ : CREATE optnolog MATERIALIZED VIEW (IF_P NOT EXISTS)? create_mv_target AS selectstmt opt_with_data
+ ;
+
+create_mv_target
+ : qualified_name opt_column_list table_access_method_clause opt_reloptions opttablespace
+ ;
+
+optnolog
+ : UNLOGGED
+ |
+ ;
+
+refreshmatviewstmt
+ : REFRESH MATERIALIZED VIEW opt_concurrently qualified_name opt_with_data
+ ;
+
+createseqstmt
+ : CREATE opttemp SEQUENCE (IF_P NOT EXISTS)? qualified_name optseqoptlist
+ ;
+
+alterseqstmt
+ : ALTER SEQUENCE (IF_P EXISTS)? qualified_name seqoptlist
+ ;
+
+optseqoptlist
+ : seqoptlist
+ |
+ ;
+
+optparenthesizedseqoptlist
+ : OPEN_PAREN seqoptlist CLOSE_PAREN
+ |
+ ;
+
+seqoptlist
+ : seqoptelem+
+ ;
+
+seqoptelem
+ : AS simpletypename
+ | CACHE numericonly
+ | CYCLE
+ | INCREMENT opt_by numericonly
+ | MAXVALUE numericonly
+ | MINVALUE numericonly
+ | NO (MAXVALUE | MINVALUE | CYCLE)
+ | OWNED BY any_name
+ | SEQUENCE NAME_P any_name
+ | START opt_with numericonly
+ | RESTART opt_with numericonly?
+ ;
+
+opt_by
+ : BY
+ |
+ ;
+
+numericonly
+ : fconst
+ | PLUS fconst
+ | MINUS fconst
+ | signediconst
+ ;
+
+numericonly_list
+ : numericonly (COMMA numericonly)*
+ ;
+
+createplangstmt
+ : CREATE opt_or_replace opt_trusted opt_procedural LANGUAGE name (
+ HANDLER handler_name opt_inline_handler opt_validator
+ )?
+ ;
+
+opt_trusted
+ : TRUSTED
+ |
+ ;
+
+handler_name
+ : name attrs?
+ ;
+
+opt_inline_handler
+ : INLINE_P handler_name
+ |
+ ;
+
+validator_clause
+ : VALIDATOR handler_name
+ | NO VALIDATOR
+ ;
+
+opt_validator
+ : validator_clause
+ |
+ ;
+
+opt_procedural
+ : PROCEDURAL
+ |
+ ;
+
+createtablespacestmt
+ : CREATE TABLESPACE name opttablespaceowner LOCATION sconst opt_reloptions
+ ;
+
+opttablespaceowner
+ : OWNER rolespec
+ |
+ ;
+
+droptablespacestmt
+ : DROP TABLESPACE (IF_P EXISTS)? name
+ ;
+
+createextensionstmt
+ : CREATE EXTENSION (IF_P NOT EXISTS)? name opt_with create_extension_opt_list
+ ;
+
+create_extension_opt_list
+ : create_extension_opt_item*
+ ;
+
+create_extension_opt_item
+ : SCHEMA name
+ | VERSION_P nonreservedword_or_sconst
+ | FROM nonreservedword_or_sconst
+ | CASCADE
+ ;
+
+alterextensionstmt
+ : ALTER EXTENSION name UPDATE alter_extension_opt_list
+ ;
+
+alter_extension_opt_list
+ : alter_extension_opt_item*
+ ;
+
+alter_extension_opt_item
+ : TO nonreservedword_or_sconst
+ ;
+
+alterextensioncontentsstmt
+ : ALTER EXTENSION name add_drop object_type_name name
+ | ALTER EXTENSION name add_drop object_type_any_name any_name
+ | ALTER EXTENSION name add_drop AGGREGATE aggregate_with_argtypes
+ | ALTER EXTENSION name add_drop CAST OPEN_PAREN typename AS typename CLOSE_PAREN
+ | ALTER EXTENSION name add_drop DOMAIN_P typename
+ | ALTER EXTENSION name add_drop FUNCTION function_with_argtypes
+ | ALTER EXTENSION name add_drop OPERATOR operator_with_argtypes
+ | ALTER EXTENSION name add_drop OPERATOR CLASS any_name USING name
+ | ALTER EXTENSION name add_drop OPERATOR FAMILY any_name USING name
+ | ALTER EXTENSION name add_drop PROCEDURE function_with_argtypes
+ | ALTER EXTENSION name add_drop ROUTINE function_with_argtypes
+ | ALTER EXTENSION name add_drop TRANSFORM FOR typename LANGUAGE name
+ | ALTER EXTENSION name add_drop TYPE_P typename
+ ;
+
+createfdwstmt
+ : CREATE FOREIGN DATA_P WRAPPER name opt_fdw_options create_generic_options
+ ;
+
+fdw_option
+ : HANDLER handler_name
+ | NO HANDLER
+ | VALIDATOR handler_name
+ | NO VALIDATOR
+ ;
+
+fdw_options
+ : fdw_option+
+ ;
+
+opt_fdw_options
+ : fdw_options
+ |
+ ;
+
+alterfdwstmt
+ : ALTER FOREIGN DATA_P WRAPPER name opt_fdw_options alter_generic_options
+ | ALTER FOREIGN DATA_P WRAPPER name fdw_options
+ ;
+
+create_generic_options
+ : OPTIONS OPEN_PAREN generic_option_list CLOSE_PAREN
+ |
+ ;
+
+generic_option_list
+ : generic_option_elem (COMMA generic_option_elem)*
+ ;
+
+alter_generic_options
+ : OPTIONS OPEN_PAREN alter_generic_option_list CLOSE_PAREN
+ ;
+
+alter_generic_option_list
+ : alter_generic_option_elem (COMMA alter_generic_option_elem)*
+ ;
+
+alter_generic_option_elem
+ : generic_option_elem
+ | SET generic_option_elem
+ | ADD_P generic_option_elem
+ | DROP generic_option_name
+ ;
+
+generic_option_elem
+ : generic_option_name generic_option_arg
+ ;
+
+generic_option_name
+ : collabel
+ ;
+
+generic_option_arg
+ : sconst
+ ;
+
+createforeignserverstmt
+ : CREATE SERVER name opt_type opt_foreign_server_version FOREIGN DATA_P WRAPPER name create_generic_options
+ | CREATE SERVER IF_P NOT EXISTS name opt_type opt_foreign_server_version FOREIGN DATA_P WRAPPER name create_generic_options
+ ;
+
+opt_type
+ : TYPE_P sconst
+ |
+ ;
+
+foreign_server_version
+ : VERSION_P (sconst | NULL_P)
+ ;
+
+opt_foreign_server_version
+ : foreign_server_version
+ |
+ ;
+
+alterforeignserverstmt
+ : ALTER SERVER name (alter_generic_options | foreign_server_version alter_generic_options?)
+ ;
+
+createforeigntablestmt
+ : CREATE FOREIGN TABLE qualified_name OPEN_PAREN opttableelementlist CLOSE_PAREN optinherit SERVER name create_generic_options
+ | CREATE FOREIGN TABLE IF_P NOT EXISTS qualified_name OPEN_PAREN opttableelementlist CLOSE_PAREN optinherit SERVER name create_generic_options
+ | CREATE FOREIGN TABLE qualified_name PARTITION OF qualified_name opttypedtableelementlist partitionboundspec SERVER name create_generic_options
+ | CREATE FOREIGN TABLE IF_P NOT EXISTS qualified_name PARTITION OF qualified_name opttypedtableelementlist partitionboundspec SERVER name
+ create_generic_options
+ ;
+
+importforeignschemastmt
+ : IMPORT_P FOREIGN SCHEMA name import_qualification FROM SERVER name INTO name create_generic_options
+ ;
+
+import_qualification_type
+ : LIMIT TO
+ | EXCEPT
+ ;
+
+import_qualification
+ : import_qualification_type OPEN_PAREN relation_expr_list CLOSE_PAREN
+ |
+ ;
+
+createusermappingstmt
+ : CREATE USER MAPPING FOR auth_ident SERVER name create_generic_options
+ | CREATE USER MAPPING IF_P NOT EXISTS FOR auth_ident SERVER name create_generic_options
+ ;
+
+auth_ident
+ : rolespec
+ | USER
+ ;
+
+dropusermappingstmt
+ : DROP USER MAPPING FOR auth_ident SERVER name
+ | DROP USER MAPPING IF_P EXISTS FOR auth_ident SERVER name
+ ;
+
+alterusermappingstmt
+ : ALTER USER MAPPING FOR auth_ident SERVER name alter_generic_options
+ ;
+
+createpolicystmt
+ : CREATE POLICY name ON qualified_name rowsecuritydefaultpermissive rowsecuritydefaultforcmd rowsecuritydefaulttorole rowsecurityoptionalexpr
+ rowsecurityoptionalwithcheck
+ ;
+
+alterpolicystmt
+ : ALTER POLICY name ON qualified_name rowsecurityoptionaltorole rowsecurityoptionalexpr rowsecurityoptionalwithcheck
+ ;
+
+rowsecurityoptionalexpr
+ : USING OPEN_PAREN a_expr CLOSE_PAREN
+ |
+ ;
+
+rowsecurityoptionalwithcheck
+ : WITH CHECK OPEN_PAREN a_expr CLOSE_PAREN
+ |
+ ;
+
+rowsecuritydefaulttorole
+ : TO role_list
+ |
+ ;
+
+rowsecurityoptionaltorole
+ : TO role_list
+ |
+ ;
+
+rowsecuritydefaultpermissive
+ : AS identifier
+ |
+ ;
+
+rowsecuritydefaultforcmd
+ : FOR row_security_cmd
+ |
+ ;
+
+row_security_cmd
+ : ALL
+ | SELECT
+ | INSERT
+ | UPDATE
+ | DELETE_P
+ ;
+
+createamstmt
+ : CREATE ACCESS METHOD name TYPE_P am_type HANDLER handler_name
+ ;
+
+am_type
+ : INDEX
+ | TABLE
+ ;
+
+createtrigstmt
+ : CREATE TRIGGER name triggeractiontime triggerevents ON qualified_name triggerreferencing triggerforspec triggerwhen EXECUTE
+ function_or_procedure func_name OPEN_PAREN triggerfuncargs CLOSE_PAREN
+ | CREATE CONSTRAINT TRIGGER name AFTER triggerevents ON qualified_name optconstrfromtable constraintattributespec FOR EACH ROW triggerwhen EXECUTE
+ function_or_procedure func_name OPEN_PAREN triggerfuncargs CLOSE_PAREN
+ ;
+
+triggeractiontime
+ : BEFORE
+ | AFTER
+ | INSTEAD OF
+ ;
+
+triggerevents
+ : triggeroneevent (OR triggeroneevent)*
+ ;
+
+triggeroneevent
+ : INSERT
+ | DELETE_P
+ | UPDATE
+ | UPDATE OF columnlist
+ | TRUNCATE
+ ;
+
+triggerreferencing
+ : REFERENCING triggertransitions
+ |
+ ;
+
+triggertransitions
+ : triggertransition+
+ ;
+
+triggertransition
+ : transitionoldornew transitionrowortable opt_as transitionrelname
+ ;
+
+transitionoldornew
+ : NEW
+ | OLD
+ ;
+
+transitionrowortable
+ : TABLE
+ | ROW
+ ;
+
+transitionrelname
+ : colid
+ ;
+
+triggerforspec
+ : FOR triggerforopteach triggerfortype
+ |
+ ;
+
+triggerforopteach
+ : EACH
+ |
+ ;
+
+triggerfortype
+ : ROW
+ | STATEMENT
+ ;
+
+triggerwhen
+ : WHEN OPEN_PAREN a_expr CLOSE_PAREN
+ |
+ ;
+
+function_or_procedure
+ : FUNCTION
+ | PROCEDURE
+ ;
+
+triggerfuncargs
+ : (triggerfuncarg |) (COMMA triggerfuncarg)*
+ ;
+
+triggerfuncarg
+ : iconst
+ | fconst
+ | sconst
+ | collabel
+ ;
+
+optconstrfromtable
+ : FROM qualified_name
+ |
+ ;
+
+constraintattributespec
+ : constraintattributeElem*
+ ;
+
+constraintattributeElem
+ : NOT DEFERRABLE
+ | DEFERRABLE
+ | INITIALLY IMMEDIATE
+ | INITIALLY DEFERRED
+ | NOT VALID
+ | NO INHERIT
+ ;
+
+createeventtrigstmt
+ : CREATE EVENT TRIGGER name ON collabel EXECUTE function_or_procedure func_name OPEN_PAREN CLOSE_PAREN
+ | CREATE EVENT TRIGGER name ON collabel WHEN event_trigger_when_list EXECUTE function_or_procedure func_name OPEN_PAREN CLOSE_PAREN
+ ;
+
+event_trigger_when_list
+ : event_trigger_when_item (AND event_trigger_when_item)*
+ ;
+
+event_trigger_when_item
+ : colid IN_P OPEN_PAREN event_trigger_value_list CLOSE_PAREN
+ ;
+
+event_trigger_value_list
+ : sconst (COMMA sconst)*
+ ;
+
+altereventtrigstmt
+ : ALTER EVENT TRIGGER name enable_trigger
+ ;
+
+enable_trigger
+ : ENABLE_P
+ | ENABLE_P REPLICA
+ | ENABLE_P ALWAYS
+ | DISABLE_P
+ ;
+
+createassertionstmt
+ : CREATE ASSERTION any_name CHECK OPEN_PAREN a_expr CLOSE_PAREN constraintattributespec
+ ;
+
+definestmt
+ : CREATE opt_or_replace AGGREGATE func_name aggr_args definition
+ | CREATE opt_or_replace AGGREGATE func_name old_aggr_definition
+ | CREATE OPERATOR any_operator definition
+ | CREATE TYPE_P any_name definition
+ | CREATE TYPE_P any_name
+ | CREATE TYPE_P any_name AS OPEN_PAREN opttablefuncelementlist CLOSE_PAREN
+ | CREATE TYPE_P any_name AS ENUM_P OPEN_PAREN opt_enum_val_list CLOSE_PAREN
+ | CREATE TYPE_P any_name AS RANGE definition
+ | CREATE TEXT_P SEARCH PARSER any_name definition
+ | CREATE TEXT_P SEARCH DICTIONARY any_name definition
+ | CREATE TEXT_P SEARCH TEMPLATE any_name definition
+ | CREATE TEXT_P SEARCH CONFIGURATION any_name definition
+ | CREATE COLLATION any_name definition
+ | CREATE COLLATION IF_P NOT EXISTS any_name definition
+ | CREATE COLLATION any_name FROM any_name
+ | CREATE COLLATION IF_P NOT EXISTS any_name FROM any_name
+ ;
+
+definition
+ : OPEN_PAREN def_list CLOSE_PAREN
+ ;
+
+def_list
+ : def_elem (COMMA def_elem)*
+ ;
+
+def_elem
+ : collabel (EQUAL def_arg)?
+ ;
+
+def_arg
+ : func_type
+ | reserved_keyword
+ | qual_all_op
+ | numericonly
+ | sconst
+ | NONE
+ ;
+
+old_aggr_definition
+ : OPEN_PAREN old_aggr_list CLOSE_PAREN
+ ;
+
+old_aggr_list
+ : old_aggr_elem (COMMA old_aggr_elem)*
+ ;
+
+old_aggr_elem
+ : identifier EQUAL def_arg
+ ;
+
+opt_enum_val_list
+ : enum_val_list
+ |
+ ;
+
+enum_val_list
+ : sconst (COMMA sconst)*
+ ;
+
+alterenumstmt
+ : ALTER TYPE_P any_name ADD_P VALUE_P opt_if_not_exists sconst
+ | ALTER TYPE_P any_name ADD_P VALUE_P opt_if_not_exists sconst BEFORE sconst
+ | ALTER TYPE_P any_name ADD_P VALUE_P opt_if_not_exists sconst AFTER sconst
+ | ALTER TYPE_P any_name RENAME VALUE_P sconst TO sconst
+ ;
+
+opt_if_not_exists
+ : IF_P NOT EXISTS
+ |
+ ;
+
+createopclassstmt
+ : CREATE OPERATOR CLASS any_name opt_default FOR TYPE_P typename USING name opt_opfamily AS opclass_item_list
+ ;
+
+opclass_item_list
+ : opclass_item (COMMA opclass_item)*
+ ;
+
+opclass_item
+ : OPERATOR iconst any_operator opclass_purpose opt_recheck
+ | OPERATOR iconst operator_with_argtypes opclass_purpose opt_recheck
+ | FUNCTION iconst function_with_argtypes
+ | FUNCTION iconst OPEN_PAREN type_list CLOSE_PAREN function_with_argtypes
+ | STORAGE typename
+ ;
+
+opt_default
+ : DEFAULT
+ |
+ ;
+
+opt_opfamily
+ : FAMILY any_name
+ |
+ ;
+
+opclass_purpose
+ : FOR SEARCH
+ | FOR ORDER BY any_name
+ |
+ ;
+
+opt_recheck
+ : RECHECK
+ |
+ ;
+
+createopfamilystmt
+ : CREATE OPERATOR FAMILY any_name USING name
+ ;
+
+alteropfamilystmt
+ : ALTER OPERATOR FAMILY any_name USING name ADD_P opclass_item_list
+ | ALTER OPERATOR FAMILY any_name USING name DROP opclass_drop_list
+ ;
+
+opclass_drop_list
+ : opclass_drop (COMMA opclass_drop)*
+ ;
+
+opclass_drop
+ : OPERATOR iconst OPEN_PAREN type_list CLOSE_PAREN
+ | FUNCTION iconst OPEN_PAREN type_list CLOSE_PAREN
+ ;
+
+dropopclassstmt
+ : DROP OPERATOR CLASS any_name USING name opt_drop_behavior
+ | DROP OPERATOR CLASS IF_P EXISTS any_name USING name opt_drop_behavior
+ ;
+
+dropopfamilystmt
+ : DROP OPERATOR FAMILY any_name USING name opt_drop_behavior
+ | DROP OPERATOR FAMILY IF_P EXISTS any_name USING name opt_drop_behavior
+ ;
+
+dropownedstmt
+ : DROP OWNED BY role_list opt_drop_behavior
+ ;
+
+reassignownedstmt
+ : REASSIGN OWNED BY role_list TO rolespec
+ ;
+
+dropstmt
+ : DROP object_type_any_name IF_P EXISTS any_name_list opt_drop_behavior
+ | DROP object_type_any_name any_name_list opt_drop_behavior
+ | DROP drop_type_name IF_P EXISTS name_list opt_drop_behavior
+ | DROP drop_type_name name_list opt_drop_behavior
+ | DROP object_type_name_on_any_name name ON any_name opt_drop_behavior
+ | DROP object_type_name_on_any_name IF_P EXISTS name ON any_name opt_drop_behavior
+ | DROP TYPE_P type_name_list opt_drop_behavior
+ | DROP TYPE_P IF_P EXISTS type_name_list opt_drop_behavior
+ | DROP DOMAIN_P type_name_list opt_drop_behavior
+ | DROP DOMAIN_P IF_P EXISTS type_name_list opt_drop_behavior
+ | DROP INDEX CONCURRENTLY any_name_list opt_drop_behavior
+ | DROP INDEX CONCURRENTLY IF_P EXISTS any_name_list opt_drop_behavior
+ ;
+
+object_type_any_name
+ : TABLE
+ | SEQUENCE
+ | VIEW
+ | MATERIALIZED VIEW
+ | TOPIC
+ | STREAM
+ | INDEX
+ | FOREIGN TABLE
+ | COLLATION
+ | CONVERSION_P
+ | STATISTICS
+ | TEXT_P SEARCH PARSER
+ | TEXT_P SEARCH DICTIONARY
+ | TEXT_P SEARCH TEMPLATE
+ | TEXT_P SEARCH CONFIGURATION
+ ;
+
+object_type_name
+ : drop_type_name
+ | DATABASE
+ | ROLE
+ | SUBSCRIPTION
+ | TABLESPACE
+ ;
+
+drop_type_name
+ : ACCESS METHOD
+ | EVENT TRIGGER
+ | EXTENSION
+ | FOREIGN DATA_P WRAPPER
+ | opt_procedural LANGUAGE
+ | PUBLICATION
+ | SCHEMA
+ | SERVER
+ ;
+
+object_type_name_on_any_name
+ : POLICY
+ | RULE
+ | TRIGGER
+ ;
+
+any_name_list
+ : any_name (COMMA any_name)*
+ ;
+
+any_name
+ : colid attrs?
+ ;
+
+attrs
+ : (DOT attr_name)+
+ ;
+
+type_name_list
+ : typename (COMMA typename)*
+ ;
+
+truncatestmt
+ : TRUNCATE opt_table relation_expr_list opt_restart_seqs opt_drop_behavior
+ ;
+
+opt_restart_seqs
+ : CONTINUE_P IDENTITY_P
+ | RESTART IDENTITY_P
+ |
+ ;
+
+commentstmt
+ : COMMENT ON object_type_any_name any_name IS comment_text
+ | COMMENT ON COLUMN any_name IS comment_text
+ | COMMENT ON object_type_name name IS comment_text
+ | COMMENT ON TYPE_P typename IS comment_text
+ | COMMENT ON DOMAIN_P typename IS comment_text
+ | COMMENT ON AGGREGATE aggregate_with_argtypes IS comment_text
+ | COMMENT ON FUNCTION function_with_argtypes IS comment_text
+ | COMMENT ON OPERATOR operator_with_argtypes IS comment_text
+ | COMMENT ON CONSTRAINT name ON any_name IS comment_text
+ | COMMENT ON CONSTRAINT name ON DOMAIN_P any_name IS comment_text
+ | COMMENT ON object_type_name_on_any_name name ON any_name IS comment_text
+ | COMMENT ON PROCEDURE function_with_argtypes IS comment_text
+ | COMMENT ON ROUTINE function_with_argtypes IS comment_text
+ | COMMENT ON TRANSFORM FOR typename LANGUAGE name IS comment_text
+ | COMMENT ON OPERATOR CLASS any_name USING name IS comment_text
+ | COMMENT ON OPERATOR FAMILY any_name USING name IS comment_text
+ | COMMENT ON LARGE_P OBJECT_P numericonly IS comment_text
+ | COMMENT ON CAST OPEN_PAREN typename AS typename CLOSE_PAREN IS comment_text
+ ;
+
+comment_text
+ : sconst
+ | NULL_P
+ ;
+
+seclabelstmt
+ : SECURITY LABEL opt_provider ON object_type_any_name any_name IS security_label
+ | SECURITY LABEL opt_provider ON COLUMN any_name IS security_label
+ | SECURITY LABEL opt_provider ON object_type_name name IS security_label
+ | SECURITY LABEL opt_provider ON TYPE_P typename IS security_label
+ | SECURITY LABEL opt_provider ON DOMAIN_P typename IS security_label
+ | SECURITY LABEL opt_provider ON AGGREGATE aggregate_with_argtypes IS security_label
+ | SECURITY LABEL opt_provider ON FUNCTION function_with_argtypes IS security_label
+ | SECURITY LABEL opt_provider ON LARGE_P OBJECT_P numericonly IS security_label
+ | SECURITY LABEL opt_provider ON PROCEDURE function_with_argtypes IS security_label
+ | SECURITY LABEL opt_provider ON ROUTINE function_with_argtypes IS security_label
+ ;
+
+opt_provider
+ : FOR nonreservedword_or_sconst
+ |
+ ;
+
+security_label
+ : sconst
+ | NULL_P
+ ;
+
+fetchstmt
+ : FETCH fetch_args
+ | MOVE fetch_args
+ ;
+
+fetch_args
+ : cursor_name
+ | from_in cursor_name
+ | NEXT opt_from_in cursor_name
+ | PRIOR opt_from_in cursor_name
+ | FIRST_P opt_from_in cursor_name
+ | LAST_P opt_from_in cursor_name
+ | ABSOLUTE_P signediconst opt_from_in cursor_name
+ | RELATIVE_P signediconst opt_from_in cursor_name
+ | signediconst opt_from_in cursor_name
+ | ALL opt_from_in cursor_name
+ | FORWARD opt_from_in cursor_name
+ | FORWARD signediconst opt_from_in cursor_name
+ | FORWARD ALL opt_from_in cursor_name
+ | BACKWARD opt_from_in cursor_name
+ | BACKWARD signediconst opt_from_in cursor_name
+ | BACKWARD ALL opt_from_in cursor_name
+ ;
+
+from_in
+ : FROM
+ | IN_P
+ ;
+
+opt_from_in
+ : from_in
+ |
+ ;
+
+grantstmt
+ : GRANT privileges ON privilege_target TO grantee_list opt_grant_grant_option
+ ;
+
+revokestmt
+ : REVOKE privileges ON privilege_target FROM grantee_list opt_drop_behavior
+ | REVOKE GRANT OPTION FOR privileges ON privilege_target FROM grantee_list opt_drop_behavior
+ ;
+
+privileges
+ : privilege_list
+ | ALL
+ | ALL PRIVILEGES
+ | ALL OPEN_PAREN columnlist CLOSE_PAREN
+ | ALL PRIVILEGES OPEN_PAREN columnlist CLOSE_PAREN
+ ;
+
+privilege_list
+ : privilege (COMMA privilege)*
+ ;
+
+privilege
+ : SELECT opt_column_list
+ | REFERENCES opt_column_list
+ | CREATE opt_column_list
+ | colid opt_column_list
+ ;
+
+privilege_target
+ : qualified_name_list
+ | TABLE qualified_name_list
+ | SEQUENCE qualified_name_list
+ | FOREIGN DATA_P WRAPPER name_list
+ | FOREIGN SERVER name_list
+ | FUNCTION function_with_argtypes_list
+ | PROCEDURE function_with_argtypes_list
+ | ROUTINE function_with_argtypes_list
+ | DATABASE name_list
+ | DOMAIN_P any_name_list
+ | LANGUAGE name_list
+ | LARGE_P OBJECT_P numericonly_list
+ | SCHEMA name_list
+ | TABLESPACE name_list
+ | TYPE_P any_name_list
+ | ALL TABLES IN_P SCHEMA name_list
+ | ALL SEQUENCES IN_P SCHEMA name_list
+ | ALL FUNCTIONS IN_P SCHEMA name_list
+ | ALL PROCEDURES IN_P SCHEMA name_list
+ | ALL ROUTINES IN_P SCHEMA name_list
+ ;
+
+grantee_list
+ : grantee (COMMA grantee)*
+ ;
+
+grantee
+ : rolespec
+ | GROUP_P rolespec
+ ;
+
+opt_grant_grant_option
+ : WITH GRANT OPTION
+ |
+ ;
+
+grantrolestmt
+ : GRANT privilege_list TO role_list opt_grant_admin_option opt_granted_by
+ ;
+
+revokerolestmt
+ : REVOKE privilege_list FROM role_list opt_granted_by opt_drop_behavior
+ | REVOKE ADMIN OPTION FOR privilege_list FROM role_list opt_granted_by opt_drop_behavior
+ ;
+
+opt_grant_admin_option
+ : WITH ADMIN OPTION
+ |
+ ;
+
+opt_granted_by
+ : GRANTED BY rolespec
+ |
+ ;
+
+alterdefaultprivilegesstmt
+ : ALTER DEFAULT PRIVILEGES defacloptionlist defaclaction
+ ;
+
+defacloptionlist
+ : defacloption*
+ ;
+
+defacloption
+ : IN_P SCHEMA name_list
+ | FOR ROLE role_list
+ | FOR USER role_list
+ ;
+
+defaclaction
+ : GRANT privileges ON defacl_privilege_target TO grantee_list opt_grant_grant_option
+ | REVOKE privileges ON defacl_privilege_target FROM grantee_list opt_drop_behavior
+ | REVOKE GRANT OPTION FOR privileges ON defacl_privilege_target FROM grantee_list opt_drop_behavior
+ ;
+
+defacl_privilege_target
+ : TABLES
+ | FUNCTIONS
+ | ROUTINES
+ | SEQUENCES
+ | TYPES_P
+ | SCHEMAS
+ ;
+
+//create index
+
+indexstmt
+ : CREATE opt_unique INDEX opt_concurrently opt_index_name ON relation_expr access_method_clause OPEN_PAREN index_params CLOSE_PAREN opt_include
+ opt_reloptions opttablespace where_clause
+ | CREATE opt_unique INDEX opt_concurrently IF_P NOT EXISTS name ON relation_expr access_method_clause OPEN_PAREN index_params CLOSE_PAREN
+ opt_include opt_reloptions opttablespace where_clause
+ ;
+
+opt_unique
+ : UNIQUE
+ |
+ ;
+
+opt_concurrently
+ : CONCURRENTLY
+ |
+ ;
+
+opt_index_name
+ : name
+ |
+ ;
+
+access_method_clause
+ : USING name
+ |
+ ;
+
+index_params
+ : index_elem (COMMA index_elem)*
+ ;
+
+index_elem_options
+ : opt_collate opt_class opt_asc_desc opt_nulls_order
+ | opt_collate any_name reloptions opt_asc_desc opt_nulls_order
+ ;
+
+index_elem
+ : colid index_elem_options
+ | func_expr_windowless index_elem_options
+ | OPEN_PAREN a_expr CLOSE_PAREN index_elem_options
+ ;
+
+opt_include
+ : INCLUDE OPEN_PAREN index_including_params CLOSE_PAREN
+ |
+ ;
+
+index_including_params
+ : index_elem (COMMA index_elem)*
+ ;
+
+opt_collate
+ : COLLATE any_name
+ |
+ ;
+
+opt_class
+ : any_name
+ |
+ ;
+
+opt_asc_desc
+ : ASC
+ | DESC
+ |
+ ;
+
+//TOD NULLS_LA was used
+
+opt_nulls_order
+ : NULLS_P FIRST_P
+ | NULLS_P LAST_P
+ |
+ ;
+
+createfunctionstmt
+ : CREATE opt_or_replace (FUNCTION | PROCEDURE) func_name func_args_with_defaults (
+ RETURNS (func_return | TABLE OPEN_PAREN table_func_column_list CLOSE_PAREN)
+ )? createfunc_opt_list
+ ;
+
+opt_type_parameters
+ : '<' type_parameters '>'
+ |
+ ;
+
+type_parameters
+ : type_parameter (COMMA type_parameter)*
+ ;
+
+type_parameter
+ : colid typename
+ ;
+
+opt_or_replace
+ : OR REPLACE
+ |
+ ;
+
+func_args
+ : OPEN_PAREN func_args_list? CLOSE_PAREN
+ ;
+
+func_args_list
+ : func_arg (COMMA func_arg)*
+ ;
+
+function_with_argtypes_list
+ : function_with_argtypes (COMMA function_with_argtypes)*
+ ;
+
+function_with_argtypes
+ : func_name func_args
+ | type_func_name_keyword
+ | colid indirection?
+ ;
+
+func_args_with_defaults
+ : OPEN_PAREN func_args_with_defaults_list? CLOSE_PAREN
+ ;
+
+func_args_with_defaults_list
+ : func_arg_with_default (COMMA func_arg_with_default)*
+ ;
+
+func_arg
+ : arg_class param_name? func_type
+ | param_name arg_class? func_type
+ | func_type
+ ;
+
+arg_class
+ : IN_P OUT_P?
+ | OUT_P
+ | INOUT
+ | VARIADIC
+ ;
+
+param_name
+ : type_function_name
+ | builtin_function_name
+ | LEFT
+ | RIGHT
+ ;
+
+func_return
+ : func_type
+ ;
+
+func_type
+ : typename
+ ;
+
+func_arg_with_default
+ : func_arg ((DEFAULT | EQUAL) a_expr)?
+ ;
+
+aggr_arg
+ : func_arg
+ ;
+
+aggr_args
+ : OPEN_PAREN (
+ STAR
+ | aggr_args_list
+ | ORDER BY aggr_args_list
+ | aggr_args_list ORDER BY aggr_args_list
+ ) CLOSE_PAREN
+ ;
+
+aggr_args_list
+ : aggr_arg (COMMA aggr_arg)*
+ ;
+
+aggregate_with_argtypes
+ : func_name aggr_args
+ ;
+
+aggregate_with_argtypes_list
+ : aggregate_with_argtypes (COMMA aggregate_with_argtypes)*
+ ;
+
+createfunc_opt_list
+ : createfunc_opt_item+ {
+ parseRoutineBody(_localctx);
+ }
+ // | createfunc_opt_list createfunc_opt_item
+ ;
+
+common_func_opt_item
+ : CALLED ON NULL_P INPUT_P
+ | RETURNS NULL_P ON NULL_P INPUT_P
+ | STRICT_P
+ | IMMUTABLE
+ | STABLE
+ | VOLATILE
+ | EXTERNAL SECURITY DEFINER
+ | EXTERNAL SECURITY INVOKER
+ | SECURITY DEFINER
+ | SECURITY INVOKER
+ | LEAKPROOF
+ | NOT LEAKPROOF
+ | COST numericonly
+ | ROWS numericonly
+ | SUPPORT any_name
+ | functionsetresetclause
+ | PARALLEL colid
+ ;
+
+createfunc_opt_item
+ : AS func_as
+ | LANGUAGE nonreservedword_or_sconst
+ | TRANSFORM transform_type_list
+ | WINDOW
+ | common_func_opt_item
+ ;
+
+//https://www.postgresql.org/docs/9.1/sql-createfunction.html
+
+// | AS 'definition'
+
+// | AS 'obj_file', 'link_symbol'
+
+func_as
+ locals[ParserRuleContext Definition]
+ :
+ /* |AS 'definition'*/ def = sconst
+ /*| AS 'obj_file', 'link_symbol'*/
+ | sconst COMMA sconst
+ ;
+
+transform_type_list
+ : FOR TYPE_P typename (COMMA FOR TYPE_P typename)*
+ ;
+
+opt_definition
+ : WITH definition
+ |
+ ;
+
+table_func_column
+ : param_name func_type
+ ;
+
+table_func_column_list
+ : table_func_column (COMMA table_func_column)*
+ ;
+
+alterfunctionstmt
+ : ALTER (FUNCTION | PROCEDURE | ROUTINE) function_with_argtypes alterfunc_opt_list opt_restrict
+ ;
+
+alterfunc_opt_list
+ : common_func_opt_item+
+ ;
+
+opt_restrict
+ : RESTRICT
+ |
+ ;
+
+removefuncstmt
+ : DROP FUNCTION function_with_argtypes_list opt_drop_behavior
+ | DROP FUNCTION IF_P EXISTS function_with_argtypes_list opt_drop_behavior
+ | DROP PROCEDURE function_with_argtypes_list opt_drop_behavior
+ | DROP PROCEDURE IF_P EXISTS function_with_argtypes_list opt_drop_behavior
+ | DROP ROUTINE function_with_argtypes_list opt_drop_behavior
+ | DROP ROUTINE IF_P EXISTS function_with_argtypes_list opt_drop_behavior
+ ;
+
+removeaggrstmt
+ : DROP AGGREGATE aggregate_with_argtypes_list opt_drop_behavior
+ | DROP AGGREGATE IF_P EXISTS aggregate_with_argtypes_list opt_drop_behavior
+ ;
+
+removeoperstmt
+ : DROP OPERATOR operator_with_argtypes_list opt_drop_behavior
+ | DROP OPERATOR IF_P EXISTS operator_with_argtypes_list opt_drop_behavior
+ ;
+
+oper_argtypes
+ : OPEN_PAREN typename CLOSE_PAREN
+ | OPEN_PAREN typename COMMA typename CLOSE_PAREN
+ | OPEN_PAREN NONE COMMA typename CLOSE_PAREN
+ | OPEN_PAREN typename COMMA NONE CLOSE_PAREN
+ ;
+
+any_operator
+ : (colid DOT)* all_op
+ ;
+
+operator_with_argtypes_list
+ : operator_with_argtypes (COMMA operator_with_argtypes)*
+ ;
+
+operator_with_argtypes
+ : any_operator oper_argtypes
+ ;
+
+dostmt
+ : DO dostmt_opt_list
+ ;
+
+dostmt_opt_list
+ : dostmt_opt_item+
+ ;
+
+dostmt_opt_item
+ : sconst
+ | LANGUAGE nonreservedword_or_sconst
+ ;
+
+createcaststmt
+ : CREATE CAST OPEN_PAREN typename AS typename CLOSE_PAREN WITH FUNCTION function_with_argtypes cast_context
+ | CREATE CAST OPEN_PAREN typename AS typename CLOSE_PAREN WITHOUT FUNCTION cast_context
+ | CREATE CAST OPEN_PAREN typename AS typename CLOSE_PAREN WITH INOUT cast_context
+ ;
+
+cast_context
+ : AS IMPLICIT_P
+ | AS ASSIGNMENT
+ |
+ ;
+
+dropcaststmt
+ : DROP CAST opt_if_exists OPEN_PAREN typename AS typename CLOSE_PAREN opt_drop_behavior
+ ;
+
+opt_if_exists
+ : IF_P EXISTS
+ |
+ ;
+
+createtransformstmt
+ : CREATE opt_or_replace TRANSFORM FOR typename LANGUAGE name OPEN_PAREN transform_element_list CLOSE_PAREN
+ ;
+
+transform_element_list
+ : FROM SQL_P WITH FUNCTION function_with_argtypes COMMA TO SQL_P WITH FUNCTION function_with_argtypes
+ | TO SQL_P WITH FUNCTION function_with_argtypes COMMA FROM SQL_P WITH FUNCTION function_with_argtypes
+ | FROM SQL_P WITH FUNCTION function_with_argtypes
+ | TO SQL_P WITH FUNCTION function_with_argtypes
+ ;
+
+droptransformstmt
+ : DROP TRANSFORM opt_if_exists FOR typename LANGUAGE name opt_drop_behavior
+ ;
+
+reindexstmt
+ : REINDEX reindex_target_type opt_concurrently qualified_name
+ | REINDEX reindex_target_multitable opt_concurrently name
+ | REINDEX OPEN_PAREN reindex_option_list CLOSE_PAREN reindex_target_type opt_concurrently qualified_name
+ | REINDEX OPEN_PAREN reindex_option_list CLOSE_PAREN reindex_target_multitable opt_concurrently name
+ ;
+
+reindex_target_type
+ : INDEX
+ | TABLE
+ | SCHEMA
+ | DATABASE
+ | SYSTEM_P
+ ;
+
+reindex_target_multitable
+ : SCHEMA
+ | SYSTEM_P
+ | DATABASE
+ ;
+
+reindex_option_list
+ : reindex_option_elem (COMMA reindex_option_elem)*
+ ;
+
+reindex_option_elem
+ : VERBOSE
+ | TABLESPACE
+ | CONCURRENTLY
+ ;
+
+altertblspcstmt
+ : ALTER TABLESPACE name SET reloptions
+ | ALTER TABLESPACE name RESET reloptions
+ ;
+
+renamestmt
+ : ALTER AGGREGATE aggregate_with_argtypes RENAME TO name
+ | ALTER COLLATION any_name RENAME TO name
+ | ALTER CONVERSION_P any_name RENAME TO name
+ | ALTER DATABASE name RENAME TO name
+ | ALTER DOMAIN_P any_name RENAME TO name
+ | ALTER DOMAIN_P any_name RENAME CONSTRAINT name TO name
+ | ALTER FOREIGN DATA_P WRAPPER name RENAME TO name
+ | ALTER FUNCTION function_with_argtypes RENAME TO name
+ | ALTER GROUP_P roleid RENAME TO roleid
+ | ALTER opt_procedural LANGUAGE name RENAME TO name
+ | ALTER OPERATOR CLASS any_name USING name RENAME TO name
+ | ALTER OPERATOR FAMILY any_name USING name RENAME TO name
+ | ALTER POLICY name ON qualified_name RENAME TO name
+ | ALTER POLICY IF_P EXISTS name ON qualified_name RENAME TO name
+ | ALTER PROCEDURE function_with_argtypes RENAME TO name
+ | ALTER PUBLICATION name RENAME TO name
+ | ALTER ROUTINE function_with_argtypes RENAME TO name
+ | ALTER SCHEMA name RENAME TO name
+ | ALTER SERVER name RENAME TO name
+ | ALTER SUBSCRIPTION name RENAME TO name
+ | ALTER TABLE relation_expr RENAME TO name
+ | ALTER TABLE IF_P EXISTS relation_expr RENAME TO name
+ | ALTER SEQUENCE qualified_name RENAME TO name
+ | ALTER SEQUENCE IF_P EXISTS qualified_name RENAME TO name
+ | ALTER VIEW qualified_name RENAME TO name
+ | ALTER VIEW IF_P EXISTS qualified_name RENAME TO name
+ | ALTER MATERIALIZED VIEW qualified_name RENAME TO name
+ | ALTER MATERIALIZED VIEW IF_P EXISTS qualified_name RENAME TO name
+ | ALTER INDEX qualified_name RENAME TO name
+ | ALTER INDEX IF_P EXISTS qualified_name RENAME TO name
+ | ALTER FOREIGN TABLE relation_expr RENAME TO name
+ | ALTER FOREIGN TABLE IF_P EXISTS relation_expr RENAME TO name
+ | ALTER TABLE relation_expr RENAME opt_column name TO name
+ | ALTER TABLE IF_P EXISTS relation_expr RENAME opt_column name TO name
+ | ALTER VIEW qualified_name RENAME opt_column name TO name
+ | ALTER VIEW IF_P EXISTS qualified_name RENAME opt_column name TO name
+ | ALTER MATERIALIZED VIEW qualified_name RENAME opt_column name TO name
+ | ALTER MATERIALIZED VIEW IF_P EXISTS qualified_name RENAME opt_column name TO name
+ | ALTER TABLE relation_expr RENAME CONSTRAINT name TO name
+ | ALTER TABLE IF_P EXISTS relation_expr RENAME CONSTRAINT name TO name
+ | ALTER FOREIGN TABLE relation_expr RENAME opt_column name TO name
+ | ALTER FOREIGN TABLE IF_P EXISTS relation_expr RENAME opt_column name TO name
+ | ALTER RULE name ON qualified_name RENAME TO name
+ | ALTER TRIGGER name ON qualified_name RENAME TO name
+ | ALTER EVENT TRIGGER name RENAME TO name
+ | ALTER ROLE roleid RENAME TO roleid
+ | ALTER USER roleid RENAME TO roleid
+ | ALTER TABLESPACE name RENAME TO name
+ | ALTER STATISTICS any_name RENAME TO name
+ | ALTER TEXT_P SEARCH PARSER any_name RENAME TO name
+ | ALTER TEXT_P SEARCH DICTIONARY any_name RENAME TO name
+ | ALTER TEXT_P SEARCH TEMPLATE any_name RENAME TO name
+ | ALTER TEXT_P SEARCH CONFIGURATION any_name RENAME TO name
+ | ALTER TYPE_P any_name RENAME TO name
+ | ALTER TYPE_P any_name RENAME ATTRIBUTE name TO name opt_drop_behavior
+ ;
+
+opt_column
+ : COLUMN
+ |
+ ;
+
+opt_set_data
+ : SET DATA_P
+ |
+ ;
+
+alterobjectdependsstmt
+ : ALTER FUNCTION function_with_argtypes opt_no DEPENDS ON EXTENSION name
+ | ALTER PROCEDURE function_with_argtypes opt_no DEPENDS ON EXTENSION name
+ | ALTER ROUTINE function_with_argtypes opt_no DEPENDS ON EXTENSION name
+ | ALTER TRIGGER name ON qualified_name opt_no DEPENDS ON EXTENSION name
+ | ALTER MATERIALIZED VIEW qualified_name opt_no DEPENDS ON EXTENSION name
+ | ALTER INDEX qualified_name opt_no DEPENDS ON EXTENSION name
+ ;
+
+opt_no
+ : NO
+ |
+ ;
+
+alterobjectschemastmt
+ : ALTER AGGREGATE aggregate_with_argtypes SET SCHEMA name
+ | ALTER COLLATION any_name SET SCHEMA name
+ | ALTER CONVERSION_P any_name SET SCHEMA name
+ | ALTER DOMAIN_P any_name SET SCHEMA name
+ | ALTER EXTENSION name SET SCHEMA name
+ | ALTER FUNCTION function_with_argtypes SET SCHEMA name
+ | ALTER OPERATOR operator_with_argtypes SET SCHEMA name
+ | ALTER OPERATOR CLASS any_name USING name SET SCHEMA name
+ | ALTER OPERATOR FAMILY any_name USING name SET SCHEMA name
+ | ALTER PROCEDURE function_with_argtypes SET SCHEMA name
+ | ALTER ROUTINE function_with_argtypes SET SCHEMA name
+ | ALTER TABLE relation_expr SET SCHEMA name
+ | ALTER TABLE IF_P EXISTS relation_expr SET SCHEMA name
+ | ALTER STATISTICS any_name SET SCHEMA name
+ | ALTER TEXT_P SEARCH PARSER any_name SET SCHEMA name
+ | ALTER TEXT_P SEARCH DICTIONARY any_name SET SCHEMA name
+ | ALTER TEXT_P SEARCH TEMPLATE any_name SET SCHEMA name
+ | ALTER TEXT_P SEARCH CONFIGURATION any_name SET SCHEMA name
+ | ALTER SEQUENCE qualified_name SET SCHEMA name
+ | ALTER SEQUENCE IF_P EXISTS qualified_name SET SCHEMA name
+ | ALTER VIEW qualified_name SET SCHEMA name
+ | ALTER VIEW IF_P EXISTS qualified_name SET SCHEMA name
+ | ALTER MATERIALIZED VIEW qualified_name SET SCHEMA name
+ | ALTER MATERIALIZED VIEW IF_P EXISTS qualified_name SET SCHEMA name
+ | ALTER FOREIGN TABLE relation_expr SET SCHEMA name
+ | ALTER FOREIGN TABLE IF_P EXISTS relation_expr SET SCHEMA name
+ | ALTER TYPE_P any_name SET SCHEMA name
+ ;
+
+alteroperatorstmt
+ : ALTER OPERATOR operator_with_argtypes SET OPEN_PAREN operator_def_list CLOSE_PAREN
+ ;
+
+operator_def_list
+ : operator_def_elem (COMMA operator_def_elem)*
+ ;
+
+operator_def_elem
+ : collabel EQUAL NONE
+ | collabel EQUAL operator_def_arg
+ ;
+
+operator_def_arg
+ : func_type
+ | reserved_keyword
+ | qual_all_op
+ | numericonly
+ | sconst
+ ;
+
+altertypestmt
+ : ALTER TYPE_P any_name SET OPEN_PAREN operator_def_list CLOSE_PAREN
+ ;
+
+alterownerstmt
+ : ALTER AGGREGATE aggregate_with_argtypes OWNER TO rolespec
+ | ALTER COLLATION any_name OWNER TO rolespec
+ | ALTER CONVERSION_P any_name OWNER TO rolespec
+ | ALTER DATABASE name OWNER TO rolespec
+ | ALTER DOMAIN_P any_name OWNER TO rolespec
+ | ALTER FUNCTION function_with_argtypes OWNER TO rolespec
+ | ALTER opt_procedural LANGUAGE name OWNER TO rolespec
+ | ALTER LARGE_P OBJECT_P numericonly OWNER TO rolespec
+ | ALTER OPERATOR operator_with_argtypes OWNER TO rolespec
+ | ALTER OPERATOR CLASS any_name USING name OWNER TO rolespec
+ | ALTER OPERATOR FAMILY any_name USING name OWNER TO rolespec
+ | ALTER PROCEDURE function_with_argtypes OWNER TO rolespec
+ | ALTER ROUTINE function_with_argtypes OWNER TO rolespec
+ | ALTER SCHEMA name OWNER TO rolespec
+ | ALTER TYPE_P any_name OWNER TO rolespec
+ | ALTER TABLESPACE name OWNER TO rolespec
+ | ALTER STATISTICS any_name OWNER TO rolespec
+ | ALTER TEXT_P SEARCH DICTIONARY any_name OWNER TO rolespec
+ | ALTER TEXT_P SEARCH CONFIGURATION any_name OWNER TO rolespec
+ | ALTER FOREIGN DATA_P WRAPPER name OWNER TO rolespec
+ | ALTER SERVER name OWNER TO rolespec
+ | ALTER EVENT TRIGGER name OWNER TO rolespec
+ | ALTER PUBLICATION name OWNER TO rolespec
+ | ALTER SUBSCRIPTION name OWNER TO rolespec
+ ;
+
+createpublicationstmt
+ : CREATE PUBLICATION name opt_publication_for_tables opt_definition
+ ;
+
+opt_publication_for_tables
+ : publication_for_tables
+ |
+ ;
+
+publication_for_tables
+ : FOR TABLE relation_expr_list
+ | FOR ALL TABLES
+ ;
+
+alterpublicationstmt
+ : ALTER PUBLICATION name SET definition
+ | ALTER PUBLICATION name ADD_P TABLE relation_expr_list
+ | ALTER PUBLICATION name SET TABLE relation_expr_list
+ | ALTER PUBLICATION name DROP TABLE relation_expr_list
+ ;
+
+createsubscriptionstmt
+ : CREATE SUBSCRIPTION name CONNECTION sconst PUBLICATION publication_name_list opt_definition
+ ;
+
+publication_name_list
+ : publication_name_item (COMMA publication_name_item)*
+ ;
+
+publication_name_item
+ : collabel
+ ;
+
+altersubscriptionstmt
+ : ALTER SUBSCRIPTION name SET definition
+ | ALTER SUBSCRIPTION name CONNECTION sconst
+ | ALTER SUBSCRIPTION name REFRESH PUBLICATION opt_definition
+ | ALTER SUBSCRIPTION name SET PUBLICATION publication_name_list opt_definition
+ | ALTER SUBSCRIPTION name ENABLE_P
+ | ALTER SUBSCRIPTION name DISABLE_P
+ ;
+
+dropsubscriptionstmt
+ : DROP SUBSCRIPTION name opt_drop_behavior
+ | DROP SUBSCRIPTION IF_P EXISTS name opt_drop_behavior
+ ;
+
+rulestmt
+ : CREATE opt_or_replace RULE name AS ON event TO qualified_name where_clause DO opt_instead ruleactionlist
+ ;
+
+ruleactionlist
+ : NOTHING
+ | ruleactionstmt
+ | OPEN_PAREN ruleactionmulti CLOSE_PAREN
+ ;
+
+ruleactionmulti
+ : ruleactionstmtOrEmpty (SEMI ruleactionstmtOrEmpty)*
+ ;
+
+ruleactionstmt
+ : selectstmt
+ | insertstmt
+ | updatestmt
+ | deletestmt
+ | notifystmt
+ ;
+
+ruleactionstmtOrEmpty
+ : ruleactionstmt
+ |
+ ;
+
+event
+ : SELECT
+ | UPDATE
+ | DELETE_P
+ | INSERT
+ ;
+
+opt_instead
+ : INSTEAD
+ | ALSO
+ |
+ ;
+
+notifystmt
+ : NOTIFY colid notify_payload
+ ;
+
+notify_payload
+ : COMMA sconst
+ |
+ ;
+
+listenstmt
+ : LISTEN colid
+ ;
+
+unlistenstmt
+ : UNLISTEN colid
+ | UNLISTEN STAR
+ ;
+
+transactionstmt
+ : ABORT_P opt_transaction opt_transaction_chain
+ | BEGIN_P opt_transaction transaction_mode_list_or_empty
+ | START TRANSACTION transaction_mode_list_or_empty
+ | COMMIT opt_transaction opt_transaction_chain
+ | END_P opt_transaction opt_transaction_chain
+ | ROLLBACK opt_transaction opt_transaction_chain
+ | SAVEPOINT colid
+ | RELEASE SAVEPOINT colid
+ | RELEASE colid
+ | ROLLBACK opt_transaction TO SAVEPOINT colid
+ | ROLLBACK opt_transaction TO colid
+ | PREPARE TRANSACTION sconst
+ | COMMIT PREPARED sconst
+ | ROLLBACK PREPARED sconst
+ ;
+
+opt_transaction
+ : WORK
+ | TRANSACTION
+ |
+ ;
+
+transaction_mode_item
+ : ISOLATION LEVEL iso_level
+ | READ ONLY
+ | READ WRITE
+ | DEFERRABLE
+ | NOT DEFERRABLE
+ ;
+
+transaction_mode_list
+ : transaction_mode_item (COMMA? transaction_mode_item)*
+ ;
+
+transaction_mode_list_or_empty
+ : transaction_mode_list
+ |
+ ;
+
+opt_transaction_chain
+ : AND NO? CHAIN
+ |
+ ;
+
+viewstmt
+ : CREATE (OR REPLACE)? opttemp (
+ VIEW qualified_name opt_column_list opt_reloptions
+ | RECURSIVE VIEW qualified_name OPEN_PAREN columnlist CLOSE_PAREN opt_reloptions
+ ) AS selectstmt opt_check_option
+ ;
+
+opt_check_option
+ : WITH (CASCADED | LOCAL)? CHECK OPTION
+ |
+ ;
+
+loadstmt
+ : LOAD file_name
+ ;
+
+createdbstmt
+ : CREATE DATABASE name opt_with createdb_opt_list
+ ;
+
+createdb_opt_list
+ : createdb_opt_items
+ |
+ ;
+
+createdb_opt_items
+ : createdb_opt_item+
+ ;
+
+createdb_opt_item
+ : createdb_opt_name opt_equal (signediconst | opt_boolean_or_string | DEFAULT)
+ ;
+
+createdb_opt_name
+ : identifier
+ | CONNECTION LIMIT
+ | ENCODING
+ | LOCATION
+ | OWNER
+ | TABLESPACE
+ | TEMPLATE
+ ;
+
+opt_equal
+ : EQUAL
+ |
+ ;
+
+alterdatabasestmt
+ : ALTER DATABASE name (WITH createdb_opt_list | createdb_opt_list | SET TABLESPACE name)
+ ;
+
+alterdatabasesetstmt
+ : ALTER DATABASE name setresetclause
+ ;
+
+dropdbstmt
+ : DROP DATABASE (IF_P EXISTS)? name (opt_with OPEN_PAREN drop_option_list CLOSE_PAREN)?
+ ;
+
+drop_option_list
+ : drop_option (COMMA drop_option)*
+ ;
+
+drop_option
+ : FORCE
+ ;
+
+altercollationstmt
+ : ALTER COLLATION any_name REFRESH VERSION_P
+ ;
+
+altersystemstmt
+ : ALTER SYSTEM_P (SET | RESET) generic_set
+ ;
+
+createdomainstmt
+ : CREATE DOMAIN_P any_name opt_as typename colquallist
+ ;
+
+alterdomainstmt
+ : ALTER DOMAIN_P any_name (
+ alter_column_default
+ | DROP NOT NULL_P
+ | SET NOT NULL_P
+ | ADD_P tableconstraint
+ | DROP CONSTRAINT (IF_P EXISTS)? name opt_drop_behavior
+ | VALIDATE CONSTRAINT name
+ )
+ ;
+
+opt_as
+ : AS
+ |
+ ;
+
+altertsdictionarystmt
+ : ALTER TEXT_P SEARCH DICTIONARY any_name definition
+ ;
+
+altertsconfigurationstmt
+ : ALTER TEXT_P SEARCH CONFIGURATION any_name ADD_P MAPPING FOR name_list any_with any_name_list
+ | ALTER TEXT_P SEARCH CONFIGURATION any_name ALTER MAPPING FOR name_list any_with any_name_list
+ | ALTER TEXT_P SEARCH CONFIGURATION any_name ALTER MAPPING REPLACE any_name any_with any_name
+ | ALTER TEXT_P SEARCH CONFIGURATION any_name ALTER MAPPING FOR name_list REPLACE any_name any_with any_name
+ | ALTER TEXT_P SEARCH CONFIGURATION any_name DROP MAPPING FOR name_list
+ | ALTER TEXT_P SEARCH CONFIGURATION any_name DROP MAPPING IF_P EXISTS FOR name_list
+ ;
+
+any_with
+ : WITH
+ //TODO
+
+ // | WITH_LA
+ ;
+
+createconversionstmt
+ : CREATE opt_default CONVERSION_P any_name FOR sconst TO sconst FROM any_name
+ ;
+
+clusterstmt
+ : CLUSTER opt_verbose qualified_name cluster_index_specification
+ | CLUSTER opt_verbose
+ | CLUSTER opt_verbose name ON qualified_name
+ ;
+
+cluster_index_specification
+ : USING name
+ |
+ ;
+
+vacuumstmt
+ : VACUUM opt_full opt_freeze opt_verbose opt_analyze opt_vacuum_relation_list
+ | VACUUM OPEN_PAREN vac_analyze_option_list CLOSE_PAREN opt_vacuum_relation_list
+ ;
+
+analyzestmt
+ : analyze_keyword opt_verbose opt_vacuum_relation_list
+ | analyze_keyword OPEN_PAREN vac_analyze_option_list CLOSE_PAREN opt_vacuum_relation_list
+ ;
+
+vac_analyze_option_list
+ : vac_analyze_option_elem (COMMA vac_analyze_option_elem)*
+ ;
+
+analyze_keyword
+ : ANALYZE
+ | ANALYSE
+ ;
+
+vac_analyze_option_elem
+ : vac_analyze_option_name vac_analyze_option_arg
+ ;
+
+vac_analyze_option_name
+ : nonreservedword
+ | analyze_keyword
+ ;
+
+vac_analyze_option_arg
+ : opt_boolean_or_string
+ | numericonly
+ |
+ ;
+
+opt_analyze
+ : analyze_keyword
+ |
+ ;
+
+opt_verbose
+ : VERBOSE
+ |
+ ;
+
+opt_full
+ : FULL
+ |
+ ;
+
+opt_freeze
+ : FREEZE
+ |
+ ;
+
+opt_name_list
+ : OPEN_PAREN name_list CLOSE_PAREN
+ |
+ ;
+
+vacuum_relation
+ : qualified_name opt_name_list
+ ;
+
+vacuum_relation_list
+ : vacuum_relation (COMMA vacuum_relation)*
+ ;
+
+opt_vacuum_relation_list
+ : vacuum_relation_list
+ |
+ ;
+
+explainstmt
+ : EXPLAIN explainablestmt
+ | EXPLAIN analyze_keyword opt_verbose explainablestmt
+ | EXPLAIN VERBOSE explainablestmt
+ | EXPLAIN OPEN_PAREN explain_option_list CLOSE_PAREN explainablestmt
+ ;
+
+explainablestmt
+ : selectstmt
+ | insertstmt
+ | updatestmt
+ | deletestmt
+ | declarecursorstmt
+ | createasstmt
+ | creatematviewstmt
+ | refreshmatviewstmt
+ | executestmt
+ ;
+
+explain_option_list
+ : explain_option_elem (COMMA explain_option_elem)*
+ ;
+
+explain_option_elem
+ : explain_option_name explain_option_arg
+ ;
+
+explain_option_name
+ : nonreservedword
+ | analyze_keyword
+ ;
+
+explain_option_arg
+ : opt_boolean_or_string
+ | numericonly
+ |
+ ;
+
+preparestmt
+ : PREPARE name prep_type_clause AS preparablestmt
+ ;
+
+prep_type_clause
+ : OPEN_PAREN type_list CLOSE_PAREN
+ |
+ ;
+
+preparablestmt
+ : selectstmt
+ | insertstmt
+ | updatestmt
+ | deletestmt
+ ;
+
+executestmt
+ : EXECUTE name execute_param_clause
+ | CREATE opttemp TABLE create_as_target AS EXECUTE name execute_param_clause opt_with_data
+ | CREATE opttemp TABLE IF_P NOT EXISTS create_as_target AS EXECUTE name execute_param_clause opt_with_data
+ ;
+
+execute_param_clause
+ : OPEN_PAREN expr_list CLOSE_PAREN
+ |
+ ;
+
+deallocatestmt
+ : DEALLOCATE name
+ | DEALLOCATE PREPARE name
+ | DEALLOCATE ALL
+ | DEALLOCATE PREPARE ALL
+ ;
+
+insertstmt
+ : opt_with_clause INSERT INTO insert_target insert_rest opt_on_conflict returning_clause
+ ;
+
+insert_target
+ : qualified_name (AS colid)?
+ ;
+
+insert_rest
+ : selectstmt
+ | OVERRIDING override_kind VALUE_P selectstmt
+ | OPEN_PAREN insert_column_list CLOSE_PAREN (OVERRIDING override_kind VALUE_P)? selectstmt
+ | DEFAULT VALUES
+ ;
+
+override_kind
+ : USER
+ | SYSTEM_P
+ ;
+
+insert_column_list
+ : insert_column_item (COMMA insert_column_item)*
+ ;
+
+insert_column_item
+ : colid opt_indirection
+ ;
+
+opt_on_conflict
+ : ON CONFLICT opt_conf_expr DO (UPDATE SET set_clause_list where_clause | NOTHING)
+ |
+ ;
+
+opt_conf_expr
+ : OPEN_PAREN index_params CLOSE_PAREN where_clause
+ | ON CONSTRAINT name
+ |
+ ;
+
+returning_clause
+ : RETURNING target_list
+ |
+ ;
+
+// https://www.postgresql.org/docs/current/sql-merge.html
+mergestmt
+ : MERGE INTO? qualified_name alias_clause? USING (select_with_parens | qualified_name) alias_clause? ON a_expr (
+ merge_insert_clause merge_update_clause?
+ | merge_update_clause merge_insert_clause?
+ ) merge_delete_clause?
+ ;
+
+merge_insert_clause
+ : WHEN NOT MATCHED (AND a_expr)? THEN? INSERT (OPEN_PAREN insert_column_list CLOSE_PAREN)? values_clause
+ ;
+
+merge_update_clause
+ : WHEN MATCHED (AND a_expr)? THEN? UPDATE SET set_clause_list
+ ;
+
+merge_delete_clause
+ : WHEN MATCHED THEN? DELETE_P
+ ;
+
+deletestmt
+ : opt_with_clause DELETE_P FROM relation_expr_opt_alias using_clause where_or_current_clause returning_clause
+ ;
+
+using_clause
+ : USING from_list
+ |
+ ;
+
+lockstmt
+ : LOCK_P opt_table relation_expr_list opt_lock opt_nowait
+ ;
+
+opt_lock
+ : IN_P lock_type MODE
+ |
+ ;
+
+lock_type
+ : ACCESS (SHARE | EXCLUSIVE)
+ | ROW (SHARE | EXCLUSIVE)
+ | SHARE (UPDATE EXCLUSIVE | ROW EXCLUSIVE)?
+ | EXCLUSIVE
+ ;
+
+opt_nowait
+ : NOWAIT
+ |
+ ;
+
+opt_nowait_or_skip
+ : NOWAIT
+ | SKIP_P LOCKED
+ |
+ ;
+
+updatestmt
+ : opt_with_clause UPDATE relation_expr_opt_alias SET set_clause_list from_clause where_or_current_clause returning_clause
+ ;
+
+set_clause_list
+ : set_clause (COMMA set_clause)*
+ ;
+
+set_clause
+ : set_target EQUAL a_expr
+ | OPEN_PAREN set_target_list CLOSE_PAREN EQUAL a_expr
+ ;
+
+set_target
+ : colid opt_indirection
+ ;
+
+set_target_list
+ : set_target (COMMA set_target)*
+ ;
+
+declarecursorstmt
+ : DECLARE cursor_name cursor_options CURSOR opt_hold FOR selectstmt
+ ;
+
+cursor_name
+ : name
+ ;
+
+cursor_options
+ : (NO SCROLL | SCROLL | BINARY | INSENSITIVE)*
+ ;
+
+opt_hold
+ :
+ | WITH HOLD
+ | WITHOUT HOLD
+ ;
+
+/*
+TODO: why select_with_parens alternative is needed at all?
+i guess it because original byson grammar can choose selectstmt(2)->select_with_parens on only OPEN_PARENT/SELECT kewords at the begining of statement;
+(select * from tab);
+parse can go through selectstmt( )->select_no_parens(1)->select_clause(2)->select_with_parens(1)->select_no_parens(1)->select_clause(1)->simple_select
+instead of selectstmt(1)->select_no_parens(1)->select_clause(2)->select_with_parens(1)->select_no_parens(1)->select_clause(1)->simple_select
+all standard tests passed on both variants
+*/
+
+selectstmt
+ : select_no_parens
+ | select_with_parens
+ ;
+
+select_with_parens
+ : OPEN_PAREN select_no_parens CLOSE_PAREN
+ | OPEN_PAREN select_with_parens CLOSE_PAREN
+ ;
+
+select_no_parens
+ : select_clause opt_sort_clause (
+ for_locking_clause opt_select_limit
+ | select_limit opt_for_locking_clause
+ )?
+ | with_clause select_clause opt_sort_clause (
+ for_locking_clause opt_select_limit
+ | select_limit opt_for_locking_clause
+ )?
+ ;
+
+select_clause
+ : simple_select_intersect ((UNION | EXCEPT) all_or_distinct simple_select_intersect)*
+ ;
+
+simple_select_intersect
+ : simple_select_pramary (INTERSECT all_or_distinct simple_select_pramary)*
+ ;
+
+simple_select_pramary
+ : (
+ SELECT (opt_all_clause into_clause opt_target_list | distinct_clause target_list) into_clause from_clause where_clause group_clause
+ having_clause window_clause
+ )
+ | values_clause
+ | TABLE relation_expr
+ | select_with_parens
+ ;
+
+with_clause
+ : WITH RECURSIVE? cte_list
+ ;
+
+cte_list
+ : common_table_expr (COMMA common_table_expr)*
+ ;
+
+common_table_expr
+ : name opt_name_list AS opt_materialized OPEN_PAREN preparablestmt CLOSE_PAREN
+ ;
+
+opt_materialized
+ : MATERIALIZED
+ | NOT MATERIALIZED
+ |
+ ;
+
+opt_with_clause
+ : with_clause
+ |
+ ;
+
+into_clause
+ : INTO (opt_strict opttempTableName | into_target)
+ |
+ ;
+
+opt_strict
+ :
+ | STRICT_P
+ ;
+
+opttempTableName
+ : (LOCAL | GLOBAL)? (TEMPORARY | TEMP) opt_table qualified_name
+ | UNLOGGED opt_table qualified_name
+ | TABLE qualified_name
+ | qualified_name
+ ;
+
+opt_table
+ : TABLE
+ |
+ ;
+
+all_or_distinct
+ : ALL
+ | DISTINCT
+ |
+ ;
+
+distinct_clause
+ : DISTINCT (ON OPEN_PAREN expr_list CLOSE_PAREN)?
+ ;
+
+opt_all_clause
+ : ALL
+ |
+ ;
+
+opt_sort_clause
+ : sort_clause
+ |
+ ;
+
+sort_clause
+ : ORDER BY sortby_list
+ ;
+
+sortby_list
+ : sortby (COMMA sortby)*
+ ;
+
+sortby
+ : a_expr (USING qual_all_op | opt_asc_desc) opt_nulls_order
+ ;
+
+select_limit
+ : limit_clause offset_clause?
+ | offset_clause limit_clause?
+ ;
+
+opt_select_limit
+ : select_limit
+ |
+ ;
+
+limit_clause
+ : LIMIT select_limit_value (COMMA select_offset_value)?
+ | FETCH first_or_next (
+ select_fetch_first_value row_or_rows (ONLY | WITH TIES)
+ | row_or_rows (ONLY | WITH TIES)
+ )
+ ;
+
+offset_clause
+ : OFFSET (select_offset_value | select_fetch_first_value row_or_rows)
+ ;
+
+select_limit_value
+ : a_expr
+ | ALL
+ ;
+
+select_offset_value
+ : a_expr
+ ;
+
+select_fetch_first_value
+ : c_expr
+ | PLUS i_or_f_const
+ | MINUS i_or_f_const
+ ;
+
+i_or_f_const
+ : iconst
+ | fconst
+ ;
+
+row_or_rows
+ : ROW
+ | ROWS
+ ;
+
+first_or_next
+ : FIRST_P
+ | NEXT
+ ;
+
+group_clause
+ : GROUP_P BY group_by_list
+ |
+ ;
+
+group_by_list
+ : group_by_item (COMMA group_by_item)*
+ ;
+
+group_by_item
+ : empty_grouping_set
+ | cube_clause
+ | rollup_clause
+ | grouping_sets_clause
+ | a_expr
+ ;
+
+empty_grouping_set
+ : OPEN_PAREN CLOSE_PAREN
+ ;
+
+rollup_clause
+ : ROLLUP OPEN_PAREN expr_list CLOSE_PAREN
+ ;
+
+cube_clause
+ : CUBE OPEN_PAREN expr_list CLOSE_PAREN
+ ;
+
+grouping_sets_clause
+ : GROUPING SETS OPEN_PAREN group_by_list CLOSE_PAREN
+ ;
+
+having_clause
+ : HAVING a_expr
+ |
+ ;
+
+for_locking_clause
+ : for_locking_items
+ | FOR READ ONLY
+ ;
+
+opt_for_locking_clause
+ : for_locking_clause
+ |
+ ;
+
+for_locking_items
+ : for_locking_item+
+ ;
+
+for_locking_item
+ : for_locking_strength locked_rels_list opt_nowait_or_skip
+ ;
+
+for_locking_strength
+ : FOR ((NO KEY)? UPDATE | KEY? SHARE)
+ ;
+
+locked_rels_list
+ : OF qualified_name_list
+ |
+ ;
+
+values_clause
+ : VALUES OPEN_PAREN expr_list CLOSE_PAREN (COMMA OPEN_PAREN expr_list CLOSE_PAREN)*
+ ;
+
+from_clause
+ : FROM from_list
+ |
+ ;
+
+from_list
+ : non_ansi_join
+ | table_ref (COMMA table_ref)*
+ ;
+
+non_ansi_join
+ : table_ref (COMMA table_ref)+
+ ;
+
+table_ref
+ : (
+ relation_expr opt_alias_clause tablesample_clause?
+ | func_table func_alias_clause
+ | xmltable opt_alias_clause
+ | select_with_parens opt_alias_clause
+ | LATERAL_P (
+ xmltable opt_alias_clause
+ | func_table func_alias_clause
+ | select_with_parens opt_alias_clause
+ )
+ | OPEN_PAREN table_ref (
+ CROSS JOIN table_ref
+ | NATURAL join_type? JOIN table_ref
+ | join_type? JOIN table_ref join_qual
+ )? CLOSE_PAREN opt_alias_clause
+ ) (
+ CROSS JOIN table_ref
+ | NATURAL join_type? JOIN table_ref
+ | join_type? JOIN table_ref join_qual
+ )*
+ ;
+
+alias_clause
+ : AS? colid (OPEN_PAREN name_list CLOSE_PAREN)?
+ ;
+
+opt_alias_clause
+ : table_alias_clause
+ |
+ ;
+
+table_alias_clause
+ : AS? table_alias (OPEN_PAREN name_list CLOSE_PAREN)?
+ ;
+
+func_alias_clause
+ : alias_clause
+ | (AS colid? | colid) OPEN_PAREN tablefuncelementlist CLOSE_PAREN
+ |
+ ;
+
+join_type
+ : (FULL | LEFT | RIGHT | INNER_P) OUTER_P?
+ ;
+
+join_qual
+ : USING OPEN_PAREN name_list CLOSE_PAREN
+ | ON a_expr
+ ;
+
+relation_expr
+ : qualified_name STAR?
+ | ONLY (qualified_name | OPEN_PAREN qualified_name CLOSE_PAREN)
+ ;
+
+relation_expr_list
+ : relation_expr (COMMA relation_expr)*
+ ;
+
+relation_expr_opt_alias
+ : relation_expr (AS? colid)?
+ ;
+
+tablesample_clause
+ : TABLESAMPLE func_name OPEN_PAREN expr_list CLOSE_PAREN opt_repeatable_clause
+ ;
+
+opt_repeatable_clause
+ : REPEATABLE OPEN_PAREN a_expr CLOSE_PAREN
+ |
+ ;
+
+func_table
+ : func_expr_windowless opt_ordinality
+ | ROWS FROM OPEN_PAREN rowsfrom_list CLOSE_PAREN opt_ordinality
+ ;
+
+rowsfrom_item
+ : func_expr_windowless opt_col_def_list
+ ;
+
+rowsfrom_list
+ : rowsfrom_item (COMMA rowsfrom_item)*
+ ;
+
+opt_col_def_list
+ : AS OPEN_PAREN tablefuncelementlist CLOSE_PAREN
+ |
+ ;
+
+//TODO WITH_LA was used
+
+opt_ordinality
+ : WITH ORDINALITY
+ |
+ ;
+
+where_clause
+ : WHERE a_expr
+ |
+ ;
+
+where_or_current_clause
+ : WHERE (CURRENT_P OF cursor_name | a_expr)
+ |
+ ;
+
+opttablefuncelementlist
+ : tablefuncelementlist
+ |
+ ;
+
+tablefuncelementlist
+ : tablefuncelement (COMMA tablefuncelement)*
+ ;
+
+tablefuncelement
+ : colid typename opt_collate_clause
+ ;
+
+xmltable
+ : XMLTABLE OPEN_PAREN (
+ c_expr xmlexists_argument COLUMNS xmltable_column_list
+ | XMLNAMESPACES OPEN_PAREN xml_namespace_list CLOSE_PAREN COMMA c_expr xmlexists_argument COLUMNS xmltable_column_list
+ ) CLOSE_PAREN
+ ;
+
+xmltable_column_list
+ : xmltable_column_el (COMMA xmltable_column_el)*
+ ;
+
+xmltable_column_el
+ : colid (typename xmltable_column_option_list? | FOR ORDINALITY)
+ ;
+
+xmltable_column_option_list
+ : xmltable_column_option_el+
+ ;
+
+xmltable_column_option_el
+ : DEFAULT a_expr
+ | identifier a_expr
+ | NOT NULL_P
+ | NULL_P
+ ;
+
+xml_namespace_list
+ : xml_namespace_el (COMMA xml_namespace_el)*
+ ;
+
+xml_namespace_el
+ : b_expr AS collabel
+ | DEFAULT b_expr
+ ;
+
+typename
+ : SETOF? simpletypename (opt_array_bounds | ARRAY (OPEN_BRACKET iconst CLOSE_BRACKET)?)
+ | qualified_name PERCENT (ROWTYPE | TYPE_P)
+ ;
+
+opt_array_bounds
+ : (OPEN_BRACKET iconst? CLOSE_BRACKET)*
+ ;
+
+simpletypename
+ : generictype
+ | numeric
+ | bit
+ | character
+ | constdatetime
+ | constinterval (opt_interval | OPEN_PAREN iconst CLOSE_PAREN)
+ ;
+
+consttypename
+ : numeric
+ | constbit
+ | constcharacter
+ | constdatetime
+ ;
+
+generictype
+ : (builtin_function_name | type_function_name | LEFT | RIGHT) attrs? opt_type_modifiers opt_type_parameters
+ ;
+
+opt_type_modifiers
+ : OPEN_PAREN expr_list CLOSE_PAREN
+ |
+ ;
+
+numeric
+ : INT_P
+ | INTEGER
+ | SMALLINT
+ | BIGINT
+ | REAL
+ | FLOAT_P opt_float
+ | DOUBLE_P PRECISION
+ | DECIMAL_P opt_type_modifiers
+ | DEC opt_type_modifiers
+ | NUMERIC opt_type_modifiers
+ | BOOLEAN_P
+ ;
+
+opt_float
+ : OPEN_PAREN iconst CLOSE_PAREN
+ |
+ ;
+
+//todo: merge alts
+
+bit
+ : bitwithlength
+ | bitwithoutlength
+ ;
+
+constbit
+ : bitwithlength
+ | bitwithoutlength
+ ;
+
+bitwithlength
+ : BIT opt_varying OPEN_PAREN expr_list CLOSE_PAREN
+ ;
+
+bitwithoutlength
+ : BIT opt_varying
+ ;
+
+character
+ : character_c (OPEN_PAREN iconst CLOSE_PAREN)?
+ ;
+
+constcharacter
+ : character_c (OPEN_PAREN iconst CLOSE_PAREN)?
+ ;
+
+character_c
+ : (CHARACTER | CHAR_P | NCHAR) opt_varying
+ | VARCHAR
+ | NATIONAL (CHARACTER | CHAR_P) opt_varying
+ ;
+
+opt_varying
+ : VARYING
+ |
+ ;
+
+constdatetime
+ : (TIMESTAMP | TIME) (OPEN_PAREN iconst CLOSE_PAREN)? opt_timezone
+ ;
+
+constinterval
+ : INTERVAL
+ ;
+
+//TODO with_la was used
+
+opt_timezone
+ : WITH TIME ZONE
+ | WITHOUT TIME ZONE
+ |
+ ;
+
+opt_interval
+ : YEAR_P
+ | MONTH_P
+ | DAY_P
+ | HOUR_P
+ | MINUTE_P
+ | interval_second
+ | YEAR_P TO MONTH_P
+ | DAY_P TO (HOUR_P | MINUTE_P | interval_second)
+ | HOUR_P TO (MINUTE_P | interval_second)
+ | MINUTE_P TO interval_second
+ |
+ ;
+
+interval_second
+ : SECOND_P (OPEN_PAREN iconst CLOSE_PAREN)?
+ ;
+
+opt_escape
+ : ESCAPE a_expr
+ |
+ ;
+
+//precendence accroding to Table 4.2. Operator Precedence (highest to lowest)
+
+//https://www.postgresql.org/docs/12/sql-syntax-lexical.html#SQL-PRECEDENCE
+
+/*
+original version of a_expr, for info
+ a_expr: c_expr
+ //:: left PostgreSQL-style typecast
+ | a_expr TYPECAST typename -- 1
+ | a_expr COLLATE any_name -- 2
+ | a_expr AT TIME ZONE a_expr-- 3
+ //right unary plus, unary minus
+ | (PLUS| MINUS) a_expr -- 4
+ //left exponentiation
+ | a_expr CARET a_expr -- 5
+ //left multiplication, division, modulo
+ | a_expr (STAR | SLASH | PERCENT) a_expr -- 6
+ //left addition, subtraction
+ | a_expr (PLUS | MINUS) a_expr -- 7
+ //left all other native and user-defined operators
+ | a_expr qual_op a_expr -- 8
+ | qual_op a_expr -- 9
+ //range containment, set membership, string matching BETWEEN IN LIKE ILIKE SIMILAR
+ | a_expr NOT? (LIKE|ILIKE|SIMILAR TO|(BETWEEN SYMMETRIC?)) a_expr opt_escape -- 10
+ //< > = <= >= <> comparison operators
+ | a_expr (LT | GT | EQUAL | LESS_EQUALS | GREATER_EQUALS | NOT_EQUALS) a_expr -- 11
+ //IS ISNULL NOTNULL IS TRUE, IS FALSE, IS NULL, IS DISTINCT FROM, etc
+ | a_expr IS NOT?
+ (
+ NULL_P
+ |TRUE_P
+ |FALSE_P
+ |UNKNOWN
+ |DISTINCT FROM a_expr
+ |OF OPEN_PAREN type_list CLOSE_PAREN
+ |DOCUMENT_P
+ |unicode_normal_form? NORMALIZED
+ ) -- 12
+ | a_expr (ISNULL|NOTNULL) -- 13
+ | row OVERLAPS row -- 14
+ //NOT right logical negation
+ | NOT a_expr -- 15
+ //AND left logical conjunction
+ | a_expr AND a_expr -- 16
+ //OR left logical disjunction
+ | a_expr OR a_expr -- 17
+ | a_expr (LESS_LESS|GREATER_GREATER) a_expr -- 18
+ | a_expr qual_op -- 19
+ | a_expr NOT? IN_P in_expr -- 20
+ | a_expr subquery_Op sub_type (select_with_parens|OPEN_PAREN a_expr CLOSE_PAREN) -- 21
+ | UNIQUE select_with_parens -- 22
+ | DEFAULT -- 23
+;
+*/
+
+a_expr
+ : a_expr_qual
+ ;
+
+/*23*/
+
+/*moved to c_expr*/
+
+/*22*/
+
+/*moved to c_expr*/
+
+/*19*/
+
+a_expr_qual
+ : a_expr_lessless qual_op?
+ ;
+
+/*18*/
+
+a_expr_lessless
+ : a_expr_or ((LESS_LESS | GREATER_GREATER) a_expr_or)*
+ ;
+
+/*17*/
+
+a_expr_or
+ : a_expr_and (OR a_expr_and)*
+ ;
+
+/*16*/
+
+a_expr_and
+ : a_expr_between (AND a_expr_between)*
+ ;
+
+/*21*/
+
+a_expr_between
+ : a_expr_in (NOT? BETWEEN SYMMETRIC? a_expr_in AND a_expr_in)?
+ ;
+
+/*20*/
+
+a_expr_in
+ : a_expr_unary_not (NOT? IN_P in_expr)?
+ ;
+
+/*15*/
+
+a_expr_unary_not
+ : NOT? a_expr_isnull
+ ;
+
+/*14*/
+
+/*moved to c_expr*/
+
+/*13*/
+
+a_expr_isnull
+ : a_expr_is_not (ISNULL | NOTNULL)?
+ ;
+
+/*12*/
+
+a_expr_is_not
+ : a_expr_compare (
+ IS NOT? (
+ NULL_P
+ | TRUE_P
+ | FALSE_P
+ | UNKNOWN
+ | DISTINCT FROM a_expr
+ | OF OPEN_PAREN type_list CLOSE_PAREN
+ | DOCUMENT_P
+ | unicode_normal_form? NORMALIZED
+ )
+ )?
+ ;
+
+/*11*/
+
+a_expr_compare
+ : a_expr_like (
+ (LT | GT | EQUAL | LESS_EQUALS | GREATER_EQUALS | NOT_EQUALS) a_expr_like
+ | subquery_Op sub_type (select_with_parens | OPEN_PAREN a_expr CLOSE_PAREN) /*21*/
+ )?
+ ;
+
+/*10*/
+
+a_expr_like
+ : a_expr_qual_op (NOT? (LIKE | ILIKE | SIMILAR TO) a_expr_qual_op opt_escape)?
+ ;
+
+/* 8*/
+
+a_expr_qual_op
+ : a_expr_unary_qualop (qual_op a_expr_unary_qualop)*
+ ;
+
+/* 9*/
+
+a_expr_unary_qualop
+ : qual_op? a_expr_add
+ ;
+
+/* 7*/
+
+a_expr_add
+ : a_expr_mul ((MINUS | PLUS) a_expr_mul)*
+ ;
+
+/* 6*/
+
+a_expr_mul
+ : a_expr_caret ((STAR | SLASH | PERCENT) a_expr_caret)*
+ ;
+
+/* 5*/
+
+a_expr_caret
+ : a_expr_unary_sign (CARET a_expr)?
+ ;
+
+/* 4*/
+
+a_expr_unary_sign
+ : (MINUS | PLUS)? a_expr_at_time_zone /* */
+ ;
+
+/* 3*/
+
+a_expr_at_time_zone
+ : a_expr_collate (AT TIME ZONE a_expr)?
+ ;
+
+/* 2*/
+
+a_expr_collate
+ : a_expr_typecast (COLLATE any_name)?
+ ;
+
+/* 1*/
+
+a_expr_typecast
+ : c_expr (TYPECAST typename)*
+ ;
+
+b_expr
+ : c_expr
+ | b_expr TYPECAST typename
+ //right unary plus, unary minus
+ | (PLUS | MINUS) b_expr
+ //^ left exponentiation
+ | b_expr CARET b_expr
+ //* / % left multiplication, division, modulo
+ | b_expr (STAR | SLASH | PERCENT) b_expr
+ //+ - left addition, subtraction
+ | b_expr (PLUS | MINUS) b_expr
+ //(any other operator) left all other native and user-defined operators
+ | b_expr qual_op b_expr
+ //< > = <= >= <> comparison operators
+ | b_expr (LT | GT | EQUAL | LESS_EQUALS | GREATER_EQUALS | NOT_EQUALS) b_expr
+ | qual_op b_expr
+ | b_expr qual_op
+ //S ISNULL NOTNULL IS TRUE, IS FALSE, IS NULL, IS DISTINCT FROM, etc
+ | b_expr IS NOT? (DISTINCT FROM b_expr | OF OPEN_PAREN type_list CLOSE_PAREN | DOCUMENT_P)
+ ;
+
+c_expr
+ : EXISTS select_with_parens # c_expr_exists
+ | ARRAY (select_with_parens | array_expr) # c_expr_expr
+ | PARAM opt_indirection # c_expr_expr
+ | GROUPING OPEN_PAREN expr_list CLOSE_PAREN # c_expr_expr
+ | /*22*/ UNIQUE select_with_parens # c_expr_expr
+ | columnref # c_expr_expr
+ | aexprconst # c_expr_expr
+ | plsqlvariablename # c_expr_expr
+ | OPEN_PAREN a_expr_in_parens = a_expr CLOSE_PAREN opt_indirection # c_expr_expr
+ | case_expr # c_expr_case
+ | func_expr # c_expr_expr
+ | select_with_parens indirection? # c_expr_expr
+ | explicit_row # c_expr_expr
+ | implicit_row # c_expr_expr
+ | row OVERLAPS row /* 14*/ # c_expr_expr
+ ;
+
+plsqlvariablename
+ : PLSQLVARIABLENAME
+ ;
+
+func_application
+ : func_name OPEN_PAREN (
+ func_arg_list (COMMA VARIADIC func_arg_expr)? opt_sort_clause
+ | VARIADIC func_arg_expr opt_sort_clause
+ | (ALL | DISTINCT) func_arg_list opt_sort_clause
+ | STAR
+ |
+ ) CLOSE_PAREN
+ ;
+
+func_expr
+ : func_application within_group_clause filter_clause over_clause
+ | func_expr_common_subexpr
+ ;
+
+func_expr_windowless
+ : func_application
+ | func_expr_common_subexpr
+ ;
+
+func_expr_common_subexpr
+ : COLLATION FOR OPEN_PAREN a_expr CLOSE_PAREN
+ | CURRENT_DATE
+ | CURRENT_TIME (OPEN_PAREN iconst CLOSE_PAREN)?
+ | CURRENT_TIMESTAMP (OPEN_PAREN iconst CLOSE_PAREN)?
+ | LOCALTIME (OPEN_PAREN iconst CLOSE_PAREN)?
+ | LOCALTIMESTAMP (OPEN_PAREN iconst CLOSE_PAREN)?
+ | CURRENT_ROLE
+ | CURRENT_USER
+ | SESSION_USER
+ | USER
+ | CURRENT_CATALOG
+ | CURRENT_SCHEMA
+ | CAST OPEN_PAREN a_expr AS typename CLOSE_PAREN
+ | EXTRACT OPEN_PAREN extract_list CLOSE_PAREN
+ | NORMALIZE OPEN_PAREN a_expr (COMMA unicode_normal_form)? CLOSE_PAREN
+ | OVERLAY OPEN_PAREN overlay_list CLOSE_PAREN
+ | POSITION OPEN_PAREN position_list CLOSE_PAREN
+ | SUBSTRING OPEN_PAREN substr_list CLOSE_PAREN
+ | TREAT OPEN_PAREN a_expr AS typename CLOSE_PAREN
+ | TRIM OPEN_PAREN (BOTH | LEADING | TRAILING)? trim_list CLOSE_PAREN
+ | NULLIF OPEN_PAREN a_expr COMMA a_expr CLOSE_PAREN
+ | COALESCE OPEN_PAREN expr_list CLOSE_PAREN
+ | GREATEST OPEN_PAREN expr_list CLOSE_PAREN
+ | LEAST OPEN_PAREN expr_list CLOSE_PAREN
+ | XMLCONCAT OPEN_PAREN expr_list CLOSE_PAREN
+ | XMLELEMENT OPEN_PAREN NAME_P collabel (COMMA (xml_attributes | expr_list))? CLOSE_PAREN
+ | XMLEXISTS OPEN_PAREN c_expr xmlexists_argument CLOSE_PAREN
+ | XMLFOREST OPEN_PAREN xml_attribute_list CLOSE_PAREN
+ | XMLPARSE OPEN_PAREN document_or_content a_expr xml_whitespace_option CLOSE_PAREN
+ | XMLPI OPEN_PAREN NAME_P collabel (COMMA a_expr)? CLOSE_PAREN
+ | XMLROOT OPEN_PAREN XML_P a_expr COMMA xml_root_version opt_xml_root_standalone CLOSE_PAREN
+ | XMLSERIALIZE OPEN_PAREN document_or_content a_expr AS simpletypename CLOSE_PAREN
+ ;
+
+xml_root_version
+ : VERSION_P a_expr
+ | VERSION_P NO VALUE_P
+ ;
+
+opt_xml_root_standalone
+ : COMMA STANDALONE_P YES_P
+ | COMMA STANDALONE_P NO
+ | COMMA STANDALONE_P NO VALUE_P
+ |
+ ;
+
+xml_attributes
+ : XMLATTRIBUTES OPEN_PAREN xml_attribute_list CLOSE_PAREN
+ ;
+
+xml_attribute_list
+ : xml_attribute_el (COMMA xml_attribute_el)*
+ ;
+
+xml_attribute_el
+ : a_expr (AS collabel)?
+ ;
+
+document_or_content
+ : DOCUMENT_P
+ | CONTENT_P
+ ;
+
+xml_whitespace_option
+ : PRESERVE WHITESPACE_P
+ | STRIP_P WHITESPACE_P
+ |
+ ;
+
+xmlexists_argument
+ : PASSING c_expr
+ | PASSING c_expr xml_passing_mech
+ | PASSING xml_passing_mech c_expr
+ | PASSING xml_passing_mech c_expr xml_passing_mech
+ ;
+
+xml_passing_mech
+ : BY (REF | VALUE_P)
+ ;
+
+within_group_clause
+ : WITHIN GROUP_P OPEN_PAREN sort_clause CLOSE_PAREN
+ |
+ ;
+
+filter_clause
+ : FILTER OPEN_PAREN WHERE a_expr CLOSE_PAREN
+ |
+ ;
+
+window_clause
+ : WINDOW window_definition_list
+ |
+ ;
+
+window_definition_list
+ : window_definition (COMMA window_definition)*
+ ;
+
+window_definition
+ : colid AS window_specification
+ ;
+
+over_clause
+ : OVER (window_specification | colid)
+ |
+ ;
+
+window_specification
+ : OPEN_PAREN opt_existing_window_name opt_partition_clause opt_sort_clause opt_frame_clause CLOSE_PAREN
+ ;
+
+opt_existing_window_name
+ : colid
+ |
+ ;
+
+opt_partition_clause
+ : PARTITION BY expr_list
+ |
+ ;
+
+opt_frame_clause
+ : RANGE frame_extent opt_window_exclusion_clause
+ | ROWS frame_extent opt_window_exclusion_clause
+ | GROUPS frame_extent opt_window_exclusion_clause
+ |
+ ;
+
+frame_extent
+ : frame_bound
+ | BETWEEN frame_bound AND frame_bound
+ ;
+
+frame_bound
+ : UNBOUNDED (PRECEDING | FOLLOWING)
+ | CURRENT_P ROW
+ | a_expr (PRECEDING | FOLLOWING)
+ ;
+
+opt_window_exclusion_clause
+ : EXCLUDE (CURRENT_P ROW | GROUP_P | TIES | NO OTHERS)
+ |
+ ;
+
+row
+ : ROW OPEN_PAREN expr_list? CLOSE_PAREN
+ | OPEN_PAREN expr_list COMMA a_expr CLOSE_PAREN
+ ;
+
+explicit_row
+ : ROW OPEN_PAREN expr_list? CLOSE_PAREN
+ ;
+
+/*
+TODO:
+for some reason v1
+implicit_row: OPEN_PAREN expr_list COMMA a_expr CLOSE_PAREN;
+works better than v2
+implicit_row: OPEN_PAREN expr_list CLOSE_PAREN;
+while looks like they are almost the same, except v2 requieres at least 2 items in list
+while v1 allows single item in list
+*/
+
+implicit_row
+ : OPEN_PAREN expr_list COMMA a_expr CLOSE_PAREN
+ ;
+
+sub_type
+ : ANY
+ | SOME
+ | ALL
+ ;
+
+all_op
+ : Operator
+ | mathop
+ ;
+
+mathop
+ : PLUS
+ | MINUS
+ | STAR
+ | SLASH
+ | PERCENT
+ | CARET
+ | LT
+ | GT
+ | EQUAL
+ | LESS_EQUALS
+ | GREATER_EQUALS
+ | NOT_EQUALS
+ ;
+
+qual_op
+ : Operator
+ | OPERATOR OPEN_PAREN any_operator CLOSE_PAREN
+ ;
+
+qual_all_op
+ : all_op
+ | OPERATOR OPEN_PAREN any_operator CLOSE_PAREN
+ ;
+
+subquery_Op
+ : all_op
+ | OPERATOR OPEN_PAREN any_operator CLOSE_PAREN
+ | LIKE
+ | NOT LIKE
+ | ILIKE
+ | NOT ILIKE
+ ;
+
+expr_list
+ : a_expr (COMMA a_expr)*
+ ;
+
+func_arg_list
+ : func_arg_expr (COMMA func_arg_expr)*
+ ;
+
+func_arg_expr
+ : a_expr
+ | param_name (COLON_EQUALS | EQUALS_GREATER) a_expr
+ ;
+
+type_list
+ : typename (COMMA typename)*
+ ;
+
+array_expr
+ : OPEN_BRACKET (expr_list | array_expr_list)? CLOSE_BRACKET
+ ;
+
+array_expr_list
+ : array_expr (COMMA array_expr)*
+ ;
+
+extract_list
+ : extract_arg FROM a_expr
+ |
+ ;
+
+extract_arg
+ : identifier
+ | YEAR_P
+ | MONTH_P
+ | DAY_P
+ | HOUR_P
+ | MINUTE_P
+ | SECOND_P
+ | sconst
+ ;
+
+unicode_normal_form
+ : NFC
+ | NFD
+ | NFKC
+ | NFKD
+ ;
+
+overlay_list
+ : a_expr PLACING a_expr FROM a_expr (FOR a_expr)?
+ ;
+
+position_list
+ : b_expr IN_P b_expr
+ |
+ ;
+
+substr_list
+ : a_expr FROM a_expr FOR a_expr
+ | a_expr FOR a_expr FROM a_expr
+ | a_expr FROM a_expr
+ | a_expr FOR a_expr
+ | a_expr SIMILAR a_expr ESCAPE a_expr
+ | expr_list
+ ;
+
+trim_list
+ : a_expr FROM expr_list
+ | FROM expr_list
+ | expr_list
+ ;
+
+in_expr
+ : select_with_parens # in_expr_select
+ | OPEN_PAREN expr_list CLOSE_PAREN # in_expr_list
+ ;
+
+case_expr
+ : CASE case_arg when_clause_list case_default END_P
+ ;
+
+when_clause_list
+ : when_clause+
+ ;
+
+when_clause
+ : WHEN a_expr THEN a_expr
+ ;
+
+case_default
+ : ELSE a_expr
+ |
+ ;
+
+case_arg
+ : a_expr
+ |
+ ;
+
+columnref
+ : colid indirection?
+ ;
+
+indirection_el
+ : DOT (attr_name | STAR)
+ | OPEN_BRACKET (a_expr | opt_slice_bound COLON opt_slice_bound) CLOSE_BRACKET
+ ;
+
+opt_slice_bound
+ : a_expr
+ |
+ ;
+
+indirection
+ : indirection_el+
+ ;
+
+opt_indirection
+ : indirection_el*
+ ;
+
+opt_target_list
+ : target_list
+ |
+ ;
+
+target_list
+ : target_el (COMMA target_el)*
+ ;
+
+target_el
+ : a_expr (AS collabel | identifier |) # target_label
+ | STAR # target_star
+ ;
+
+qualified_name_list
+ : qualified_name (COMMA qualified_name)*
+ ;
+
+qualified_name
+ : colid indirection?
+ ;
+
+name_list
+ : name (COMMA name)*
+ ;
+
+name
+ : colid
+ ;
+
+attr_name
+ : collabel
+ ;
+
+file_name
+ : sconst
+ ;
+
+func_name
+ : builtin_function_name
+ | type_function_name
+ | colid indirection
+ | LEFT
+ | RIGHT
+ ;
+
+aexprconst
+ : iconst
+ | fconst
+ | sconst
+ | bconst
+ | xconst
+ | func_name (sconst | OPEN_PAREN func_arg_list opt_sort_clause CLOSE_PAREN sconst)
+ | consttypename sconst
+ | constinterval (sconst opt_interval | OPEN_PAREN iconst CLOSE_PAREN sconst)
+ | TRUE_P
+ | FALSE_P
+ | NULL_P
+ ;
+
+xconst
+ : HexadecimalStringConstant
+ ;
+
+bconst
+ : BinaryStringConstant
+ ;
+
+fconst
+ : Numeric
+ ;
+
+iconst
+ : Integral
+ ;
+
+sconst
+ : anysconst opt_uescape
+ ;
+
+anysconst
+ : StringConstant
+ | UnicodeEscapeStringConstant
+ | BeginDollarStringConstant DollarText* EndDollarStringConstant
+ | EscapeStringConstant
+ ;
+
+opt_uescape
+ : UESCAPE anysconst
+ |
+ ;
+
+signediconst
+ : iconst
+ | PLUS iconst
+ | MINUS iconst
+ ;
+
+roleid
+ : rolespec
+ ;
+
+rolespec
+ : nonreservedword
+ | CURRENT_USER
+ | SESSION_USER
+ ;
+
+role_list
+ : rolespec (COMMA rolespec)*
+ ;
+
+colid
+ : identifier
+ | unreserved_keyword
+ | col_name_keyword
+ | plsql_unreserved_keyword
+ | LEFT
+ | RIGHT
+ ;
+
+table_alias
+ : identifier
+ | unreserved_keyword
+ | col_name_keyword
+ | plsql_unreserved_keyword
+ ;
+
+type_function_name
+ : identifier
+ | unreserved_keyword
+ | plsql_unreserved_keyword
+ | type_func_name_keyword
+ ;
+
+nonreservedword
+ : identifier
+ | unreserved_keyword
+ | col_name_keyword
+ | type_func_name_keyword
+ ;
+
+collabel
+ : identifier
+ | plsql_unreserved_keyword
+ | unreserved_keyword
+ | col_name_keyword
+ | type_func_name_keyword
+ | reserved_keyword
+ ;
+
+identifier
+ : Identifier opt_uescape
+ | QuotedIdentifier
+ | UnicodeQuotedIdentifier
+ | plsqlvariablename
+ | plsqlidentifier
+ | plsql_unreserved_keyword
+ ;
+
+plsqlidentifier
+ : PLSQLIDENTIFIER
+ ;
+
+unreserved_keyword
+ : ABORT_P
+ | ABSOLUTE_P
+ | ACCESS
+ | ACTION
+ | ADD_P
+ | ADMIN
+ | AFTER
+ | AGGREGATE
+ | ALSO
+ | ALTER
+ | ALWAYS
+ | ASSERTION
+ | ASSIGNMENT
+ | AT
+ | ATTACH
+ | ATTRIBUTE
+ | BACKWARD
+ | BEFORE
+ | BEGIN_P
+ | BY
+ | CACHE
+ | CALL
+ | CALLED
+ | CASCADE
+ | CASCADED
+ | CATALOG
+ | CHAIN
+ | CHARACTERISTICS
+ | CHECKPOINT
+ | CLASS
+ | CLOSE
+ | CLUSTER
+ | COLUMNS
+ | COMMENT
+ | COMMENTS
+ | COMMIT
+ | COMMITTED
+ | CONFIGURATION
+ | CONFLICT
+ | CONNECTION
+ | CONSTRAINTS
+ | CONTENT_P
+ | CONTINUE_P
+ | CONVERSION_P
+ | COPY
+ | COST
+ | CSV
+ | CUBE
+ | CURRENT_P
+ | CURSOR
+ | CYCLE
+ | DATA_P
+ | DATABASE
+ | DAY_P
+ | DEALLOCATE
+ | DECLARE
+ | DEFAULTS
+ | DEFERRED
+ | DEFINER
+ | DELETE_P
+ | DELIMITER
+ | DELIMITERS
+ | DEPENDS
+ | DETACH
+ | DICTIONARY
+ | DISABLE_P
+ | DISCARD
+ | DOCUMENT_P
+ | DOMAIN_P
+ | DOUBLE_P
+ | DROP
+ | EACH
+ | ENABLE_P
+ | ENCODING
+ | ENCRYPTED
+ | ENUM_P
+ | ESCAPE
+ | EVENT
+ | EXCLUDE
+ | EXCLUDING
+ | EXCLUSIVE
+ | EXECUTE
+ | EXPLAIN
+ | EXPRESSION
+ | EXTENSION
+ | EXTERNAL
+ | FAMILY
+ | FILTER
+ | FIRST_P
+ | FOLLOWING
+ | FORCE
+ | FORWARD
+ | FUNCTION
+ | FUNCTIONS
+ | GENERATED
+ | GLOBAL
+ | GRANTED
+ | GROUPS
+ | HANDLER
+ | HEADER_P
+ | HOLD
+ | HOUR_P
+ | IDENTITY_P
+ | IF_P
+ | IMMEDIATE
+ | IMMUTABLE
+ | IMPLICIT_P
+ | IMPORT_P
+ | INCLUDE
+ | INCLUDING
+ | INCREMENT
+ | INDEX
+ | INDEXES
+ | INHERIT
+ | INHERITS
+ | INLINE_P
+ | INPUT_P
+ | INSENSITIVE
+ | INSERT
+ | INSTEAD
+ | INVOKER
+ | ISOLATION
+ | KEY
+ | LABEL
+ | LANGUAGE
+ | LARGE_P
+ | LAST_P
+ | LEAKPROOF
+ | LEVEL
+ | LISTEN
+ | LOAD
+ | LOCAL
+ | LOCATION
+ | LOCK_P
+ | LOCKED
+ | LOGGED
+ | MAPPING
+ | MATCH
+ | MATERIALIZED
+ | MAXVALUE
+ | METHOD
+ | MINUTE_P
+ | MINVALUE
+ | MODE
+ | MONTH_P
+ | MOVE
+ | NAME_P
+ | NAMES
+ | NEW
+ | NEXT
+ | NFC
+ | NFD
+ | NFKC
+ | NFKD
+ | NO
+ | NORMALIZED
+ | NOTHING
+ | NOTIFY
+ | NOWAIT
+ | NULLS_P
+ | OBJECT_P
+ | OF
+ | OFF
+ | OIDS
+ | OLD
+ | OPERATOR
+ | OPTION
+ | OPTIONS
+ | ORDINALITY
+ | OTHERS
+ | OVER
+ | OVERRIDING
+ | OWNED
+ | OWNER
+ | PARALLEL
+ | PARSER
+ | PARTIAL
+ | PARTITION
+ | PASSING
+ | PASSWORD
+ | PLANS
+ | POLICY
+ | PRECEDING
+ | PREPARE
+ | PREPARED
+ | PRESERVE
+ | PRIOR
+ | PRIVILEGES
+ | PROCEDURAL
+ | PROCEDURE
+ | PROCEDURES
+ | PROGRAM
+ | PUBLICATION
+ | QUOTE
+ | RANGE
+ | READ
+ | REASSIGN
+ | RECHECK
+ | RECURSIVE
+ | REF
+ | REFERENCING
+ | REFRESH
+ | REINDEX
+ | RELATIVE_P
+ | RELEASE
+ | RENAME
+ | REPEATABLE
+ | REPLICA
+ | RESET
+ | RESTART
+ | RESTRICT
+ | RETURNS
+ | REVOKE
+ | ROLE
+ | ROLLBACK
+ | ROLLUP
+ | ROUTINE
+ | ROUTINES
+ | ROWS
+ | RULE
+ | SAVEPOINT
+ | SCHEMA
+ | SCHEMAS
+ | SCROLL
+ | SEARCH
+ | SECOND_P
+ | SECURITY
+ | SEQUENCE
+ | SEQUENCES
+ | SERIALIZABLE
+ | SERVER
+ | SESSION
+ | SET
+ | SETS
+ | SHARE
+ | SHOW
+ | SIMPLE
+ | SKIP_P
+ | SNAPSHOT
+ | SQL_P
+ | STABLE
+ | STANDALONE_P
+ | START
+ | STATEMENT
+ | STATISTICS
+ | STDIN
+ | STDOUT
+ | STORAGE
+ | STORED
+ | STRICT_P
+ | STRIP_P
+ | SUBSCRIPTION
+ | SUPPORT
+ | SYSID
+ | SYSTEM_P
+ | TABLES
+ | TABLESPACE
+ | TEMP
+ | TEMPLATE
+ | TEMPORARY
+ | TEXT_P
+ | TIES
+ | TRANSACTION
+ | TRANSFORM
+ | TRIGGER
+ | TRUNCATE
+ | TRUSTED
+ | TYPE_P
+ | TYPES_P
+ | UESCAPE
+ | UNBOUNDED
+ | UNCOMMITTED
+ | UNENCRYPTED
+ | UNKNOWN
+ | UNLISTEN
+ | UNLOGGED
+ | UNTIL
+ | UPDATE
+ | VACUUM
+ | VALID
+ | VALIDATE
+ | VALIDATOR
+ | VALUE_P
+ | VARYING
+ | VERSION_P
+ | VIEW
+ | VIEWS
+ | VOLATILE
+ | WHITESPACE_P
+ | WITHIN
+ | WITHOUT
+ | WORK
+ | WRAPPER
+ | WRITE
+ | XML_P
+ | YEAR_P
+ | YES_P
+ | ZONE
+ ;
+
+col_name_keyword
+ : BETWEEN
+ | BIGINT
+ | bit
+ | BOOLEAN_P
+ | CHAR_P
+ | character
+ | COALESCE
+ | DEC
+ | DECIMAL_P
+ | EXISTS
+ | EXTRACT
+ | FLOAT_P
+ | GREATEST
+ | GROUPING
+ | INOUT
+ | INT_P
+ | INTEGER
+ | INTERVAL
+ | LEAST
+ | NATIONAL
+ | NCHAR
+ | NONE
+ | NORMALIZE
+ | NULLIF
+ | numeric
+ | OUT_P
+ | OVERLAY
+ | POSITION
+ | PRECISION
+ | REAL
+ | ROW
+ | SETOF
+ | SMALLINT
+ | SUBSTRING
+ | TIME
+ | TIMESTAMP
+ | TREAT
+ | TRIM
+ | VALUES
+ | VARCHAR
+ | XMLATTRIBUTES
+ | XMLCONCAT
+ | XMLELEMENT
+ | XMLEXISTS
+ | XMLFOREST
+ | XMLNAMESPACES
+ | XMLPARSE
+ | XMLPI
+ | XMLROOT
+ | XMLSERIALIZE
+ | XMLTABLE
+ | builtin_function_name
+ ;
+
+type_func_name_keyword
+ : AUTHORIZATION
+ | BINARY
+ | COLLATION
+ | CONCURRENTLY
+ | CROSS
+ | CURRENT_SCHEMA
+ | FREEZE
+ | FULL
+ | ILIKE
+ | INNER_P
+ | IS
+ | ISNULL
+ | JOIN
+ | LIKE
+ | NATURAL
+ | NOTNULL
+ | OUTER_P
+ | OVERLAPS
+ | SIMILAR
+ | TABLESAMPLE
+ | VERBOSE
+ ;
+
+reserved_keyword
+ : ALL
+ | ANALYSE
+ | ANALYZE
+ | AND
+ | ANY
+ | ARRAY
+ | AS
+ | ASC
+ | ASYMMETRIC
+ | BOTH
+ | CASE
+ | CAST
+ | CHECK
+ | COLLATE
+ | COLUMN
+ | CONSTRAINT
+ | CREATE
+ | CURRENT_CATALOG
+ | CURRENT_DATE
+ | CURRENT_ROLE
+ | CURRENT_TIME
+ | CURRENT_TIMESTAMP
+ | CURRENT_USER
+ // | DEFAULT
+ | DEFERRABLE
+ | DESC
+ | DISTINCT
+ | DO
+ | ELSE
+ | END_P
+ | EXCEPT
+ | FALSE_P
+ | FETCH
+ | FOR
+ | FOREIGN
+ | FROM
+ | GRANT
+ | GROUP_P
+ | HAVING
+ | IN_P
+ | INITIALLY
+ | INTERSECT
+ /*
+from pl_gram.y, line ~2982
+ * Fortunately, INTO is a fully reserved word in the main grammar, so
+ * at least we need not worry about it appearing as an identifier.
+*/
+
+ // | INTO
+ | LATERAL_P
+ | LEADING
+ | LIMIT
+ | LOCALTIME
+ | LOCALTIMESTAMP
+ | NOT
+ | NULL_P
+ | OFFSET
+ | ON
+ | ONLY
+ | OR
+ | ORDER
+ | PLACING
+ | PRIMARY
+ | REFERENCES
+ | RETURNING
+ | SELECT
+ | SESSION_USER
+ | SOME
+ | SYMMETRIC
+ | TABLE
+ | THEN
+ | TO
+ | TRAILING
+ | TRUE_P
+ | UNION
+ | UNIQUE
+ | USER
+ | USING
+ | VARIADIC
+ | WHEN
+ | WHERE
+ | WINDOW
+ | WITH
+ ;
+
+builtin_function_name
+ : XMLCOMMENT
+ | XML_IS_WELL_FORMED
+ | XML_IS_WELL_FORMED_DOCUMENT
+ | XML_IS_WELL_FORMED_CONTENT
+ | XMLAGG
+ | XPATH
+ | XPATH_EXISTS
+ | ABS
+ | CBRT
+ | CEIL
+ | CEILING
+ | DEGREES
+ | DIV
+ | EXP
+ | FACTORIAL
+ | FLOOR
+ | GCD
+ | LCM
+ | LN
+ | LOG
+ | LOG10
+ | MIN_SCALE
+ | MOD
+ | PI
+ | POWER
+ | RADIANS
+ | ROUND
+ | SCALE
+ | SIGN
+ | SQRT
+ | TRIM_SCALE
+ | TRUNC
+ | WIDTH_BUCKET
+ | RANDOM
+ | SETSEED
+ | ACOS
+ | ACOSD
+ | ACOSH
+ | ASIN
+ | ASIND
+ | ASINH
+ | ATAN
+ | ATAND
+ | ATANH
+ | ATAN2
+ | ATAN2D
+ | COS
+ | COSD
+ | COSH
+ | COT
+ | COTD
+ | SIN
+ | SIND
+ | SINH
+ | TAN
+ | TAND
+ | TANH
+ | BIT_LENGTH
+ | CHAR_LENGTH
+ | CHARACTER_LENGTH
+ | LOWER
+ | OCTET_LENGTH
+ | OCTET_LENGTH
+ | UPPER
+ | ASCII
+ | BTRIM
+ | CHR
+ | CONCAT
+ | CONCAT_WS
+ | FORMAT
+ | INITCAP
+ | LENGTH
+ | LPAD
+ | LTRIM
+ | MD5
+ | PARSE_IDENT
+ | PG_CLIENT_ENCODING
+ | QUOTE_IDENT
+ | QUOTE_LITERAL
+ | QUOTE_NULLABLE
+ | REGEXP_COUNT
+ | REGEXP_INSTR
+ | REGEXP_LIKE
+ | REGEXP_MATCH
+ | REGEXP_MATCHES
+ | REGEXP_REPLACE
+ | REGEXP_SPLIT_TO_ARRAY
+ | REGEXP_SPLIT_TO_TABLE
+ | REGEXP_SUBSTR
+ | REPEAT
+ | REPLACE
+ | REVERSE
+ | RPAD
+ | RTRIM
+ | SPLIT_PART
+ | STARTS_WITH
+ | STRING_TO_ARRAY
+ | STRING_TO_TABLE
+ | STRPOS
+ | SUBSTR
+ | TO_ASCII
+ | TO_HEX
+ | TRANSLATE
+ | UNISTR
+ | AGE
+ | DATE_BIN
+ | DATE_PART
+ | DATE_TRUNC
+ | ISFINITE
+ | JUSTIFY_DAYS
+ | JUSTIFY_HOURS
+ | JUSTIFY_INTERVAL
+ | MAKE_DATE
+ | MAKE_INTERVAL
+ | MAKE_TIME
+ | MAKE_TIMESTAMP
+ | MAKE_TIMESTAMPTZ
+ | CLOCK_TIMESTAMP
+ | NOW
+ | STATEMENT_TIMESTAMP
+ | TIMEOFDAY
+ | TRANSACTION_TIMESTAMP
+ | TO_TIMESTAMP
+ | JUSTIFY_INTERVAL
+ | JUSTIFY_INTERVAL
+ | TO_CHAR
+ | TO_DATE
+ | TO_NUMBER
+ ;
+
+/************************************************************************************************************************************************************/
+/*PL/SQL GRAMMAR */
+
+/*PLSQL grammar */
+
+/************************************************************************************************************************************************************/
+pl_function
+ : comp_options pl_block opt_semi
+ ;
+
+comp_options
+ : comp_option*
+ ;
+
+comp_option
+ : sharp OPTION DUMP
+ | sharp PRINT_STRICT_PARAMS option_value
+ | sharp VARIABLE_CONFLICT ERROR
+ | sharp VARIABLE_CONFLICT USE_VARIABLE
+ | sharp VARIABLE_CONFLICT USE_COLUMN
+ ;
+
+sharp
+ : Operator
+ ;
+
+option_value
+ : sconst
+ | reserved_keyword
+ | plsql_unreserved_keyword
+ | unreserved_keyword
+ ;
+
+opt_semi
+ :
+ | SEMI
+ ;
+
+// exception_sect means opt_exception_sect in original grammar, don't be confused!
+
+pl_block
+ : decl_sect BEGIN_P proc_sect exception_sect END_P opt_label
+ ;
+
+decl_sect
+ : opt_block_label (decl_start decl_stmts?)?
+ ;
+
+decl_start
+ : DECLARE
+ ;
+
+decl_stmts
+ : decl_stmt+
+ ;
+
+label_decl
+ : LESS_LESS any_identifier GREATER_GREATER
+ ;
+
+decl_stmt
+ : decl_statement
+ | DECLARE
+ | label_decl
+ ;
+
+decl_statement
+ : decl_varname (
+ ALIAS FOR decl_aliasitem
+ | decl_const decl_datatype decl_collate decl_notnull decl_defval
+ | opt_scrollable CURSOR decl_cursor_args decl_is_for decl_cursor_query
+ ) SEMI
+ ;
+
+opt_scrollable
+ :
+ | NO SCROLL
+ | SCROLL
+ ;
+
+decl_cursor_query
+ : selectstmt
+ ;
+
+decl_cursor_args
+ :
+ | OPEN_PAREN decl_cursor_arglist CLOSE_PAREN
+ ;
+
+decl_cursor_arglist
+ : decl_cursor_arg (COMMA decl_cursor_arg)*
+ ;
+
+decl_cursor_arg
+ : decl_varname decl_datatype
+ ;
+
+decl_is_for
+ : IS
+ | FOR
+ ;
+
+decl_aliasitem
+ : PARAM
+ | colid
+ ;
+
+decl_varname
+ : any_identifier
+ ;
+
+decl_const
+ :
+ | CONSTANT
+ ;
+
+decl_datatype
+ : typename
+ ; //TODO: $$ = read_datatype(yychar);
+
+decl_collate
+ :
+ | COLLATE any_name
+ ;
+
+decl_notnull
+ :
+ | NOT NULL_P
+ ;
+
+decl_defval
+ :
+ | decl_defkey sql_expression
+ ;
+
+decl_defkey
+ : assign_operator
+ | DEFAULT
+ ;
+
+assign_operator
+ : EQUAL
+ | COLON_EQUALS
+ ;
+
+proc_sect
+ : proc_stmt*
+ ;
+
+proc_stmt
+ : pl_block SEMI
+ | stmt_return
+ | stmt_raise
+ | stmt_assign
+ | stmt_if
+ | stmt_case
+ | stmt_loop
+ | stmt_while
+ | stmt_for
+ | stmt_foreach_a
+ | stmt_exit
+ | stmt_assert
+ | stmt_execsql
+ | stmt_dynexecute
+ | stmt_perform
+ | stmt_call
+ | stmt_getdiag
+ | stmt_open
+ | stmt_fetch
+ | stmt_move
+ | stmt_close
+ | stmt_null
+ | stmt_commit
+ | stmt_rollback
+ | stmt_set
+ ;
+
+stmt_perform
+ : PERFORM expr_until_semi SEMI
+ ;
+
+stmt_call
+ : CALL any_identifier OPEN_PAREN opt_expr_list CLOSE_PAREN SEMI
+ | DO any_identifier OPEN_PAREN opt_expr_list CLOSE_PAREN SEMI
+ ;
+
+opt_expr_list
+ :
+ | expr_list
+ ;
+
+stmt_assign
+ : assign_var assign_operator sql_expression SEMI
+ ;
+
+stmt_getdiag
+ : GET getdiag_area_opt DIAGNOSTICS getdiag_list SEMI
+ ;
+
+getdiag_area_opt
+ :
+ | CURRENT_P
+ | STACKED
+ ;
+
+getdiag_list
+ : getdiag_list_item (COMMA getdiag_list_item)*
+ ;
+
+getdiag_list_item
+ : getdiag_target assign_operator getdiag_item
+ ;
+
+getdiag_item
+ : colid
+ ;
+
+getdiag_target
+ : assign_var
+ ;
+
+assign_var
+ : (any_name | PARAM) (OPEN_BRACKET expr_until_rightbracket CLOSE_BRACKET)*
+ ;
+
+stmt_if
+ : IF_P expr_until_then THEN proc_sect stmt_elsifs stmt_else END_P IF_P SEMI
+ ;
+
+stmt_elsifs
+ : (ELSIF a_expr THEN proc_sect)*
+ ;
+
+stmt_else
+ :
+ | ELSE proc_sect
+ ;
+
+stmt_case
+ : CASE opt_expr_until_when case_when_list opt_case_else END_P CASE SEMI
+ ;
+
+opt_expr_until_when
+ :
+ | sql_expression
+ ;
+
+case_when_list
+ : case_when+
+ ;
+
+case_when
+ : WHEN expr_list THEN proc_sect
+ ;
+
+opt_case_else
+ :
+ | ELSE proc_sect
+ ;
+
+stmt_loop
+ : opt_loop_label loop_body
+ ;
+
+stmt_while
+ : opt_loop_label WHILE expr_until_loop loop_body
+ ;
+
+stmt_for
+ : opt_loop_label FOR for_control loop_body
+ ;
+
+//TODO: rewrite using read_sql_expression logic?
+
+for_control
+ : for_variable IN_P (
+ cursor_name opt_cursor_parameters
+ | selectstmt
+ | explainstmt
+ | EXECUTE a_expr opt_for_using_expression
+ | opt_reverse a_expr DOT_DOT a_expr opt_by_expression
+ )
+ ;
+
+opt_for_using_expression
+ :
+ | USING expr_list
+ ;
+
+opt_cursor_parameters
+ :
+ | OPEN_PAREN a_expr (COMMA a_expr)* CLOSE_PAREN
+ ;
+
+opt_reverse
+ :
+ | REVERSE
+ ;
+
+opt_by_expression
+ :
+ | BY a_expr
+ ;
+
+for_variable
+ : any_name_list
+ ;
+
+stmt_foreach_a
+ : opt_loop_label FOREACH for_variable foreach_slice IN_P ARRAY a_expr loop_body
+ ;
+
+foreach_slice
+ :
+ | SLICE iconst
+ ;
+
+stmt_exit
+ : exit_type opt_label opt_exitcond SEMI
+ ;
+
+exit_type
+ : EXIT
+ | CONTINUE_P
+ ;
+
+//todo implement RETURN statement according to initial grammar line 1754
+
+stmt_return
+ : RETURN (
+ NEXT sql_expression
+ | QUERY (EXECUTE a_expr opt_for_using_expression | selectstmt)
+ | opt_return_result
+ ) SEMI
+ ;
+
+opt_return_result
+ :
+ | sql_expression
+ ;
+
+//https://www.postgresql.org/docs/current/plpgsql-errors-and-messages.html
+
+//RAISE [ level ] 'format' [, expression [, ... ]] [ USING option = expression [, ... ] ];
+
+//RAISE [ level ] condition_name [ USING option = expression [, ... ] ];
+
+//RAISE [ level ] SQLSTATE 'sqlstate' [ USING option = expression [, ... ] ];
+
+//RAISE [ level ] USING option = expression [, ... ];
+
+//RAISE ;
+
+stmt_raise
+ : RAISE opt_stmt_raise_level sconst opt_raise_list opt_raise_using SEMI
+ | RAISE opt_stmt_raise_level identifier opt_raise_using SEMI
+ | RAISE opt_stmt_raise_level SQLSTATE sconst opt_raise_using SEMI
+ | RAISE opt_stmt_raise_level opt_raise_using SEMI
+ | RAISE
+ ;
+
+opt_stmt_raise_level
+ :
+ |
+ | DEBUG
+ | LOG
+ | INFO
+ | NOTICE
+ | WARNING
+ | EXCEPTION
+ ;
+
+opt_raise_list
+ :
+ | (COMMA a_expr)+
+ ;
+
+opt_raise_using
+ :
+ | USING opt_raise_using_elem_list
+ ;
+
+opt_raise_using_elem
+ : identifier EQUAL a_expr
+ ;
+
+opt_raise_using_elem_list
+ : opt_raise_using_elem (COMMA opt_raise_using_elem)*
+ ;
+
+//todo imnplement
+
+stmt_assert
+ : ASSERT sql_expression opt_stmt_assert_message SEMI
+ ;
+
+opt_stmt_assert_message
+ :
+ | COMMA sql_expression
+ ;
+
+loop_body
+ : LOOP proc_sect END_P LOOP opt_label SEMI
+ ;
+
+//TODO: looks like all other statements like INSERT/SELECT/UPDATE/DELETE are handled here;
+
+//pls take a look at original grammar
+
+stmt_execsql
+ : make_execsql_stmt SEMI
+ /*K_IMPORT
+ | K_INSERT
+ | t_word
+ | t_cword
+*/
+ ;
+
+//https://www.postgresql.org/docs/current/plpgsql-statements.html#PLPGSQL-STATEMENTS-SQL-NORESULT
+
+//EXECUTE command-string [ INTO [STRICT] target ] [ USING expression [, ... ] ];
+
+stmt_dynexecute
+ : EXECUTE a_expr (
+ /*this is silly, but i have to time to find nice way to code */ opt_execute_into opt_execute_using
+ | opt_execute_using opt_execute_into
+ |
+ ) SEMI
+ ;
+
+opt_execute_using
+ :
+ | USING opt_execute_using_list
+ ;
+
+opt_execute_using_list
+ : a_expr (COMMA a_expr)*
+ ;
+
+opt_execute_into
+ :
+ | INTO STRICT_P? into_target
+ ;
+
+//https://www.postgresql.org/docs/current/plpgsql-cursors.html#PLPGSQL-CURSOR-OPENING
+
+//OPEN unbound_cursorvar [ [ NO ] SCROLL ] FOR query;
+
+//OPEN unbound_cursorvar [ [ NO ] SCROLL ] FOR EXECUTE query_string
+
+// [ USING expression [, ... ] ];
+
+//OPEN bound_cursorvar [ ( [ argument_name := ] argument_value [, ...] ) ];
+
+stmt_open
+ : OPEN (
+ cursor_variable opt_scroll_option FOR (selectstmt | EXECUTE sql_expression opt_open_using)
+ | colid (OPEN_PAREN opt_open_bound_list CLOSE_PAREN)?
+ ) SEMI
+ ;
+
+opt_open_bound_list_item
+ : colid COLON_EQUALS a_expr
+ | a_expr
+ ;
+
+opt_open_bound_list
+ : opt_open_bound_list_item (COMMA opt_open_bound_list_item)*
+ ;
+
+opt_open_using
+ :
+ | USING expr_list
+ ;
+
+opt_scroll_option
+ :
+ | opt_scroll_option_no SCROLL
+ ;
+
+opt_scroll_option_no
+ :
+ | NO
+ ;
+
+//https://www.postgresql.org/docs/current/plpgsql-cursors.html#PLPGSQL-CURSOR-OPENING
+
+//FETCH [ direction { FROM | IN } ] cursor INTO target;
+
+stmt_fetch
+ : FETCH direction = opt_fetch_direction opt_cursor_from cursor_variable INTO into_target SEMI
+ ;
+
+into_target
+ : expr_list
+ ;
+
+opt_cursor_from
+ :
+ | FROM
+ | IN_P
+ ;
+
+opt_fetch_direction
+ :
+ |
+ | NEXT
+ | PRIOR
+ | FIRST_P
+ | LAST_P
+ | ABSOLUTE_P a_expr
+ | RELATIVE_P a_expr
+ | a_expr
+ | ALL
+ | (FORWARD | BACKWARD) (a_expr | ALL)?
+ ;
+
+//https://www.postgresql.org/docs/current/plpgsql-cursors.html#PLPGSQL-CURSOR-OPENING
+
+//MOVE [ direction { FROM | IN } ] cursor;
+
+stmt_move
+ : MOVE opt_fetch_direction cursor_variable SEMI
+ ;
+
+stmt_close
+ : CLOSE cursor_variable SEMI
+ ;
+
+stmt_null
+ : NULL_P SEMI
+ ;
+
+stmt_commit
+ : COMMIT plsql_opt_transaction_chain SEMI
+ ;
+
+stmt_rollback
+ : ROLLBACK plsql_opt_transaction_chain SEMI
+ ;
+
+plsql_opt_transaction_chain
+ : AND NO? CHAIN
+ |
+ ;
+
+stmt_set
+ : SET any_name TO DEFAULT SEMI
+ | RESET (any_name | ALL) SEMI
+ ;
+
+cursor_variable
+ : colid
+ | PARAM
+ ;
+
+exception_sect
+ :
+ | EXCEPTION proc_exceptions
+ ;
+
+proc_exceptions
+ : proc_exception+
+ ;
+
+proc_exception
+ : WHEN proc_conditions THEN proc_sect
+ ;
+
+proc_conditions
+ : proc_condition (OR proc_condition)*
+ ;
+
+proc_condition
+ : any_identifier
+ | SQLSTATE sconst
+ ;
+
+//expr_until_semi:
+
+//;
+
+//expr_until_rightbracket:
+
+//;
+
+//expr_until_loop:
+
+//;
+
+opt_block_label
+ :
+ | label_decl
+ ;
+
+opt_loop_label
+ :
+ | label_decl
+ ;
+
+opt_label
+ :
+ | any_identifier
+ ;
+
+opt_exitcond
+ : WHEN expr_until_semi
+ |
+ ;
+
+any_identifier
+ : colid
+ | plsql_unreserved_keyword
+ ;
+
+plsql_unreserved_keyword
+ : ABSOLUTE_P
+ | ALIAS
+ | AND
+ | ARRAY
+ | ASSERT
+ | BACKWARD
+ | CALL
+ | CHAIN
+ | CLOSE
+ | COLLATE
+ | COLUMN
+ //| COLUMN_NAME
+ | COMMIT
+ | CONSTANT
+ | CONSTRAINT
+ //| CONSTRAINT_NAME
+ | CONTINUE_P
+ | CURRENT_P
+ | CURSOR
+ //| DATATYPE
+ | DEBUG
+ | DEFAULT
+ //| DETAIL
+ | DIAGNOSTICS
+ | DO
+ | DUMP
+ | ELSIF
+ //| ERRCODE
+ | ERROR
+ | EXCEPTION
+ | EXIT
+ | FETCH
+ | FIRST_P
+ | FORWARD
+ | GET
+ //| HINT
+
+ //| IMPORT
+ | INFO
+ | INSERT
+ | IS
+ | LAST_P
+ //| MESSAGE
+
+ //| MESSAGE_TEXT
+ | MOVE
+ | NEXT
+ | NO
+ | NOTICE
+ | OPEN
+ | OPTION
+ | PERFORM
+ //| PG_CONTEXT
+
+ //| PG_DATATYPE_NAME
+
+ //| PG_EXCEPTION_CONTEXT
+
+ //| PG_EXCEPTION_DETAIL
+
+ //| PG_EXCEPTION_HINT
+ | PRINT_STRICT_PARAMS
+ | PRIOR
+ | QUERY
+ | RAISE
+ | RELATIVE_P
+ | RESET
+ | RETURN
+ //| RETURNED_SQLSTATE
+ | ROLLBACK
+ //| ROW_COUNT
+ | ROWTYPE
+ | SCHEMA
+ //| SCHEMA_NAME
+ | SCROLL
+ | SET
+ | SLICE
+ | SQLSTATE
+ | STACKED
+ | TABLE
+ //| TABLE_NAME
+ | TYPE_P
+ | USE_COLUMN
+ | USE_VARIABLE
+ | VARIABLE_CONFLICT
+ | WARNING
+ | OUTER_P
+ ;
+
+sql_expression
+ : opt_target_list into_clause from_clause where_clause group_clause having_clause window_clause
+ ;
+
+expr_until_then
+ : sql_expression
+ ;
+
+expr_until_semi
+ : sql_expression
+ ;
+
+expr_until_rightbracket
+ : a_expr
+ ;
+
+expr_until_loop
+ : a_expr
+ ;
+
+make_execsql_stmt
+ : stmt opt_returning_clause_into
+ ;
+
+opt_returning_clause_into
+ : INTO opt_strict into_target
+ |
+ ;
diff --git a/incubator/binding-pgsql/src/main/java/io/aklivity/zilla/runtime/binding/pgsql/parser/LexerDispatchingErrorListener.java b/incubator/binding-pgsql/src/main/java/io/aklivity/zilla/runtime/binding/pgsql/parser/LexerDispatchingErrorListener.java
new file mode 100644
index 0000000000..b9a7168cd9
--- /dev/null
+++ b/incubator/binding-pgsql/src/main/java/io/aklivity/zilla/runtime/binding/pgsql/parser/LexerDispatchingErrorListener.java
@@ -0,0 +1,86 @@
+/*
+ * Copyright 2021-2023 Aklivity Inc
+ *
+ * Licensed under the Aklivity Community License (the "License"); you may not use
+ * this file except in compliance with the License. You may obtain a copy of the
+ * License at
+ *
+ * https://www.aklivity.io/aklivity-community-license/
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OF ANY KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations under the License.
+ */
+package io.aklivity.zilla.runtime.binding.pgsql.parser;
+
+import java.util.BitSet;
+
+import org.antlr.v4.runtime.ANTLRErrorListener;
+import org.antlr.v4.runtime.Lexer;
+import org.antlr.v4.runtime.Parser;
+import org.antlr.v4.runtime.ProxyErrorListener;
+import org.antlr.v4.runtime.RecognitionException;
+import org.antlr.v4.runtime.Recognizer;
+import org.antlr.v4.runtime.atn.ATNConfigSet;
+import org.antlr.v4.runtime.dfa.DFA;
+
+public class LexerDispatchingErrorListener implements ANTLRErrorListener
+{
+ Lexer parent;
+
+ public LexerDispatchingErrorListener(
+ Lexer parent)
+ {
+ this.parent = parent;
+ }
+
+ public void syntaxError(
+ Recognizer, ?> recognizer,
+ Object offendingSymbol,
+ int line,
+ int charPositionInLine,
+ String msg,
+ RecognitionException e)
+ {
+ ProxyErrorListener foo = new ProxyErrorListener(parent.getErrorListeners());
+ foo.syntaxError(recognizer, offendingSymbol, line, charPositionInLine, msg, e);
+ }
+
+ public void reportAmbiguity(
+ Parser recognizer,
+ DFA dfa,
+ int startIndex,
+ int stopIndex,
+ boolean exact,
+ BitSet ambigAlts,
+ ATNConfigSet configs)
+ {
+ ProxyErrorListener proxyError = new ProxyErrorListener(parent.getErrorListeners());
+ proxyError.reportAmbiguity(recognizer, dfa, startIndex, stopIndex, exact, ambigAlts, configs);
+ }
+
+ public void reportAttemptingFullContext(
+ Parser recognizer,
+ DFA dfa,
+ int startIndex,
+ int stopIndex,
+ BitSet conflictingAlts,
+ ATNConfigSet configs)
+ {
+ ProxyErrorListener proxyError = new ProxyErrorListener(parent.getErrorListeners());
+ proxyError.reportAttemptingFullContext(recognizer, dfa, startIndex, stopIndex, conflictingAlts, configs);
+ }
+
+ public void reportContextSensitivity(
+ Parser recognizer,
+ DFA dfa,
+ int startIndex,
+ int stopIndex,
+ int prediction,
+ ATNConfigSet configs)
+ {
+ ProxyErrorListener proxyError = new ProxyErrorListener(parent.getErrorListeners());
+ proxyError.reportContextSensitivity(recognizer, dfa, startIndex, stopIndex, prediction, configs);
+ }
+}
diff --git a/incubator/binding-pgsql/src/main/java/io/aklivity/zilla/runtime/binding/pgsql/parser/ParserDispatchingErrorListener.java b/incubator/binding-pgsql/src/main/java/io/aklivity/zilla/runtime/binding/pgsql/parser/ParserDispatchingErrorListener.java
new file mode 100644
index 0000000000..3531e2c33f
--- /dev/null
+++ b/incubator/binding-pgsql/src/main/java/io/aklivity/zilla/runtime/binding/pgsql/parser/ParserDispatchingErrorListener.java
@@ -0,0 +1,86 @@
+/*
+ * Copyright 2021-2023 Aklivity Inc
+ *
+ * Licensed under the Aklivity Community License (the "License"); you may not use
+ * this file except in compliance with the License. You may obtain a copy of the
+ * License at
+ *
+ * https://www.aklivity.io/aklivity-community-license/
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OF ANY KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations under the License.
+ */
+package io.aklivity.zilla.runtime.binding.pgsql.parser;
+
+import java.util.BitSet;
+
+import org.antlr.v4.runtime.ANTLRErrorListener;
+import org.antlr.v4.runtime.Parser;
+import org.antlr.v4.runtime.ProxyErrorListener;
+import org.antlr.v4.runtime.RecognitionException;
+import org.antlr.v4.runtime.Recognizer;
+import org.antlr.v4.runtime.atn.ATNConfigSet;
+import org.antlr.v4.runtime.dfa.DFA;
+
+
+public class ParserDispatchingErrorListener implements ANTLRErrorListener
+{
+ @SuppressWarnings("checkstyle:MemberName")
+ Parser parent;
+
+ public ParserDispatchingErrorListener(
+ Parser parent)
+ {
+ this.parent = parent;
+ }
+
+ public void syntaxError(
+ Recognizer, ?> recognizer, Object offendingSymbol,
+ int line,
+ int charPositionInLine,
+ String msg,
+ RecognitionException e)
+ {
+ var foo = new ProxyErrorListener(parent.getErrorListeners());
+ foo.syntaxError(recognizer, offendingSymbol, line, charPositionInLine, msg, e);
+ }
+
+ public void reportAmbiguity(
+ Parser recognizer,
+ DFA dfa,
+ int startIndex,
+ int stopIndex,
+ boolean exact,
+ BitSet ambigAlts,
+ ATNConfigSet configs)
+ {
+ ProxyErrorListener foo = new ProxyErrorListener(parent.getErrorListeners());
+ foo.reportAmbiguity(recognizer, dfa, startIndex, stopIndex, exact, ambigAlts, configs);
+ }
+
+ public void reportAttemptingFullContext(
+ Parser recognizer,
+ DFA dfa,
+ int startIndex,
+ int stopIndex,
+ BitSet conflictingAlts,
+ ATNConfigSet configs)
+ {
+ ProxyErrorListener foo = new ProxyErrorListener(parent.getErrorListeners());
+ foo.reportAttemptingFullContext(recognizer, dfa, startIndex, stopIndex, conflictingAlts, configs);
+ }
+
+ public void reportContextSensitivity(
+ Parser recognizer,
+ DFA dfa,
+ int startIndex,
+ int stopIndex,
+ int prediction,
+ ATNConfigSet configs)
+ {
+ ProxyErrorListener foo = new ProxyErrorListener(parent.getErrorListeners());
+ foo.reportContextSensitivity(recognizer, dfa, startIndex, stopIndex, prediction, configs);
+ }
+}
diff --git a/incubator/binding-pgsql/src/main/java/io/aklivity/zilla/runtime/binding/pgsql/parser/PgsqlParser.java b/incubator/binding-pgsql/src/main/java/io/aklivity/zilla/runtime/binding/pgsql/parser/PgsqlParser.java
new file mode 100644
index 0000000000..0479aa08a8
--- /dev/null
+++ b/incubator/binding-pgsql/src/main/java/io/aklivity/zilla/runtime/binding/pgsql/parser/PgsqlParser.java
@@ -0,0 +1,123 @@
+/*
+ * Copyright 2021-2023 Aklivity Inc
+ *
+ * Licensed under the Aklivity Community License (the "License"); you may not use
+ * this file except in compliance with the License. You may obtain a copy of the
+ * License at
+ *
+ * https://www.aklivity.io/aklivity-community-license/
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OF ANY KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations under the License.
+ */
+package io.aklivity.zilla.runtime.binding.pgsql.parser;
+
+import java.util.List;
+
+import org.antlr.v4.runtime.BailErrorStrategy;
+import org.antlr.v4.runtime.CharStream;
+import org.antlr.v4.runtime.CharStreams;
+import org.antlr.v4.runtime.CommonTokenStream;
+import org.antlr.v4.runtime.tree.ParseTreeWalker;
+
+import io.aklivity.zilla.runtime.binding.pgsql.parser.listener.SqlCommandListener;
+import io.aklivity.zilla.runtime.binding.pgsql.parser.listener.SqlCreateFunctionListener;
+import io.aklivity.zilla.runtime.binding.pgsql.parser.listener.SqlCreateMaterializedViewListener;
+import io.aklivity.zilla.runtime.binding.pgsql.parser.listener.SqlCreateStreamListener;
+import io.aklivity.zilla.runtime.binding.pgsql.parser.listener.SqlCreateTableTopicListener;
+import io.aklivity.zilla.runtime.binding.pgsql.parser.listener.SqlDropListener;
+import io.aklivity.zilla.runtime.binding.pgsql.parser.model.FunctionInfo;
+import io.aklivity.zilla.runtime.binding.pgsql.parser.model.StreamInfo;
+import io.aklivity.zilla.runtime.binding.pgsql.parser.model.TableInfo;
+import io.aklivity.zilla.runtime.binding.pgsql.parser.model.ViewInfo;
+
+public final class PgsqlParser
+{
+ private final ParseTreeWalker walker;
+ private final BailErrorStrategy errorStrategy;
+ private final PostgreSqlLexer lexer;
+ private final CommonTokenStream tokens;
+ private final PostgreSqlParser parser;
+ private final SqlCommandListener commandListener;
+ private final SqlCreateStreamListener createStreamListener;
+ private final SqlCreateTableTopicListener createTableListener;
+ private final SqlCreateFunctionListener createFunctionListener;
+ private final SqlCreateMaterializedViewListener createMaterializedViewListener;
+ private final SqlDropListener dropListener;
+
+ public PgsqlParser()
+ {
+ this.walker = new ParseTreeWalker();
+ this.errorStrategy = new BailErrorStrategy();
+ this.lexer = new PostgreSqlLexer(null);
+ this.tokens = new CommonTokenStream(lexer);
+ this.parser = new PostgreSqlParser(tokens);
+ this.commandListener = new SqlCommandListener();
+ this.createTableListener = new SqlCreateTableTopicListener(tokens);
+ this.createStreamListener = new SqlCreateStreamListener(tokens);
+ this.createFunctionListener = new SqlCreateFunctionListener(tokens);
+ this.createMaterializedViewListener = new SqlCreateMaterializedViewListener(tokens);
+ this.dropListener = new SqlDropListener();
+ parser.setErrorHandler(errorStrategy);
+ }
+
+ public String parseCommand(
+ String sql)
+ {
+ parser(sql, commandListener);
+ return commandListener.command();
+ }
+
+ public TableInfo parseCreateTable(
+ String sql)
+ {
+ parser(sql, createTableListener);
+ return createTableListener.tableInfo();
+ }
+
+ public StreamInfo parseCreateStream(
+ String sql)
+ {
+ parser(sql, createStreamListener);
+ return createStreamListener.streamInfo();
+ }
+
+ public FunctionInfo parseCreateFunction(
+ String sql)
+ {
+ parser(sql, createFunctionListener);
+ return createFunctionListener.functionInfo();
+ }
+
+ public ViewInfo parseCreateMaterializedView(
+ String sql)
+ {
+ parser(sql, createMaterializedViewListener);
+ return createMaterializedViewListener.viewInfo();
+ }
+
+ public List parseDrop(
+ String sql)
+ {
+ parser(sql, dropListener);
+ return dropListener.drops();
+ }
+
+ private void parser(
+ String sql,
+ PostgreSqlParserBaseListener listener)
+ {
+ sql = sql.replace("\u0000", "");
+
+ CharStream input = CharStreams.fromString(sql);
+ lexer.reset();
+ lexer.setInputStream(input);
+
+ tokens.setTokenSource(lexer);
+ parser.setTokenStream(tokens);
+
+ walker.walk(listener, parser.root());
+ }
+}
diff --git a/incubator/binding-pgsql/src/main/java/io/aklivity/zilla/runtime/binding/pgsql/parser/PostgreSqlLexerBase.java b/incubator/binding-pgsql/src/main/java/io/aklivity/zilla/runtime/binding/pgsql/parser/PostgreSqlLexerBase.java
new file mode 100644
index 0000000000..59295577b9
--- /dev/null
+++ b/incubator/binding-pgsql/src/main/java/io/aklivity/zilla/runtime/binding/pgsql/parser/PostgreSqlLexerBase.java
@@ -0,0 +1,95 @@
+/*
+ * Copyright 2021-2023 Aklivity Inc
+ *
+ * Licensed under the Aklivity Community License (the "License"); you may not use
+ * this file except in compliance with the License. You may obtain a copy of the
+ * License at
+ *
+ * https://www.aklivity.io/aklivity-community-license/
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OF ANY KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations under the License.
+ */
+package io.aklivity.zilla.runtime.binding.pgsql.parser;
+
+import java.util.ArrayDeque;
+import java.util.Deque;
+
+import org.antlr.v4.runtime.CharStream;
+import org.antlr.v4.runtime.Lexer;
+
+public abstract class PostgreSqlLexerBase extends Lexer
+{
+ protected final Deque tags = new ArrayDeque<>();
+
+ protected PostgreSqlLexerBase(CharStream input)
+ {
+ super(input);
+ }
+
+ public void pushTag()
+ {
+ tags.push(getText());
+ }
+
+ public boolean isTag()
+ {
+ return getText().equals(tags.peek());
+ }
+
+ public void popTag()
+ {
+ tags.pop();
+ }
+
+ public boolean checkLA(int c)
+ {
+ return getInputStream().LA(1) != c;
+ }
+
+ public boolean charIsLetter()
+ {
+ return Character.isLetter(getInputStream().LA(-1));
+ }
+
+ public void handleNumericFail()
+ {
+ getInputStream().seek(getInputStream().index() - 2);
+ setType(PostgreSqlLexer.Integral);
+ }
+
+ public void handleLessLessGreaterGreater()
+ {
+ if ("<<".equals(getText()))
+ {
+ setType(PostgreSqlLexer.LESS_LESS);
+ }
+ if (">>".equals(getText()))
+ {
+ setType(PostgreSqlLexer.GREATER_GREATER);
+ }
+ }
+
+ public void unterminatedBlockCommentDebugAssert()
+ {
+ //Debug.Assert(InputStream.LA(1) == -1 /*EOF*/);
+ }
+
+ public boolean checkIfUtf32Letter()
+ {
+ int codePoint = getInputStream().LA(-2) << 8 + getInputStream().LA(-1);
+ char[] c;
+ if (codePoint < 0x10000)
+ {
+ c = new char[]{(char) codePoint};
+ }
+ else
+ {
+ codePoint -= 0x10000;
+ c = new char[]{(char) (codePoint / 0x400 + 0xd800), (char) (codePoint % 0x400 + 0xdc00)};
+ }
+ return Character.isLetter(c[0]);
+ }
+}
diff --git a/incubator/binding-pgsql/src/main/java/io/aklivity/zilla/runtime/binding/pgsql/parser/PostgreSqlParserBase.java b/incubator/binding-pgsql/src/main/java/io/aklivity/zilla/runtime/binding/pgsql/parser/PostgreSqlParserBase.java
new file mode 100644
index 0000000000..71f927759e
--- /dev/null
+++ b/incubator/binding-pgsql/src/main/java/io/aklivity/zilla/runtime/binding/pgsql/parser/PostgreSqlParserBase.java
@@ -0,0 +1,171 @@
+/*
+ * Copyright 2021-2023 Aklivity Inc
+ *
+ * Licensed under the Aklivity Community License (the "License"); you may not use
+ * this file except in compliance with the License. You may obtain a copy of the
+ * License at
+ *
+ * https://www.aklivity.io/aklivity-community-license/
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OF ANY KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations under the License.
+ */
+package io.aklivity.zilla.runtime.binding.pgsql.parser;
+
+import java.util.List;
+
+import org.antlr.v4.runtime.CharStream;
+import org.antlr.v4.runtime.CharStreams;
+import org.antlr.v4.runtime.CommonTokenStream;
+import org.antlr.v4.runtime.Lexer;
+import org.antlr.v4.runtime.Parser;
+import org.antlr.v4.runtime.ParserRuleContext;
+import org.antlr.v4.runtime.TokenStream;
+
+public abstract class PostgreSqlParserBase extends Parser
+{
+
+ public PostgreSqlParserBase(TokenStream input)
+ {
+ super(input);
+ }
+
+ ParserRuleContext getParsedSqlTree(
+ String script,
+ int line)
+ {
+ PostgreSqlParser ph = getPostgreSqlParser(script);
+ ParserRuleContext result = ph.root();
+ return result;
+ }
+
+ public void parseRoutineBody(
+ PostgreSqlParser.Createfunc_opt_listContext localctx)
+ {
+ String lang = null;
+ for (PostgreSqlParser.Createfunc_opt_itemContext coi : localctx.createfunc_opt_item())
+ {
+ if (coi.LANGUAGE() != null)
+ {
+ if (coi.nonreservedword_or_sconst() != null)
+ {
+ if (coi.nonreservedword_or_sconst().sconst() != null)
+ {
+ lang = coi.nonreservedword_or_sconst().sconst().getText();
+ break;
+ }
+ if (coi.nonreservedword_or_sconst().nonreservedword() != null)
+ {
+ if (coi.nonreservedword_or_sconst().nonreservedword().identifier() != null)
+ {
+ if (coi.nonreservedword_or_sconst().nonreservedword().identifier().Identifier() != null)
+ {
+ lang = coi.nonreservedword_or_sconst().nonreservedword().identifier().Identifier().getText();
+ break;
+ }
+ }
+ }
+ }
+ }
+ }
+ if (null == lang)
+ {
+ return;
+ }
+ PostgreSqlParser.Createfunc_opt_itemContext funcAs = null;
+ for (PostgreSqlParser.Createfunc_opt_itemContext a : localctx.createfunc_opt_item())
+ {
+ if (a.func_as() != null)
+ {
+ funcAs = a;
+ break;
+ }
+
+ }
+ if (funcAs != null)
+ {
+ String txt = getRoutineBodyString(funcAs.func_as().sconst(0));
+ PostgreSqlParser ph = getPostgreSqlParser(txt);
+ switch (lang)
+ {
+ case "plpgsql":
+ funcAs.func_as().Definition = ph.plsqlroot();
+ break;
+ case "sql":
+ funcAs.func_as().Definition = ph.root();
+ break;
+ }
+ }
+ }
+
+ private String trimQuotes(String s)
+ {
+ return (s == null || s.isEmpty()) ? s : s.substring(1, s.length() - 1);
+ }
+
+ public String unquote(
+ String s)
+ {
+ int slength = s.length();
+ StringBuilder r = new StringBuilder(slength);
+ int i = 0;
+ while (i < slength)
+ {
+ Character c = s.charAt(i);
+ r.append(c);
+ if (c == '\'' && i < slength - 1 && s.charAt(i + 1) == '\'')
+ {
+ i++;
+ }
+ i++;
+ }
+ return r.toString();
+ }
+
+ public String getRoutineBodyString(
+ PostgreSqlParser.SconstContext rule)
+ {
+ PostgreSqlParser.AnysconstContext anysconst = rule.anysconst();
+ org.antlr.v4.runtime.tree.TerminalNode stringConstant = anysconst.StringConstant();
+ if (null != stringConstant)
+ {
+ return trimQuotes(stringConstant.getText());
+ }
+ org.antlr.v4.runtime.tree.TerminalNode unicodeEscapeStringConstant = anysconst.UnicodeEscapeStringConstant();
+ if (null != unicodeEscapeStringConstant)
+ {
+ return unquote(unicodeEscapeStringConstant.getText());
+ }
+ org.antlr.v4.runtime.tree.TerminalNode escapeStringConstant = anysconst.EscapeStringConstant();
+ if (null != escapeStringConstant)
+ {
+ return unquote(escapeStringConstant.getText());
+ }
+ String result = "";
+ List dollartext = anysconst.DollarText();
+ for (org.antlr.v4.runtime.tree.TerminalNode s : dollartext)
+ {
+ result += s.getText();
+ }
+ return result;
+ }
+
+ public PostgreSqlParser getPostgreSqlParser(
+ String script)
+ {
+ CharStream charStream = CharStreams.fromString(script);
+ Lexer lexer = new PostgreSqlLexer(charStream);
+ CommonTokenStream tokens = new CommonTokenStream(lexer);
+ PostgreSqlParser parser = new PostgreSqlParser(tokens);
+ lexer.removeErrorListeners();
+ parser.removeErrorListeners();
+ LexerDispatchingErrorListener listenerLexer =
+ new LexerDispatchingErrorListener((Lexer)(this.getInputStream().getTokenSource()));
+ ParserDispatchingErrorListener listenerParser = new ParserDispatchingErrorListener(this);
+ lexer.addErrorListener(listenerLexer);
+ parser.addErrorListener(listenerParser);
+ return parser;
+ }
+}
diff --git a/incubator/binding-pgsql/src/main/java/io/aklivity/zilla/runtime/binding/pgsql/parser/listener/SqlCommandListener.java b/incubator/binding-pgsql/src/main/java/io/aklivity/zilla/runtime/binding/pgsql/parser/listener/SqlCommandListener.java
new file mode 100644
index 0000000000..ce9f2ce2ce
--- /dev/null
+++ b/incubator/binding-pgsql/src/main/java/io/aklivity/zilla/runtime/binding/pgsql/parser/listener/SqlCommandListener.java
@@ -0,0 +1,75 @@
+/*
+ * Copyright 2021-2023 Aklivity Inc
+ *
+ * Licensed under the Aklivity Community License (the "License"); you may not use
+ * this file except in compliance with the License. You may obtain a copy of the
+ * License at
+ *
+ * https://www.aklivity.io/aklivity-community-license/
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OF ANY KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations under the License.
+ */
+package io.aklivity.zilla.runtime.binding.pgsql.parser.listener;
+
+import io.aklivity.zilla.runtime.binding.pgsql.parser.PostgreSqlParser;
+import io.aklivity.zilla.runtime.binding.pgsql.parser.PostgreSqlParserBaseListener;
+
+public class SqlCommandListener extends PostgreSqlParserBaseListener
+{
+ private String command = "";
+
+ public String command()
+ {
+ return command;
+ }
+
+ @Override
+ public void enterRoot(
+ PostgreSqlParser.RootContext ctx)
+ {
+ command = "";
+ }
+
+ @Override
+ public void enterCreatestmt(
+ PostgreSqlParser.CreatestmtContext ctx)
+ {
+ command = "CREATE %s".formatted(ctx.opttable_type().getText());
+ }
+
+ @Override
+ public void enterCreatestreamstmt(
+ PostgreSqlParser.CreatestreamstmtContext ctx)
+ {
+ command = "CREATE STREAM";
+ }
+
+ @Override
+ public void enterCreatematviewstmt(
+ PostgreSqlParser.CreatematviewstmtContext ctx)
+ {
+ command = "CREATE MATERIALIZED VIEW";
+ }
+
+ @Override
+ public void enterCreatefunctionstmt(
+ PostgreSqlParser.CreatefunctionstmtContext ctx)
+ {
+ String functionBody = ctx.getText();
+
+ if (!functionBody.contains("$$"))
+ {
+ command = "CREATE FUNCTION";
+ }
+ }
+
+ @Override
+ public void enterDropstmt(
+ PostgreSqlParser.DropstmtContext ctx)
+ {
+ command = "DROP %s".formatted(ctx.object_type_any_name().getText());
+ }
+}
diff --git a/incubator/binding-pgsql/src/main/java/io/aklivity/zilla/runtime/binding/pgsql/parser/listener/SqlCreateFunctionListener.java b/incubator/binding-pgsql/src/main/java/io/aklivity/zilla/runtime/binding/pgsql/parser/listener/SqlCreateFunctionListener.java
new file mode 100644
index 0000000000..85c1a98127
--- /dev/null
+++ b/incubator/binding-pgsql/src/main/java/io/aklivity/zilla/runtime/binding/pgsql/parser/listener/SqlCreateFunctionListener.java
@@ -0,0 +1,107 @@
+/*
+ * Copyright 2021-2023 Aklivity Inc
+ *
+ * Licensed under the Aklivity Community License (the "License"); you may not use
+ * this file except in compliance with the License. You may obtain a copy of the
+ * License at
+ *
+ * https://www.aklivity.io/aklivity-community-license/
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OF ANY KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations under the License.
+ */
+package io.aklivity.zilla.runtime.binding.pgsql.parser.listener;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.antlr.v4.runtime.TokenStream;
+
+import io.aklivity.zilla.runtime.binding.pgsql.parser.PostgreSqlParser;
+import io.aklivity.zilla.runtime.binding.pgsql.parser.PostgreSqlParserBaseListener;
+import io.aklivity.zilla.runtime.binding.pgsql.parser.model.FunctionArgument;
+import io.aklivity.zilla.runtime.binding.pgsql.parser.model.FunctionInfo;
+
+public class SqlCreateFunctionListener extends PostgreSqlParserBaseListener
+{
+ private final List arguments = new ArrayList<>();
+ private final List tables = new ArrayList<>();
+
+ private final TokenStream tokens;
+
+ private String name;
+ private String returnType;
+ private String asFunction;
+ private String language;
+
+ public SqlCreateFunctionListener(
+ TokenStream tokens)
+ {
+ this.tokens = tokens;
+ }
+
+ public FunctionInfo functionInfo()
+ {
+ return new FunctionInfo(name, arguments, returnType, tables, asFunction, language);
+ }
+
+ @Override
+ public void enterRoot(
+ PostgreSqlParser.RootContext ctx)
+ {
+ name = null;
+ returnType = null;
+ asFunction = null;
+ language = null;
+ arguments.clear();
+ tables.clear();
+ }
+
+ @Override
+ public void enterCreatefunctionstmt(
+ PostgreSqlParser.CreatefunctionstmtContext ctx)
+ {
+ name = ctx.func_name().getText();
+ }
+
+ @Override
+ public void enterFunc_arg(
+ PostgreSqlParser.Func_argContext ctx)
+ {
+ String argName = ctx.param_name() != null ? ctx.param_name().getText() : null;
+ String argType = tokens.getText(ctx.func_type());
+ arguments.add(new FunctionArgument(argName, argType));
+ }
+
+ @Override
+ public void enterTable_func_column(
+ PostgreSqlParser.Table_func_columnContext ctx)
+ {
+ String argName = ctx.param_name() != null ? ctx.param_name().getText() : null;
+ String argType = ctx.func_type().getText();
+ tables.add(new FunctionArgument(argName, argType));
+ }
+
+ @Override
+ public void enterFunc_type(
+ PostgreSqlParser.Func_typeContext ctx)
+ {
+ returnType = tokens.getText(ctx.typename());
+ }
+
+ @Override
+ public void enterFunc_as(
+ PostgreSqlParser.Func_asContext ctx)
+ {
+ asFunction = ctx.getText();
+ }
+
+ @Override
+ public void enterNonreservedword_or_sconst(
+ PostgreSqlParser.Nonreservedword_or_sconstContext ctx)
+ {
+ language = ctx.getText();
+ }
+}
diff --git a/incubator/binding-pgsql/src/main/java/io/aklivity/zilla/runtime/binding/pgsql/parser/listener/SqlCreateMaterializedViewListener.java b/incubator/binding-pgsql/src/main/java/io/aklivity/zilla/runtime/binding/pgsql/parser/listener/SqlCreateMaterializedViewListener.java
new file mode 100644
index 0000000000..f4e8c5d5a8
--- /dev/null
+++ b/incubator/binding-pgsql/src/main/java/io/aklivity/zilla/runtime/binding/pgsql/parser/listener/SqlCreateMaterializedViewListener.java
@@ -0,0 +1,62 @@
+/*
+ * Copyright 2021-2023 Aklivity Inc
+ *
+ * Licensed under the Aklivity Community License (the "License"); you may not use
+ * this file except in compliance with the License. You may obtain a copy of the
+ * License at
+ *
+ * https://www.aklivity.io/aklivity-community-license/
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OF ANY KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations under the License.
+ */
+package io.aklivity.zilla.runtime.binding.pgsql.parser.listener;
+
+import org.antlr.v4.runtime.TokenStream;
+
+import io.aklivity.zilla.runtime.binding.pgsql.parser.PostgreSqlParser;
+import io.aklivity.zilla.runtime.binding.pgsql.parser.PostgreSqlParserBaseListener;
+import io.aklivity.zilla.runtime.binding.pgsql.parser.model.ViewInfo;
+
+public class SqlCreateMaterializedViewListener extends PostgreSqlParserBaseListener
+{
+ private final TokenStream tokens;
+
+ private String name;
+ private String select;
+
+ public SqlCreateMaterializedViewListener(
+ TokenStream tokens)
+ {
+ this.tokens = tokens;
+ }
+
+ public ViewInfo viewInfo()
+ {
+ return new ViewInfo(name, select);
+ }
+
+ @Override
+ public void enterRoot(
+ PostgreSqlParser.RootContext ctx)
+ {
+ name = null;
+ select = null;
+ }
+
+ @Override
+ public void enterCreatematviewstmt(
+ PostgreSqlParser.CreatematviewstmtContext ctx)
+ {
+ name = ctx.create_mv_target().qualified_name().getText();
+ }
+
+ @Override
+ public void enterSelectstmt(
+ PostgreSqlParser.SelectstmtContext ctx)
+ {
+ select = tokens.getText(ctx);
+ }
+}
diff --git a/incubator/binding-pgsql/src/main/java/io/aklivity/zilla/runtime/binding/pgsql/parser/listener/SqlCreateStreamListener.java b/incubator/binding-pgsql/src/main/java/io/aklivity/zilla/runtime/binding/pgsql/parser/listener/SqlCreateStreamListener.java
new file mode 100644
index 0000000000..34a2638676
--- /dev/null
+++ b/incubator/binding-pgsql/src/main/java/io/aklivity/zilla/runtime/binding/pgsql/parser/listener/SqlCreateStreamListener.java
@@ -0,0 +1,73 @@
+/*
+ * Copyright 2021-2023 Aklivity Inc
+ *
+ * Licensed under the Aklivity Community License (the "License"); you may not use
+ * this file except in compliance with the License. You may obtain a copy of the
+ * License at
+ *
+ * https://www.aklivity.io/aklivity-community-license/
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OF ANY KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations under the License.
+ */
+package io.aklivity.zilla.runtime.binding.pgsql.parser.listener;
+
+import java.util.LinkedHashMap;
+import java.util.Map;
+
+import org.antlr.v4.runtime.TokenStream;
+
+import io.aklivity.zilla.runtime.binding.pgsql.parser.PostgreSqlParser;
+import io.aklivity.zilla.runtime.binding.pgsql.parser.PostgreSqlParserBaseListener;
+import io.aklivity.zilla.runtime.binding.pgsql.parser.model.StreamInfo;
+
+public class SqlCreateStreamListener extends PostgreSqlParserBaseListener
+{
+ private final Map columns = new LinkedHashMap<>();
+ private final TokenStream tokens;
+
+ private String name;
+
+ public SqlCreateStreamListener(
+ TokenStream tokens)
+ {
+ this.tokens = tokens;
+ }
+
+ public StreamInfo streamInfo()
+ {
+ return new StreamInfo(name, columns);
+ }
+
+ @Override
+ public void enterRoot(
+ PostgreSqlParser.RootContext ctx)
+ {
+ name = null;
+ columns.clear();
+ }
+
+ @Override
+ public void enterQualified_name(
+ PostgreSqlParser.Qualified_nameContext ctx)
+ {
+ name = ctx.getText();
+ }
+
+ @Override
+ public void enterCreatestreamstmt(
+ PostgreSqlParser.CreatestreamstmtContext ctx)
+ {
+ if (ctx.stream_columns() != null)
+ {
+ for (PostgreSqlParser.Stream_columnContext streamElement : ctx.stream_columns().stream_column())
+ {
+ String columnName = streamElement.colid().getText();
+ String dataType = tokens.getText(streamElement.typename());
+ columns.put(columnName, dataType);
+ }
+ }
+ }
+}
diff --git a/incubator/binding-pgsql/src/main/java/io/aklivity/zilla/runtime/binding/pgsql/parser/listener/SqlCreateTableTopicListener.java b/incubator/binding-pgsql/src/main/java/io/aklivity/zilla/runtime/binding/pgsql/parser/listener/SqlCreateTableTopicListener.java
new file mode 100644
index 0000000000..9ec17a7243
--- /dev/null
+++ b/incubator/binding-pgsql/src/main/java/io/aklivity/zilla/runtime/binding/pgsql/parser/listener/SqlCreateTableTopicListener.java
@@ -0,0 +1,99 @@
+/*
+ * Copyright 2021-2023 Aklivity Inc
+ *
+ * Licensed under the Aklivity Community License (the "License"); you may not use
+ * this file except in compliance with the License. You may obtain a copy of the
+ * License at
+ *
+ * https://www.aklivity.io/aklivity-community-license/
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OF ANY KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations under the License.
+ */
+package io.aklivity.zilla.runtime.binding.pgsql.parser.listener;
+
+import java.util.LinkedHashMap;
+import java.util.Map;
+import java.util.Set;
+
+import org.agrona.collections.ObjectHashSet;
+import org.antlr.v4.runtime.TokenStream;
+
+import io.aklivity.zilla.runtime.binding.pgsql.parser.PostgreSqlParser;
+import io.aklivity.zilla.runtime.binding.pgsql.parser.PostgreSqlParserBaseListener;
+import io.aklivity.zilla.runtime.binding.pgsql.parser.model.TableInfo;
+
+public class SqlCreateTableTopicListener extends PostgreSqlParserBaseListener
+{
+ private final Map columns = new LinkedHashMap<>();
+ private final Set primaryKeys = new ObjectHashSet<>();
+ private final TokenStream tokens;
+
+ private String name;
+
+ public SqlCreateTableTopicListener(
+ TokenStream tokens)
+ {
+ this.tokens = tokens;
+ }
+
+ public TableInfo tableInfo()
+ {
+ return new TableInfo(name, columns, primaryKeys);
+ }
+
+ @Override
+ public void enterRoot(
+ PostgreSqlParser.RootContext ctx)
+ {
+ name = null;
+ columns.clear();
+ primaryKeys.clear();
+ }
+
+ @Override
+ public void enterQualified_name(
+ PostgreSqlParser.Qualified_nameContext ctx)
+ {
+ name = ctx.getText();
+ }
+
+ @Override
+ public void enterCreatestmt(
+ PostgreSqlParser.CreatestmtContext ctx)
+ {
+ if (ctx.opttableelementlist().tableelementlist() != null)
+ {
+ for (PostgreSqlParser.TableelementContext tableElement : ctx.opttableelementlist().tableelementlist().tableelement())
+ {
+ if (tableElement.columnDef() != null)
+ {
+ String columnName = tableElement.columnDef().colid().getText();
+ String dataType = tokens.getText(tableElement.columnDef().typename());
+ columns.put(columnName, dataType);
+
+ for (PostgreSqlParser.ColconstraintContext constraint :
+ tableElement.columnDef().colquallist().colconstraint())
+ {
+ if (constraint.colconstraintelem().PRIMARY() != null &&
+ constraint.colconstraintelem().KEY() != null)
+ {
+ primaryKeys.add(columnName);
+ }
+ }
+ }
+ else if (tableElement.tableconstraint() != null)
+ {
+ if (tableElement.tableconstraint().constraintelem().PRIMARY() != null &&
+ tableElement.tableconstraint().constraintelem().KEY() != null)
+ {
+ tableElement.tableconstraint().constraintelem().columnlist().columnElem().forEach(
+ column -> primaryKeys.add(column.getText()));
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/incubator/binding-pgsql/src/main/java/io/aklivity/zilla/runtime/binding/pgsql/parser/listener/SqlDropListener.java b/incubator/binding-pgsql/src/main/java/io/aklivity/zilla/runtime/binding/pgsql/parser/listener/SqlDropListener.java
new file mode 100644
index 0000000000..a7fecb380f
--- /dev/null
+++ b/incubator/binding-pgsql/src/main/java/io/aklivity/zilla/runtime/binding/pgsql/parser/listener/SqlDropListener.java
@@ -0,0 +1,45 @@
+/*
+ * Copyright 2021-2023 Aklivity Inc
+ *
+ * Licensed under the Aklivity Community License (the "License"); you may not use
+ * this file except in compliance with the License. You may obtain a copy of the
+ * License at
+ *
+ * https://www.aklivity.io/aklivity-community-license/
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OF ANY KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations under the License.
+ */
+package io.aklivity.zilla.runtime.binding.pgsql.parser.listener;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import io.aklivity.zilla.runtime.binding.pgsql.parser.PostgreSqlParser;
+import io.aklivity.zilla.runtime.binding.pgsql.parser.PostgreSqlParserBaseListener;
+
+public class SqlDropListener extends PostgreSqlParserBaseListener
+{
+ private final List drops = new ArrayList<>();
+
+ public List drops()
+ {
+ return drops;
+ }
+
+ @Override
+ public void enterRoot(
+ PostgreSqlParser.RootContext ctx)
+ {
+ drops.clear();
+ }
+
+ @Override
+ public void enterDropstmt(
+ PostgreSqlParser.DropstmtContext ctx)
+ {
+ ctx.any_name_list().any_name().forEach(name -> drops.add(name.getText()));
+ }
+}
diff --git a/incubator/binding-pgsql/src/main/java/io/aklivity/zilla/runtime/binding/pgsql/parser/model/FunctionArgument.java b/incubator/binding-pgsql/src/main/java/io/aklivity/zilla/runtime/binding/pgsql/parser/model/FunctionArgument.java
new file mode 100644
index 0000000000..91f04b17f4
--- /dev/null
+++ b/incubator/binding-pgsql/src/main/java/io/aklivity/zilla/runtime/binding/pgsql/parser/model/FunctionArgument.java
@@ -0,0 +1,21 @@
+/*
+ * Copyright 2021-2023 Aklivity Inc
+ *
+ * Licensed under the Aklivity Community License (the "License"); you may not use
+ * this file except in compliance with the License. You may obtain a copy of the
+ * License at
+ *
+ * https://www.aklivity.io/aklivity-community-license/
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OF ANY KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations under the License.
+ */
+package io.aklivity.zilla.runtime.binding.pgsql.parser.model;
+
+public record FunctionArgument(
+ String name,
+ String type)
+{
+}
diff --git a/incubator/binding-pgsql/src/main/java/io/aklivity/zilla/runtime/binding/pgsql/parser/model/FunctionInfo.java b/incubator/binding-pgsql/src/main/java/io/aklivity/zilla/runtime/binding/pgsql/parser/model/FunctionInfo.java
new file mode 100644
index 0000000000..f41b7939de
--- /dev/null
+++ b/incubator/binding-pgsql/src/main/java/io/aklivity/zilla/runtime/binding/pgsql/parser/model/FunctionInfo.java
@@ -0,0 +1,27 @@
+/*
+ * Copyright 2021-2023 Aklivity Inc
+ *
+ * Licensed under the Aklivity Community License (the "License"); you may not use
+ * this file except in compliance with the License. You may obtain a copy of the
+ * License at
+ *
+ * https://www.aklivity.io/aklivity-community-license/
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OF ANY KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations under the License.
+ */
+package io.aklivity.zilla.runtime.binding.pgsql.parser.model;
+
+import java.util.List;
+
+public record FunctionInfo(
+ String name,
+ List arguments,
+ String returnType,
+ List tables,
+ String asFunction,
+ String language)
+{
+}
diff --git a/incubator/binding-risingwave/src/main/java/io/aklivity/zilla/runtime/binding/risingwave/internal/statement/RisingwaveCreateTableCommand.java b/incubator/binding-pgsql/src/main/java/io/aklivity/zilla/runtime/binding/pgsql/parser/model/StreamInfo.java
similarity index 56%
rename from incubator/binding-risingwave/src/main/java/io/aklivity/zilla/runtime/binding/risingwave/internal/statement/RisingwaveCreateTableCommand.java
rename to incubator/binding-pgsql/src/main/java/io/aklivity/zilla/runtime/binding/pgsql/parser/model/StreamInfo.java
index 02c14773b0..a666131e4f 100644
--- a/incubator/binding-risingwave/src/main/java/io/aklivity/zilla/runtime/binding/risingwave/internal/statement/RisingwaveCreateTableCommand.java
+++ b/incubator/binding-pgsql/src/main/java/io/aklivity/zilla/runtime/binding/pgsql/parser/model/StreamInfo.java
@@ -12,22 +12,12 @@
* WARRANTIES OF ANY KIND, either express or implied. See the License for the
* specific language governing permissions and limitations under the License.
*/
-package io.aklivity.zilla.runtime.binding.risingwave.internal.statement;
+package io.aklivity.zilla.runtime.binding.pgsql.parser.model;
import java.util.Map;
-import net.sf.jsqlparser.statement.create.table.CreateTable;
-
-public final class RisingwaveCreateTableCommand
+public record StreamInfo(
+ String name,
+ Map columns)
{
- public final CreateTable createTable;
- public final Map includes;
-
- public RisingwaveCreateTableCommand(
- CreateTable createTable,
- Map includes)
- {
- this.createTable = createTable;
- this.includes = includes;
- }
}
diff --git a/incubator/binding-pgsql/src/main/java/io/aklivity/zilla/runtime/binding/pgsql/parser/model/TableInfo.java b/incubator/binding-pgsql/src/main/java/io/aklivity/zilla/runtime/binding/pgsql/parser/model/TableInfo.java
new file mode 100644
index 0000000000..2f1b3e272b
--- /dev/null
+++ b/incubator/binding-pgsql/src/main/java/io/aklivity/zilla/runtime/binding/pgsql/parser/model/TableInfo.java
@@ -0,0 +1,25 @@
+/*
+ * Copyright 2021-2023 Aklivity Inc
+ *
+ * Licensed under the Aklivity Community License (the "License"); you may not use
+ * this file except in compliance with the License. You may obtain a copy of the
+ * License at
+ *
+ * https://www.aklivity.io/aklivity-community-license/
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OF ANY KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations under the License.
+ */
+package io.aklivity.zilla.runtime.binding.pgsql.parser.model;
+
+import java.util.Map;
+import java.util.Set;
+
+public record TableInfo(
+ String name,
+ Map columns,
+ Set primaryKeys)
+{
+}
diff --git a/incubator/binding-pgsql/src/main/java/io/aklivity/zilla/runtime/binding/pgsql/parser/model/ViewInfo.java b/incubator/binding-pgsql/src/main/java/io/aklivity/zilla/runtime/binding/pgsql/parser/model/ViewInfo.java
new file mode 100644
index 0000000000..2f6f43e280
--- /dev/null
+++ b/incubator/binding-pgsql/src/main/java/io/aklivity/zilla/runtime/binding/pgsql/parser/model/ViewInfo.java
@@ -0,0 +1,21 @@
+/*
+ * Copyright 2021-2023 Aklivity Inc
+ *
+ * Licensed under the Aklivity Community License (the "License"); you may not use
+ * this file except in compliance with the License. You may obtain a copy of the
+ * License at
+ *
+ * https://www.aklivity.io/aklivity-community-license/
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OF ANY KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations under the License.
+ */
+package io.aklivity.zilla.runtime.binding.pgsql.parser.model;
+
+public record ViewInfo(
+ String name,
+ String select)
+{
+}
diff --git a/incubator/binding-pgsql/src/main/moditect/module-info.java b/incubator/binding-pgsql/src/main/moditect/module-info.java
index 3868d46eb3..b8ee14bb35 100644
--- a/incubator/binding-pgsql/src/main/moditect/module-info.java
+++ b/incubator/binding-pgsql/src/main/moditect/module-info.java
@@ -15,6 +15,11 @@
module io.aklivity.zilla.runtime.binding.pgsql
{
requires io.aklivity.zilla.runtime.engine;
+ requires org.antlr.antlr4.runtime;
+
+ exports io.aklivity.zilla.runtime.binding.pgsql.parser;
+ exports io.aklivity.zilla.runtime.binding.pgsql.parser.listener;
+ exports io.aklivity.zilla.runtime.binding.pgsql.parser.model;
provides io.aklivity.zilla.runtime.engine.binding.BindingFactorySpi
with io.aklivity.zilla.runtime.binding.pgsql.internal.PgsqlBindingFactorySpi;
diff --git a/incubator/binding-pgsql/src/test/java/io/aklivity/zilla/runtime/binding/pgsql/parser/PgsqlParserTest.java b/incubator/binding-pgsql/src/test/java/io/aklivity/zilla/runtime/binding/pgsql/parser/PgsqlParserTest.java
new file mode 100644
index 0000000000..201977e28f
--- /dev/null
+++ b/incubator/binding-pgsql/src/test/java/io/aklivity/zilla/runtime/binding/pgsql/parser/PgsqlParserTest.java
@@ -0,0 +1,356 @@
+/*
+ * Copyright 2021-2023 Aklivity Inc
+ *
+ * Licensed under the Aklivity Community License (the "License"); you may not use
+ * this file except in compliance with the License. You may obtain a copy of the
+ * License at
+ *
+ * https://www.aklivity.io/aklivity-community-license/
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OF ANY KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations under the License.
+ */
+package io.aklivity.zilla.runtime.binding.pgsql.parser;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+import java.util.List;
+
+import org.antlr.v4.runtime.misc.ParseCancellationException;
+import org.junit.Before;
+import org.junit.Test;
+
+import io.aklivity.zilla.runtime.binding.pgsql.parser.model.FunctionInfo;
+import io.aklivity.zilla.runtime.binding.pgsql.parser.model.StreamInfo;
+import io.aklivity.zilla.runtime.binding.pgsql.parser.model.TableInfo;
+import io.aklivity.zilla.runtime.binding.pgsql.parser.model.ViewInfo;
+
+public class PgsqlParserTest
+{
+ private PgsqlParser parser;
+
+ @Before
+ public void setUp()
+ {
+ parser = new PgsqlParser();
+ }
+
+ @Test
+ public void shouldParseWithPrimaryKeySql()
+ {
+ String sql = "CREATE TABLE test (id INT PRIMARY KEY, name VARCHAR(100));";
+ TableInfo tableInfo = parser.parseCreateTable(sql);
+ assertNotNull(tableInfo);
+ assertTrue(tableInfo.primaryKeys().contains("id"));
+ }
+
+ @Test
+ public void shouldCreateParseWithPrimaryKeysSql()
+ {
+ String sql = """
+ CREATE TABLE example_table (
+ id INT PRIMARY KEY,
+ name VARCHAR(100),
+ age INT,
+ PRIMARY KEY (id, name)
+ );""";
+ TableInfo tableInfo = parser.parseCreateTable(sql);
+ assertNotNull(tableInfo);
+ assertEquals(2, tableInfo.primaryKeys().size());
+ assertEquals(3, tableInfo.columns().size());
+ assertTrue(tableInfo.primaryKeys().contains("id"));
+ assertTrue(tableInfo.primaryKeys().contains("name"));
+ }
+
+ @Test
+ public void shouldParseCreateTableName()
+ {
+ String sql = "CREATE TABLE test (id INT);";
+ TableInfo tableInfo = parser.parseCreateTable(sql);
+ assertEquals("test", tableInfo.name());
+ }
+
+ @Test
+ public void shouldParseCreateTableNameWithDoublePrecisionTypeField()
+ {
+ String sql = "CREATE TABLE test (id DOUBLE PRECISION);";
+ TableInfo tableInfo = parser.parseCreateTable(sql);
+ assertEquals("test", tableInfo.name());
+ assertEquals("DOUBLE PRECISION", tableInfo.columns().get("id"));
+ }
+
+ @Test
+ public void shouldParseCreateTableColumns()
+ {
+ String sql = "CREATE TABLE test (id INT, name VARCHAR(100));";
+ TableInfo tableInfo = parser.parseCreateTable(sql);
+ assertEquals(2, tableInfo.columns().size());
+ assertEquals("INT", tableInfo.columns().get("id"));
+ assertEquals("VARCHAR(100)", tableInfo.columns().get("name"));
+ }
+
+ @Test
+ public void shouldParseCreatreTablePrimaryKey()
+ {
+ String sql = "CREATE TABLE test (id INT PRIMARY KEY, name VARCHAR(100));";
+ TableInfo tableInfo = parser.parseCreateTable(sql);
+ assertEquals(1, tableInfo.primaryKeys().size());
+ assertTrue(tableInfo.primaryKeys().contains("id"));
+ }
+
+ @Test
+ public void shouldParseCreateTableCompositePrimaryKey()
+ {
+ String sql = "CREATE TABLE test (id INT, name VARCHAR(100), PRIMARY KEY (id, name));";
+ TableInfo tableInfo = parser.parseCreateTable(sql);
+ assertEquals(2, tableInfo.primaryKeys().size());
+ assertTrue(tableInfo.primaryKeys().contains("id"));
+ assertTrue(tableInfo.primaryKeys().contains("name"));
+ }
+
+ @Test
+ public void shouldHandleEmptyCreateTable()
+ {
+ String sql = "CREATE TABLE test ();";
+ TableInfo tableInfo = parser.parseCreateTable(sql);
+ assertEquals(0, tableInfo.columns().size());
+ assertEquals(0, tableInfo.primaryKeys().size());
+ }
+
+ @Test
+ public void shouldHandleEmptySql()
+ {
+ String sql = "";
+ TableInfo tableInfo = parser.parseCreateTable(sql);
+ assertNotNull(tableInfo);
+ }
+
+ @Test
+ public void shouldParseCreateMaterializedView()
+ {
+ String sql = "CREATE MATERIALIZED VIEW test_view AS SELECT * FROM test_table;";
+ ViewInfo viewInfo = parser.parseCreateMaterializedView(sql);
+ assertNotNull(viewInfo);
+ assertEquals("test_view", viewInfo.name());
+ assertEquals("SELECT * FROM test_table", viewInfo.select());
+ }
+
+ @Test(expected = ParseCancellationException.class)
+ public void shouldHandleEmptyCreateMaterializedView()
+ {
+ String sql = "CREATE MATERIALIZED VIEW test_view AS ;";
+ ViewInfo viewInfo = parser.parseCreateMaterializedView(sql);
+ assertNotNull(viewInfo);
+ assertEquals("test_view", viewInfo.name());
+ }
+
+ @Test(expected = ParseCancellationException.class)
+ public void shouldHandleInvalidCreateMaterializedView()
+ {
+ String sql = "CREATE MATERIALIZED VIEW test_view";
+ parser.parseCreateMaterializedView(sql);
+ }
+
+ @Test(expected = ParseCancellationException.class)
+ public void shouldHandleInvalidCreateTable()
+ {
+ String sql = "CREATE TABLE test";
+ parser.parseCreateTable(sql);
+ }
+
+ @Test
+ public void shouldParseDropSingleTable()
+ {
+ String sql = "DROP TABLE test_table;";
+ List drops = parser.parseDrop(sql);
+ assertEquals(1, drops.size());
+ assertTrue(drops.contains("test_table"));
+ }
+
+ @Test
+ public void shouldParseDropMultipleTables()
+ {
+ String sql = "DROP TABLE table1, table2;";
+ List drops = parser.parseDrop(sql);
+ assertEquals(2, drops.size());
+ assertTrue(drops.contains("table1"));
+ assertTrue(drops.contains("table2"));
+ }
+
+ @Test(expected = ParseCancellationException.class)
+ public void shouldHandleEmptyDropStatement()
+ {
+ String sql = "DROP TABLE;";
+ List drops = parser.parseDrop(sql);
+ assertEquals(0, drops.size());
+ }
+
+ @Test
+ public void shouldParseDropView()
+ {
+ String sql = "DROP VIEW test_view;";
+ List drops = parser.parseDrop(sql);
+ assertEquals(1, drops.size());
+ assertTrue(drops.contains("test_view"));
+ }
+
+ @Test
+ public void shouldParseDropMaterializedView()
+ {
+ String sql = "DROP MATERIALIZED VIEW test_materialized_view;";
+ List drops = parser.parseDrop(sql);
+ assertEquals(1, drops.size());
+ assertTrue(drops.contains("test_materialized_view"));
+ }
+
+ @Test
+ public void shouldParseCreateStream()
+ {
+ String sql = "CREATE STREAM test_stream (id INT, name VARCHAR(100));";
+ StreamInfo streamInfo = parser.parseCreateStream(sql);
+ assertNotNull(streamInfo);
+ assertEquals("test_stream", streamInfo.name());
+ assertEquals(2, streamInfo.columns().size());
+ assertEquals("INT", streamInfo.columns().get("id"));
+ assertEquals("VARCHAR(100)", streamInfo.columns().get("name"));
+ }
+
+ @Test
+ public void shouldParseCreateStreamIfNotExists()
+ {
+ String sql = "CREATE STREAM IF NOT EXISTS test_stream (id INT, name VARCHAR(100));";
+ StreamInfo streamInfo = parser.parseCreateStream(sql);
+ assertNotNull(streamInfo);
+ assertEquals("test_stream", streamInfo.name());
+ assertEquals(2, streamInfo.columns().size());
+ assertEquals("INT", streamInfo.columns().get("id"));
+ assertEquals("VARCHAR(100)", streamInfo.columns().get("name"));
+ }
+
+ @Test(expected = ParseCancellationException.class)
+ public void shouldHandleInvalidCreateStream()
+ {
+ String sql = "CREATE STREAM test_stream";
+ parser.parseCreateStream(sql);
+ }
+
+ @Test
+ public void shouldParseCreateFunction()
+ {
+ String sql = "CREATE FUNCTION test_function() RETURNS INT AS $$ BEGIN RETURN 1; END $$ LANGUAGE plpgsql;";
+ FunctionInfo functionInfo = parser.parseCreateFunction(sql);
+ assertNotNull(functionInfo);
+ assertEquals("test_function", functionInfo.name());
+ assertEquals("INT", functionInfo.returnType());
+ }
+
+ @Test
+ public void shouldParseCreateFunctionWithLanguage()
+ {
+ String sql = "CREATE FUNCTION test_function(int) RETURNS TABLE (x INT) LANGUAGE python AS 'test_function';";
+ FunctionInfo functionInfo = parser.parseCreateFunction(sql);
+ assertNotNull(functionInfo);
+ assertEquals("test_function", functionInfo.name());
+ assertEquals("INT", functionInfo.returnType());
+ assertEquals("python", functionInfo.language());
+ }
+
+ @Test
+ public void shouldParseCreateFunctionWithStructReturnType()
+ {
+ String sql = "CREATE FUNCTION test_function(int) RETURNS struct" +
+ " LANGUAGE python AS 'test_function';";
+ FunctionInfo functionInfo = parser.parseCreateFunction(sql);
+ assertNotNull(functionInfo);
+ assertEquals("test_function", functionInfo.name());
+ assertEquals("struct", functionInfo.returnType());
+ assertEquals("python", functionInfo.language());
+ }
+
+ @Test(expected = ParseCancellationException.class)
+ public void shouldHandleInvalidCreateFunction()
+ {
+ String sql = "CREATE FUNCTION test_function()";
+ parser.parseCreateFunction(sql);
+ }
+
+ @Test
+ public void shouldParseCreateTableWithUniqueConstraint()
+ {
+ String sql = "CREATE TABLE test (id INT UNIQUE, name VARCHAR(100));";
+ TableInfo tableInfo = parser.parseCreateTable(sql);
+ assertNotNull(tableInfo);
+ assertEquals(2, tableInfo.columns().size());
+ assertTrue(tableInfo.columns().containsKey("id"));
+ assertTrue(tableInfo.columns().containsKey("name"));
+ }
+
+ @Test
+ public void shouldParseCreateTableWithForeignKey()
+ {
+ String sql = "CREATE TABLE test (id INT, name VARCHAR(100), CONSTRAINT fk_name FOREIGN KEY (name)" +
+ " REFERENCES other_table(name));";
+ TableInfo tableInfo = parser.parseCreateTable(sql);
+ assertNotNull(tableInfo);
+ assertEquals(2, tableInfo.columns().size());
+ assertTrue(tableInfo.columns().containsKey("id"));
+ assertTrue(tableInfo.columns().containsKey("name"));
+ }
+
+ @Test
+ public void shouldParseCreateTableWithCheckConstraint()
+ {
+ String sql = "CREATE TABLE test (id INT, name VARCHAR(100), CHECK (id > 0));";
+ TableInfo tableInfo = parser.parseCreateTable(sql);
+ assertNotNull(tableInfo);
+ assertEquals(2, tableInfo.columns().size());
+ assertTrue(tableInfo.columns().containsKey("id"));
+ assertTrue(tableInfo.columns().containsKey("name"));
+ }
+
+ @Test
+ public void shouldHandleInvalidCreateTableWithMissingColumns()
+ {
+ String sql = "CREATE TABLE test ();";
+ parser.parseCreateTable(sql);
+ }
+
+ @Test
+ public void shouldParseCreateTableWithDefaultValues()
+ {
+ String sql = "CREATE TABLE test (id INT DEFAULT 0, name VARCHAR(100) DEFAULT 'unknown');";
+ TableInfo tableInfo = parser.parseCreateTable(sql);
+ assertNotNull(tableInfo);
+ assertEquals(2, tableInfo.columns().size());
+ assertEquals("INT", tableInfo.columns().get("id"));
+ assertEquals("VARCHAR(100)", tableInfo.columns().get("name"));
+ }
+
+ @Test
+ public void shouldParseCreateTableWithNotNullConstraint()
+ {
+ String sql = "CREATE TABLE test (id INT NOT NULL, name VARCHAR(100) NOT NULL);";
+ TableInfo tableInfo = parser.parseCreateTable(sql);
+ assertNotNull(tableInfo);
+ assertEquals(2, tableInfo.columns().size());
+ assertTrue(tableInfo.columns().containsKey("id"));
+ assertTrue(tableInfo.columns().containsKey("name"));
+ }
+
+ @Test
+ public void shouldParseCreateTableWithMultipleConstraints()
+ {
+ String sql = "CREATE TABLE test (id INT PRIMARY KEY, name VARCHAR(100) UNIQUE, age INT CHECK (age > 0));";
+ TableInfo tableInfo = parser.parseCreateTable(sql);
+ assertNotNull(tableInfo);
+ assertEquals(3, tableInfo.columns().size());
+ assertTrue(tableInfo.primaryKeys().contains("id"));
+ assertTrue(tableInfo.columns().containsKey("name"));
+ assertTrue(tableInfo.columns().containsKey("age"));
+ }
+
+}
diff --git a/incubator/binding-risingwave.spec/src/main/scripts/io/aklivity/zilla/specs/binding/risingwave/streams/effective/create.function.python/client.rpt b/incubator/binding-risingwave.spec/src/main/scripts/io/aklivity/zilla/specs/binding/risingwave/streams/effective/create.function.python/client.rpt
index 33ee75c8cb..9612e522fa 100644
--- a/incubator/binding-risingwave.spec/src/main/scripts/io/aklivity/zilla/specs/binding/risingwave/streams/effective/create.function.python/client.rpt
+++ b/incubator/binding-risingwave.spec/src/main/scripts/io/aklivity/zilla/specs/binding/risingwave/streams/effective/create.function.python/client.rpt
@@ -32,9 +32,9 @@ write zilla:data.ext ${pgsql:dataEx()
.query()
.build()
.build()}
-write "CREATE FUNCTION gcd(int , int)\n"
+write "CREATE FUNCTION gcd(int, int)\n"
"RETURNS int\n"
- "AS gcd\n"
+ "AS 'gcd'\n"
"LANGUAGE python\n"
"USING LINK 'http://localhost:8816';"
[0x00]
diff --git a/incubator/binding-risingwave.spec/src/main/scripts/io/aklivity/zilla/specs/binding/risingwave/streams/effective/create.function.python/server.rpt b/incubator/binding-risingwave.spec/src/main/scripts/io/aklivity/zilla/specs/binding/risingwave/streams/effective/create.function.python/server.rpt
index 7bda0b7335..538c98b141 100644
--- a/incubator/binding-risingwave.spec/src/main/scripts/io/aklivity/zilla/specs/binding/risingwave/streams/effective/create.function.python/server.rpt
+++ b/incubator/binding-risingwave.spec/src/main/scripts/io/aklivity/zilla/specs/binding/risingwave/streams/effective/create.function.python/server.rpt
@@ -34,9 +34,9 @@ read zilla:data.ext ${pgsql:dataEx()
.query()
.build()
.build()}
-read "CREATE FUNCTION gcd(int , int)\n"
+read "CREATE FUNCTION gcd(int, int)\n"
"RETURNS int\n"
- "AS gcd\n"
+ "AS 'gcd'\n"
"LANGUAGE python\n"
"USING LINK 'http://localhost:8816';"
[0x00]
diff --git a/incubator/binding-risingwave.spec/src/main/scripts/io/aklivity/zilla/specs/binding/risingwave/streams/effective/create.function.return.struct/client.rpt b/incubator/binding-risingwave.spec/src/main/scripts/io/aklivity/zilla/specs/binding/risingwave/streams/effective/create.function.return.struct/client.rpt
index 6c81524818..0a33a54114 100644
--- a/incubator/binding-risingwave.spec/src/main/scripts/io/aklivity/zilla/specs/binding/risingwave/streams/effective/create.function.return.struct/client.rpt
+++ b/incubator/binding-risingwave.spec/src/main/scripts/io/aklivity/zilla/specs/binding/risingwave/streams/effective/create.function.return.struct/client.rpt
@@ -33,8 +33,8 @@ write zilla:data.ext ${pgsql:dataEx()
.build()
.build()}
write "CREATE FUNCTION key_value(bytea)\n"
- "RETURNS struct < key varchar , value varchar >\n"
- "AS key_value\n"
+ "RETURNS struct\n"
+ "AS 'key_value'\n"
"LANGUAGE python\n"
"USING LINK 'http://localhost:8816';"
[0x00]
diff --git a/incubator/binding-risingwave.spec/src/main/scripts/io/aklivity/zilla/specs/binding/risingwave/streams/effective/create.function.return.struct/server.rpt b/incubator/binding-risingwave.spec/src/main/scripts/io/aklivity/zilla/specs/binding/risingwave/streams/effective/create.function.return.struct/server.rpt
index 23335bb651..cffa0b2496 100644
--- a/incubator/binding-risingwave.spec/src/main/scripts/io/aklivity/zilla/specs/binding/risingwave/streams/effective/create.function.return.struct/server.rpt
+++ b/incubator/binding-risingwave.spec/src/main/scripts/io/aklivity/zilla/specs/binding/risingwave/streams/effective/create.function.return.struct/server.rpt
@@ -35,8 +35,8 @@ read zilla:data.ext ${pgsql:dataEx()
.build()
.build()}
read "CREATE FUNCTION key_value(bytea)\n"
- "RETURNS struct < key varchar , value varchar >\n"
- "AS key_value\n"
+ "RETURNS struct\n"
+ "AS 'key_value'\n"
"LANGUAGE python\n"
"USING LINK 'http://localhost:8816';"
[0x00]
diff --git a/incubator/binding-risingwave.spec/src/main/scripts/io/aklivity/zilla/specs/binding/risingwave/streams/effective/create.function.return.table/client.rpt b/incubator/binding-risingwave.spec/src/main/scripts/io/aklivity/zilla/specs/binding/risingwave/streams/effective/create.function.return.table/client.rpt
index ebcab805e4..88160cdb0d 100644
--- a/incubator/binding-risingwave.spec/src/main/scripts/io/aklivity/zilla/specs/binding/risingwave/streams/effective/create.function.return.table/client.rpt
+++ b/incubator/binding-risingwave.spec/src/main/scripts/io/aklivity/zilla/specs/binding/risingwave/streams/effective/create.function.return.table/client.rpt
@@ -33,8 +33,8 @@ write zilla:data.ext ${pgsql:dataEx()
.build()
.build()}
write "CREATE FUNCTION series(int)\n"
- "RETURNS TABLE ( x int )\n"
- "AS series\n"
+ "RETURNS TABLE (x int)\n"
+ "AS 'series'\n"
"LANGUAGE java\n"
"USING LINK 'http://localhost:8815';"
[0x00]
diff --git a/incubator/binding-risingwave.spec/src/main/scripts/io/aklivity/zilla/specs/binding/risingwave/streams/effective/create.function.return.table/server.rpt b/incubator/binding-risingwave.spec/src/main/scripts/io/aklivity/zilla/specs/binding/risingwave/streams/effective/create.function.return.table/server.rpt
index ec7a49322a..f02bca873d 100644
--- a/incubator/binding-risingwave.spec/src/main/scripts/io/aklivity/zilla/specs/binding/risingwave/streams/effective/create.function.return.table/server.rpt
+++ b/incubator/binding-risingwave.spec/src/main/scripts/io/aklivity/zilla/specs/binding/risingwave/streams/effective/create.function.return.table/server.rpt
@@ -35,8 +35,8 @@ read zilla:data.ext ${pgsql:dataEx()
.build()
.build()}
read "CREATE FUNCTION series(int)\n"
- "RETURNS TABLE ( x int )\n"
- "AS series\n"
+ "RETURNS TABLE (x int)\n"
+ "AS 'series'\n"
"LANGUAGE java\n"
"USING LINK 'http://localhost:8815';"
[0x00]
diff --git a/incubator/binding-risingwave.spec/src/main/scripts/io/aklivity/zilla/specs/binding/risingwave/streams/effective/create.function/client.rpt b/incubator/binding-risingwave.spec/src/main/scripts/io/aklivity/zilla/specs/binding/risingwave/streams/effective/create.function/client.rpt
index 182d430247..1a9a69c6e0 100644
--- a/incubator/binding-risingwave.spec/src/main/scripts/io/aklivity/zilla/specs/binding/risingwave/streams/effective/create.function/client.rpt
+++ b/incubator/binding-risingwave.spec/src/main/scripts/io/aklivity/zilla/specs/binding/risingwave/streams/effective/create.function/client.rpt
@@ -32,9 +32,9 @@ write zilla:data.ext ${pgsql:dataEx()
.query()
.build()
.build()}
-write "CREATE FUNCTION gcd(int , int)\n"
+write "CREATE FUNCTION gcd(int, int)\n"
"RETURNS int\n"
- "AS gcd\n"
+ "AS 'gcd'\n"
"LANGUAGE java\n"
"USING LINK 'http://localhost:8815';"
[0x00]
diff --git a/incubator/binding-risingwave.spec/src/main/scripts/io/aklivity/zilla/specs/binding/risingwave/streams/effective/create.function/server.rpt b/incubator/binding-risingwave.spec/src/main/scripts/io/aklivity/zilla/specs/binding/risingwave/streams/effective/create.function/server.rpt
index 475e1d7c17..b925f5bcdd 100644
--- a/incubator/binding-risingwave.spec/src/main/scripts/io/aklivity/zilla/specs/binding/risingwave/streams/effective/create.function/server.rpt
+++ b/incubator/binding-risingwave.spec/src/main/scripts/io/aklivity/zilla/specs/binding/risingwave/streams/effective/create.function/server.rpt
@@ -34,9 +34,9 @@ read zilla:data.ext ${pgsql:dataEx()
.query()
.build()
.build()}
-read "CREATE FUNCTION gcd(int , int)\n"
+read "CREATE FUNCTION gcd(int, int)\n"
"RETURNS int\n"
- "AS gcd\n"
+ "AS 'gcd'\n"
"LANGUAGE java\n"
"USING LINK 'http://localhost:8815';"
[0x00]
diff --git a/incubator/binding-risingwave.spec/src/main/scripts/io/aklivity/zilla/specs/binding/risingwave/streams/effective/create.stream.with.includes/client.rpt b/incubator/binding-risingwave.spec/src/main/scripts/io/aklivity/zilla/specs/binding/risingwave/streams/effective/create.stream.with.includes/client.rpt
index 679a78508e..ca19a105fb 100644
--- a/incubator/binding-risingwave.spec/src/main/scripts/io/aklivity/zilla/specs/binding/risingwave/streams/effective/create.stream.with.includes/client.rpt
+++ b/incubator/binding-risingwave.spec/src/main/scripts/io/aklivity/zilla/specs/binding/risingwave/streams/effective/create.stream.with.includes/client.rpt
@@ -33,9 +33,9 @@ write zilla:data.ext ${pgsql:dataEx()
.build()
.build()}
write "CREATE SOURCE IF NOT EXISTS weather (*)\n"
- "INCLUDE header 'zilla:correlation-id' AS correlation_id\n"
- "INCLUDE header 'zilla:identity' AS identity\n"
- "INCLUDE timestamp AS timestamp\n"
+ "INCLUDE header 'zilla:correlation-id' AS zilla_correlation_id\n"
+ "INCLUDE header 'zilla:identity' AS zilla_identity\n"
+ "INCLUDE timestamp AS zilla_timestamp\n"
"WITH (\n"
" connector='kafka',\n"
" properties.bootstrap.server='localhost:9092',\n"
diff --git a/incubator/binding-risingwave.spec/src/main/scripts/io/aklivity/zilla/specs/binding/risingwave/streams/effective/create.stream.with.includes/server.rpt b/incubator/binding-risingwave.spec/src/main/scripts/io/aklivity/zilla/specs/binding/risingwave/streams/effective/create.stream.with.includes/server.rpt
index 9871eea900..cabb3d2999 100644
--- a/incubator/binding-risingwave.spec/src/main/scripts/io/aklivity/zilla/specs/binding/risingwave/streams/effective/create.stream.with.includes/server.rpt
+++ b/incubator/binding-risingwave.spec/src/main/scripts/io/aklivity/zilla/specs/binding/risingwave/streams/effective/create.stream.with.includes/server.rpt
@@ -37,9 +37,9 @@ read zilla:data.ext ${pgsql:dataEx()
.build()
.build()}
read "CREATE SOURCE IF NOT EXISTS weather (*)\n"
- "INCLUDE header 'zilla:correlation-id' AS correlation_id\n"
- "INCLUDE header 'zilla:identity' AS identity\n"
- "INCLUDE timestamp AS timestamp\n"
+ "INCLUDE header 'zilla:correlation-id' AS zilla_correlation_id\n"
+ "INCLUDE header 'zilla:identity' AS zilla_identity\n"
+ "INCLUDE timestamp AS zilla_timestamp\n"
"WITH (\n"
" connector='kafka',\n"
" properties.bootstrap.server='localhost:9092',\n"
diff --git a/incubator/binding-risingwave.spec/src/main/scripts/io/aklivity/zilla/specs/binding/risingwave/streams/effective/create.table.with.primary.key.and.includes/client.rpt b/incubator/binding-risingwave.spec/src/main/scripts/io/aklivity/zilla/specs/binding/risingwave/streams/effective/create.table.with.primary.key.and.includes/client.rpt
index 7c587a897b..f5775ad345 100644
--- a/incubator/binding-risingwave.spec/src/main/scripts/io/aklivity/zilla/specs/binding/risingwave/streams/effective/create.table.with.primary.key.and.includes/client.rpt
+++ b/incubator/binding-risingwave.spec/src/main/scripts/io/aklivity/zilla/specs/binding/risingwave/streams/effective/create.table.with.primary.key.and.includes/client.rpt
@@ -35,7 +35,7 @@ write zilla:data.ext ${pgsql:dataEx()
write "CREATE SOURCE IF NOT EXISTS cities_source (*)\n"
"INCLUDE header 'zilla:correlation-id' AS zilla_correlation_id_header\n"
"INCLUDE header 'zilla:identity' AS zilla_identity_header\n"
- "INCLUDE timestamp AS timestamp\n"
+ "INCLUDE timestamp AS zilla_timestamp_timestamp\n"
"WITH (\n"
" connector='kafka',\n"
" properties.bootstrap.server='localhost:9092',\n"
@@ -67,11 +67,11 @@ write zilla:data.ext ${pgsql:dataEx()
.query()
.build()
.build()}
-write "CREATE MATERIALIZED VIEW IF NOT EXISTS cities_view AS"
- " SELECT id, name, description,"
- " COALESCE(correlation_id, zilla_correlation_id_header::varchar) as correlation_id,"
- " COALESCE(identity, zilla_identity_header::varchar) as identity,"
- " timestamp"
+write "CREATE MATERIALIZED VIEW IF NOT EXISTS cities_view"
+ " AS SELECT id, name, description,"
+ " COALESCE(zilla_correlation_id, zilla_correlation_id_header::varchar) as zilla_correlation_id,"
+ " COALESCE(zilla_identity, zilla_identity_header::varchar) as zilla_identity,"
+ " COALESCE(zilla_timestamp, zilla_timestamp_timestamp::varchar) as zilla_timestamp"
" FROM cities_source;"
[0x00]
write flush
@@ -97,7 +97,7 @@ write zilla:data.ext ${pgsql:dataEx()
.build()}
write "CREATE TABLE IF NOT EXISTS cities"
" (id VARCHAR, name VARCHAR, description VARCHAR,"
- " correlation_id VARCHAR, identity VARCHAR, timestamp TIMESTAMP,"
+ " zilla_correlation_id VARCHAR, zilla_identity VARCHAR, zilla_timestamp TIMESTAMP,"
" PRIMARY KEY (id));"
[0x00]
write flush
@@ -192,7 +192,7 @@ write zilla:data.ext ${pgsql:dataEx()
.build()}
write "CREATE TOPIC IF NOT EXISTS cities "
"(id VARCHAR, name VARCHAR, description VARCHAR,"
- " correlation_id VARCHAR, identity VARCHAR, timestamp TIMESTAMP,"
+ " zilla_correlation_id VARCHAR, zilla_identity VARCHAR, zilla_timestamp TIMESTAMP,"
" PRIMARY KEY (id));"
[0x00]
write flush
diff --git a/incubator/binding-risingwave.spec/src/main/scripts/io/aklivity/zilla/specs/binding/risingwave/streams/effective/create.table.with.primary.key.and.includes/server.rpt b/incubator/binding-risingwave.spec/src/main/scripts/io/aklivity/zilla/specs/binding/risingwave/streams/effective/create.table.with.primary.key.and.includes/server.rpt
index 4bc34b76a3..48be7e8fd1 100644
--- a/incubator/binding-risingwave.spec/src/main/scripts/io/aklivity/zilla/specs/binding/risingwave/streams/effective/create.table.with.primary.key.and.includes/server.rpt
+++ b/incubator/binding-risingwave.spec/src/main/scripts/io/aklivity/zilla/specs/binding/risingwave/streams/effective/create.table.with.primary.key.and.includes/server.rpt
@@ -39,7 +39,7 @@ read zilla:data.ext ${pgsql:dataEx()
read "CREATE SOURCE IF NOT EXISTS cities_source (*)\n"
"INCLUDE header 'zilla:correlation-id' AS zilla_correlation_id_header\n"
"INCLUDE header 'zilla:identity' AS zilla_identity_header\n"
- "INCLUDE timestamp AS timestamp\n"
+ "INCLUDE timestamp AS zilla_timestamp_timestamp\n"
"WITH (\n"
" connector='kafka',\n"
" properties.bootstrap.server='localhost:9092',\n"
@@ -70,11 +70,11 @@ read zilla:data.ext ${pgsql:dataEx()
.query()
.build()
.build()}
-read "CREATE MATERIALIZED VIEW IF NOT EXISTS cities_view AS"
- " SELECT id, name, description,"
- " COALESCE(correlation_id, zilla_correlation_id_header::varchar) as correlation_id,"
- " COALESCE(identity, zilla_identity_header::varchar) as identity,"
- " timestamp"
+read "CREATE MATERIALIZED VIEW IF NOT EXISTS cities_view"
+ " AS SELECT id, name, description,"
+ " COALESCE(zilla_correlation_id, zilla_correlation_id_header::varchar) as zilla_correlation_id,"
+ " COALESCE(zilla_identity, zilla_identity_header::varchar) as zilla_identity,"
+ " COALESCE(zilla_timestamp, zilla_timestamp_timestamp::varchar) as zilla_timestamp"
" FROM cities_source;"
[0x00]
@@ -99,7 +99,7 @@ read zilla:data.ext ${pgsql:dataEx()
.build()}
read "CREATE TABLE IF NOT EXISTS cities"
" (id VARCHAR, name VARCHAR, description VARCHAR,"
- " correlation_id VARCHAR, identity VARCHAR, timestamp TIMESTAMP,"
+ " zilla_correlation_id VARCHAR, zilla_identity VARCHAR, zilla_timestamp TIMESTAMP,"
" PRIMARY KEY (id));"
[0x00]
@@ -193,7 +193,7 @@ read zilla:data.ext ${pgsql:dataEx()
.build()}
read "CREATE TOPIC IF NOT EXISTS cities "
"(id VARCHAR, name VARCHAR, description VARCHAR,"
- " correlation_id VARCHAR, identity VARCHAR, timestamp TIMESTAMP,"
+ " zilla_correlation_id VARCHAR, zilla_identity VARCHAR, zilla_timestamp TIMESTAMP,"
" PRIMARY KEY (id));"
[0x00]
diff --git a/incubator/binding-risingwave.spec/src/main/scripts/io/aklivity/zilla/specs/binding/risingwave/streams/pgsql/create.function.python/client.rpt b/incubator/binding-risingwave.spec/src/main/scripts/io/aklivity/zilla/specs/binding/risingwave/streams/pgsql/create.function.python/client.rpt
index 340e999227..93bfa33205 100644
--- a/incubator/binding-risingwave.spec/src/main/scripts/io/aklivity/zilla/specs/binding/risingwave/streams/pgsql/create.function.python/client.rpt
+++ b/incubator/binding-risingwave.spec/src/main/scripts/io/aklivity/zilla/specs/binding/risingwave/streams/pgsql/create.function.python/client.rpt
@@ -33,7 +33,7 @@ write zilla:data.ext ${pgsql:dataEx()
.build()
.build()}
write "CREATE FUNCTION gcd(int, int) RETURNS int "
- "LANGUAGE python AS gcd;"
+ "LANGUAGE python AS 'gcd';"
[0x00]
write flush
diff --git a/incubator/binding-risingwave.spec/src/main/scripts/io/aklivity/zilla/specs/binding/risingwave/streams/pgsql/create.function.python/server.rpt b/incubator/binding-risingwave.spec/src/main/scripts/io/aklivity/zilla/specs/binding/risingwave/streams/pgsql/create.function.python/server.rpt
index 20e83d8382..0170ffc27a 100644
--- a/incubator/binding-risingwave.spec/src/main/scripts/io/aklivity/zilla/specs/binding/risingwave/streams/pgsql/create.function.python/server.rpt
+++ b/incubator/binding-risingwave.spec/src/main/scripts/io/aklivity/zilla/specs/binding/risingwave/streams/pgsql/create.function.python/server.rpt
@@ -37,7 +37,7 @@ read zilla:data.ext ${pgsql:dataEx()
.build()
.build()}
read "CREATE FUNCTION gcd(int, int) RETURNS int "
- "LANGUAGE python AS gcd;"
+ "LANGUAGE python AS 'gcd';"
[0x00]
write advise zilla:flush ${pgsql:flushEx()
diff --git a/incubator/binding-risingwave.spec/src/main/scripts/io/aklivity/zilla/specs/binding/risingwave/streams/pgsql/create.function.return.struct/client.rpt b/incubator/binding-risingwave.spec/src/main/scripts/io/aklivity/zilla/specs/binding/risingwave/streams/pgsql/create.function.return.struct/client.rpt
index bf1030e822..7b03821097 100644
--- a/incubator/binding-risingwave.spec/src/main/scripts/io/aklivity/zilla/specs/binding/risingwave/streams/pgsql/create.function.return.struct/client.rpt
+++ b/incubator/binding-risingwave.spec/src/main/scripts/io/aklivity/zilla/specs/binding/risingwave/streams/pgsql/create.function.return.struct/client.rpt
@@ -33,7 +33,7 @@ write zilla:data.ext ${pgsql:dataEx()
.build()
.build()}
write "CREATE FUNCTION key_value(bytea) RETURNS struct "
- "LANGUAGE python AS key_value;"
+ "LANGUAGE python AS 'key_value';"
[0x00]
write flush
diff --git a/incubator/binding-risingwave.spec/src/main/scripts/io/aklivity/zilla/specs/binding/risingwave/streams/pgsql/create.function.return.struct/server.rpt b/incubator/binding-risingwave.spec/src/main/scripts/io/aklivity/zilla/specs/binding/risingwave/streams/pgsql/create.function.return.struct/server.rpt
index 05a9d55584..dddbbe6eee 100644
--- a/incubator/binding-risingwave.spec/src/main/scripts/io/aklivity/zilla/specs/binding/risingwave/streams/pgsql/create.function.return.struct/server.rpt
+++ b/incubator/binding-risingwave.spec/src/main/scripts/io/aklivity/zilla/specs/binding/risingwave/streams/pgsql/create.function.return.struct/server.rpt
@@ -37,7 +37,7 @@ read zilla:data.ext ${pgsql:dataEx()
.build()
.build()}
read "CREATE FUNCTION key_value(bytea) RETURNS struct "
- "LANGUAGE python AS key_value;"
+ "LANGUAGE python AS 'key_value';"
[0x00]
write advise zilla:flush ${pgsql:flushEx()
diff --git a/incubator/binding-risingwave.spec/src/main/scripts/io/aklivity/zilla/specs/binding/risingwave/streams/pgsql/create.function.return.table/client.rpt b/incubator/binding-risingwave.spec/src/main/scripts/io/aklivity/zilla/specs/binding/risingwave/streams/pgsql/create.function.return.table/client.rpt
index 8f7384ab62..e8599cdbf5 100644
--- a/incubator/binding-risingwave.spec/src/main/scripts/io/aklivity/zilla/specs/binding/risingwave/streams/pgsql/create.function.return.table/client.rpt
+++ b/incubator/binding-risingwave.spec/src/main/scripts/io/aklivity/zilla/specs/binding/risingwave/streams/pgsql/create.function.return.table/client.rpt
@@ -33,7 +33,7 @@ write zilla:data.ext ${pgsql:dataEx()
.build()
.build()}
write "CREATE FUNCTION series(int) RETURNS TABLE (x int) "
- "AS series;"
+ "AS 'series';"
[0x00]
write flush
diff --git a/incubator/binding-risingwave.spec/src/main/scripts/io/aklivity/zilla/specs/binding/risingwave/streams/pgsql/create.function.return.table/server.rpt b/incubator/binding-risingwave.spec/src/main/scripts/io/aklivity/zilla/specs/binding/risingwave/streams/pgsql/create.function.return.table/server.rpt
index 073520fff6..38ada2e027 100644
--- a/incubator/binding-risingwave.spec/src/main/scripts/io/aklivity/zilla/specs/binding/risingwave/streams/pgsql/create.function.return.table/server.rpt
+++ b/incubator/binding-risingwave.spec/src/main/scripts/io/aklivity/zilla/specs/binding/risingwave/streams/pgsql/create.function.return.table/server.rpt
@@ -37,7 +37,7 @@ read zilla:data.ext ${pgsql:dataEx()
.build()
.build()}
read "CREATE FUNCTION series(int) RETURNS TABLE (x int) "
- "AS series;"
+ "AS 'series';"
[0x00]
write advise zilla:flush ${pgsql:flushEx()
diff --git a/incubator/binding-risingwave.spec/src/main/scripts/io/aklivity/zilla/specs/binding/risingwave/streams/pgsql/create.function/client.rpt b/incubator/binding-risingwave.spec/src/main/scripts/io/aklivity/zilla/specs/binding/risingwave/streams/pgsql/create.function/client.rpt
index 49ccf60200..cada6175a2 100644
--- a/incubator/binding-risingwave.spec/src/main/scripts/io/aklivity/zilla/specs/binding/risingwave/streams/pgsql/create.function/client.rpt
+++ b/incubator/binding-risingwave.spec/src/main/scripts/io/aklivity/zilla/specs/binding/risingwave/streams/pgsql/create.function/client.rpt
@@ -33,7 +33,7 @@ write zilla:data.ext ${pgsql:dataEx()
.build()
.build()}
write "CREATE FUNCTION gcd(int, int) RETURNS int "
- "AS gcd;"
+ "AS 'gcd';"
[0x00]
write flush
diff --git a/incubator/binding-risingwave.spec/src/main/scripts/io/aklivity/zilla/specs/binding/risingwave/streams/pgsql/create.function/server.rpt b/incubator/binding-risingwave.spec/src/main/scripts/io/aklivity/zilla/specs/binding/risingwave/streams/pgsql/create.function/server.rpt
index 4fc06f7a40..8036c14b74 100644
--- a/incubator/binding-risingwave.spec/src/main/scripts/io/aklivity/zilla/specs/binding/risingwave/streams/pgsql/create.function/server.rpt
+++ b/incubator/binding-risingwave.spec/src/main/scripts/io/aklivity/zilla/specs/binding/risingwave/streams/pgsql/create.function/server.rpt
@@ -37,7 +37,7 @@ read zilla:data.ext ${pgsql:dataEx()
.build()
.build()}
read "CREATE FUNCTION gcd(int, int) RETURNS int "
- "AS gcd;"
+ "AS 'gcd';"
[0x00]
write advise zilla:flush ${pgsql:flushEx()
diff --git a/incubator/binding-risingwave.spec/src/main/scripts/io/aklivity/zilla/specs/binding/risingwave/streams/pgsql/create.stream.with.includes/client.rpt b/incubator/binding-risingwave.spec/src/main/scripts/io/aklivity/zilla/specs/binding/risingwave/streams/pgsql/create.stream.with.includes/client.rpt
index dbb1c245b7..61a9befb91 100644
--- a/incubator/binding-risingwave.spec/src/main/scripts/io/aklivity/zilla/specs/binding/risingwave/streams/pgsql/create.stream.with.includes/client.rpt
+++ b/incubator/binding-risingwave.spec/src/main/scripts/io/aklivity/zilla/specs/binding/risingwave/streams/pgsql/create.stream.with.includes/client.rpt
@@ -33,10 +33,8 @@ write zilla:data.ext ${pgsql:dataEx()
.build()
.build()}
write "CREATE STREAM IF NOT EXISTS weather "
- "(city VARCHAR, temperature DOUBLE, date DATE)\n"
- "INCLUDE zilla_correlation_id AS correlation_id\n"
- "INCLUDE zilla_identity AS identity\n"
- "INCLUDE timestamp as timestamp;"
+ "(city VARCHAR, temperature DOUBLE, date DATE,"
+ " zilla_correlation_id VARCHAR, zilla_identity VARCHAR, zilla_timestamp TIMESTAMP);"
[0x00]
write flush
diff --git a/incubator/binding-risingwave.spec/src/main/scripts/io/aklivity/zilla/specs/binding/risingwave/streams/pgsql/create.stream.with.includes/server.rpt b/incubator/binding-risingwave.spec/src/main/scripts/io/aklivity/zilla/specs/binding/risingwave/streams/pgsql/create.stream.with.includes/server.rpt
index 19833142cf..e328e36ca6 100644
--- a/incubator/binding-risingwave.spec/src/main/scripts/io/aklivity/zilla/specs/binding/risingwave/streams/pgsql/create.stream.with.includes/server.rpt
+++ b/incubator/binding-risingwave.spec/src/main/scripts/io/aklivity/zilla/specs/binding/risingwave/streams/pgsql/create.stream.with.includes/server.rpt
@@ -37,12 +37,11 @@ read zilla:data.ext ${pgsql:dataEx()
.build()
.build()}
read "CREATE STREAM IF NOT EXISTS weather "
- "(city VARCHAR, temperature DOUBLE, date DATE)\n"
- "INCLUDE zilla_correlation_id AS correlation_id\n"
- "INCLUDE zilla_identity AS identity\n"
- "INCLUDE timestamp as timestamp;"
+ "(city VARCHAR, temperature DOUBLE, date DATE,"
+ " zilla_correlation_id VARCHAR, zilla_identity VARCHAR, zilla_timestamp TIMESTAMP);"
[0x00]
+
write advise zilla:flush ${pgsql:flushEx()
.typeId(zilla:id("pgsql"))
.completion()
diff --git a/incubator/binding-risingwave.spec/src/main/scripts/io/aklivity/zilla/specs/binding/risingwave/streams/pgsql/create.table.with.primary.key.and.includes/client.rpt b/incubator/binding-risingwave.spec/src/main/scripts/io/aklivity/zilla/specs/binding/risingwave/streams/pgsql/create.table.with.primary.key.and.includes/client.rpt
index f40e1041f9..823f4ffbe8 100644
--- a/incubator/binding-risingwave.spec/src/main/scripts/io/aklivity/zilla/specs/binding/risingwave/streams/pgsql/create.table.with.primary.key.and.includes/client.rpt
+++ b/incubator/binding-risingwave.spec/src/main/scripts/io/aklivity/zilla/specs/binding/risingwave/streams/pgsql/create.table.with.primary.key.and.includes/client.rpt
@@ -33,10 +33,9 @@ write zilla:data.ext ${pgsql:dataEx()
.build()
.build()}
write "CREATE TABLE IF NOT EXISTS cities "
- "(id VARCHAR, name VARCHAR, description VARCHAR, PRIMARY KEY (id))\n"
- "INCLUDE zilla_correlation_id AS correlation_id\n"
- "INCLUDE zilla_identity AS identity\n"
- "INCLUDE timestamp as timestamp;"
+ "(id VARCHAR, name VARCHAR, description VARCHAR,"
+ " zilla_correlation_id VARCHAR, zilla_identity VARCHAR, zilla_timestamp TIMESTAMP,"
+ " PRIMARY KEY (id));"
[0x00]
write flush
diff --git a/incubator/binding-risingwave.spec/src/main/scripts/io/aklivity/zilla/specs/binding/risingwave/streams/pgsql/create.table.with.primary.key.and.includes/server.rpt b/incubator/binding-risingwave.spec/src/main/scripts/io/aklivity/zilla/specs/binding/risingwave/streams/pgsql/create.table.with.primary.key.and.includes/server.rpt
index ed5fda502c..3c916e9f9c 100644
--- a/incubator/binding-risingwave.spec/src/main/scripts/io/aklivity/zilla/specs/binding/risingwave/streams/pgsql/create.table.with.primary.key.and.includes/server.rpt
+++ b/incubator/binding-risingwave.spec/src/main/scripts/io/aklivity/zilla/specs/binding/risingwave/streams/pgsql/create.table.with.primary.key.and.includes/server.rpt
@@ -37,10 +37,9 @@ read zilla:data.ext ${pgsql:dataEx()
.build()
.build()}
read "CREATE TABLE IF NOT EXISTS cities "
- "(id VARCHAR, name VARCHAR, description VARCHAR, PRIMARY KEY (id))\n"
- "INCLUDE zilla_correlation_id AS correlation_id\n"
- "INCLUDE zilla_identity AS identity\n"
- "INCLUDE timestamp as timestamp;"
+ "(id VARCHAR, name VARCHAR, description VARCHAR,"
+ " zilla_correlation_id VARCHAR, zilla_identity VARCHAR, zilla_timestamp TIMESTAMP,"
+ " PRIMARY KEY (id));"
[0x00]
write advise zilla:flush ${pgsql:flushEx()
diff --git a/incubator/binding-risingwave/NOTICE b/incubator/binding-risingwave/NOTICE
index c6b7d9c015..3913dbbc71 100644
--- a/incubator/binding-risingwave/NOTICE
+++ b/incubator/binding-risingwave/NOTICE
@@ -10,5 +10,5 @@ WARRANTIES OF ANY KIND, either express or implied. See the License for the
specific language governing permissions and limitations under the License.
This project includes:
- JSQLParser library under GNU Library or Lesser General Public License (LGPL) V2.1 or The Apache Software License, Version 2.0
+ zilla::incubator::binding-pgsql under Aklivity Community License Agreement
diff --git a/incubator/binding-risingwave/pom.xml b/incubator/binding-risingwave/pom.xml
index 98571514a4..a087cd9681 100644
--- a/incubator/binding-risingwave/pom.xml
+++ b/incubator/binding-risingwave/pom.xml
@@ -24,7 +24,7 @@
- 0.86
+ 0.91
0
@@ -42,8 +42,8 @@
provided
- com.github.jsqlparser
- jsqlparser
+ io.aklivity.zilla
+ binding-pgsql
${project.groupId}
@@ -195,7 +195,6 @@
io/aklivity/zilla/runtime/binding/risingwave/internal/types/**/*.class
- net/sf/jsqlparser/parser/*
diff --git a/incubator/binding-risingwave/src/main/java/io/aklivity/zilla/runtime/binding/risingwave/internal/statement/RisingwaveCommandTemplate.java b/incubator/binding-risingwave/src/main/java/io/aklivity/zilla/runtime/binding/risingwave/internal/statement/RisingwaveCommandTemplate.java
index bb65d54a24..c107737304 100644
--- a/incubator/binding-risingwave/src/main/java/io/aklivity/zilla/runtime/binding/risingwave/internal/statement/RisingwaveCommandTemplate.java
+++ b/incubator/binding-risingwave/src/main/java/io/aklivity/zilla/runtime/binding/risingwave/internal/statement/RisingwaveCommandTemplate.java
@@ -14,138 +14,32 @@
*/
package io.aklivity.zilla.runtime.binding.risingwave.internal.statement;
-import java.io.StringReader;
-import java.util.LinkedHashMap;
-import java.util.List;
import java.util.Map;
-import org.agrona.DirectBuffer;
import org.agrona.collections.Object2ObjectHashMap;
-import net.sf.jsqlparser.parser.CCJSqlParserManager;
-import net.sf.jsqlparser.statement.create.table.CreateTable;
-import net.sf.jsqlparser.statement.create.table.Index;
public abstract class RisingwaveCommandTemplate
{
- private final CCJSqlParserManager parserManager = new CCJSqlParserManager();
- private final Map includeMap = new LinkedHashMap<>();
+ protected static final String ZILLA_CORRELATION_ID = "zilla_correlation_id";
+ protected static final String ZILLA_IDENTITY = "zilla_identity";
+ protected static final String ZILLA_TIMESTAMP = "zilla_timestamp";
protected final StringBuilder fieldBuilder = new StringBuilder();
protected final StringBuilder includeBuilder = new StringBuilder();
protected static final Map ZILLA_MAPPINGS = new Object2ObjectHashMap<>();
static
{
- ZILLA_MAPPINGS.put("zilla_correlation_id", "INCLUDE header 'zilla:correlation-id' AS %s\n");
- ZILLA_MAPPINGS.put("zilla_identity", "INCLUDE header 'zilla:identity' AS %s\n");
- ZILLA_MAPPINGS.put("timestamp", "INCLUDE timestamp AS %s\n");
+ ZILLA_MAPPINGS.put(ZILLA_CORRELATION_ID, "INCLUDE header 'zilla:correlation-id' AS %s\n");
+ ZILLA_MAPPINGS.put(ZILLA_IDENTITY, "INCLUDE header 'zilla:identity' AS %s\n");
+ ZILLA_MAPPINGS.put(ZILLA_TIMESTAMP, "INCLUDE timestamp AS %s\n");
}
protected static final Map ZILLA_INCLUDE_TYPE_MAPPINGS = new Object2ObjectHashMap<>();
static
{
- ZILLA_INCLUDE_TYPE_MAPPINGS.put("zilla_correlation_id", "VARCHAR");
- ZILLA_INCLUDE_TYPE_MAPPINGS.put("zilla_identity", "VARCHAR");
- ZILLA_INCLUDE_TYPE_MAPPINGS.put("timestamp", "TIMESTAMP");
- }
-
- public String primaryKey(
- CreateTable statement)
- {
- String primaryKey = null;
-
- final List indexes = statement.getIndexes();
-
- if (indexes != null && !indexes.isEmpty())
- {
- match:
- for (Index index : indexes)
- {
- if ("PRIMARY KEY".equalsIgnoreCase(index.getType()))
- {
- final List primaryKeyColumns = index.getColumns();
- primaryKey = primaryKeyColumns.get(0).columnName;
- break match;
- }
- }
- }
-
- return primaryKey;
- }
-
- public RisingwaveCreateTableCommand parserCreateTable(
- DirectBuffer buffer,
- int offset,
- int length)
- {
- String query = buffer.getStringWithoutLengthUtf8(offset, length);
- query = query.replaceAll("(?i)\\bCREATE\\s+STREAM\\b", "CREATE TABLE");
-
- int includeIndex = query.indexOf("INCLUDE");
-
- String createTablePart;
- String includePart = null;
-
- CreateTable createTable = null;
- Map includes = null;
-
- if (includeIndex != -1)
- {
- createTablePart = query.substring(0, includeIndex).trim();
- includePart = query.substring(includeIndex).trim();
- }
- else
- {
- createTablePart = query.trim();
- }
-
- try
- {
- createTable = (CreateTable) parserManager.parse(new StringReader(createTablePart));
- }
- catch (Exception ignore)
- {
- }
-
- if (includePart != null)
- {
- includes = parseSpecificIncludes(includePart);
- }
-
- return new RisingwaveCreateTableCommand(createTable, includes);
- }
-
- private Map parseSpecificIncludes(
- String includePart)
- {
- String[] includeClauses = includePart.toLowerCase().split("include");
- for (String clause : includeClauses)
- {
- clause = clause.trim();
- if (!clause.isEmpty())
- {
- String[] parts = clause.toLowerCase().split("as");
- if (parts.length == 2)
- {
- String key = parts[0].trim();
- String value = parts[1].trim().replace(";", "");
-
- if (isValidInclude(key))
- {
- includeMap.put(key, value);
- }
- }
- }
- }
-
- return includeMap;
- }
-
- private static boolean isValidInclude(
- String key)
- {
- return "zilla_correlation_id".equals(key) ||
- "zilla_identity".equals(key) ||
- "timestamp".equals(key);
+ ZILLA_INCLUDE_TYPE_MAPPINGS.put(ZILLA_CORRELATION_ID, "VARCHAR");
+ ZILLA_INCLUDE_TYPE_MAPPINGS.put(ZILLA_IDENTITY, "VARCHAR");
+ ZILLA_INCLUDE_TYPE_MAPPINGS.put(ZILLA_TIMESTAMP, "TIMESTAMP");
}
}
diff --git a/incubator/binding-risingwave/src/main/java/io/aklivity/zilla/runtime/binding/risingwave/internal/statement/RisingwaveCreateFunctionTemplate.java b/incubator/binding-risingwave/src/main/java/io/aklivity/zilla/runtime/binding/risingwave/internal/statement/RisingwaveCreateFunctionTemplate.java
index 6c687b2e90..b171265ba2 100644
--- a/incubator/binding-risingwave/src/main/java/io/aklivity/zilla/runtime/binding/risingwave/internal/statement/RisingwaveCreateFunctionTemplate.java
+++ b/incubator/binding-risingwave/src/main/java/io/aklivity/zilla/runtime/binding/risingwave/internal/statement/RisingwaveCreateFunctionTemplate.java
@@ -16,13 +16,12 @@
import java.util.List;
+import io.aklivity.zilla.runtime.binding.pgsql.parser.model.FunctionArgument;
+import io.aklivity.zilla.runtime.binding.pgsql.parser.model.FunctionInfo;
import io.aklivity.zilla.runtime.binding.risingwave.config.RisingwaveUdfConfig;
-import net.sf.jsqlparser.statement.Statement;
-import net.sf.jsqlparser.statement.create.function.CreateFunction;
public class RisingwaveCreateFunctionTemplate extends RisingwaveCommandTemplate
{
- private static final List KEYWORDS = List.of("LANGUAGE", "AS", "USING");
private final String sqlFormat = """
CREATE FUNCTION %s(%s)
RETURNS %s
@@ -30,8 +29,8 @@ public class RisingwaveCreateFunctionTemplate extends RisingwaveCommandTemplate
LANGUAGE %s
USING LINK '%s';\u0000""";
- private final String java;
- private final String python;
+ private final String javaServer;
+ private final String pythonServer;
public RisingwaveCreateFunctionTemplate(
List udfs)
@@ -54,58 +53,50 @@ else if (udf.language.equalsIgnoreCase("python"))
}
}
- this.java = javaServer;
- this.python = pythonServer;
+ this.javaServer = javaServer;
+ this.pythonServer = pythonServer;
}
public String generate(
- Statement statement)
+ FunctionInfo functionInfo)
{
- CreateFunction createFunction = (CreateFunction) statement;
- List parts = createFunction.getFunctionDeclarationParts();
+ String functionName = functionInfo.name();
+ String asFunction = functionInfo.asFunction();
+ List arguments = functionInfo.arguments();
+ List tables = functionInfo.tables();
- String functionName = parts.get(0);
+ fieldBuilder.setLength(0);
- int paramStartIndex = parts.indexOf("(");
- int paramEndIndex = parts.indexOf(")");
- String parameters = paramStartIndex >= 0 && paramEndIndex > paramStartIndex
- ? String.join(" ", parts.subList(paramStartIndex + 1, paramEndIndex))
- : "";
+ arguments
+ .forEach(arg -> fieldBuilder.append(
+ arg.name() != null
+ ? "%s %s, ".formatted(arg.name(), arg.type())
+ : "%s, ".formatted(arg.type())));
- int returnsIndex = parts.indexOf("RETURNS");
- String returnType = returnsIndex >= 0 ? parts.get(returnsIndex + 1) : "";
-
- if (returnsIndex >= 0)
+ if (!arguments.isEmpty())
{
- int nextKeywordIndex = findNextKeywordIndex(parts, returnsIndex + 1);
- returnType = nextKeywordIndex >= 0
- ? String.join(" ", parts.subList(returnsIndex + 1, nextKeywordIndex))
- : String.join(" ", parts.subList(returnsIndex + 1, parts.size()));
+ fieldBuilder.delete(fieldBuilder.length() - 2, fieldBuilder.length());
}
+ String funcArguments = fieldBuilder.toString();
- int asIndex = parts.indexOf("AS");
- String body = asIndex >= 0 ? parts.get(asIndex + 1) : "";
-
- int langIndex = parts.indexOf("LANGUAGE");
- String language = langIndex >= 0 ? parts.get(langIndex + 1) : "java";
-
- return sqlFormat.formatted(functionName, parameters, returnType.trim(), body, language,
- "python".equalsIgnoreCase(language) ? python : java);
- }
+ String language = functionInfo.language() != null ? functionInfo.language() : "java";
+ String server = "python".equalsIgnoreCase(language) ? pythonServer : javaServer;
- private int findNextKeywordIndex(
- List parts,
- int startIndex)
- {
- int endIndex = -1;
- for (int index = startIndex; index < parts.size(); index++)
+ String returnType = functionInfo.returnType();
+ if (!tables.isEmpty())
{
- if (KEYWORDS.contains(parts.get(index).toUpperCase()))
- {
- endIndex = index;
- break;
- }
+ fieldBuilder.setLength(0);
+ fieldBuilder.append("TABLE (");
+ tables.forEach(arg -> fieldBuilder.append(
+ arg.name() != null
+ ? "%s %s, ".formatted(arg.name(), arg.type())
+ : "%s, ".formatted(arg.type())));
+ fieldBuilder.delete(fieldBuilder.length() - 2, fieldBuilder.length());
+ fieldBuilder.append(")");
+
+ returnType = fieldBuilder.toString();
}
- return endIndex;
+
+ return sqlFormat.formatted(functionName, funcArguments, returnType, asFunction, language, server);
}
}
diff --git a/incubator/binding-risingwave/src/main/java/io/aklivity/zilla/runtime/binding/risingwave/internal/statement/RisingwaveCreateMaterializedViewTemplate.java b/incubator/binding-risingwave/src/main/java/io/aklivity/zilla/runtime/binding/risingwave/internal/statement/RisingwaveCreateMaterializedViewTemplate.java
index 4a57891eb3..a6f852d0b0 100644
--- a/incubator/binding-risingwave/src/main/java/io/aklivity/zilla/runtime/binding/risingwave/internal/statement/RisingwaveCreateMaterializedViewTemplate.java
+++ b/incubator/binding-risingwave/src/main/java/io/aklivity/zilla/runtime/binding/risingwave/internal/statement/RisingwaveCreateMaterializedViewTemplate.java
@@ -14,53 +14,63 @@
*/
package io.aklivity.zilla.runtime.binding.risingwave.internal.statement;
-import net.sf.jsqlparser.statement.create.table.CreateTable;
-import net.sf.jsqlparser.statement.create.view.CreateView;
+import java.util.LinkedHashMap;
+import java.util.Map;
+
+import io.aklivity.zilla.runtime.binding.pgsql.parser.model.TableInfo;
+import io.aklivity.zilla.runtime.binding.pgsql.parser.model.ViewInfo;
+
public class RisingwaveCreateMaterializedViewTemplate extends RisingwaveCommandTemplate
{
private final String sqlFormat = """
CREATE MATERIALIZED VIEW IF NOT EXISTS %s AS %s;\u0000""";
private final String fieldFormat = "%s, ";
- private final String includeFormat = "COALESCE(%s, zilla_%s_header::varchar) as %s, ";
+ private final String includeFormat = "COALESCE(%s, %s_header::varchar) as %s, ";
+ private final String timestampFormat = "COALESCE(%s, %s_timestamp::varchar) as %s, ";
public RisingwaveCreateMaterializedViewTemplate()
{
}
public String generate(
- CreateView createView)
+ ViewInfo viewInfo)
{
- String view = createView.getView().getName();
- String select = createView.getSelect().toString();
+ String name = viewInfo.name();
+ String select = viewInfo.select();
- return String.format(sqlFormat, view, select);
+ return String.format(sqlFormat, name, select);
}
public String generate(
- RisingwaveCreateTableCommand command)
+ TableInfo tableInfo)
{
- CreateTable createTable = command.createTable;
- String name = createTable.getTable().getName();
+ String name = tableInfo.name();
String select = "*";
- if (command.includes != null)
+ Map includes = tableInfo.columns().entrySet().stream()
+ .filter(e -> ZILLA_MAPPINGS.containsKey(e.getKey()))
+ .collect(LinkedHashMap::new, (m, e) -> m.put(e.getKey(), e.getValue()), Map::putAll);
+
+ if (!includes.isEmpty())
{
fieldBuilder.setLength(0);
- createTable.getColumnDefinitions()
- .forEach(c -> fieldBuilder.append(
- String.format(fieldFormat, c.getColumnName())));
- command.includes.forEach((k, v) ->
+ tableInfo.columns().keySet()
+ .stream()
+ .filter(c -> !ZILLA_MAPPINGS.containsKey(c))
+ .forEach(c -> fieldBuilder.append(String.format(fieldFormat, c)));
+
+ includes.forEach((k, v) ->
{
- if ("timestamp".equals(k))
+ if (ZILLA_TIMESTAMP.equals(k))
{
- fieldBuilder.append(String.format(fieldFormat, v));
+ fieldBuilder.append(String.format(timestampFormat, k, k, k));
}
else
{
- fieldBuilder.append(String.format(includeFormat, v, v, v));
+ fieldBuilder.append(String.format(includeFormat, k, k, k));
}
});
diff --git a/incubator/binding-risingwave/src/main/java/io/aklivity/zilla/runtime/binding/risingwave/internal/statement/RisingwaveCreateSinkTemplate.java b/incubator/binding-risingwave/src/main/java/io/aklivity/zilla/runtime/binding/risingwave/internal/statement/RisingwaveCreateSinkTemplate.java
index e30a55b5f3..2025b81d0e 100644
--- a/incubator/binding-risingwave/src/main/java/io/aklivity/zilla/runtime/binding/risingwave/internal/statement/RisingwaveCreateSinkTemplate.java
+++ b/incubator/binding-risingwave/src/main/java/io/aklivity/zilla/runtime/binding/risingwave/internal/statement/RisingwaveCreateSinkTemplate.java
@@ -17,8 +17,8 @@
import java.util.Map;
import java.util.Optional;
-import net.sf.jsqlparser.statement.create.table.CreateTable;
-import net.sf.jsqlparser.statement.create.view.CreateView;
+import io.aklivity.zilla.runtime.binding.pgsql.parser.model.TableInfo;
+import io.aklivity.zilla.runtime.binding.pgsql.parser.model.ViewInfo;
public class RisingwaveCreateSinkTemplate extends RisingwaveCommandTemplate
{
@@ -51,9 +51,9 @@ public RisingwaveCreateSinkTemplate(
public String generate(
String database,
Map columns,
- CreateView createView)
+ ViewInfo viewInfo)
{
- String viewName = createView.getView().getName();
+ String viewName = viewInfo.name();
Optional> primaryKeyMatch = columns.entrySet().stream()
.filter(e -> "id".equalsIgnoreCase(e.getKey()))
@@ -74,19 +74,18 @@ public String generate(
public String generate(
String database,
- String primaryKey,
- CreateTable createTable)
+ TableInfo tableInfo)
{
- String table = createTable.getTable().getName();
+ String table = tableInfo.name();
return String.format(sqlKafkaFormat, table, table, bootstrapServer, database, table,
- primaryKeyFormat.formatted(primaryKey), schemaRegistry);
+ primaryKeyFormat.formatted(tableInfo.primaryKeys().stream().findFirst().get()), schemaRegistry);
}
public String generate(
- CreateTable createTable)
+ TableInfo tableInfo)
{
- String table = createTable.getTable().getName();
+ String table = tableInfo.name();
return String.format(sqlFormat, table, table, table);
}
diff --git a/incubator/binding-risingwave/src/main/java/io/aklivity/zilla/runtime/binding/risingwave/internal/statement/RisingwaveCreateSourceTemplate.java b/incubator/binding-risingwave/src/main/java/io/aklivity/zilla/runtime/binding/risingwave/internal/statement/RisingwaveCreateSourceTemplate.java
index 1e64e8456d..f154574431 100644
--- a/incubator/binding-risingwave/src/main/java/io/aklivity/zilla/runtime/binding/risingwave/internal/statement/RisingwaveCreateSourceTemplate.java
+++ b/incubator/binding-risingwave/src/main/java/io/aklivity/zilla/runtime/binding/risingwave/internal/statement/RisingwaveCreateSourceTemplate.java
@@ -14,8 +14,12 @@
*/
package io.aklivity.zilla.runtime.binding.risingwave.internal.statement;
+import java.util.LinkedHashMap;
import java.util.Map;
+import io.aklivity.zilla.runtime.binding.pgsql.parser.model.StreamInfo;
+import io.aklivity.zilla.runtime.binding.pgsql.parser.model.TableInfo;
+
public class RisingwaveCreateSourceTemplate extends RisingwaveCommandTemplate
{
private final String sqlFormat = """
@@ -46,16 +50,19 @@ public RisingwaveCreateSourceTemplate(
public String generateStreamSource(
String database,
- RisingwaveCreateTableCommand command)
+ StreamInfo streamInfo)
{
- String table = command.createTable.getTable().getName();
+ String table = streamInfo.name();
includeBuilder.setLength(0);
- final Map includes = command.includes;
- if (includes != null && !includes.isEmpty())
+ Map includes = streamInfo.columns().entrySet().stream()
+ .filter(e -> ZILLA_MAPPINGS.containsKey(e.getKey()))
+ .collect(LinkedHashMap::new, (m, e) -> m.put(e.getKey(), e.getValue()), Map::putAll);
+
+ if (!includes.isEmpty())
{
includeBuilder.append("\n");
- includes.forEach((k, v) -> includeBuilder.append(String.format(ZILLA_MAPPINGS.get(k), v)));
+ includes.forEach((k, v) -> includeBuilder.append(String.format(ZILLA_MAPPINGS.get(k), k)));
includeBuilder.delete(includeBuilder.length() - 1, includeBuilder.length());
}
@@ -64,27 +71,29 @@ public String generateStreamSource(
public String generateTableSource(
String database,
- RisingwaveCreateTableCommand command)
+ TableInfo tableInfo)
{
- String table = command.createTable.getTable().getName();
+ String table = tableInfo.name();
String sourceName = "%s_source".formatted(table);
includeBuilder.setLength(0);
- final Map includes = command.includes;
- if (includes != null && !includes.isEmpty())
+ Map includes = tableInfo.columns().entrySet().stream()
+ .filter(e -> ZILLA_MAPPINGS.containsKey(e.getKey()))
+ .collect(LinkedHashMap::new, (m, e) -> m.put(e.getKey(), e.getValue()), Map::putAll);
+
+ if (!includes.isEmpty())
{
includeBuilder.append("\n");
includes.forEach((k, v) ->
{
- if ("timestamp".equals(k))
+ if (ZILLA_TIMESTAMP.equals(k))
{
- includeBuilder.append(String.format(ZILLA_MAPPINGS.get(k), v));
+ includeBuilder.append(String.format(ZILLA_MAPPINGS.get(k), "%s_timestamp".formatted(k)));
}
else
{
- includeBuilder.append(String.format(ZILLA_MAPPINGS.get(k), "zilla_%s_header".formatted(v)));
+ includeBuilder.append(String.format(ZILLA_MAPPINGS.get(k), "%s_header".formatted(k)));
}
-
});
includeBuilder.delete(includeBuilder.length() - 1, includeBuilder.length());
}
diff --git a/incubator/binding-risingwave/src/main/java/io/aklivity/zilla/runtime/binding/risingwave/internal/statement/RisingwaveCreateTableTemplate.java b/incubator/binding-risingwave/src/main/java/io/aklivity/zilla/runtime/binding/risingwave/internal/statement/RisingwaveCreateTableTemplate.java
index 9e8f98acf0..9c225454af 100644
--- a/incubator/binding-risingwave/src/main/java/io/aklivity/zilla/runtime/binding/risingwave/internal/statement/RisingwaveCreateTableTemplate.java
+++ b/incubator/binding-risingwave/src/main/java/io/aklivity/zilla/runtime/binding/risingwave/internal/statement/RisingwaveCreateTableTemplate.java
@@ -14,7 +14,7 @@
*/
package io.aklivity.zilla.runtime.binding.risingwave.internal.statement;
-import net.sf.jsqlparser.statement.create.table.CreateTable;
+import io.aklivity.zilla.runtime.binding.pgsql.parser.model.TableInfo;
public class RisingwaveCreateTableTemplate extends RisingwaveCommandTemplate
{
@@ -28,24 +28,18 @@ public RisingwaveCreateTableTemplate()
}
public String generate(
- RisingwaveCreateTableCommand command)
+ TableInfo tableInfo)
{
- CreateTable createTable = command.createTable;
- String topic = createTable.getTable().getName();
- String primaryKeyField = primaryKey(createTable);
- String primaryKey = primaryKeyField != null ? String.format(primaryKeyFormat, primaryKeyField) : "";
+ String topic = tableInfo.name();
+ String primaryKey = !tableInfo.primaryKeys().isEmpty()
+ ? String.format(primaryKeyFormat, tableInfo.primaryKeys().stream().findFirst().get())
+ : "";
fieldBuilder.setLength(0);
- createTable.getColumnDefinitions()
- .forEach(c -> fieldBuilder.append(
- String.format(fieldFormat, c.getColumnName(), c.getColDataType().getDataType())));
-
- if (command.includes != null)
- {
- command.includes.forEach((k, v) -> fieldBuilder.append(
- String.format(fieldFormat, v, ZILLA_INCLUDE_TYPE_MAPPINGS.get(k))));
- }
+ tableInfo.columns()
+ .forEach((k, v) -> fieldBuilder.append(
+ String.format(fieldFormat, k, v)));
fieldBuilder.delete(fieldBuilder.length() - 2, fieldBuilder.length());
diff --git a/incubator/binding-risingwave/src/main/java/io/aklivity/zilla/runtime/binding/risingwave/internal/statement/RisingwaveCreateTopicTemplate.java b/incubator/binding-risingwave/src/main/java/io/aklivity/zilla/runtime/binding/risingwave/internal/statement/RisingwaveCreateTopicTemplate.java
index f088a3111a..39a1b16c2f 100644
--- a/incubator/binding-risingwave/src/main/java/io/aklivity/zilla/runtime/binding/risingwave/internal/statement/RisingwaveCreateTopicTemplate.java
+++ b/incubator/binding-risingwave/src/main/java/io/aklivity/zilla/runtime/binding/risingwave/internal/statement/RisingwaveCreateTopicTemplate.java
@@ -16,8 +16,9 @@
import java.util.Map;
-import net.sf.jsqlparser.statement.create.table.CreateTable;
-import net.sf.jsqlparser.statement.create.view.CreateView;
+import io.aklivity.zilla.runtime.binding.pgsql.parser.model.StreamInfo;
+import io.aklivity.zilla.runtime.binding.pgsql.parser.model.TableInfo;
+import io.aklivity.zilla.runtime.binding.pgsql.parser.model.ViewInfo;
public class RisingwaveCreateTopicTemplate extends RisingwaveCommandTemplate
{
@@ -34,17 +35,18 @@ public RisingwaveCreateTopicTemplate()
}
public String generate(
- CreateTable createTable)
+ TableInfo tableInfo)
{
- String topic = createTable.getTable().getName();
- String primaryKeyField = primaryKey(createTable);
- String primaryKey = primaryKeyField != null ? String.format(primaryKeyFormat, primaryKeyField) : "";
+ String topic = tableInfo.name();
+ String primaryKey = !tableInfo.primaryKeys().isEmpty()
+ ? String.format(primaryKeyFormat, tableInfo.primaryKeys().stream().findFirst().get())
+ : "";
fieldBuilder.setLength(0);
- createTable.getColumnDefinitions()
- .forEach(c -> fieldBuilder.append(
- String.format(fieldFormat, c.getColumnName(), c.getColDataType().getDataType())));
+ tableInfo.columns()
+ .forEach((k, v) -> fieldBuilder.append(
+ String.format(fieldFormat, k, v)));
fieldBuilder.delete(fieldBuilder.length() - 2, fieldBuilder.length());
@@ -52,35 +54,29 @@ public String generate(
}
public String generate(
- RisingwaveCreateTableCommand command)
+ StreamInfo streamInfo)
{
- CreateTable createTable = command.createTable;
- String topic = createTable.getTable().getName();
- String primaryKeyField = primaryKey(createTable);
- String primaryKey = primaryKeyField != null ? String.format(primaryKeyFormat, primaryKeyField) : "";
+ String topic = streamInfo.name();
fieldBuilder.setLength(0);
- createTable.getColumnDefinitions()
- .forEach(c -> fieldBuilder.append(
- String.format(fieldFormat, c.getColumnName(), c.getColDataType().getDataType())));
-
- if (command.includes != null)
- {
- command.includes.forEach((k, v) -> fieldBuilder.append(
- String.format(fieldFormat, v, ZILLA_INCLUDE_TYPE_MAPPINGS.get(k))));
- }
+ streamInfo.columns()
+ .entrySet()
+ .stream()
+ .filter(e -> !ZILLA_MAPPINGS.containsKey(e.getKey()))
+ .forEach(e -> fieldBuilder.append(
+ String.format(fieldFormat, e.getKey(), e.getValue())));
fieldBuilder.delete(fieldBuilder.length() - 2, fieldBuilder.length());
- return String.format(sqlFormat, topic, fieldBuilder, primaryKey);
+ return String.format(sqlFormat, topic, fieldBuilder, "");
}
public String generate(
- CreateView createView,
+ ViewInfo viewInfo,
Map columns)
{
- String topic = createView.getView().getName();
+ String topic = viewInfo.name();
primaryKeyBuilder.setLength(0);
columns.keySet().forEach(k -> primaryKeyBuilder.append(k).append(", "));
diff --git a/incubator/binding-risingwave/src/main/java/io/aklivity/zilla/runtime/binding/risingwave/internal/statement/RisingwaveDescribeTemplate.java b/incubator/binding-risingwave/src/main/java/io/aklivity/zilla/runtime/binding/risingwave/internal/statement/RisingwaveDescribeTemplate.java
index 238d75bb06..4f0718acd4 100644
--- a/incubator/binding-risingwave/src/main/java/io/aklivity/zilla/runtime/binding/risingwave/internal/statement/RisingwaveDescribeTemplate.java
+++ b/incubator/binding-risingwave/src/main/java/io/aklivity/zilla/runtime/binding/risingwave/internal/statement/RisingwaveDescribeTemplate.java
@@ -14,8 +14,7 @@
*/
package io.aklivity.zilla.runtime.binding.risingwave.internal.statement;
-import net.sf.jsqlparser.statement.Statement;
-import net.sf.jsqlparser.statement.create.view.CreateView;
+import io.aklivity.zilla.runtime.binding.pgsql.parser.model.ViewInfo;
public class RisingwaveDescribeTemplate extends RisingwaveCommandTemplate
{
@@ -27,11 +26,10 @@ public RisingwaveDescribeTemplate()
}
public String generate(
- Statement statement)
+ ViewInfo viewInfo)
{
- CreateView createView = (CreateView) statement;
- String view = createView.getView().getName();
+ String name = viewInfo.name();
- return String.format(sqlFormat, view);
+ return String.format(sqlFormat, name);
}
}
diff --git a/incubator/binding-risingwave/src/main/java/io/aklivity/zilla/runtime/binding/risingwave/internal/statement/RisingwaveSqlCommandParser.java b/incubator/binding-risingwave/src/main/java/io/aklivity/zilla/runtime/binding/risingwave/internal/statement/RisingwaveSqlCommandParser.java
deleted file mode 100644
index a3ddf19ed0..0000000000
--- a/incubator/binding-risingwave/src/main/java/io/aklivity/zilla/runtime/binding/risingwave/internal/statement/RisingwaveSqlCommandParser.java
+++ /dev/null
@@ -1,104 +0,0 @@
-/*
- * Copyright 2021-2023 Aklivity Inc
- *
- * Licensed under the Aklivity Community License (the "License"); you may not use
- * this file except in compliance with the License. You may obtain a copy of the
- * License at
- *
- * https://www.aklivity.io/aklivity-community-license/
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- * WARRANTIES OF ANY KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations under the License.
- */
-package io.aklivity.zilla.runtime.binding.risingwave.internal.statement;
-
-import java.nio.charset.StandardCharsets;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-
-import io.aklivity.zilla.runtime.binding.risingwave.internal.config.RisingwaveCommandType;
-
-public final class RisingwaveSqlCommandParser
-{
- private static final String SQL_FUNCTION_PATTERN =
- "CREATE\\s+FUNCTION[\\s\\S]+?\\$\\$[\\s\\S]+?\\$\\$";
- private static final String SQL_COMMAND_PATTERN =
- "(?i)\\b(CREATE FUNCTION)\\b.*?\\$\\$(.*?)\\$\\$\\s*;[\\x00\\n]*" +
- "|\\b(CREATE FUNCTION)\\b.*?RETURNS .*?AS.*?;[\\x00\\n]*" +
- "|\\b(CREATE MATERIALIZED VIEW|CREATE SOURCE|CREATE SINK|CREATE INDEX|CREATE STREAM" +
- "|CREATE VIEW|SHOW TABLES|DESCRIBE|SHOW)\\b.*?;[\\x00\\n]*" +
- "|\\b(SELECT|INSERT|UPDATE|DELETE|ALTER|DROP|CREATE TABLE|CREATE SCHEMA|CREATE DATABASE)\\b.*?;[\\x00\\n]*" +
- "|\\b(SET)\\b\\s+.*?=.*[\\x00\\n]*";
-
- private final Pattern functionPattern = Pattern.compile(SQL_FUNCTION_PATTERN, Pattern.CASE_INSENSITIVE);
- private final Pattern sqlPattern = Pattern.compile(SQL_COMMAND_PATTERN, Pattern.DOTALL);
-
- public RisingwaveSqlCommandParser()
- {
- }
-
- public String detectFirstSQLCommand(
- String input)
- {
- String command = null;
- Matcher matcher = sqlPattern.matcher(input);
-
- if (matcher.find())
- {
- command = matcher.group();
- }
-
- return command;
- }
-
- public RisingwaveCommandType decodeCommandType(
- String input)
- {
- RisingwaveCommandType matchingCommand = RisingwaveCommandType.UNKNOWN_COMMAND;
-
- command:
- for (RisingwaveCommandType command : RisingwaveCommandType.values())
- {
- byte[] strBytes = input.getBytes(StandardCharsets.UTF_8);
- byte[] prefixBytes = command.value();
-
- boolean match = strBytes.length > prefixBytes.length;
-
- if (match)
- {
- for (int i = 0; i < prefixBytes.length; i++)
- {
- if (strBytes[i] != prefixBytes[i])
- {
- match = false;
- break;
- }
- }
- }
-
- if (match)
- {
- matchingCommand = command;
- break command;
- }
- }
-
- if (matchingCommand == RisingwaveCommandType.CREATE_FUNCTION_COMMAND &&
- isEmbeddedFunction(input))
- {
- matchingCommand = RisingwaveCommandType.UNKNOWN_COMMAND;
- }
-
-
- return matchingCommand;
- }
-
- private boolean isEmbeddedFunction(
- String sqlQuery)
- {
- Matcher matcher = functionPattern.matcher(sqlQuery);
- return matcher.find();
- }
-}
diff --git a/incubator/binding-risingwave/src/main/java/io/aklivity/zilla/runtime/binding/risingwave/internal/stream/RisingwaveProxyFactory.java b/incubator/binding-risingwave/src/main/java/io/aklivity/zilla/runtime/binding/risingwave/internal/stream/RisingwaveProxyFactory.java
index 3037753452..5225180c8b 100644
--- a/incubator/binding-risingwave/src/main/java/io/aklivity/zilla/runtime/binding/risingwave/internal/stream/RisingwaveProxyFactory.java
+++ b/incubator/binding-risingwave/src/main/java/io/aklivity/zilla/runtime/binding/risingwave/internal/stream/RisingwaveProxyFactory.java
@@ -17,9 +17,6 @@
import static io.aklivity.zilla.runtime.engine.buffer.BufferPool.NO_SLOT;
import static java.util.Objects.requireNonNull;
-import java.io.InputStreamReader;
-import java.io.Reader;
-import java.io.StringReader;
import java.nio.ByteOrder;
import java.util.ArrayList;
import java.util.LinkedHashMap;
@@ -36,14 +33,16 @@
import org.agrona.collections.LongArrayQueue;
import org.agrona.collections.Object2ObjectHashMap;
import org.agrona.concurrent.UnsafeBuffer;
-import org.agrona.io.DirectBufferInputStream;
+import io.aklivity.zilla.runtime.binding.pgsql.parser.PgsqlParser;
+import io.aklivity.zilla.runtime.binding.pgsql.parser.model.FunctionInfo;
+import io.aklivity.zilla.runtime.binding.pgsql.parser.model.StreamInfo;
+import io.aklivity.zilla.runtime.binding.pgsql.parser.model.TableInfo;
+import io.aklivity.zilla.runtime.binding.pgsql.parser.model.ViewInfo;
import io.aklivity.zilla.runtime.binding.risingwave.internal.RisingwaveConfiguration;
import io.aklivity.zilla.runtime.binding.risingwave.internal.config.RisingwaveBindingConfig;
import io.aklivity.zilla.runtime.binding.risingwave.internal.config.RisingwaveCommandType;
import io.aklivity.zilla.runtime.binding.risingwave.internal.config.RisingwaveRouteConfig;
-import io.aklivity.zilla.runtime.binding.risingwave.internal.statement.RisingwaveCreateTableCommand;
-import io.aklivity.zilla.runtime.binding.risingwave.internal.statement.RisingwaveSqlCommandParser;
import io.aklivity.zilla.runtime.binding.risingwave.internal.types.Flyweight;
import io.aklivity.zilla.runtime.binding.risingwave.internal.types.OctetsFW;
import io.aklivity.zilla.runtime.binding.risingwave.internal.types.String32FW;
@@ -65,10 +64,6 @@
import io.aklivity.zilla.runtime.engine.buffer.BufferPool;
import io.aklivity.zilla.runtime.engine.catalog.CatalogHandler;
import io.aklivity.zilla.runtime.engine.config.BindingConfig;
-import net.sf.jsqlparser.parser.CCJSqlParserManager;
-import net.sf.jsqlparser.statement.Statement;
-import net.sf.jsqlparser.statement.create.function.CreateFunction;
-import net.sf.jsqlparser.statement.create.view.CreateView;
public final class RisingwaveProxyFactory implements RisingwaveStreamFactory
{
@@ -86,10 +81,9 @@ public final class RisingwaveProxyFactory implements RisingwaveStreamFactory
private static final OctetsFW EMPTY_OCTETS = new OctetsFW().wrap(EMPTY_BUFFER, 0, 0);
private static final Consumer EMPTY_EXTENSION = ex -> {};
- private final RisingwaveSqlCommandParser sqlCommandParser = new RisingwaveSqlCommandParser();
- private final CCJSqlParserManager parserManager = new CCJSqlParserManager();
- private final DirectBufferInputStream inputStream = new DirectBufferInputStream(EMPTY_BUFFER);
- private final Reader reader = new InputStreamReader(inputStream);
+ private final PgsqlParser parser = new PgsqlParser();
+ private final List statements = new ArrayList<>();
+ private final StringBuilder currentStatement = new StringBuilder();
private final BeginFW beginRO = new BeginFW();
private final DataFW dataRO = new DataFW();
@@ -731,24 +725,17 @@ private void doParseQuery(
{
final MutableDirectBuffer parserBuffer = bufferPool.buffer(parserSlot);
- int progress = 0;
-
- parse:
- while (progress <= parserSlotOffset)
- {
- final String query = parserBuffer.getStringWithoutLengthUtf8(progress, parserSlotOffset);
- final String statement = sqlCommandParser.detectFirstSQLCommand(query);
- int statementLength = statement != null ? statement.length() : parserSlotOffset;
-
- if (statement != null)
+ String sql = parserBuffer.getStringWithoutLengthAscii(0, parserSlotOffset);
+ splitStatements(sql)
+ .stream()
+ .findFirst()
+ .ifPresent(s ->
{
- final RisingwaveCommandType command = sqlCommandParser.decodeCommandType(statement);
- final PgsqlTransform transform = clientTransforms.get(command);
- transform.transform(this, traceId, authorizationId, parserBuffer, progress, statementLength);
- break parse;
- }
- progress += statementLength;
- }
+ String statement = s;
+ String command = parser.parseCommand(statement);
+ final PgsqlTransform transform = clientTransforms.get(RisingwaveCommandType.valueOf(command.getBytes()));
+ transform.transform(this, traceId, authorizationId, statement);
+ });
}
}
@@ -1497,47 +1484,45 @@ private void decodeCreateTableCommand(
PgsqlServer server,
long traceId,
long authorization,
- DirectBuffer buffer,
- int offset,
- int length)
+ String statement)
{
if (server.commandsProcessed == 6 ||
server.commandsProcessed == COMMAND_PROCESSED_ERRORED)
{
+ final int length = statement.length();
server.onCommandCompleted(traceId, authorization, length, RisingwaveCompletionCommand.CREATE_TABLE_COMMAND);
}
else
{
final RisingwaveBindingConfig binding = server.binding;
- final RisingwaveCreateTableCommand command = binding.createTable.parserCreateTable(buffer, offset, length);
- final String primaryKey = binding.createTable.primaryKey(command.createTable);
+ final TableInfo tableInfo = parser.parseCreateTable(statement);
String newStatement = "";
int progress = 0;
if (server.commandsProcessed == 0)
{
- newStatement = binding.createTopic.generate(command);
+ newStatement = binding.createTopic.generate(tableInfo);
}
else if (server.commandsProcessed == 1)
{
- newStatement = binding.createSource.generateTableSource(server.database, command);
+ newStatement = binding.createSource.generateTableSource(server.database, tableInfo);
}
else if (server.commandsProcessed == 2)
{
- newStatement = binding.createView.generate(command);
+ newStatement = binding.createView.generate(tableInfo);
}
else if (server.commandsProcessed == 3)
{
- newStatement = binding.createTable.generate(command);
+ newStatement = binding.createTable.generate(tableInfo);
}
else if (server.commandsProcessed == 4)
{
- newStatement = binding.createSink.generate(command.createTable);
+ newStatement = binding.createSink.generate(tableInfo);
}
else if (server.commandsProcessed == 5)
{
- newStatement = binding.createSink.generate(server.database, primaryKey, command.createTable);
+ newStatement = binding.createSink.generate(server.database, tableInfo);
}
statementBuffer.putBytes(progress, newStatement.getBytes());
@@ -1556,30 +1541,29 @@ private void decodeCreateStreamCommand(
PgsqlServer server,
long traceId,
long authorization,
- DirectBuffer buffer,
- int offset,
- int length)
+ String statement)
{
if (server.commandsProcessed == 2 ||
server.commandsProcessed == COMMAND_PROCESSED_ERRORED)
{
+ final int length = statement.length();
server.onCommandCompleted(traceId, authorization, length, RisingwaveCompletionCommand.CREATE_STREAM_COMMAND);
}
else
{
final RisingwaveBindingConfig binding = server.binding;
- final RisingwaveCreateTableCommand command = binding.createTable.parserCreateTable(buffer, offset, length);
+ final StreamInfo streamInfo = parser.parseCreateStream(statement);
String newStatement = "";
int progress = 0;
if (server.commandsProcessed == 0)
{
- newStatement = binding.createTopic.generate(command.createTable);
+ newStatement = binding.createTopic.generate(streamInfo);
}
else if (server.commandsProcessed == 1)
{
- newStatement = binding.createSource.generateStreamSource(server.database, command);
+ newStatement = binding.createSource.generateStreamSource(server.database, streamInfo);
}
statementBuffer.putBytes(progress, newStatement.getBytes());
@@ -1598,20 +1582,19 @@ private void decodeCreateMaterializedViewCommand(
PgsqlServer server,
long traceId,
long authorization,
- DirectBuffer buffer,
- int offset,
- int length)
+ String statement)
{
if (server.commandsProcessed == 4 ||
server.commandsProcessed == COMMAND_PROCESSED_ERRORED)
{
+ final int length = statement.length();
server.onCommandCompleted(traceId, authorization, length,
RisingwaveCompletionCommand.CREATE_MATERIALIZED_VIEW_COMMAND);
}
else
{
final RisingwaveBindingConfig binding = server.binding;
- final CreateView statement = (CreateView) parseStatement(buffer, offset, length);
+ final ViewInfo viewInfo = parser.parseCreateMaterializedView(statement);
PgsqlFlushCommand typeCommand = ignoreFlushCommand;
PgsqlDataCommand dataCommand = proxyDataCommand;
@@ -1620,22 +1603,22 @@ private void decodeCreateMaterializedViewCommand(
if (server.commandsProcessed == 0)
{
- newStatement = binding.createView.generate(statement);
+ newStatement = binding.createView.generate(viewInfo);
}
else if (server.commandsProcessed == 1)
{
- newStatement = binding.describeView.generate(statement);
+ newStatement = binding.describeView.generate(viewInfo);
typeCommand = typeFlushCommand;
dataCommand = rowDataCommand;
server.columns.clear();
}
else if (server.commandsProcessed == 2)
{
- newStatement = binding.createTopic.generate(statement, server.columns);
+ newStatement = binding.createTopic.generate(viewInfo, server.columns);
}
else if (server.commandsProcessed == 3)
{
- newStatement = binding.createSink.generate(server.database, server.columns, statement);
+ newStatement = binding.createSink.generate(server.database, server.columns, viewInfo);
}
statementBuffer.putBytes(progress, newStatement.getBytes());
@@ -1656,26 +1639,25 @@ private void decodeCreateFunctionCommand(
PgsqlServer server,
long traceId,
long authorization,
- DirectBuffer buffer,
- int offset,
- int length)
+ String statement)
{
if (server.commandsProcessed == 1 ||
server.commandsProcessed == COMMAND_PROCESSED_ERRORED)
{
+ final int length = statement.length();
server.onCommandCompleted(traceId, authorization, length, RisingwaveCompletionCommand.CREATE_FUNCTION_COMMAND);
}
else
{
final RisingwaveBindingConfig binding = server.binding;
- final CreateFunction statement = (CreateFunction) parseStatement(buffer, offset, length);
+ final FunctionInfo functionInfo = parser.parseCreateFunction(statement);
String newStatement = "";
int progress = 0;
if (server.commandsProcessed == 0)
{
- newStatement = binding.createFunction.generate(statement);
+ newStatement = binding.createFunction.generate(functionInfo);
}
statementBuffer.putBytes(progress, newStatement.getBytes());
@@ -1694,10 +1676,10 @@ private void decodeUnknownCommand(
PgsqlServer server,
long traceId,
long authorization,
- DirectBuffer buffer,
- int offset,
- int length)
+ String statement)
{
+ final int length = statement.length();
+
if (server.commandsProcessed == 1 ||
server.commandsProcessed == COMMAND_PROCESSED_ERRORED)
{
@@ -1705,11 +1687,13 @@ private void decodeUnknownCommand(
}
else
{
+ statementBuffer.putBytes(0, statement.getBytes());
+
final RisingwaveRouteConfig route =
- server.binding.resolve(authorization, buffer, offset, length);
+ server.binding.resolve(authorization, statementBuffer, 0, length);
final PgsqlClient client = server.streamsByRouteIds.get(route.id);
- client.doPgsqlQuery(traceId, authorization, buffer, offset, length);
+ client.doPgsqlQuery(traceId, authorization, statementBuffer, 0, length);
client.completionCommand = proxyFlushCommand;
}
}
@@ -1809,42 +1793,50 @@ private void proxyDataCommand(
server.doAppData(routedId, traceId, authorization, flags, buffer, offset, limit, extension);
}
- private Statement parseStatement(
- DirectBuffer buffer,
- int offset,
- int length)
+ public List splitStatements(
+ String sql)
{
- Statement statement = null;
- try
+ statements.clear();
+ currentStatement.setLength(0);
+
+ boolean inDollarQuotes = false;
+ int length = sql.length();
+ int start = 0;
+
+ for (int i = 0; i < length; i++)
{
- //TODO: Avoid object creation
- String query = buffer.getStringWithoutLengthUtf8(offset, length);
- RisingwaveCommandType commandType = sqlCommandParser.decodeCommandType(query);
- if (commandType.equals(RisingwaveCommandType.CREATE_MATERIALIZED_VIEW_COMMAND))
- {
- String sql = buffer.getStringWithoutLengthUtf8(offset, length);
- // Replace "CREATE MATERIALIZED VIEW" with "CREATE VIEW" for compatibility
- sql = sql.replace("CREATE MATERIALIZED VIEW", "CREATE VIEW");
- // Remove "IF NOT EXISTS" clause because JSqlParser doesn't support it
- sql = sql.replace("IF NOT EXISTS", "");
- statement = parserManager.parse(new StringReader(sql));
- }
- else if (commandType.equals(RisingwaveCommandType.CREATE_FUNCTION_COMMAND))
+ char c = sql.charAt(i);
+
+ if (c == '$' && i + 1 < length && sql.charAt(i + 1) == '$')
{
- query = query.substring(0, query.length() - 1);
- statement = parserManager.parse(new StringReader(query));
+ inDollarQuotes = !inDollarQuotes;
+ i++;
}
- else
+ else if (c == ';' && !inDollarQuotes)
{
- inputStream.wrap(buffer, offset, length);
- statement = parserManager.parse(reader);
+ int j = i + 1;
+ while (j < length && Character.isWhitespace(sql.charAt(j)))
+ {
+ j++;
+ }
+
+ if (j < length && sql.charAt(j) == '\0')
+ {
+ i = j;
+ }
+
+ statements.add(sql.substring(start, i + 1));
+ start = j;
+ i = j - 1;
}
}
- catch (Exception ignored)
+
+ if (start < length)
{
+ statements.add(sql.substring(start, length));
}
- return statement;
+ return statements;
}
@FunctionalInterface
@@ -1854,9 +1846,7 @@ void transform(
PgsqlServer server,
long traceId,
long authorization,
- DirectBuffer writeBuffer,
- int offset,
- int length);
+ String statement);
}
@FunctionalInterface
diff --git a/incubator/binding-risingwave/src/main/moditect/module-info.java b/incubator/binding-risingwave/src/main/moditect/module-info.java
index 77bc6206bd..0155d5c356 100644
--- a/incubator/binding-risingwave/src/main/moditect/module-info.java
+++ b/incubator/binding-risingwave/src/main/moditect/module-info.java
@@ -14,8 +14,8 @@
*/
module io.aklivity.zilla.runtime.binding.risingwave
{
- requires net.sf.jsqlparser;
requires io.aklivity.zilla.runtime.engine;
+ requires io.aklivity.zilla.runtime.binding.pgsql;
exports io.aklivity.zilla.runtime.binding.risingwave.config;
diff --git a/incubator/binding-risingwave/src/test/java/io/aklivity/zilla/runtime/binding/risingwave/internal/statement/RisingwaveCreateFunctionTemplateTest.java b/incubator/binding-risingwave/src/test/java/io/aklivity/zilla/runtime/binding/risingwave/internal/statement/RisingwaveCreateFunctionTemplateTest.java
new file mode 100644
index 0000000000..b0defa56e0
--- /dev/null
+++ b/incubator/binding-risingwave/src/test/java/io/aklivity/zilla/runtime/binding/risingwave/internal/statement/RisingwaveCreateFunctionTemplateTest.java
@@ -0,0 +1,178 @@
+/*
+ * Copyright 2021-2023 Aklivity Inc
+ *
+ * Licensed under the Aklivity Community License (the "License"); you may not use
+ * this file except in compliance with the License. You may obtain a copy of the
+ * License at
+ *
+ * https://www.aklivity.io/aklivity-community-license/
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OF ANY KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations under the License.
+ */
+package io.aklivity.zilla.runtime.binding.risingwave.internal.statement;
+
+import static org.junit.Assert.assertEquals;
+
+import java.util.List;
+
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+import io.aklivity.zilla.runtime.binding.pgsql.parser.model.FunctionArgument;
+import io.aklivity.zilla.runtime.binding.pgsql.parser.model.FunctionInfo;
+import io.aklivity.zilla.runtime.binding.risingwave.config.RisingwaveUdfConfig;
+
+
+public class RisingwaveCreateFunctionTemplateTest
+{
+ private static RisingwaveCreateFunctionTemplate template;
+
+ @BeforeClass
+ public static void setUp()
+ {
+ template = new RisingwaveCreateFunctionTemplate(List.of(
+ RisingwaveUdfConfig.builder().server("http://localhost:8815").language("java").build(),
+ RisingwaveUdfConfig.builder().server("http://localhost:8816").language("python").build()));
+ }
+
+ @Test
+ public void shouldGenerateFunctionWithValidFunctionInfo()
+ {
+ FunctionInfo functionInfo = new FunctionInfo(
+ "test_function",
+ List.of(new FunctionArgument("arg1", "INT")),
+ "INT",
+ List.of(),
+ "test_function",
+ "java");
+ String expectedSQL = """
+ CREATE FUNCTION test_function(arg1 INT)
+ RETURNS INT
+ AS test_function
+ LANGUAGE java
+ USING LINK 'http://localhost:8815';\u0000""";
+
+ String actualSQL = template.generate(functionInfo);
+
+ assertEquals(expectedSQL, actualSQL);
+ }
+
+ @Test
+ public void shouldGenerateFunctionWithTableReturnType()
+ {
+ FunctionInfo functionInfo = new FunctionInfo(
+ "test_function",
+ List.of(new FunctionArgument("arg1", "INT")),
+ "INT",
+ List.of(new FunctionArgument("tab1", "INT")),
+ "test_function",
+ "java");
+
+ String expectedSQL = """
+ CREATE FUNCTION test_function(arg1 INT)
+ RETURNS TABLE (tab1 INT)
+ AS test_function
+ LANGUAGE java
+ USING LINK 'http://localhost:8815';\u0000""";
+
+ String actualSQL = template.generate(functionInfo);
+
+ assertEquals(expectedSQL, actualSQL);
+ }
+
+ @Test
+ public void shouldGenerateFunctionWithTableAsReturnType()
+ {
+ FunctionInfo functionInfo = new FunctionInfo(
+ "test_function",
+ List.of(new FunctionArgument("arg1", "INT")),
+ "INT",
+ List.of(),
+ "test_function",
+ "java");
+
+ String expectedSQL = """
+ CREATE FUNCTION test_function(arg1 INT)
+ RETURNS INT
+ AS test_function
+ LANGUAGE java
+ USING LINK 'http://localhost:8815';\u0000""";
+
+ String actualSQL = template.generate(functionInfo);
+
+ assertEquals(expectedSQL, actualSQL);
+ }
+
+ @Test
+ public void shouldGenerateFunctionWithMultipleArguments()
+ {
+ FunctionInfo functionInfo = new FunctionInfo(
+ "test_function",
+ List.of(new FunctionArgument("arg1", "INT"), new FunctionArgument("arg2", "STRING")),
+ "STRING",
+ List.of(),
+ "test_function",
+ "python");
+
+ String expectedSQL = """
+ CREATE FUNCTION test_function(arg1 INT, arg2 STRING)
+ RETURNS STRING
+ AS test_function
+ LANGUAGE python
+ USING LINK 'http://localhost:8816';\u0000""";
+
+ String actualSQL = template.generate(functionInfo);
+
+ assertEquals(expectedSQL, actualSQL);
+ }
+
+ @Test
+ public void shouldGenerateFunctionWithUnnamedArguments()
+ {
+ FunctionInfo functionInfo = new FunctionInfo(
+ "test_function",
+ List.of(new FunctionArgument(null, "INT"), new FunctionArgument(null, "STRING")),
+ "STRING",
+ List.of(),
+ "test_function",
+ "java");
+
+ String expectedSQL = """
+ CREATE FUNCTION test_function(INT, STRING)
+ RETURNS STRING
+ AS test_function
+ LANGUAGE java
+ USING LINK 'http://localhost:8815';\u0000""";
+
+ String actualSQL = template.generate(functionInfo);
+
+ assertEquals(expectedSQL, actualSQL);
+ }
+
+ @Test
+ public void shouldGenerateFunctionWithEmptyArguments()
+ {
+ FunctionInfo functionInfo = new FunctionInfo(
+ "test_function",
+ List.of(),
+ "VOID",
+ List.of(),
+ "test_function",
+ "python");
+
+ String expectedSQL = """
+ CREATE FUNCTION test_function()
+ RETURNS VOID
+ AS test_function
+ LANGUAGE python
+ USING LINK 'http://localhost:8816';\u0000""";
+
+ String actualSQL = template.generate(functionInfo);
+
+ assertEquals(expectedSQL, actualSQL);
+ }
+
+}
diff --git a/incubator/binding-risingwave/src/test/java/io/aklivity/zilla/runtime/binding/risingwave/internal/statement/RisingwaveCreateMaterializedViewTemplateTest.java b/incubator/binding-risingwave/src/test/java/io/aklivity/zilla/runtime/binding/risingwave/internal/statement/RisingwaveCreateMaterializedViewTemplateTest.java
new file mode 100644
index 0000000000..079d0011f5
--- /dev/null
+++ b/incubator/binding-risingwave/src/test/java/io/aklivity/zilla/runtime/binding/risingwave/internal/statement/RisingwaveCreateMaterializedViewTemplateTest.java
@@ -0,0 +1,93 @@
+/*
+ * Copyright 2021-2023 Aklivity Inc
+ *
+ * Licensed under the Aklivity Community License (the "License"); you may not use
+ * this file except in compliance with the License. You may obtain a copy of the
+ * License at
+ *
+ * https://www.aklivity.io/aklivity-community-license/
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OF ANY KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations under the License.
+ */
+package io.aklivity.zilla.runtime.binding.risingwave.internal.statement;
+
+import static org.junit.Assert.assertEquals;
+
+import java.util.LinkedHashMap;
+import java.util.Map;
+import java.util.Set;
+
+import org.junit.Ignore;
+import org.junit.Test;
+
+import io.aklivity.zilla.runtime.binding.pgsql.parser.model.TableInfo;
+import io.aklivity.zilla.runtime.binding.pgsql.parser.model.ViewInfo;
+
+public class RisingwaveCreateMaterializedViewTemplateTest
+{
+ private final RisingwaveCreateMaterializedViewTemplate template = new RisingwaveCreateMaterializedViewTemplate();
+
+ @Test
+ public void shouldGenerateMaterializedViewWithValidViewInfo()
+ {
+ ViewInfo viewInfo = new ViewInfo("test_view", "SELECT * FROM test_table");
+ String expectedSQL = """
+ CREATE MATERIALIZED VIEW IF NOT EXISTS test_view AS SELECT * FROM test_table;\u0000""";
+
+ String actualSQL = template.generate(viewInfo);
+
+ assertEquals(expectedSQL, actualSQL);
+ }
+
+ @Ignore("TODO")
+ @Test
+ public void shouldGenerateMaterializedViewWithValidTableInfo()
+ {
+ TableInfo tableInfo = new TableInfo(
+ "test_table",
+ Map.of("id", "INT", "name", "STRING"),
+ Set.of("id"));
+ String expectedSQL = """
+ CREATE MATERIALIZED VIEW IF NOT EXISTS test_table_view AS SELECT id, name FROM test_table_source;\u0000""";
+
+ String actualSQL = template.generate(tableInfo);
+
+ assertEquals(expectedSQL, actualSQL);
+ }
+
+ @Test
+ public void shouldGenerateMaterializedViewWithEmptyColumns()
+ {
+ TableInfo tableInfo = new TableInfo("empty_table", Map.of(), Set.of());
+ String expectedSQL = """
+ CREATE MATERIALIZED VIEW IF NOT EXISTS empty_table_view AS SELECT * FROM empty_table_source;\u0000""";
+
+ String actualSQL = template.generate(tableInfo);
+
+ assertEquals(expectedSQL, actualSQL);
+ }
+
+ @Test
+ public void shouldGenerateMaterializedViewWithIncludes()
+ {
+ Map columns = new LinkedHashMap<>();
+ columns.put("id", "INT");
+ columns.put("zilla_correlation_id", "VARCHAR");
+ columns.put("zilla_identity", "VARCHAR");
+ columns.put("zilla_timestamp", "TIMESTAMP");
+
+ TableInfo tableInfo = new TableInfo("test_table", columns, Set.of("id"));
+ String expectedSQL = "CREATE MATERIALIZED VIEW IF NOT EXISTS test_table_view AS SELECT id," +
+ " COALESCE(zilla_correlation_id, zilla_correlation_id_header::varchar) as zilla_correlation_id," +
+ " COALESCE(zilla_identity, zilla_identity_header::varchar) as zilla_identity," +
+ " COALESCE(zilla_timestamp, zilla_timestamp_timestamp::varchar) as zilla_timestamp" +
+ " FROM test_table_source;\u0000";
+
+ String actualSQL = template.generate(tableInfo);
+
+ assertEquals(expectedSQL, actualSQL);
+ }
+}
diff --git a/incubator/binding-risingwave/src/test/java/io/aklivity/zilla/runtime/binding/risingwave/internal/statement/RisingwaveCreateSourceTemplateTest.java b/incubator/binding-risingwave/src/test/java/io/aklivity/zilla/runtime/binding/risingwave/internal/statement/RisingwaveCreateSourceTemplateTest.java
new file mode 100644
index 0000000000..b6f7d8ed11
--- /dev/null
+++ b/incubator/binding-risingwave/src/test/java/io/aklivity/zilla/runtime/binding/risingwave/internal/statement/RisingwaveCreateSourceTemplateTest.java
@@ -0,0 +1,162 @@
+/*
+ * Copyright 2021-2023 Aklivity Inc
+ *
+ * Licensed under the Aklivity Community License (the "License"); you may not use
+ * this file except in compliance with the License. You may obtain a copy of the
+ * License at
+ *
+ * https://www.aklivity.io/aklivity-community-license/
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OF ANY KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations under the License.
+ */
+package io.aklivity.zilla.runtime.binding.risingwave.internal.statement;
+
+import static org.junit.Assert.assertEquals;
+
+import java.util.LinkedHashMap;
+import java.util.Map;
+import java.util.Set;
+
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+import io.aklivity.zilla.runtime.binding.pgsql.parser.model.StreamInfo;
+import io.aklivity.zilla.runtime.binding.pgsql.parser.model.TableInfo;
+
+public class RisingwaveCreateSourceTemplateTest
+{
+ private static RisingwaveCreateSourceTemplate template;
+
+ @BeforeClass
+ public static void setUp()
+ {
+ template = new RisingwaveCreateSourceTemplate("localhost:9092", "http://localhost:8081", 1627846260000L);
+ }
+
+ @Test
+ public void shouldGenerateStreamSourceWithValidStreamInfo()
+ {
+ StreamInfo streamInfo = new StreamInfo("test_stream", Map.of("id", "INT", "name", "STRING"));
+ String expectedSQL = """
+ CREATE SOURCE IF NOT EXISTS test_stream (*)
+ WITH (
+ connector='kafka',
+ properties.bootstrap.server='localhost:9092',
+ topic='test_db.test_stream',
+ scan.startup.mode='latest',
+ scan.startup.timestamp.millis='1627846260000'
+ ) FORMAT PLAIN ENCODE AVRO (
+ schema.registry = 'http://localhost:8081'
+ );\u0000""";
+
+ String actualSQL = template.generateStreamSource("test_db", streamInfo);
+
+ assertEquals(expectedSQL, actualSQL);
+ }
+
+ @Test
+ public void shouldGenerateTableSourceWithValidTableInfoAndIncludes()
+ {
+ Map columns = new LinkedHashMap<>();
+ columns.put("id", "INT");
+ columns.put("zilla_correlation_id", "VARCHAR");
+ columns.put("zilla_identity", "VARCHAR");
+ columns.put("zilla_timestamp", "TIMESTAMP");
+
+ TableInfo tableInfo = new TableInfo(
+ "test_table", columns, Set.of("id"));
+ String expectedSQL = """
+ CREATE SOURCE IF NOT EXISTS test_table_source (*)
+ INCLUDE header 'zilla:correlation-id' AS zilla_correlation_id_header
+ INCLUDE header 'zilla:identity' AS zilla_identity_header
+ INCLUDE timestamp AS zilla_timestamp_timestamp
+ WITH (
+ connector='kafka',
+ properties.bootstrap.server='localhost:9092',
+ topic='test_db.test_table',
+ scan.startup.mode='latest',
+ scan.startup.timestamp.millis='1627846260000'
+ ) FORMAT PLAIN ENCODE AVRO (
+ schema.registry = 'http://localhost:8081'
+ );\u0000""";
+
+ String actualSQL = template.generateTableSource("test_db", tableInfo);
+
+ assertEquals(expectedSQL, actualSQL);
+ }
+
+ @Test
+ public void shouldGenerateStreamSourceWithEmptyColumnsReturnsSQLWithoutIncludes()
+ {
+ StreamInfo streamInfo = new StreamInfo("empty_stream", Map.of());
+ String expectedSQL = """
+ CREATE SOURCE IF NOT EXISTS empty_stream (*)
+ WITH (
+ connector='kafka',
+ properties.bootstrap.server='localhost:9092',
+ topic='test_db.empty_stream',
+ scan.startup.mode='latest',
+ scan.startup.timestamp.millis='1627846260000'
+ ) FORMAT PLAIN ENCODE AVRO (
+ schema.registry = 'http://localhost:8081'
+ );\u0000""";
+
+ String actualSQL = template.generateStreamSource("test_db", streamInfo);
+
+ assertEquals(expectedSQL, actualSQL);
+ }
+
+ @Test
+ public void shouldGenerateStreamSourceWithEmptyColumnsReturnsSQLWithIncludes()
+ {
+ Map columns = new LinkedHashMap<>();
+ columns.put("id", "INT");
+ columns.put("zilla_correlation_id", "VARCHAR");
+ columns.put("zilla_identity", "VARCHAR");
+ columns.put("zilla_timestamp", "TIMESTAMP");
+
+ String expectedSQL = """
+ CREATE SOURCE IF NOT EXISTS include_stream (*)
+ INCLUDE header 'zilla:correlation-id' AS zilla_correlation_id
+ INCLUDE header 'zilla:identity' AS zilla_identity
+ INCLUDE timestamp AS zilla_timestamp
+ WITH (
+ connector='kafka',
+ properties.bootstrap.server='localhost:9092',
+ topic='test_db.include_stream',
+ scan.startup.mode='latest',
+ scan.startup.timestamp.millis='1627846260000'
+ ) FORMAT PLAIN ENCODE AVRO (
+ schema.registry = 'http://localhost:8081'
+ );\u0000""";
+ StreamInfo streamInfo = new StreamInfo("include_stream", columns);
+
+ String actualSQL = template.generateStreamSource("test_db", streamInfo);
+
+ assertEquals(expectedSQL, actualSQL);
+ }
+
+ @Test
+ public void shouldGenerateTableSourceWithEmptyColumnsAndWithoutIncludes()
+ {
+ TableInfo tableInfo = new TableInfo("empty_table", Map.of(), Set.of());
+ String expectedSQL = """
+ CREATE SOURCE IF NOT EXISTS empty_table_source (*)
+ WITH (
+ connector='kafka',
+ properties.bootstrap.server='localhost:9092',
+ topic='test_db.empty_table',
+ scan.startup.mode='latest',
+ scan.startup.timestamp.millis='1627846260000'
+ ) FORMAT PLAIN ENCODE AVRO (
+ schema.registry = 'http://localhost:8081'
+ );\u0000""";
+
+ String actualSQL = template.generateTableSource("test_db", tableInfo);
+
+ assertEquals(expectedSQL, actualSQL);
+ }
+}
diff --git a/incubator/binding-risingwave/src/test/java/io/aklivity/zilla/runtime/binding/risingwave/internal/statement/RisingwaveCreateTableTemplateTest.java b/incubator/binding-risingwave/src/test/java/io/aklivity/zilla/runtime/binding/risingwave/internal/statement/RisingwaveCreateTableTemplateTest.java
new file mode 100644
index 0000000000..231384f573
--- /dev/null
+++ b/incubator/binding-risingwave/src/test/java/io/aklivity/zilla/runtime/binding/risingwave/internal/statement/RisingwaveCreateTableTemplateTest.java
@@ -0,0 +1,96 @@
+/*
+ * Copyright 2021-2023 Aklivity Inc
+ *
+ * Licensed under the Aklivity Community License (the "License"); you may not use
+ * this file except in compliance with the License. You may obtain a copy of the
+ * License at
+ *
+ * https://www.aklivity.io/aklivity-community-license/
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OF ANY KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations under the License.
+ */
+package io.aklivity.zilla.runtime.binding.risingwave.internal.statement;
+
+import static org.junit.Assert.assertEquals;
+
+import java.util.LinkedHashMap;
+import java.util.Map;
+import java.util.Set;
+
+import org.junit.BeforeClass;
+import org.junit.Ignore;
+import org.junit.Test;
+
+import io.aklivity.zilla.runtime.binding.pgsql.parser.model.TableInfo;
+
+public class RisingwaveCreateTableTemplateTest
+{
+ private static RisingwaveCreateTableTemplate template;
+
+ @BeforeClass
+ public static void setUp()
+ {
+ template = new RisingwaveCreateTableTemplate();
+ }
+
+ @Test
+ public void shouldGenerateTableWithValidTableInfo()
+ {
+ Map columns = new LinkedHashMap<>();
+ columns.put("id", "INT");
+ columns.put("name", "STRING");
+
+ TableInfo tableInfo = new TableInfo(
+ "test_table",
+ columns,
+ Set.of("id"));
+ String expectedSQL = """
+ CREATE TABLE IF NOT EXISTS test_table (id INT, name STRING, PRIMARY KEY (id));\u0000""";
+
+ String actualSQL = template.generate(tableInfo);
+
+ assertEquals(expectedSQL, actualSQL);
+ }
+
+ @Test
+ public void shouldGenerateTableWithoutPrimaryKey()
+ {
+ Map columns = new LinkedHashMap<>();
+ columns.put("id", "INT");
+ columns.put("name", "STRING");
+
+ TableInfo tableInfo = new TableInfo(
+ "test_table",
+ columns,
+ Set.of());
+ String expectedSQL = """
+ CREATE TABLE IF NOT EXISTS test_table (id INT, name STRING);\u0000""";
+
+ String actualSQL = template.generate(tableInfo);
+
+ assertEquals(expectedSQL, actualSQL);
+ }
+
+ @Ignore("TODO")
+ @Test
+ public void shouldGenerateTableWithMultiplePrimaryKeys()
+ {
+ Map columns = new LinkedHashMap<>();
+ columns.put("id", "INT");
+ columns.put("name", "STRING");
+
+ TableInfo tableInfo = new TableInfo(
+ "test_table",
+ columns,
+ Set.of("id", "name"));
+ String expectedSQL = """
+ CREATE TABLE IF NOT EXISTS test_table (id INT, name STRING, PRIMARY KEY (id));\u0000""";
+
+ String actualSQL = template.generate(tableInfo);
+
+ assertEquals(expectedSQL, actualSQL);
+ }
+}
diff --git a/pom.xml b/pom.xml
index 7fe8c4d9ca..d4f4318538 100644
--- a/pom.xml
+++ b/pom.xml
@@ -204,11 +204,6 @@
jmh-profilers
0.1.4
-
- com.github.jsqlparser
- jsqlparser
- 5.0
-
io.aklivity.k3po
driver