diff --git a/.gitignore b/.gitignore index 49d0fbf5..a924d2f1 100644 --- a/.gitignore +++ b/.gitignore @@ -6,7 +6,10 @@ tmp # OS X (Mac) .DS_Store -*/gen +*/gen/org/teiid/query/parser/v7/**/*.java +*/gen/org/teiid/query/parser/v8/**/*.java +*/gen/org/teiid/query/sql/lang/**/*.java + **/commandOutput.txt **/_remote.repositories diff --git a/komodo-teiid-client/gen/javacc/Teiid7ClientParser.jjt b/komodo-teiid-client/gen/javacc/Teiid7ClientParser.jjt new file mode 100644 index 00000000..acdfd2f2 --- /dev/null +++ b/komodo-teiid-client/gen/javacc/Teiid7ClientParser.jjt @@ -0,0 +1,4787 @@ +/* +* JBoss, Home of Professional Open Source. +* See the COPYRIGHT.txt file distributed with this work for information +* regarding copyright ownership. Some portions may be licensed +* to Red Hat, Inc. under one or more contributor license agreements. +* +* This library is free software; you can redistribute it and/or +* modify it under the terms of the GNU Lesser General Public +* License as published by the Free Software Foundation; either +* version 2.1 of the License, or (at your option) any later version. +* +* This library is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* Lesser General Public License for more details. +* +* You should have received a copy of the GNU Lesser General Public +* License along with this library; if not, write to the Free Software +* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +* 02110-1301 USA. +*/ + +options { + STATIC = false; + ERROR_REPORTING = true; + JAVA_UNICODE_ESCAPE = true; + UNICODE_INPUT = false; + IGNORE_CASE = true; + MULTI = true; + BUILD_NODE_FILES = false; + NODE_PREFIX = ""; + NODE_SCOPE_HOOK = false; + NODE_USES_PARSER = true; + NODE_PACKAGE = "org.teiid.query.sql.lang"; + VISITOR = false; + VISITOR_RETURN_TYPE = "void"; + GRAMMAR_ENCODING="UTF-8"; + KEEP_LINE_COLUMN = true; + NODE_FACTORY = "TeiidNodeFactory"; +} + +PARSER_BEGIN(Teiid7ClientParser) + +/* +* JBoss, Home of Professional Open Source. +* See the COPYRIGHT.txt file distributed with this work for information +* regarding copyright ownership. Some portions may be licensed +* to Red Hat, Inc. under one or more contributor license agreements. +* +* This library is free software; you can redistribute it and/or +* modify it under the terms of the GNU Lesser General Public +* License as published by the Free Software Foundation; either +* version 2.1 of the License, or (at your option) any later version. +* +* This library is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* Lesser General Public License for more details. +* +* You should have received a copy of the GNU Lesser General Public +* License along with this library; if not, write to the Free Software +* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +* 02110-1301 USA. +*/ +package org.teiid.query.parser.v7; + +import java.math.BigInteger; +import java.util.*; +import java.util.regex.Matcher; +import org.komodo.spi.runtime.version.TeiidVersion; +import org.komodo.spi.runtime.version.DefaultTeiidVersion; +import org.komodo.spi.query.sql.lang.MatchCriteria.MatchMode; +import org.komodo.spi.query.sql.lang.JoinType; +import org.teiid.runtime.client.Messages; +import org.teiid.language.SortSpecification.NullOrdering; +import org.teiid.metadata.Column; +import org.teiid.metadata.BaseColumn.NullType; +import org.teiid.metadata.Table; +import org.teiid.query.parser.AbstractTeiidClientParser; +import org.teiid.query.parser.ParsedDataType; +import org.teiid.query.parser.ParseInfo; +import org.teiid.query.parser.TeiidNodeFactory; +import org.teiid.query.parser.TeiidNodeFactory.ASTNodes; +import org.teiid.query.sql.lang.*; +import org.teiid.query.sql.lang.CriteriaOperator.Operator; +import org.teiid.query.sql.lang.SubqueryCompareCriteriaImpl.PredicateQuantifier; +import org.teiid.query.sql.proc.*; +import org.teiid.query.sql.symbol.*; +import org.teiid.core.types.DefaultDataTypeManager; +import org.teiid.core.util.StringUtil; + +/** + *

The SQLParser is a JavaCC-generated parser that reads a SQL string and produces a + * Query object. The SQLParser.java file is generated by JavaCC from the SQLParser.jj + * file. WARNING: DO NOT MODIFY the SQLParser.java file as it will be + * regenerated from the .jj file and your changes will be lost!

+ */ +@SuppressWarnings({"nls", "unused", "javadoc"}) +public class Teiid7ClientParser extends AbstractTeiidClientParser { + + private String getComment(Token t) { + Token optToken = t.specialToken; + if (optToken == null) { + return ""; //$NON-NLS-1$ + } + + //handle nested comments + String image = optToken.image; + while (optToken.specialToken != null) { + optToken = optToken.specialToken; + image = optToken.image + image; + } + + String hint = image.substring(2, image.length() - 2); + if (hint.startsWith("+")) { //$NON-NLS-1$ + hint = hint.substring(1); + } + + return hint; + } + + private boolean isNonStrictHint(Token t) { + String[] parts = getComment(t).split("\\s"); //$NON-NLS-1$ + for (int i = 0; i < parts.length; i++) { + if (parts[i].equalsIgnoreCase(LimitImpl.NON_STRICT)) { + return true; + } + } + return false; + } + + private SourceHintImpl getSourceHint(Token t) { + String comment = getComment(t); + Matcher matcher = SOURCE_HINT.matcher(comment); + if (!matcher.find()) { + return null; + } + SourceHintImpl sourceHint = new SourceHintImpl(); + String generalHint = matcher.group(1); + if (generalHint != null) { + sourceHint.setGeneralHint(normalizeStringLiteral(generalHint)); + } + int end = matcher.end(); + matcher = SOURCE_HINT_ARG.matcher(comment); + while (matcher.find(end)) { + end = matcher.end(); + sourceHint.setSourceHint(matcher.group(1), normalizeStringLiteral(matcher.group(2)), false); + } + return sourceHint; + } + + private SubqueryHint getSubqueryHint(Token t) { + SubqueryHint hint = new SubqueryHint(); + String[] parts = getComment(t).split("\\s"); //$NON-NLS-1$ + for (int i = 0; i < parts.length; i++) { + if (parts[i].equalsIgnoreCase(SubqueryHint.MJ)) { + hint.setMergeJoin(true); + } else if (parts[i].equalsIgnoreCase(SubqueryHint.NOUNNEST)) { + hint.setNoUnnest(true); + } else if (parts[i].equalsIgnoreCase(SubqueryHint.DJ)) { + hint.setDepJoin(); + } + } + return hint; + } + + private void setFromClauseOptions(Token groupID, FromClauseImpl fromClause){ + String[] parts = getComment(groupID).split("\\s"); //$NON-NLS-1$ + + for (int i = 0; i < parts.length; i++) { + if (parts[i].equalsIgnoreCase(OptionImpl.OPTIONAL)) { + fromClause.setOptional(true); + } else if (parts[i].equalsIgnoreCase(OptionImpl.MAKEDEP)) { + fromClause.setMakeDep(true); + } else if (parts[i].equalsIgnoreCase(OptionImpl.MAKENOTDEP)) { + fromClause.setMakeNotDep(true); + } else if (parts[i].equalsIgnoreCase(FromClauseImpl.MAKEIND)) { + fromClause.setMakeInd(true); + } else if (parts[i].equalsIgnoreCase(SubqueryHint.NOUNNEST)) { + fromClause.setNoUnnest(true); + } + } + } + + /** + * Generate an expression name based on the function type and previous names. + * @param info Parse info, including counts for each function type + * @param functionType Null for expression, the function name for aggregates + * @return New unique function name + */ + private String generateFunctionName(ParseInfo info, String functionType) { + if (functionType == null) { + functionType = "expr"; //$NON-NLS-1$ + } else { + functionType = functionType.toLowerCase(); + } + if (info.nameCounts == null) { + info.nameCounts = new HashMap(); + } + Integer num = info.nameCounts.get(functionType); + if (num == null) { + num = 0; + } + info.nameCounts.put(functionType, num + 1); + return functionType + (num == 0 ? "" : ""+num); //$NON-NLS-1$ //$NON-NLS-2$ + } + + @Override + public TeiidVersion getVersion() { + if (version == null) version = new DefaultTeiidVersion("7.7.x"); + + return version; + } + +} // end class + +PARSER_END(Teiid7ClientParser) + +TOKEN_MGR_DECLS : +{ + int commentNestingDepth; +} + +SKIP : +{ + " " | "\t" | "\n" | "\r" +} + +MORE : +{ + "/*" { commentNestingDepth = 1 ; } : IN_MULTI_LINE_COMMENT +} + + +MORE : +{ + "/*" { commentNestingDepth += 1 ; } +} + + +SPECIAL_TOKEN : +{ + "*/" { + commentNestingDepth -= 1; + SwitchTo( commentNestingDepth==0 ? DEFAULT : IN_MULTI_LINE_COMMENT ) ; + } +} + + +MORE : +{ + < ~[] > +} + +TOKEN: /* Data types */ +{ + +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +} + + +TOKEN: /* Functions with special syntax */ +{ + +| +} + +TOKEN : /* Reserved words */ +{ + +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| + +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +} + +TOKEN : /* SQL/XML Reserved words */ +{ + +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +} + +TOKEN : /* SQL/MED Reserved words */ +{ + +| +| +| +| +| +| +| +| +| +| +| +| +} + +TOKEN : /* User variables and literals */ +{ + < ALL_IN_GROUP: > + +| < ID: ( )* > +| < #QUOTED_ID: | ("\"" (("\"\"") | ~["\""] )+ "\"") > +| < #ID_PART: (("@" | "#" | ) ( | "_" | )*) > + +| < DATETYPE: "{" "d" > +| < TIMETYPE: "{" "t" > +| < TIMESTAMPTYPE: "{" "ts" > +| < BOOLEANTYPE: "{" "b" > +| < POS_REF: ["$"] ()+ > +| < INTEGERVAL: ()?()+ > +| < FLOATVAL: ()? ()* ()+ + ( ["e", "E"] (["+","-"])? ()+ )? > +| < STRINGVAL: (("N"|"E")? "'" ( ("''") | ~["'"] )* "'") > +| < #LETTER: (["a"-"z","A"-"Z"] | ["\u0153"-"\ufffd"]) > +| < #DIGIT: ["0"-"9"] > + +} + +TOKEN : /* Punctuation */ +{ + +| +| +| +| +| +| +| +| "> +| +| "> +| ="> +| +| +| +| +| +| +| +| +| +} + + +//---------------------------------------------------- +//---------------------------------------------------- + +String stringVal() : +{ + Token t = null; +} +{ + (t = ) + { + return normalizeStringLiteral(t.image); + } +} + +String id() : +{ + Token t = null; +} +{ + (t = ) + { + return normalizeId(t.image); + } +} + +/** + * Parse any of several command types - this is the main parser entry point. + * @param info instructions to parse the command + * @return Parsed command + * @throws ParseException if parsing failed + */ +CommandImpl command(ParseInfo info) : +{ + CommandImpl command = null; +} +{ + (LOOKAHEAD(2) command = createUpdateProcedure(info) | + command = userCommand(info) | + command = callableStatement(info) + ) + [] + + { + return command; + } +} + +CommandImpl designerCommand(ParseInfo info) : +{ + CommandImpl command = null; +} +{ + (LOOKAHEAD(2) command = updateProcedure(info) | + command = userCommand(info) + ) + [] + + { + return command; + } +} + +CommandImpl updateProcedure(ParseInfo info) : +{ + CommandImpl command = null; +} +{ + (command = createUpdateProcedure(info) | + command = forEachRowTriggerAction(info)) + + { + return command; + } +} + +CommandImpl createTrigger(ParseInfo info) : +{ + String target = null; + TriggerActionImpl triggerAction = null; + Token event = null; + +} +{ + target = id() nonReserved("INSTEAD") + (event = | event = | event = ) + triggerAction = forEachRowTriggerAction(info) + { + AlterTriggerImpl trigger = alterTrigger(); + trigger.setTarget(groupSymbol(target)); + trigger.setDefinition(triggerAction); + trigger.setEvent(Table.TriggerEvent.valueOf(event.image.toUpperCase())); + trigger.setCreate(true); + return trigger; + } +} + +CommandImpl alter(ParseInfo info) : +{ + String target = null; + QueryCommandImpl command = null; + StatementImpl stmt = null; + TriggerActionImpl triggerAction = null; + Token comment = null; + Token event = null; + String enabled = null; +} +{ + + ( + (nonReserved("VIEW") target = id() { comment = getToken(1).specialToken; } command = queryExpression(info)) + { + /* + * if (comment != null) { + * command.setCacheHint(getQueryCacheOptionImpl(comment.image)); + * } + */ + AlterViewImpl view = alterView(); + view.setTarget(groupSymbol(target)); + view.setDefinition(command); + return view; + } + | ( target = id() { comment = getToken(1).specialToken; } stmt = statement(info)) + { + CreateUpdateProcedureCommandImpl cup = createASTNode(ASTNodes.CREATE_UPDATE_PROCEDURE_COMMAND); + cup.setBlock(asBlock(stmt)); + cup.setUpdateProcedure(false); + /* + * if (comment != null) { + * cup.setCacheHint(getQueryCacheOptionImpl(comment.image)); + * } + */ + AlterProcedureImpl procedure = alterProcedure(); + procedure.setTarget(groupSymbol(target)); + procedure.setDefinition(cup); + return procedure; + } + | ( target = id() nonReserved("INSTEAD") + (event = | event = | event = ) + (( triggerAction = forEachRowTriggerAction(info)) + |enabled = nonReserved("ENABLED","DISABLED"))) + { + AlterTriggerImpl trigger = alterTrigger(); + trigger.setTarget(groupSymbol(target)); + trigger.setDefinition(triggerAction); + trigger.setEvent(Table.TriggerEvent.valueOf(event.image.toUpperCase())); + if (enabled != null) { + trigger.setEnabled(enabled.equalsIgnoreCase("ENABLED")); + } + return trigger; + } + ) +} + +TriggerActionImpl forEachRowTriggerAction(ParseInfo info) #TriggerActionImpl : +{ + BlockImpl b = block(); + b.setAtomic(true); + StatementImpl stmt = null; +} +{ + + ( + LOOKAHEAD(1) ( [] + ( + stmt = statement(info) + { + b.addStatement(stmt); + } + )* + + ) + | + stmt = statement(info) + { + b = asBlock(stmt); + b.setAtomic(true); + } + ) + { + jjtThis.setBlock(b); + return jjtThis; + } +} + +CommandImpl userCommand(ParseInfo info) : +{ + CommandImpl command = null; + SourceHintImpl sourceHint = null; +} +{ + {int index = 1; + Token t = null; + do + t = getToken(index++); + while (t != null && t.kind == LPAREN); + t = getToken(index); + if (t != null) + sourceHint = getSourceHint(t); + } + (command = queryExpression(info) | + command = storedProcedure(info, newStoredProcedure()) | + command = insert(info) | + command = update(info) | + command = delete(info) | + command = dropTable(info) | + LOOKAHEAD(2) command = createTempTable(info) | + command = alter(info) | + command = createTrigger(info) + ) + { + if (sourceHint != null) { +// if (command instanceof SetQueryImpl) { // ((SetQueryImpl)command).getProjectedQueryImpl().setSourceHint(sourceHint); // } else { + command.setSourceHint(sourceHint); +// } + } + return command; + } +} + +/** + * Parse drop table command. + * @param info instructions to parse the command + * @return Parsed command + * @throws ParseException if parsing failed + */ +CommandImpl dropTable(ParseInfo info) #DropImpl : +{ + String table = null; +} +{ + + table = id() + { + jjtThis.setTable(groupSymbol(table)); + return jjtThis; + } +} + +/** + * Parse create temp table command. + * @param info instructions to parse the command + * @return Parsed command + * @throws ParseException if parsing failed + */ +CommandImpl createTempTable(ParseInfo info) #CreateImpl : +{ + String table = null; + String pkId = null; + Column col = null; +} +{ +
+ table = id() + + { + jjtThis.setTable(groupSymbol(table)); + } + col = tableElement(info) + { + jjtThis.getColumns().add(col); + } + (LOOKAHEAD(2) + col = tableElement(info) + { + jjtThis.getColumns().add(col); + } + )* + [ nonReserved("KEY") + pkId = id() + { + jjtThis.getPrimaryKey().add(elementSymbol(validateName(pkId, true))); + } + ( pkId = id() + { + jjtThis.getPrimaryKey().add(elementSymbol(validateName(pkId, true))); + } + )* + + ] + + { + return jjtThis; + } +} + +Column tableElement(ParseInfo info) : +{ + String element = null; + String type = null; + boolean autoIncrement = false; + boolean notNull = false; +} +{ + element = id() + ( + type = dataTypeString() + | + nonReserved("SERIAL") + { + type = "INTEGER"; + autoIncrement = true; + notNull = true; + } + ) + [ { notNull = true; }] + { + try { + Column c = new Column(getVersion()); + c.setName(validateName(element, true)); + c.setRuntimeType(type); + c.setAutoIncremented(autoIncrement); + c.setNullType(notNull?NullType.No_Nulls:NullType.Nullable); + return c; + } catch (Exception ex) { throw new ParseException(ex.getLocalizedMessage()); + } + } +} + +/** + * Parse error statement + * @throws ParseException if parsing failed + */ +RaiseErrorStatementImpl errorStatement(ParseInfo info) : +{ + BaseExpression errMsg = null; +} +{ + + errMsg = expression(info) + + { + RaiseErrorStatementImpl errStmt = raiseErrorStatement(errMsg); + return errStmt; + } +} + +RaiseErrorStatementImpl raiseErrorStatement(BaseExpression expression) #RaiseErrorStatementImpl : +{ +} +{ + { + jjtThis.setExpression(expression); + return jjtThis; + } +} + +/** + * Parse statement + * @throws ParseException if parsing failed + */ +StatementImpl statement(ParseInfo info) : +{ + StatementImpl statement; + String label = null; +} +{ + ( + LOOKAHEAD(2) ([label = id() ] + ( + statement = loopStatement(info) | + statement = whileStatement(info) | + statement = compoundStatement(info) + ) + { + ((Labeled) statement).setLabel(label); + } + ) + | + ( + statement = ifStatement(info) | + statement = delimitedStatement(info) + ) + ) + + { + return statement; + } +} + +StatementImpl delimitedStatement(ParseInfo info) : +{ + StatementImpl stmt = null; +} +{ + (LOOKAHEAD(3) stmt = assignStatement(info) | + stmt = sqlStatement(info) | + stmt = errorStatement(info) | + stmt = declareStatement(info) | + stmt = branchingStatement(info) + ) + + { + return stmt; + } +} + +BlockImpl compoundStatement(ParseInfo info) : +{ + StatementImpl stmt = null; + BlockImpl block = block(); + Boolean atomic = null; +} +{ + [[ {atomic = Boolean.FALSE;}] {if (atomic == null) {atomic = Boolean.TRUE;}}] + ( + stmt = statement(info) + { + block.addStatement(stmt); + } + )* + + { + if (atomic != null) { + block.setAtomic(atomic); + } + return block; + } +} + +/** + * Parse break statement + * @throws ParseException if parsing failed + */ +BranchingStatementImpl branchingStatement(ParseInfo info) #BranchingStatementImpl : +{ + Token mode = null; + String label = null; +} +{ + ( + ( + (mode = | mode = ) [label = id()] + ) + | + (mode = label = id()) + ) + { + jjtThis.setMode(BranchingStatementImpl.BranchingMode.valueOf(mode.image.toUpperCase())); + jjtThis.setLabel(label); + return jjtThis; + } +} + +/** + * Parse while statement + * @throws ParseException if parsing failed + */ +WhileStatementImpl whileStatement(ParseInfo info) #WhileStatementImpl : +{ + CriteriaImpl criteria = null; + StatementImpl stmt = null; +} +{ + + + criteria = criteria(info) + + stmt = statement(info) + { + jjtThis.setCondition(criteria); + jjtThis.setBlock(asBlock(stmt)); + return jjtThis; + } +} + +/** + * Parse loop statement + * @throws ParseException if parsing failed + */ +LoopStatementImpl loopStatement(ParseInfo info) #LoopStatementImpl : +{ + String cursor = null; + QueryCommandImpl query = null; + StatementImpl stmt = null; +} +{ + + + + query = queryExpression(info) + + + cursor = id() + stmt = statement(info) + { + jjtThis.setBlock(asBlock(stmt)); + jjtThis.setCommand(query); + jjtThis.setCursorName(cursor); + return jjtThis; + } +} + +/** + * Parse if statement + * @throws ParseException if parsing failed + */ +IfStatementImpl ifStatement(ParseInfo info) #IfStatementImpl : +{ + CriteriaImpl criteria = null; + StatementImpl ifStatement = null; + StatementImpl elseStatement = null; +} +{ + + + criteria = criteria(info) + + ifStatement = statement(info) + //else blocks will be associated with the closest if block + [LOOKAHEAD(1) elseStatement = statement(info)] + { + jjtThis.setCondition(criteria); + jjtThis.setIfBlock(asBlock(ifStatement)); + jjtThis.setElseBlock(asBlock(elseStatement)); + return jjtThis; + } +} + +/** + * Parse criteria selector + * @throws ParseException if parsing failed + */ +CriteriaSelectorImpl criteriaSelector() #CriteriaSelectorImpl : +{ + String element = null; + List elements = new ArrayList(2); + Token operator = null; +} +{ + [(operator = | + operator = | + operator = | + operator = | + operator = | + operator = | + operator = | + operator = | + operator = | + (operator = ) | + operator = ) + { + jjtThis.setSelectorType(Operator.getOperator(getVersion(), operator.image)); + } + ] + + + + [LOOKAHEAD(4) + + + element = id() + + { + elements.add(elementSymbol(element)); + } + + ( + element = id() + + { + elements.add(elementSymbol(element)); + } + )* + + + { + jjtThis.setElements(elements); + } + ] + + { + return jjtThis; + } +} + +/** + * Parse has criteria + * @throws ParseException + */ +HasCriteriaImpl hasCriteria() #HasCriteriaImpl : +{ + CriteriaSelectorImpl critSelector = null; +} +{ + + critSelector = criteriaSelector() + + { + jjtThis.setSelector(critSelector); + return jjtThis; + } +} + +/** + * Parse declare statement + * @throws ParseException if parsing failed + */ +DeclareStatementImpl declareStatement(ParseInfo info) #DeclareStatementImpl : +{ + String var = null; + ConstantImpl type = null; + ElementSymbolImpl variableID = null; + BaseLanguageObject value = null; +} +{ + + type = dataType() + var = id() + { + variableID = elementSymbol(var); + } + [(nonReserved(":=")|) + value = assignStatementOperand(info) + ] + + { + jjtThis.setVariable(variableID); + jjtThis.setVariableType((String) type.getValue()); + if (value instanceof BaseExpression) { + jjtThis.setExpression((BaseExpression)value); + } + else if (value instanceof QueryCommandImpl) { + jjtThis.setExpression(scalarSubquery((QueryCommandImpl)value)); + } + else { + jjtThis.setCommand((CommandImpl)value); + } + + return jjtThis; + } +} + +/** + * Parse assignment statement + * @throws ParseException if parsing failed + */ +AssignmentStatementImpl assignStatement(ParseInfo info) : +{ + BaseLanguageObject value = null; + String var = null; + ElementSymbolImpl elementID = null; +} +{ + var = id() + { + elementID = elementSymbol(var); + } + (nonReserved(":=")|) + value = assignStatementOperand(info) + + { + return assignmentStatement(elementID, value); + } +} + +/** + * Parse operand of assignment statement, which can be nested + * arbitrarily deeply in parentheses. + * @throws ParseException if parsing failed + */ +BaseLanguageObject assignStatementOperand(ParseInfo info) : +{ + BaseLanguageObject value = null; +} +{ + + ( + LOOKAHEAD() (value = insert(info)) | //deprecated + value = update(info) | //deprecated + value = delete(info) | //deprecated + LOOKAHEAD(expression(info)) (value = expression(info)) | + value = queryExpression(info) //deprecated should be a scalar subquery + ) + + { + return value; + } +} + +/** + * Parse sql statement + * @throws ParseException if parsing failed + */ +CommandStatementImpl sqlStatement(ParseInfo info) #CommandStatementImpl : +{ + CommandImpl cmd = null; + String var = null; + ElementSymbolImpl elementID = null; + StoredProcedureImpl storedProcedure = null; +} +{ + (LOOKAHEAD(2) (cmd = userCommand(info)) | + cmd = dynamicCommand(info) | + ( + var = id() + { + storedProcedure = newStoredProcedure(); + elementID = elementSymbol(var); + SPParameterImpl parameter = new SPParameterImpl(this, 1, SPParameterImpl.RETURN_VALUE, "return"); //$NON-NLS-1$ + parameter.setExpression(elementID); + storedProcedure.addParameter(parameter); + storedProcedure.setCalledWithReturn(true); + } + (nonReserved(":=")|) + cmd = storedProcedure(info, storedProcedure) + ) + ) + + { + jjtThis.setCommand(cmd); + return jjtThis; + } +} + +TranslateCriteriaImpl translateCriteria(ParseInfo info) #TranslateCriteriaImpl : +{ + String element = null; + BaseExpression value = null; + ElementSymbolImpl leftSymbol = null; + + CriteriaSelectorImpl critSelector = null; + + CompareCriteriaImpl compCrit = null; + + List critList = null; +} +{ + + + critSelector = criteriaSelector() + + [ + { + critList = new ArrayList(2); + } + + element = id() + + value = expression(info) + { + compCrit = createASTNode(ASTNodes.COMPARE_CRITERIA); + leftSymbol = elementSymbol(element); + compCrit.setLeftExpression(leftSymbol); + compCrit.setRightExpression(value); + compCrit.setOperator(Operator.EQ); + critList.add(compCrit); + compCrit = null; + } + ( + element = id() + + value = expression(info) + { + compCrit = createASTNode(ASTNodes.COMPARE_CRITERIA); + leftSymbol = elementSymbol(element); + compCrit.setLeftExpression(leftSymbol); + compCrit.setRightExpression(value); + compCrit.setOperator(Operator.EQ); + critList.add(compCrit); + compCrit = null; + } + )* + + ] + + { + jjtThis.setSelector(critSelector); + + if ( critList != null) { + jjtThis.setTranslations(critList); + } + + return jjtThis; + } +} + +/** + * Parse create update procedure command + * @throws ParseException if parsing failed + */ +CreateUpdateProcedureCommandImpl createUpdateProcedure(ParseInfo info) #CreateUpdateProcedureCommandImpl : +{ + StatementImpl stmt = null; +} +{ + [ {jjtThis.setUpdateProcedure(false);}] + [] + + + stmt = statement(info) + { + jjtThis.setBlock(asBlock(stmt)); + return jjtThis; + } +} + +/** + * Parse error statement + * @throws ParseException if parsing failed + */ +DynamicCommandImpl dynamicCommand(ParseInfo info) #DynamicCommandImpl : +{ + BaseExpression sql = null; + String groupID = null; + GroupSymbolImpl group = null; + int updateCount = 0; + Token updateToken = null; + List elements = null; + SetClauseListImpl using = null; + SetClauseListImpl setClauseList = null; +} +{ + (|) [(|)] + sql = expression(info) + { + jjtThis.setSql(sql); + } + [ + elements = createElementsWithTypes(info) + + [ + groupID = id() + { + group = groupSymbol(groupID); + } + ] + { + jjtThis.setIntoGroup(group); + List symbols = new ArrayList(elements.size()); + for (ProjectedColumnImpl col : elements) { + symbols.add(col.getSymbol()); + } + jjtThis.setAsColumns(symbols); + jjtThis.setAsClauseSet(true); + } + ] + [ + using = setClauseList(true, info) + { + jjtThis.setUsing(using); + } + ] + [ + ((updateToken = ) + { + updateCount = Integer.parseInt(updateToken.image); + } + | + () + { + updateCount = 2; + }) + ] + { + jjtThis.setUpdatingModelCount(updateCount); + return jjtThis; + } +} + +SetClauseListImpl setClauseList(boolean shortName, ParseInfo info) #SetClauseListImpl : +{ + String element = null; + String symbolName = null; + ElementSymbolImpl symbol = null; + BaseExpression value = null; +} +{ + element = id() + + { + try { + symbolName = shortName?validateName(element, true):element; + symbol = elementSymbol(symbolName); + value = expression(info); + jjtThis.addClause(setClause(symbol, value)); + } catch (Exception ex) { + throw new ParseException(ex.getLocalizedMessage()); + } + } + ( + element = id() + + { + try { + symbolName = shortName?validateName(element, true):element; + symbol = elementSymbol(symbolName); + value = expression(info); + jjtThis.addClause(setClause(symbol, value)); + } catch (Exception ex) { + throw new ParseException(ex.getLocalizedMessage()); + } + } + )* + { + return jjtThis; + } +} + +SetClauseImpl setClause(ElementSymbolImpl symbol, BaseExpression value) #SetClauseImpl : +{ +} +{ + { + jjtThis.setSymbol(symbol); + jjtThis.setValue(value); + return jjtThis; + } +} + +/** + * Create elements with datatypes + * @throws ParseException if parsing failed + */ +List createElementsWithTypes(ParseInfo info) : +{ + String element = null; + String type = null; + ProjectedColumnImpl symbol = null; + List elements = new ArrayList(); +} +{ + element = id() + type = dataTypeString() + { + try { + symbol = projectedColumn(validateName(element, true), type); + elements.add(symbol); + } catch (Exception ex) { throw new ParseException(ex.getLocalizedMessage()); + } + } + (LOOKAHEAD(2) + element = id() + type = dataTypeString() + { + try { + symbol = projectedColumn(validateName(element, true), type); + elements.add(symbol); + } catch (Exception ex) { + throw new ParseException(ex.getLocalizedMessage()); + } + } + )* + { + return elements; + } +} + +ProjectedColumnImpl projectedColumn(String name, String type) #ProjectedColumnImpl : +{ +} +{ + { + jjtThis.setName(name); + jjtThis.setType(type); + return jjtThis; + } +} + +StoredProcedureImpl callableStatement(ParseInfo info) : +{ + StoredProcedureImpl storedProcedure = newStoredProcedure(); + storedProcedure.setCallableStatement(true); + Token call = null; + String procName = null; + OptionImpl option = null; + SPParameterImpl parameter = null; + int parameterIndex = 1; +} +{ + + [ + { + parameter = new SPParameterImpl(this, parameterIndex++, SPParameterImpl.RETURN_VALUE, "return"); //$NON-NLS-1$ + storedProcedure.addParameter(parameter); + storedProcedure.setCalledWithReturn(true); + } + ] + procName = id() + { + storedProcedure.setProcedureName(procName); + } + + //parameters + + [ + + ( + storedProcedure = executeUnnamedParams(info, storedProcedure, parameterIndex) + ) + + ] + + [option = option(info) + { + storedProcedure.setOption(option); + } + ] + + { + return storedProcedure; + } +} + + +/** + * * Parse stored query command + * @throws ParseException if parsing failed + */ +StoredProcedureImpl storedProcedure(ParseInfo info, StoredProcedureImpl storedProcedure) : +{ + String procName = null; + OptionImpl option = null; +} +{ + ( + ( | | ) + procName = id() + { + storedProcedure.setProcedureName(procName); + } + + //parameters + + + ( + LOOKAHEAD( ) + storedProcedure = executeNamedParams(info, storedProcedure) + | + storedProcedure = executeUnnamedParams(info, storedProcedure, storedProcedure.getParameterCount() + 1) + ) + + + ) + [option = option(info) + { + storedProcedure.setOption(option); + } + ] + { + return storedProcedure; + } +} + +StoredProcedureImpl newStoredProcedure() #StoredProcedureImpl : +{ +} +{ + { + return jjtThis; + } +} + +/** + *

Parse an exec statement with unnamed parameters

+ * @throws ParseException if parsing failed + */ +StoredProcedureImpl executeUnnamedParams(ParseInfo info, StoredProcedureImpl storedProcedure, int parameterIndex) : +{ + SPParameterImpl parameter = null; + BaseExpression value = null; +} +{ + + (value = expression(info) + { + parameter = new SPParameterImpl(this, parameterIndex++, value); + parameter.setParameterType(SPParameterImpl.IN); + storedProcedure.addParameter(parameter); + } + ( + value = expression(info) + { + parameter = new SPParameterImpl(this, parameterIndex++, value); + parameter.setParameterType(SPParameterImpl.IN); + storedProcedure.addParameter(parameter); + } + )* + )? + { + return storedProcedure; + } +} + +/** + *

Parse an exec statement with named parameters

+ * @throws ParseException if parsing failed + */ +StoredProcedureImpl executeNamedParams(ParseInfo info, StoredProcedureImpl storedProcedure) : +{ + String name = null; + BaseExpression value = null; + SPParameterImpl parameter = null; + int parameterIndex = 1; +} +{ + { + storedProcedure.setDisplayNamedParameters(true); + } + (name=id() + [] + value = expression(info) + { + parameter = new SPParameterImpl(this, parameterIndex++, value); + parameter.setName(name); + parameter.setParameterType(SPParameterImpl.IN); + storedProcedure.addParameter(parameter); + parameter = null; + } + ( + name=id() + [] + value = expression(info) + { + parameter = new SPParameterImpl(this, parameterIndex++, value); + parameter.setName(name); + parameter.setParameterType(SPParameterImpl.IN); + storedProcedure.addParameter(parameter); + parameter = null; + } + )* + ) + { + + return storedProcedure; + } +} + +/** + * Parse an INSERT command + * @return Parsed insert statement + * @throws ParseException if parsing failed + */ +InsertImpl insert(ParseInfo info) #InsertImpl : +{ + String group = null; + List values = null; + List columns = null; + OptionImpl option = null; + QueryCommandImpl query = null; +} +{ + + group = id() + + [LOOKAHEAD() columns = columnList(false) { + jjtThis.setVariables(columns); + }] + + ( + ( + values = expressionList(info) + + { + // Store each row of values + jjtThis.setValues(values); + } + ) + | + ( query = queryExpression(info) + { + jjtThis.setQueryExpression(query); + } + ) + ) + + [ option = option(info) + { + jjtThis.setOption(option); + } + ] + + { + // Store group + jjtThis.setGroup(groupSymbol(group) ); + + return jjtThis; + } +} + +List columnList(boolean validate) : +{ + String element = null; + List symbols = new LinkedList(); +} +{ + + element = id() + { + if (validate) { + try { + element = validateName(element, true); + } catch (Exception ex) { + throw new ParseException(ex.getLocalizedMessage()); + } + } + symbols.add(elementSymbol(element)); + } + ( + element = id() + { + if (validate) { + try { + element = validateName(element, true); + } catch (Exception ex) { + throw new ParseException(ex.getLocalizedMessage()); + } + } + symbols.add(elementSymbol(element)); + } + )* + + { + return symbols; + } +} + +/** + * Parse row values - this is a comma separated list of values. + * @return List of values, never null + * @throws ParseException if parsing failed + */ +ArrayList expressionList(ParseInfo info) : +{ + ArrayList rowVals = new ArrayList(4); + BaseExpression value = null; +} +{ + value = expression(info) + { + rowVals.add(value); + } + ( + value = expression(info) + { + rowVals.add(value); + } + )* + { + return rowVals; + } +} + +/** + * Parse an UPDATE command + * @return Parsed update statement + * @throws ParseException if parsing failed + */ +UpdateImpl update(ParseInfo info) #UpdateImpl : +{ + String group = null; + SetClauseListImpl setClauseList = null; + CriteriaImpl criteria = null; + OptionImpl option = null; +} +{ + + group = id() + + setClauseList = setClauseList(false, info) + { + jjtThis.setChangeList(setClauseList); + } + [ criteria = where(info) ] + [option = option(info) + { + jjtThis.setOption(option); + } + ] + { + // Store group + jjtThis.setGroup(groupSymbol( group) ); + + // Store optional criteria + if(criteria != null) { + jjtThis.setCriteria(criteria); + } + + return jjtThis; + } +} + + +/** + * Parse a DELETE command + * @return Parsed delete statement + * @throws ParseException if parsing failed + */ +DeleteImpl delete(ParseInfo info) #DeleteImpl : +{ + String group = null; + CriteriaImpl criteria = null; + OptionImpl option = null; +} +{ + + group = id() + [criteria = where(info)] + [option = option(info) + { + jjtThis.setOption(option); + } + ] + { + jjtThis.setGroup(groupSymbol(group)); + jjtThis.setCriteria(criteria); + + return jjtThis; + } +} + +QueryCommandImpl queryExpression(ParseInfo info) : +{ + QueryCommandImpl queryCommand = null; + List withList = null; + WithQueryCommandImpl withQueryCommand = null; +} +{ + [ withQueryCommand = withListElement(info) + { + withList = new LinkedList(); + withList.add(withQueryCommand); + } + ( + withQueryCommand = withListElement(info) + { + withList.add(withQueryCommand); + } + )* + ] + queryCommand = queryExpressionBody(info) + { + queryCommand.setWith(withList); + return queryCommand; + } +} + +WithQueryCommandImpl withListElement(ParseInfo info) #WithQueryCommandImpl : +{ + String name = null; + List columns = null; + QueryCommandImpl queryExpression = null; +} +{ + name = id() + [ columns = columnList(true)] + queryExpression = queryExpression(info) + { + try { + jjtThis.setGroupSymbol(groupSymbol(validateName(name, false))); + } catch (Exception ex) { + throw new ParseException(ex.getLocalizedMessage()); + } + jjtThis.setColumns(columns); + jjtThis.setQueryExpression(queryExpression); + return jjtThis; + } +} + +QueryCommandImpl queryExpressionBody(ParseInfo info) : +{ + QueryCommandImpl query = null; + QueryCommandImpl rightQueryImpl = null; + boolean all = false; + OptionImpl option = null; + OrderByImpl orderby = null; + LimitImpl limit = null; + SetQueryImpl.Operation type; +} +{ + query = queryTerm(info) + ( (LOOKAHEAD( , { getToken(2).kind != JOIN } ) { type = SetQueryImpl.Operation.UNION; } | { type = SetQueryImpl.Operation.EXCEPT; }) + [ { all = true; } | ] + rightQueryImpl = queryTerm(info) + { + query = setQuery(type, all, query, rightQueryImpl); + all = false; + } + ) * + [orderby = orderby(info) {query.setOrderBy( orderby );}] + [limit = limit(info) {query.setLimit( limit );}] + [LOOKAHEAD(
name=id() { + MultipleElementSymbolImpl multipleElementSymbol = createASTNode(ASTNodes.MULTIPLE_ELEMENT_SYMBOL); + + SelectImpl select = createASTNode(ASTNodes.SELECT); + select.setSymbols(Arrays.asList(multipleElementSymbol)); + + UnaryFromClauseImpl unaryFromClauseImpl = createASTNode(ASTNodes.UNARY_FROM_CLAUSE); + unaryFromClauseImpl.setGroup(groupSymbol(name)); + + FromImpl from = createASTNode(ASTNodes.FROM); + from.setClauses(Arrays.asList(unaryFromClauseImpl)); + + QueryImpl q = createASTNode(ASTNodes.QUERY); + q.setSelect(select); + q.setFrom(from); + query = q; + }) | + ( query=queryExpressionBody(info) ) + ) + { + return query; + } +} + +/** + * Parse a SELECT query + * @return Parsed query + * @throws ParseException if parsing failed + */ +QueryImpl query(ParseInfo info) #QueryImpl : +{ + SelectImpl select = null; + FromImpl from = null; + IntoImpl into = null; + CriteriaImpl criteria = null; + GroupByImpl groupBy = null; + CriteriaImpl having = null; +} +{ + select = select(info) + [into = into(info)] + [from = from(info) + + [criteria = where(info)] + [groupBy = groupBy(info)] + [having = having(info)]] + + { + // Build query from parsed pieces + jjtThis.setSelect( select ); + jjtThis.setFrom( from ); + jjtThis.setInto( into ); + jjtThis.setCriteria(criteria); + jjtThis.setGroupBy(groupBy); + jjtThis.setHaving(having); + + return jjtThis; + } +} + +IntoImpl into(ParseInfo info) #IntoImpl : +{ + String groupID = null; +} +{ + + (groupID=id()) + { + jjtThis.setGroup(groupSymbol(groupID)); + return jjtThis; + } +} + +/** + *

Parse a SELECT clause. The select must handle elements, aliased elements + * (x AS y), group.*, and *. It also must handle an optional DISTINCT at the + * beginning of the select list. It also must handle a scalar subquery expression + * in parentheses.

+ *

Example: "SELECT group.element, group2.element2 AS x, group3.*".

+ *

Example: "SELECT *".

+ *

Example: "SELECT DISTINCT a, b, c".

+ *

Example: "SELECT a, (SELECT b FROM groupC)".

+ *

Example: "SELECT a, (SELECT b FROM groupC) as d".

+ * @return Parsed select + * @throws ParseException if parsing failed + */ +SelectImpl select(ParseInfo info) #SelectImpl : +{ + boolean isDistinct = false; // unless DISTINCT keyword in SELECT + BaseExpression symbol = null; +} +{ +
{ table = true; } + ] + lparen = + ( command = queryExpression(info) | + command = storedProcedure(info, newStoredProcedure()) ) + + [] + aliasID = id() + + { + try { + jjtThis.setName(validateName(aliasID, false)); + } catch (Exception ex) { + throw new ParseException(ex.getLocalizedMessage()); + } + jjtThis.setCommand(command); + setFromClauseOptions(lparen, jjtThis); + jjtThis.setTable(table); + return jjtThis; + } +} + +/** + * Parse a unary from clause, which is just a single group name and an optional alias. + * @return Unary from clause containing the group + * @throws ParseException if parsing failed + */ +UnaryFromClauseImpl unaryFromClauseImpl(ParseInfo info) #UnaryFromClauseImpl : +{ + GroupSymbolImpl group = null; + Token groupID = null; + String aliasID = null; + UnaryFromClauseImpl clause = null; +} +{ + (groupID= [[] aliasID=id()]) + { + if(aliasID != null) { + try { + group = groupSymbol(validateName(aliasID, false), normalizeId(groupID.image)); + } catch (Exception ex) { + throw new ParseException(ex.getLocalizedMessage()); + } + } else { + group = groupSymbol(normalizeId(groupID.image)); + } + jjtThis.setGroup(group); + setFromClauseOptions(groupID, jjtThis); + return jjtThis; + } +} + +/** + *

Parse a WHERE clause. The where clause holds a criteria. + * @return Parsed where + * @throws ParseException if parsing failed + */ +CriteriaImpl where(ParseInfo info) : +{ + CriteriaImpl criteria = null; +} +{ + + criteria = criteria(info) + + { + return criteria; + } +} + +/** + *

Parse a criteria. This will parse any criteria expression.

+ * @return Parsed criteria + * @throws ParseException if parsing failed + */ +CriteriaImpl criteria(ParseInfo info) #CriteriaImpl : +{ +} +{ + jjtThis = compoundCritOr(info) + + { + return jjtThis; + } +} + +/** + *

Parse a compound logical OR criteria.

+ * @return Parsed OR criteria + * @throws ParseException if parsing failed + */ +CriteriaImpl compoundCritOr(ParseInfo info) : +{ + ArrayList logicList = new ArrayList(2); + CriteriaImpl logicPart = null; +} +{ + logicPart=compoundCritAnd(info) { logicList.add(logicPart); } + ( logicPart=compoundCritAnd(info) { logicList.add(logicPart); } )* + + { + if(logicList.size() == 1) { + return (CriteriaImpl) logicList.get(0); + } else { + CompoundCriteriaImpl cc = createASTNode(ASTNodes.COMPOUND_CRITERIA); + cc.setOperator(CompoundCriteriaImpl.OR); + cc.setCriteria(logicList); + return cc; + } + } +} + +/** + *

Parse a compound logical AND criteria.

+ * @return Parsed AND criteria + * @throws ParseException if parsing failed + */ +CriteriaImpl compoundCritAnd(ParseInfo info) #CompoundCriteriaImpl : +{ + ArrayList logicList = new ArrayList(2); + CriteriaImpl logicPart = null; +} +{ + logicPart=notCrit(info) { logicList.add(logicPart); } + ( logicPart=notCrit(info) { logicList.add(logicPart); } )* + + { + if(logicList.size() == 1) { + return (CriteriaImpl) logicList.get(0); + } else { + jjtThis.setOperator(CompoundCriteriaImpl.AND); + jjtThis.setCriteria(logicList); + return jjtThis; + } + } +} + +/** + *

Parse a logical NOT criteria.

+ * @return Parsed NOT criteria + * @throws ParseException if parsing failed + */ +CriteriaImpl notCrit(ParseInfo info) #NotCriteriaImpl : +{ + BaseExpression ex = null; + boolean isNot = false; +} +{ + [ {isNot=true;}] + ex=booleanPrimary(info) + + { + CriteriaImpl crit = null; + if (ex instanceof CriteriaImpl) { + crit = (CriteriaImpl)ex; + } else { + crit = expressionCriteria(ex); + } + if(isNot) { + jjtThis.setCriteria(crit); + return jjtThis; + } else { + return crit; + } + } +} + +/** + *

Parse a boolean primary.

+ * @return criteria + * @throws ParseException if parsing failed + */ +BaseExpression booleanPrimary(ParseInfo info) : +{ + BaseExpression ex = null; +} +{ + ( + LOOKAHEAD(2) ex = translateCriteria(info) + | + (ex = commonValueExpression(info) + [( + LOOKAHEAD(2) ex=betweenCrit(info, ex) | + LOOKAHEAD(2) ex=matchCrit(info, ex) | + LOOKAHEAD(2) ex=regexMatchCrit(info, ex) | + ex=setCrit(info, ex) | + ex=isNullCrit(info, ex) | + LOOKAHEAD(operator() (||) subquery(info)) ex=subqueryCompareCriteria(info, ex) | + ex=compareCrit(info, ex) + )] + ) + | + ex=existsCriteria(info) | + ex = hasCriteria() + ) + { + return ex; + } +} + +Token operator() : +{ + Token operator = null; +} +{ + (operator= | + operator= | + operator= | + operator= | + operator= | + operator= | + operator= + ) + { + return operator; + } +} + + +/** + *

Parse a compare criteria.

+ * @return Parsed compare criteria + * @throws ParseException if parsing failed + */ +CompareCriteriaImpl compareCrit(ParseInfo info, BaseExpression expression) #CompareCriteriaImpl : +{ + BaseExpression value = null; + Token operator = null; +} +{ + operator=operator() + value=commonValueExpression(info) + + { + // Set left expression + jjtThis.setLeftExpression(expression); + + jjtThis.setOperator(Operator.getOperator(getVersion(), operator.image)); + + // Set value + jjtThis.setRightExpression(value); + + return jjtThis; + } +} + +QueryCommandImpl subquery(ParseInfo info) : +{ + QueryCommandImpl subquery = null; + StoredProcedureImpl proc = null; +} +{ + + ( subquery = queryExpression(info) | + ( + proc = storedProcedure(info, newStoredProcedure()) //deprecated + ) + { + MultipleElementSymbolImpl multipleElementSymbol = createASTNode(ASTNodes.MULTIPLE_ELEMENT_SYMBOL); + + SelectImpl select = createASTNode(ASTNodes.SELECT); + select.setSymbols(Arrays.asList(multipleElementSymbol)); + + SubqueryFromClauseImpl subqueryFromClauseImpl = createASTNode(ASTNodes.SUBQUERY_FROM_CLAUSE); + subqueryFromClauseImpl.setName("x"); + subqueryFromClauseImpl.setCommand(proc); + + FromImpl from = createASTNode(ASTNodes.FROM); + from.setClauses(Arrays.asList(subqueryFromClauseImpl)); + + QueryImpl query = createASTNode(ASTNodes.QUERY); + query.setSelect(select); + query.setFrom(from); + subquery = query; + } + ) + + { + return subquery; + } +} + +Object[] subqueryAndHint(ParseInfo info) : +{ + QueryCommandImpl subquery = null; + Token lparen = null; +} +{ + {lparen = getToken(1);} + subquery = subquery(info) + { + return new Object[] {subquery, getSubqueryHint(lparen)}; + } +} + +/** + *

Parse a subquery compare criteria.

+ * @return Parsed subquery compare criteria + * @throws ParseException if parsing failed + */ +SubqueryCompareCriteriaImpl subqueryCompareCriteria(ParseInfo info, BaseExpression expression) #SubqueryCompareCriteriaImpl : +{ + SubqueryCompareCriteriaImpl subqueryCrit = null; + QueryCommandImpl subquery = null; + Token operator = null; + Token quantifier = null; + +} +{ + operator=operator() + ( quantifier= | + quantifier= | + quantifier= + ) + subquery = subquery(info) + + { + jjtThis.setLeftExpression(expression); + jjtThis.setCommand(subquery); + + // Set operator + jjtThis.setOperator(Operator.getOperator(getVersion(), operator.image)); + + // Set predicate quantifier + if(quantifier.image.equalsIgnoreCase("any")) { //$NON-NLS-1$ + jjtThis.setPredicateQuantifier(PredicateQuantifier.ANY); + } else if(quantifier.image.equalsIgnoreCase("some")) { //$NON-NLS-1$ + jjtThis.setPredicateQuantifier(PredicateQuantifier.SOME); + } else if(quantifier.image.equalsIgnoreCase("all")) { //$NON-NLS-1$ + jjtThis.setPredicateQuantifier(PredicateQuantifier.ALL); + } + + return jjtThis; + } +} + +/** + *

Parse a match criteria. Also parses JDBC escape syntax for match criteria.

+ * @return Parsed match criteria + * @throws ParseException if parsing failed + */ +MatchCriteriaImpl matchCrit(ParseInfo info, BaseExpression expression) #MatchCriteriaImpl : +{ + Character esc = null; + BaseExpression value = null; + boolean negated = false; + boolean similar = false; +} +{ + [ {negated = true;}] + (|( {similar = true;})) + value=commonValueExpression(info) + [ esc = charVal(info, "LIKE/SIMILAR TO ESCAPE") | + ( esc = charVal(info, "LIKE/SIMILAR TO ESCAPE") ) + ] + { + jjtThis.setLeftExpression(expression); + jjtThis.setRightExpression(value); + jjtThis.setNegated(negated); + if(esc != null) { + jjtThis.setEscapeChar(esc.charValue()); + } + jjtThis.setMode(similar?MatchMode.SIMILAR:MatchMode.LIKE); + return jjtThis; + } +} + +MatchCriteriaImpl regexMatchCrit(ParseInfo info, BaseExpression expression) : +{ + BaseExpression value = null; + boolean negated = false; +} +{ + [ {negated = true;}] + + value=commonValueExpression(info) + { + MatchCriteriaImpl matchCriteria = createASTNode(ASTNodes.MATCH_CRITERIA); + matchCriteria.setLeftExpression(expression); + matchCriteria.setRightExpression(value); + matchCriteria.setNegated(negated); + matchCriteria.setMode(MatchMode.REGEX); + return matchCriteria; + } +} + +Character charVal(ParseInfo info, String type) : +{ + String escStr = null; +} +{ + escStr=stringVal() + { + if (escStr.length() != 1) { + throw new ParseException(Messages.getString(Messages.TeiidParser.char_val)); + } + return Character.valueOf(escStr.charAt(0)); + } +} + +/** + *

Parse an [NOT] BETWEEN criteria.

+ * @return Parsed BETWEEN criteria + * @throws ParseException if parsing failed + */ +BetweenCriteriaImpl betweenCrit(ParseInfo info, BaseExpression expression) #BetweenCriteriaImpl : +{ + BaseExpression lowerExpression = null, upperExpression = null; + boolean negated = false; +} +{ + [ {negated=true;}] + + lowerExpression = commonValueExpression(info) + + upperExpression = commonValueExpression(info) + + { + jjtThis.setExpression(expression); + jjtThis.setLowerExpression(lowerExpression); + jjtThis.setUpperExpression(upperExpression); + jjtThis.setNegated(negated); + return jjtThis; + } +} + +/** + *

Parse an IS [NOT] NULL criteria.

+ * @return Parsed IS NULL criteria + * @throws ParseException if parsing failed + */ +IsNullCriteriaImpl isNullCrit(ParseInfo info, BaseExpression expression) #IsNullCriteriaImpl : +{ + boolean negated = false; +} +{ + + [ {negated = true;}] + + + { + jjtThis.setExpression(expression); + jjtThis.setNegated(negated); + return jjtThis; + } +} + +/** + *

Parse a set criteria.

+ * @return Parsed set criteria + * @throws ParseException if parsing failed + */ +AbstractSetCriteria setCrit(ParseInfo info, BaseExpression expression) : +{ + AbstractSetCriteria criteria = null; + BaseExpression value = null; + List setList = new ArrayList(); + Object[] command = null; + boolean negated = false; +} +{ + [ {negated = true;}] + + ( + LOOKAHEAD(subquery(info)) (command = subqueryAndHint(info)) | + ( + + value = commonValueExpression(info) + { + setList.add(value); + } + ( + value = commonValueExpression(info) + { + setList.add(value); + } + )* + + ) + ) + { + if (command != null) { + SubquerySetCriteriaImpl ssc = subquerySetCriteriaImpl(expression, (QueryCommandImpl)command[0]); + ssc.setSubqueryHint((SubqueryHint)command[1]); + criteria = ssc; + } else { + criteria = setCriteria(expression, setList); + } + criteria.setNegated(negated); + return criteria; + } +} + +SubquerySetCriteriaImpl subquerySetCriteriaImpl(BaseExpression expression, QueryCommandImpl command) #SubquerySetCriteriaImpl : +{ +} +{ + { + jjtThis.setExpression(expression); + jjtThis.setCommand(command); + return jjtThis; + } +} + +SetCriteriaImpl setCriteria(BaseExpression expression, List values) #SetCriteriaImpl : +{ +} +{ + { + jjtThis.setExpression(expression); + jjtThis.setValues(values); + return jjtThis; + } +} + +/** + *

Parse an exists criteria.

+ * @return Parsed exists criteria + * @throws ParseException if parsing failed + */ +ExistsCriteriaImpl existsCriteria(ParseInfo info) #ExistsCriteriaImpl : +{ + Object[] subquery = null; +} +{ + + subquery = subqueryAndHint(info) + + { + jjtThis.setCommand((QueryCommandImpl) subquery[0]); + jjtThis.setSubqueryHint((SubqueryHint) subquery[1]); + return jjtThis; + } +} + +/** + *

Parse a GROUP BY clause.

+ * @return Parsed group by + * @throws ParseException if parsing failed + */ +GroupByImpl groupBy(ParseInfo info) #GroupByImpl : +{ + List expressions = null; +} +{ + + expressions = expressionList(info) + { + jjtThis.setSymbols(expressions); + return jjtThis; + } +} + +/** + *

Parse a HAVING clause.

+ * @return Parsed having + * @throws ParseException if parsing failed + */ +CriteriaImpl having(ParseInfo info) : +{ + CriteriaImpl criteria = null; +} +{ + + criteria = criteria(info) + { + return criteria; + } +} + + +/** + *

Parse an ORDER BY clause.

+ * @return Parsed ORDER BY + * @throws ParseException if parsing failed + */ +OrderByImpl orderby(ParseInfo info) #OrderByImpl : +{ + OrderByItemImpl item = null; +} +{ + + item = sortSpecification(info) + { + jjtThis.getOrderByItems().add(item); + } + ( + item = sortSpecification(info) + { + jjtThis.getOrderByItems().add(item); + } + )* + { + return jjtThis; + } +} + +OrderByItemImpl sortSpecification(ParseInfo info) #OrderByItemImpl : +{ + SingleElementSymbol ex = null; + boolean ascending = true; + String nullOrdering = null; +} +{ + ex=sortKey(info) + [ | {ascending=false;}] + [nonReserved("NULLS") nullOrdering = nonReserved("FIRST", "LAST")] + { + jjtThis.setSymbol(ex); + jjtThis.setAscending(ascending); + if (nullOrdering != null) { + jjtThis.setNullOrdering(NullOrdering.valueOf(nullOrdering.toUpperCase())); + } + return jjtThis; + } +} + +SingleElementSymbol sortKey(ParseInfo info) : +{ + BaseExpression ex = null; +} +{ + ex=expression(info) + { + //legacy support check for positional constants + if (ex instanceof ConstantImpl) { + boolean valid = false; + ConstantImpl c = (ConstantImpl)ex; + if (c.getValue() instanceof Integer) { + Integer val = (Integer)c.getValue(); + valid = val.intValue() > 0; + } + if (!valid) { + throw new ParseException(Messages.getString(Messages.TeiidParser.non_position_constant, ex)); + } + } + if(ex instanceof ElementSymbolImpl) { + return (ElementSymbolImpl)ex; + } + String exprName = generateFunctionName(info, null); + ExpressionSymbolImpl es = expressionSymbol(); + es.setName(exprName); + es.setExpression(ex); + return es; + } +} + +ExpressionSymbolImpl expressionSymbol() #ExpressionSymbolImpl : +{ +} +{ + { + return jjtThis; + } +} + +BaseExpression intParam(ParseInfo info) : +{ + Integer val = null; +} +{ + (val = intVal() | ) + { + if (val == null) { + return reference(info.incrementReferenceCount()); + } + return constant(val, DefaultDataTypeManager.DefaultDataTypes.INTEGER); + } +} + +/** + *

Parse an LIMIT clause.

+ * @return Parsed LIMIT + * @throws ParseException if parsing failed + */ +LimitImpl limit(ParseInfo info) #LimitImpl : +{ + BaseExpression limit = null; + BaseExpression offset = null; + Token t = null; +} +{ + {t = getToken(1);} + (( offset = intParam(info) + [ limit = intParam(info)]) + { + if (limit == null) { + limit = offset; + offset = null; + } + } + | + ( offset = intParam(info) (|) + [limit = fetchLimitImpl(info)]) + | + (limit = fetchLimitImpl(info))) + { + jjtThis.setOffset(offset); + jjtThis.setRowLimit(limit); + jjtThis.setStrict(!isNonStrictHint(t)); + return jjtThis; + } +} + +BaseExpression fetchLimitImpl(ParseInfo info) : +{ + BaseExpression limit = null; +} +{ + nonReserved("FIRST", "NEXT") [limit = intParam(info)] (|) + { + if (limit == null) { + return constant(1, DefaultDataTypeManager.DefaultDataTypes.INTEGER); + } + return limit; + } +} + +/** + *

Parse an OPTION clause.

+ * @return Parsed OPTION clause + * @throws ParseException if parsing failed + */ +OptionImpl option(ParseInfo info) #OptionImpl : +{ + String id = null; + Token nocache = null; +} +{ +
+ table = id(null) + { + jjtThis.setTable(groupSymbol(table)); + return jjtThis; + } +} + +/* +name=create temporary table +description=Creates a temporary table. +example={code:sql}CREATE LOCAL TEMPORARY TABLE tmp (col integer){code} +*/ +CommandImpl createTempTable(ParseInfo info) #CreateImpl : +{ + String table = null; + String pkId = null; + Column col = null; + List pk = null; + boolean localToken = false; +} +{ + + [ + { + localToken = true; + } + ] + + + { + if(! localToken) + // LOCAL is only optional for Teiid 8.5+ requiresVersionAtLeast(Version.TEIID_8_5); + } +
+ table = id(null) + + { + jjtThis.setTable(groupSymbol(table)); + } + col = tableElement(info) + { + jjtThis.getColumns().add(col); + } + (LOOKAHEAD(2) + col = tableElement(info) + { + jjtThis.getColumns().add(col); + } + )* + [ + pk = columnList(true, true) + { + jjtThis.getPrimaryKey().addAll(pk); + } + ] + + { + return jjtThis; + } +} + +/* +name=temporary table element +description=Defines a temporary table column. +example={code:sql}col string NOT NULL{code} +*/ +Column tableElement(ParseInfo info) : +{ + String element = null; + ParsedDataType type = null; + boolean autoIncrement = false; + //TODO: once we support udts, then this will need to inherit the nullability from the type + boolean notNull = false; +} +{ + element = id(Boolean.TRUE) + ( + type = parseDataType() + | + + { + type = new ParsedDataType("INTEGER"); + autoIncrement = true; + notNull = true; + } + ) + [ { notNull = true; }] + { + Column c = new Column(getVersion()); + c.setName(element); + c.setRuntimeType(type.getType()); + c.setAutoIncremented(autoIncrement); + c.setNullType(notNull?NullType.No_Nulls:NullType.Nullable); + return c; + } +} + +/* +name=raise error statement +description=Raises an error with the given message. +example={code:sql}ERROR 'something went wrong'{code} +*/ +RaiseStatementImpl errorStatement(ParseInfo info) : +{ + BaseExpression errMsg = null; +} +{ + + errMsg = expression(info) + + { + ExceptionExpressionImpl ee = exceptionExpression(); + ee.setMessage(errMsg); + return raiseStatementFromExpression(ee); + } +} + +/* +name=raise statement +description=Raises an error or warning with the given message. +example={code:sql}RAISE SQLEXCEPTION 'something went wrong'{code} +*/ +RaiseStatementImpl raiseStatement(ParseInfo info) : +{ + RaiseStatementImpl stmt = null; + BaseExpression err = null; + boolean warning = false; +} +{ + + [ {warning = true;}] + err = exceptionReference(info) + { + stmt = raiseStatementFromExpression(err); + stmt.setWarning(warning); + return stmt; + } +} + +RaiseStatementImpl raiseStatementFromExpression(BaseExpression expression) #RaiseStatementImpl : +{ +} +{ + { + jjtThis.setExpression(expression); + return jjtThis; + } +} + +/* +name=exception reference +description=a reference to an exception +example={code:sql}SQLEXCEPTION 'something went wrong' SQLSTATE '00X', 2{code} +*/ +BaseExpression exceptionReference(ParseInfo info) : +{ + String id = null; + BaseExpression ex; +} +{ + id = id(null) {return elementSymbol(id);} + | + ex = exception(info) + { + return ex; + } +} + +/* +name=sql exception +description=creates a sql exception or warning with the specified message, state, and code +example={code:sql}SQLEXCEPTION 'something went wrong' SQLSTATE '00X', 2{code} +*/ +BaseExpression exception(ParseInfo info) : +{ + BaseExpression err = null; + BaseExpression sqlState = null; + BaseExpression errCode = null; + BaseExpression parent = null; +} +{ + + err = commonValueExpression(info) + [ sqlState = commonValueExpression(info) + [ errCode = commonValueExpression(info)] + ] + [ parent = exceptionReference(info)] + { + ExceptionExpressionImpl ee = exceptionExpression(); + ee.setMessage(err); + ee.setSqlState(sqlState); + ee.setErrorCode(errCode); + ee.setParent(parent); + return ee; + } +} + +ExceptionExpressionImpl exceptionExpression() #ExceptionExpressionImpl : +{ +} +{ + { + return jjtThis; + } +} + +/* +name=statement +description=A procedure statement. +example={code:sql}IF (x = 5) BEGIN ... END{code} +*/ +StatementImpl statement(ParseInfo info) : +{ + StatementImpl stmt; + String label = null; +} +{ + ( + LOOKAHEAD(2) ([label = id(null) ] + ( + stmt = loopStatement(info) | + stmt = whileStatement(info) | + stmt = compoundStatement(info) + ) + { + ((Labeled)stmt).setLabel(label); + } + ) + | + ( + stmt = ifStatement(info) | + stmt = delimitedStatement(info) + ) + ) + + { + return stmt; + } +} + +/* +name=delimited statement +description=A procedure statement terminated by ;. +example={code:sql}SELECT * FROM tbl;{code} +*/ +StatementImpl delimitedStatement(ParseInfo info) : +{ + StatementImpl stmt = null; +} +{ + (LOOKAHEAD(2) stmt = assignStatement(info) | + stmt = sqlStatement(info) | + stmt = errorStatement(info) | + stmt = raiseStatement(info) | + stmt = declareStatement(info) | + stmt = branchingStatement(info) | + stmt = returnStatement(info) + ) + + { + return stmt; + } +} + +/* +name=compound statement +description=A procedure statement block contained in BEGIN END. +example={code:sql}BEGIN NOT ATOMIC ... END{code} +*/ +BlockImpl compoundStatement(ParseInfo info) : +{ + StatementImpl stmt = null; + BlockImpl block = block(); + Boolean atomic = null; + String eId = null; +} +{ + [[ {atomic = Boolean.FALSE;}] {if (atomic == null) {atomic = Boolean.TRUE;}}] + (LOOKAHEAD(2) + stmt = statement(info) + { + block.addStatement(stmt, false); + } + )* + [ eId = id(Boolean.FALSE) {block.setExceptionGroup(eId);} + ( + stmt = statement(info) + { + block.addStatement(stmt, true); + } + )* + ] + + { + if (atomic != null) { + block.setAtomic(atomic); + } + return block; + } +} + +/* +name=branching statement +description=A procedure branching control statement, which typically specifies a label to return control to. +example={code:sql}BREAK x{code} +*/ +BranchingStatementImpl branchingStatement(ParseInfo info) #BranchingStatementImpl : +{ + Token mode = null; + String label = null; +} +{ + ( + ( + (mode = | mode = ) [label = id(null)] + ) + | + (mode = label = id(null)) + ) + { + jjtThis.setMode(BranchingStatementImpl.BranchingMode.valueOf(mode.image.toUpperCase())); + jjtThis.setLabel(label); + return jjtThis; + } +} + +/* +name=return statement +description=A return statement. +example={code:sql}RETURN 1{code} +*/ +ReturnStatementImpl returnStatement(ParseInfo info) #ReturnStatementImpl : +{ + BaseExpression ex = null; +} +{ + [ex = expression(info)] + { + jjtThis.setExpression(ex); + return jjtThis; + } +} + +/* +name=while statement +description=A procedure while statement that executes until its condition is false. +example={code:sql}WHILE (var) BEGIN ... END{code} +*/ +WhileStatementImpl whileStatement(ParseInfo info) #WhileStatementImpl : +{ + CriteriaImpl criteria = null; + StatementImpl stmt = null; +} +{ + + + criteria = criteria(info) + + stmt = statement(info) + { + jjtThis.setCondition(criteria); + jjtThis.setBlock(asBlock(stmt)); + return jjtThis; + } +} + +/* +name=loop statement +description=A procedure loop statement that executes over the given cursor. +example={code:sql}LOOP ON (SELECT * FROM tbl) AS x BEGIN ... END{code} +*/ +LoopStatementImpl loopStatement(ParseInfo info) #LoopStatementImpl : +{ + String cursor = null; + QueryCommandImpl query = null; + StatementImpl stmt = null; +} +{ + + + + query = queryExpression(info) + + + cursor = id(null) + stmt = statement(info) + { + jjtThis.setBlock(asBlock(stmt)); + jjtThis.setCommand(query); + jjtThis.setCursorName(cursor); + return jjtThis; + } +} + +/* +name=if statement +description=A procedure loop statement that executes over the given cursor. +example={code:sql}IF (boolVal) BEGIN variables.x = 1 END ELSE BEGIN variables.x = 2 END{code} +*/ +IfStatementImpl ifStatement(ParseInfo info) #IfStatementImpl : +{ + CriteriaImpl criteria = null; + StatementImpl ifStatement = null; + StatementImpl elseStatement = null; +} +{ + + + criteria = criteria(info) + + ifStatement = statement(info) + //else blocks will be associated with the closest if block + [LOOKAHEAD(1) elseStatement = statement(info)] + { + jjtThis.setCondition(criteria); + jjtThis.setIfBlock(asBlock(ifStatement)); + jjtThis.setElseBlock(asBlock(elseStatement)); + return jjtThis; + } +} + +/* +name=declare statement +description=A procedure declaration statement that creates a variable and optionally assigns a value. +example={code:sql}DECLARE STRING x = 'a'{code} +*/ +DeclareStatementImpl declareStatement(ParseInfo info) #DeclareStatementImpl : +{ + String var = null; + ParsedDataType type = null; + ElementSymbolImpl variableID = null; + BaseLanguageObject value = null; +} +{ + + (type = parseDataType() | {type = new ParsedDataType(getToken(0).image);}) + var = id(null) + { + variableID = elementSymbol(var); + } + [ + value = assignStatementOperand(info) + ] + + { + jjtThis.setVariable(variableID); + jjtThis.setVariableType(type.getType()); + if (value instanceof BaseExpression) { + jjtThis.setExpression((BaseExpression)value); + } + else if (value instanceof QueryCommandImpl) { + jjtThis.setExpression(scalarSubquery((QueryCommandImpl)value)); + } + else { + jjtThis.setCommand((CommandImpl)value); + } + + return jjtThis; + } +} + +/* +name=assignment statement +description=Assigns a variable a value in a procedure. +example={code:sql}x = 'b'{code} +*/ +StatementImpl assignStatement(ParseInfo info) : +{ + BaseLanguageObject value = null; + String var = null; + ElementSymbolImpl elementID = null; + boolean returnable=true; +} +{ + var = id(null) + { + elementID = elementSymbol(var); + } + + (value = assignStatementOperand(info) | + (value = storedProcedure(info, 2) [(| {returnable = false;}) ]) { + StoredProcedureImpl storedProcedure = (StoredProcedureImpl)value; + SPParameterImpl parameter = new SPParameterImpl(this, 1, SPParameterImpl.RETURN_VALUE, "return"); //$NON-NLS-1$ + parameter.setExpression(elementID); + storedProcedure.addParameter(parameter); + storedProcedure.setCalledWithReturn(true); + CommandStatementImpl cs = createASTNode(ASTNodes.COMMAND_STATEMENT); + cs.setCommand(storedProcedure); + cs.setReturnable(returnable); + return cs; + } + ) + + { + return assignmentStatement(elementID, value); + } +} + +/* +name=assignment statement operand +description=A value or command that can be used in an assignment. {note}All assigments except for expression are deprecated.{note} +*/ +BaseLanguageObject assignStatementOperand(ParseInfo info) : +{ + BaseLanguageObject value = null; +} +{ + ( + LOOKAHEAD() (value = insert(info)) | //deprecated + value = update(info) | //deprecated + value = delete(info) | //deprecated + LOOKAHEAD(1) value = expression(info) | + value = queryExpression(info) | //deprecated should be a scalar subquery + value = exception(info) + ) + { + return value; + } +} + +/* +name=data statement +description=A procedure statement that executes a SQL statement. An update statement can have its update count accessed via the ROWCOUNT variable. +*/ +CommandStatementImpl sqlStatement(ParseInfo info) #CommandStatementImpl : +{ + CommandImpl cmd = null; + String var = null; + ElementSymbolImpl elementID = null; + StoredProcedureImpl storedProcedure = null; + boolean returnable = true; +} +{ + (LOOKAHEAD(2) cmd = userCommand(info) | + cmd = dynamicCommand(info) + ) [(| {returnable = false;}) ] + + { + jjtThis.setCommand(cmd); + jjtThis.setReturnable(returnable); + return jjtThis; + } +} + +/* +unused=true +*/ +CreateProcedureCommandImpl createProcedure(ParseInfo info) # CreateProcedureCommandImpl : +{ + StatementImpl stmt = null; +} +{ + [] + stmt = statement(info) + { + jjtThis.setBlock(asBlock(stmt)); + return jjtThis; + } +} + +/* +name=procedure body definition +description=Defines a procedure body on a Procedure metadata object. +example={code:sql}BEGIN ... END{code} // Teiid 8.5+ +example={code:sql}CREATE VIRTUAL PROCEDURE BEGIN ... END{code} Teiid 8.4- +index=true +*/ +CreateProcedureCommandImpl procedureBodyCommand(ParseInfo info) : +{ + CreateProcedureCommandImpl procCmd = createASTNode(ASTNodes.CREATE_PROCEDURE_COMMAND); + StatementImpl stmt = null; +} +{ + [LOOKAHEAD(2) [] ] + stmt = statement(info) + { + procCmd.setBlock(asBlock(stmt)); + return procCmd; + } +} + +/* +name=dynamic data statement +description=A procedure statement that can execute arbitrary sql. +example={code:sql}EXECUTE IMMEDIATE 'SELECT * FROM tbl' AS x STRING INTO #temp{code} +*/ +DynamicCommandImpl dynamicCommand(ParseInfo info) #DynamicCommandImpl : +{ + BaseExpression sql = null; + String groupID = null; + GroupSymbolImpl group = null; + int updateCount = 0; + List elements = null; + SetClauseListImpl using = null; + SetClauseListImpl setClauseList = null; +} +{ + (|) [(|)] + sql = expression(info) + { + jjtThis.setSql(sql); + } + [ + elements = createElementsWithTypes(info) + + [ + groupID = id(null) + { + group = groupSymbol(groupID); + } + ] + { + jjtThis.setIntoGroup(group); + List symbols = new ArrayList(elements.size()); + for (ProjectedColumnImpl col : elements) { + symbols.add(col.getSymbol()); + } + jjtThis.setAsColumns(symbols); + jjtThis.setAsClauseSet(true); + } + ] + [ + using = setClauseList(true, info) + { + jjtThis.setUsing(using); + } + ] + [ + (updateCount = intVal() + | + + { + updateCount = 2; + }) + ] + { + jjtThis.setUpdatingModelCount(updateCount); + return jjtThis; + } +} + +/* +name=set clause list +description=A list of value assignments. +example={code:sql}col1 = 'x', col2 = 'y' ...{code} +*/ +SetClauseListImpl setClauseList(boolean shortName, ParseInfo info) #SetClauseListImpl : +{ + String element = null; + BaseExpression value = null; +} +{ + element = id(shortName?Boolean.TRUE:null) + + value = expression(info) + { + ElementSymbolImpl symbol = elementSymbol(element); + jjtThis.addClause(setClause(symbol, value)); + } + ( + element = id(null) + + value = expression(info) + { + symbol = elementSymbol(element); + jjtThis.addClause(setClause(symbol, value)); + } + )* + { + return jjtThis; + } +} + +SetClauseImpl setClause(ElementSymbolImpl symbol, BaseExpression value) #SetClauseImpl : +{ +} +{ + { + jjtThis.setSymbol(symbol); + jjtThis.setValue(value); + return jjtThis; + } +} + +/* +name=typed element list +description=A list of typed elements. +example={code:sql}col1 string, col2 integer ...{code} +*/ +List createElementsWithTypes(ParseInfo info) : +{ + String element = null; + ParsedDataType type = null; + List elements = new ArrayList(); +} +{ + element = id(Boolean.TRUE) + type = parseDataType() + { + ProjectedColumnImpl symbol = projectedColumn(element, type.getType()); + elements.add(symbol); + } + (LOOKAHEAD(2) + element = id(Boolean.TRUE) + type = parseDataType() + { + symbol = projectedColumn(element, type.getType()); + elements.add(symbol); + } + )* + { + return elements; + } +} + +ProjectedColumnImpl projectedColumn(String name, String type) #ProjectedColumnImpl : +{ +} +{ + { + jjtThis.setName(name); + jjtThis.setType(type); + return jjtThis; + } +} + +/* +name=callable statement +description=A callable statement defined using JDBC escape syntax. +example={code:sql}{? = CALL proc}{code} +index=true +*/ +StoredProcedureImpl callableStatement(ParseInfo info) : +{ + StoredProcedureImpl storedProcedure = newStoredProcedure(); + storedProcedure.setCallableStatement(true); + String procName = null; + OptionImpl option = null; + SPParameterImpl parameter = null; + int parameterIndex = 1; + List values = null; +} +{ + + [ + { + parameter = new SPParameterImpl(this, parameterIndex++, SPParameterImpl.RETURN_VALUE, "return"); //$NON-NLS-1$ + storedProcedure.addParameter(parameter); + storedProcedure.setCalledWithReturn(true); + } + ] + procName = id(null) + { + storedProcedure.setProcedureName(procName); + } + + //parameters + + [ + (LOOKAHEAD(2) + executeNamedParams(info, storedProcedure, parameterIndex) + | + [values = expressionList(info) { convertToParameters(values, storedProcedure, parameterIndex); }] + ) + + ] + + [option = option(info) + { + storedProcedure.setOption(option); + } + ] + + { + return storedProcedure; + } +} + +/* +name=call statement +description=Executes the procedure with the given parameters. +example={code:sql}CALL proc('a', 1){code} +*/ +StoredProcedureImpl storedProcedure(ParseInfo info, int startIndex) : +{ + String procName = null; + OptionImpl option = null; + List values = null; + StoredProcedureImpl storedProcedure = newStoredProcedure(); + SourceHintImpl sourceHint = null; +} +{ + { if (versionAtLeast(Version.TEIID_8_4)) sourceHint = getSourceHint(this); } + ( + ( | | ) + procName = id(null) + { + storedProcedure.setProcedureName(procName); + } + + //parameters + + + ( + LOOKAHEAD(2) + executeNamedParams(info, storedProcedure, startIndex) + | + [values = expressionList(info) { convertToParameters(values, storedProcedure, startIndex); }] + ) + + + ) + [option = option(info) + { + storedProcedure.setOption(option); + } + ] + { + if (versionAtLeast(Version.TEIID_8_4)) + storedProcedure.setSourceHint(sourceHint); + + return storedProcedure; + } +} + +StoredProcedureImpl newStoredProcedure() #StoredProcedureImpl : +{ +} +{ + { + return jjtThis; + } +} + +/* +name=named parameter list +description=A list of named parameters. +example={code:sql}param1 => 'x', param2 => 1{code} +*/ +void executeNamedParams(ParseInfo info, StoredProcedureImpl storedProcedure, int parameterIndex) : +{ + String name = null; + BaseExpression value = null; + SPParameterImpl parameter = null; +} +{ + { + storedProcedure.setDisplayNamedParameters(true); + } + (name=id(null) + [] + value = expression(info) + { + parameter = new SPParameterImpl(this, parameterIndex++, value); + parameter.setName(name); + parameter.setParameterType(SPParameterImpl.IN); + storedProcedure.addParameter(parameter); + parameter = null; + } + ( + name=id(null) + [] + value = expression(info) + { + parameter = new SPParameterImpl(this, parameterIndex++, value); + parameter.setName(name); + parameter.setParameterType(SPParameterImpl.IN); + storedProcedure.addParameter(parameter); + parameter = null; + } + )* + ) +} + +/* +name=insert statement +description=Inserts values into the given target. +example={code:sql}INSERT INTO tbl (col1, col2) VALUES ('a', 1){code} +*/ +InsertImpl insert(ParseInfo info) #InsertImpl : +{ + boolean merge = false; + String group = null; + List values = null; + List columns = null; + OptionImpl option = null; + QueryCommandImpl query = null; +} +{ + (|{merge=true;}) + group = id(null) + + [LOOKAHEAD( id(null)) columns = columnList(false, true) { + jjtThis.setVariables(columns); + }] + + ( + query = queryExpression(info) + { + jjtThis.setQueryExpression(query); + } + ) + + [ option = option(info) + { + jjtThis.setOption(option); + } + ] + + { + // Store group + jjtThis.setGroup(groupSymbol(group) ); + jjtThis.setMerge(merge); + return jjtThis; + } +} + +/* +name=expression list +description=A list of expressions. +example={code:sql}col1, 'a', ...{code} +*/ +ArrayList expressionList(ParseInfo info) : +{ + ArrayList rowVals = new ArrayList(4); + BaseExpression value = null; +} +{ + value = expression(info) + { + rowVals.add(value); + } + ( + value = expression(info) + { + rowVals.add(value); + } + )* + { + return rowVals; + } +} + +/* +name=update statement +description=UpdateImpl values in the given target. +example={code:sql}UPDATE tbl SET (col1 = 'a') WHERE col2 = 1{code} +*/ +UpdateImpl update(ParseInfo info) #UpdateImpl : +{ + String group = null; + SetClauseListImpl setClauseList = null; + CriteriaImpl criteria = null; + OptionImpl option = null; +} +{ + + group = id(null) + + setClauseList = setClauseList(false, info) + { + jjtThis.setChangeList(setClauseList); + } + [ criteria = where(info) ] + [option = option(info) + { + jjtThis.setOption(option); + } + ] + { + // Store group + jjtThis.setGroup(groupSymbol( group) ); + + // Store optional criteria + if(criteria != null) { + jjtThis.setCriteria(criteria); + } + + return jjtThis; + } +} + +/* +name=delete statement +description=DeleteImpl rows from the given target. +example={code:sql}DELETE FROM tbl WHERE col2 = 1{code} +*/ +DeleteImpl delete(ParseInfo info) #DeleteImpl : +{ + String group = null; + CriteriaImpl criteria = null; + OptionImpl option = null; +} +{ + + group = id(null) + [criteria = where(info)] + [option = option(info) + { + jjtThis.setOption(option); + } + ] + { + jjtThis.setGroup(groupSymbol(group)); + jjtThis.setCriteria(criteria); + + return jjtThis; + } +} + +/* +name=query expression +description=A declarative query for data. +example={code:sql}SELECT * FROM tbl WHERE col2 = 1{code} +*/ +QueryCommandImpl queryExpression(ParseInfo info) : +{ + QueryCommandImpl queryCommand = null; + List withList = null; + WithQueryCommandImpl withQueryCommand = null; + SourceHintImpl sourceHint = null; +} +{ + [ withQueryCommand = withListElement(info) + { + withList = new LinkedList(); + withList.add(withQueryCommand); + } + ( + withQueryCommand = withListElement(info) + { + withList.add(withQueryCommand); + } + )* + ] + { if (versionAtLeast(Version.TEIID_8_4)) sourceHint = getSourceHint(this); } + queryCommand = queryExpressionBody(info) + { + queryCommand.setWith(withList); + + if (versionAtLeast(Version.TEIID_8_4)) + setSourceHint(sourceHint, queryCommand); + + return queryCommand; + } +} + +/* +name=with list element +description=A query expression for use in the enclosing query. +example={code:sql}X (Y, Z) AS (SELECT 1, 2){code} +*/ +WithQueryCommandImpl withListElement(ParseInfo info) #WithQueryCommandImpl : +{ + String name = null; + List columns = null; + QueryCommandImpl queryExpression = null; +} +{ + name = id(Boolean.FALSE) + [ columns = columnList(true, true)] + queryExpression = queryExpression(info) + { + jjtThis.setGroupSymbol(groupSymbol(name)); + jjtThis.setColumns(columns); + jjtThis.setQueryExpression(queryExpression); + return jjtThis; + } +} + +/* +name=query expression body +description=The body of a query expression, which can optionally be ordered and limited. +example={code:sql}SELECT * FROM tbl ORDER BY col1 LIMIT 1{code} +*/ +QueryCommandImpl queryExpressionBody(ParseInfo info) : +{ + QueryCommandImpl query = null; + QueryCommandImpl rightQueryImpl = null; + boolean all = false; + OptionImpl option = null; + OrderByImpl orderby = null; + LimitImpl limit = null; + SetQueryImpl.Operation type; +} +{ + query = queryTerm(info) + ( (LOOKAHEAD( , { getToken(2).kind != JOIN } ) { type = SetQueryImpl.Operation.UNION; } | { type = SetQueryImpl.Operation.EXCEPT; }) + [ { all = true; } | ] + rightQueryImpl = queryTerm(info) + { + query = setQuery(type, all, query, rightQueryImpl); + all = false; + } + ) * + [orderby = orderby(info) {query.setOrderBy( orderby );}] + [limit = limit(info) {query.setLimit( limit );}] + [LOOKAHEAD(
name=id(null) { + MultipleElementSymbolImpl multipleElementSymbol = createASTNode(ASTNodes.MULTIPLE_ELEMENT_SYMBOL); + + select = createASTNode(ASTNodes.SELECT); + select.setSymbols(Arrays.asList(multipleElementSymbol)); + + UnaryFromClauseImpl unaryFromClauseImpl = createASTNode(ASTNodes.UNARY_FROM_CLAUSE); + unaryFromClauseImpl.setGroup(groupSymbol(name)); + + FromImpl from = createASTNode(ASTNodes.FROM); + from.setClauses(Arrays.asList(unaryFromClauseImpl)); + + q = createASTNode(ASTNodes.QUERY); + q.setSelect(select); + q.setFrom(from); + query = q; + }) | + ( query=queryExpressionBody(info) ) + ) + { + return query; + } +} + +/* +name=query +description=A SELECT query. +example={code:sql}SELECT col1, max(col2) FROM tbl GROUP BY col1{code} +*/ +QueryImpl query(ParseInfo info) #QueryImpl : +{ + SelectImpl select = null; + FromImpl from = null; + IntoImpl into = null; + CriteriaImpl criteria = null; + GroupByImpl groupBy = null; + CriteriaImpl having = null; +} +{ + select = select(info) + [into = into(info)] + [from = from(info) + + [criteria = where(info)] + [groupBy = groupBy(info)] + [having = having(info)]] + + { + // Build query from parsed pieces + jjtThis.setSelect( select ); + jjtThis.setFrom( from ); + jjtThis.setInto( into ); + jjtThis.setCriteria(criteria); + jjtThis.setGroupBy(groupBy); + jjtThis.setHaving(having); + + return jjtThis; + } +} + +/* +name=into clause +description=Used to direct the query into a table. {note}This is deprecated. Use INSERT INTO with a query expression instead.{note} +example={code:sql}INTO tbl{code} +*/ +IntoImpl into(ParseInfo info) #IntoImpl : +{ + String groupID = null; +} +{ + + (groupID=id(null)) + { + jjtThis.setGroup(groupSymbol(groupID)); + return jjtThis; + } +} + +/* +name=select clause +description=The columns returned by a query. Can optionally be distinct. +example={code:sql}SELECT *{code}\n{code:sql}SELECT DISTINCT a, b, c{code} + */ +SelectImpl select(ParseInfo info) #SelectImpl : +{ + boolean isDistinct = false; // unless DISTINCT keyword in SELECT + BaseExpression symbol = null; +} +{ +
|) { table = true; } + ] + lparen = + ( command = queryExpression(info) | + command = storedProcedure(info, 1) ) + + [] + aliasID = id(Boolean.FALSE) + + { + jjtThis.setName(aliasID); + jjtThis.setCommand(command); + setFromClauseOptions(lparen, jjtThis); + jjtThis.setTable(table); + return jjtThis; + } +} + +/* +name=table name +description=A table named in the FROM clause. +example={code:sql}tbl AS x{code} +*/ +UnaryFromClauseImpl unaryFromClauseImpl(ParseInfo info) #UnaryFromClauseImpl : +{ + GroupSymbolImpl group = null; + String groupID = null; + Token groupToken = null; + String aliasID = null; +} +{ + (groupID=id(null) {groupToken = getToken(0);} [[] aliasID=id(Boolean.FALSE)]) + { + if(aliasID != null) { + group = groupSymbol(aliasID, groupID); + } else { + group = groupSymbol(groupID); + } + jjtThis.setGroup(group); + setFromClauseOptions(groupToken, jjtThis); + return jjtThis; + } +} + +/* +name=where clause +description=Specifies a search condition +example={code:sql}WHERE x = 'a'{code} +*/ +CriteriaImpl where(ParseInfo info) : +{ + CriteriaImpl criteria = null; +} +{ + + criteria = criteria(info) + + { + return criteria; + } +} + +/* +name=condition +description=A boolean expression. +*/ +CriteriaImpl criteria(ParseInfo info) #CriteriaImpl : +{ +} +{ + jjtThis = compoundCritOr(info) + + { + return jjtThis; + } +} + +/* +name=boolean value expression +description=An optionally ORed boolean expression. +*/ +CriteriaImpl compoundCritOr(ParseInfo info) : +{ + ArrayList logicList = null; + CriteriaImpl logicPart = null; + CriteriaImpl logicPart1 = null; +} +{ + logicPart=compoundCritAnd(info) + ( logicPart1=compoundCritAnd(info) { + if (logicList == null) { + logicList = new ArrayList(2); + logicList.add(logicPart); + } + + logicList.add(logicPart1); + } + )* + + { + if(logicList == null) { + return logicPart; + } else { + CompoundCriteriaImpl cc = createASTNode(ASTNodes.COMPOUND_CRITERIA); + cc.setOperator(CompoundCriteriaImpl.OR); + cc.setCriteria(logicList); + return cc; + } + } +} + +/* +name=boolean term +description=An optional ANDed boolean factor. +*/ +CriteriaImpl compoundCritAnd(ParseInfo info) #CompoundCriteriaImpl : +{ + ArrayList logicList = null; + CriteriaImpl logicPart = null; + CriteriaImpl logicPart1 = null; +} +{ + logicPart=notCrit(info) + ( logicPart1=notCrit(info) { + if (logicList == null) { + logicList = new ArrayList(2); + logicList.add(logicPart); + } + + logicList.add(logicPart1); + } + )* + + { + if(logicList == null) { + return logicPart; + } else { + jjtThis.setOperator(CompoundCriteriaImpl.AND); + jjtThis.setCriteria(logicList); + return jjtThis; + } + } +} + +/* +name=boolean factor +description=A boolean factor. +example={code:sql}NOT x = 'a'{code} +*/ +CriteriaImpl notCrit(ParseInfo info) #NotCriteriaImpl : +{ + BaseExpression ex = null; + boolean isNot = false; +} +{ + [ {isNot=true;}] + ex=booleanPrimary(info) + + { + CriteriaImpl crit = null; + if (ex instanceof CriteriaImpl) { + crit = (CriteriaImpl)ex; + } else { + crit = expressionCriteria(ex); + } + if(isNot) { + jjtThis.setCriteria(crit); + return jjtThis; + } else { + return crit; + } + } +} + +/* +name=boolean primary +description=A boolean predicate or simple expression. +example={code:sql}col LIKE 'a%'{code} +*/ +BaseExpression booleanPrimary(ParseInfo info) : +{ + BaseExpression ex = null; +} +{ + ( + (ex = commonValueExpression(info) + [( + LOOKAHEAD(2) ex=betweenCrit(info, ex) | + LOOKAHEAD(2) ex=matchCrit(info, ex) | + LOOKAHEAD(2) ex=regexMatchCrit(info, ex) | + ex=setCrit(info, ex) | + ex=isNullCrit(info, ex) | + LOOKAHEAD(operator() (||) subquery(info)) ex=subqueryCompareCriteria(info, ex) | + ex=compareCrit(info, ex) + )] + ) + | + ex=existsCriteria(info) + ) + { + return ex; + } +} + +/* +name=comparison operator +description=A comparison operator. +example={code:sql}={code} +*/ +Token operator() : +{ + Token operator = null; +} +{ + (operator= | + operator= | + operator= | + operator= | + operator= | + operator= | + operator= + ) + { + return operator; + } +} + +/* +name=comparison predicate +description=A value comparison. +example={code:sql}= 'a'{code} +*/ +CompareCriteriaImpl compareCrit(ParseInfo info, BaseExpression expression) #CompareCriteriaImpl : +{ + BaseExpression value = null; + Token operator = null; +} +{ + operator=operator() + value=commonValueExpression(info) + + { + // Set left expression + jjtThis.setLeftExpression(expression); + + jjtThis.setOperator(Operator.getOperator(getVersion(), operator.image)); + + // Set value + jjtThis.setRightExpression(value); + + return jjtThis; + } +} + +/* +name=subquery +description=A subquery. +example={code:sql}(SELECT * FROM tbl){code} +*/ +QueryCommandImpl subquery(ParseInfo info) : +{ + QueryCommandImpl subquery = null; + StoredProcedureImpl proc = null; +} +{ + + ( subquery = queryExpression(info) | + ( + proc = storedProcedure(info, 1) //deprecated + ) + { + MultipleElementSymbolImpl multipleElementSymbol = createASTNode(ASTNodes.MULTIPLE_ELEMENT_SYMBOL); + + SelectImpl select = createASTNode(ASTNodes.SELECT); + select.setSymbols(Arrays.asList(multipleElementSymbol)); + + SubqueryFromClauseImpl subqueryFromClauseImpl = createASTNode(ASTNodes.SUBQUERY_FROM_CLAUSE); + subqueryFromClauseImpl.setName("x"); + subqueryFromClauseImpl.setCommand(proc); + + FromImpl from = createASTNode(ASTNodes.FROM); + from.setClauses(Arrays.asList(subqueryFromClauseImpl)); + + QueryImpl query = createASTNode(ASTNodes.QUERY); + query.setSelect(select); + query.setFrom(from); + subquery = query; + } + ) + + { + return subquery; + } +} + +/* +name=quantified comparison predicate +description=A subquery comparison. +example={code:sql}= ANY (SELECT col FROM tbl){code} +*/ +SubqueryCompareCriteriaImpl subqueryCompareCriteria(ParseInfo info, BaseExpression expression) #SubqueryCompareCriteriaImpl : +{ + QueryCommandImpl subquery = null; + Token operator = null; + Token quantifier = null; + +} +{ + operator=operator() + ( quantifier= | + quantifier= | + quantifier= + ) + subquery = subquery(info) + + { + jjtThis.setLeftExpression(expression); + jjtThis.setCommand(subquery); + + // Set operator + jjtThis.setOperator(Operator.getOperator(getVersion(), operator.image)); + + // Set predicate quantifier + if(quantifier.image.equalsIgnoreCase("any")) { //$NON-NLS-1$ + jjtThis.setPredicateQuantifier(PredicateQuantifier.ANY); + } else if(quantifier.image.equalsIgnoreCase("some")) { //$NON-NLS-1$ + jjtThis.setPredicateQuantifier(PredicateQuantifier.SOME); + } else if(quantifier.image.equalsIgnoreCase("all")) { //$NON-NLS-1$ + jjtThis.setPredicateQuantifier(PredicateQuantifier.ALL); + } + + return jjtThis; + } +} + +/* +name=match predicate +description=Matches based upon a pattern. +example={code:sql}LIKE 'a_'{code} +*/ +MatchCriteriaImpl matchCrit(ParseInfo info, BaseExpression expression) #MatchCriteriaImpl : +{ + Character esc = null; + BaseExpression value = null; + boolean negated = false; + boolean similar = false; + Token t = null; +} +{ + [ {negated = true;}] + (|( {similar = true;})) + {t = getToken(1);} + value=commonValueExpression(info) + [ esc = charVal(info, "LIKE/SIMILAR TO ESCAPE") | + ( esc = charVal(info, "LIKE/SIMILAR TO ESCAPE") ) + ] + { + jjtThis.setLeftExpression(expression); + jjtThis.setRightExpression(value); + jjtThis.setNegated(negated); + if(esc != null) { + jjtThis.setEscapeChar(esc.charValue()); + } else if (!similar && value instanceof ConstantImpl) { + if (t.image != null && t.image.startsWith("E'")) { + jjtThis.setEscapeChar('\\'); + } + } + jjtThis.setMode(similar?MatchMode.SIMILAR:MatchMode.LIKE); + return jjtThis; + } +} + +/* +name=like regex predicate +description=A regular expression match. +example={code:sql}LIKE_REGEX 'a.*b'{code} +*/ +MatchCriteriaImpl regexMatchCrit(ParseInfo info, BaseExpression expression) : +{ + BaseExpression value = null; + boolean negated = false; +} +{ + [ {negated = true;}] + + value=commonValueExpression(info) + { + MatchCriteriaImpl matchcriteria = createASTNode(ASTNodes.MATCH_CRITERIA); + matchcriteria.setLeftExpression(expression); + matchcriteria.setRightExpression(value); + matchcriteria.setNegated(negated); + matchcriteria.setMode(MatchMode.REGEX); + return matchcriteria; + } +} + +/* +name=character +description=A single character. +example={code:sql}'a'{code} +*/ +Character charVal(ParseInfo info, String type) : +{ + String escStr = null; +} +{ + escStr=stringVal() + { + if (escStr.length() != 1) { + throw new ParseException(Messages.getString(Messages.TeiidParser.char_val)); + } + return Character.valueOf(escStr.charAt(0)); + } +} + +/* +name=between predicate +description=A comparison between two values. +example={code:sql}BETWEEN 1 AND 5{code} +*/ +BetweenCriteriaImpl betweenCrit(ParseInfo info, BaseExpression expression) #BetweenCriteriaImpl : +{ + BaseExpression lowerExpression = null, upperExpression = null; + boolean negated = false; +} +{ + [ {negated=true;}] + + lowerExpression = commonValueExpression(info) + + upperExpression = commonValueExpression(info) + + { + jjtThis.setExpression(expression); + jjtThis.setLowerExpression(lowerExpression); + jjtThis.setUpperExpression(upperExpression); + jjtThis.setNegated(negated); + return jjtThis; + } +} + +/* +name=is null predicate +description=A null test. +example={code:sql}IS NOT NULL{code} +*/ +IsNullCriteriaImpl isNullCrit(ParseInfo info, BaseExpression expression) #IsNullCriteriaImpl : +{ + boolean negated = false; +} +{ + + [ {negated = true;}] + + + { + jjtThis.setExpression(expression); + jjtThis.setNegated(negated); + return jjtThis; + } +} + +/* +name=in predicate +description=A comparison with multiple values. +example={code:sql}IN (1, 5){code} +*/ +AbstractSetCriteria setCrit(ParseInfo info, BaseExpression expression) : +{ + BaseExpression value = null; + List setList = new ArrayList(); + QueryCommandImpl command = null; + SubqueryHint hint = null; + boolean negated = false; + AbstractSetCriteria criteria = null; +} +{ + [ {negated = true;}] + + ( + LOOKAHEAD(subquery(info)) { hint = getSubqueryHint(getToken(1)); } (command = subquery(info)) | + ( + + value = commonValueExpression(info) + { + setList.add(value); + } + ( + value = commonValueExpression(info) + { + setList.add(value); + } + )* + + ) + ) + { + if (command != null) { + SubquerySetCriteriaImpl ssc = subquerySetCriteriaImpl(expression, command); + ssc.setSubqueryHint(hint); + criteria = ssc; + } else { + criteria = setCriteria(expression, setList); + } + criteria.setNegated(negated); + return criteria; + } +} + +SubquerySetCriteriaImpl subquerySetCriteriaImpl(BaseExpression expression, QueryCommandImpl command) #SubquerySetCriteriaImpl : +{ +} +{ + { + jjtThis.setExpression(expression); + jjtThis.setCommand(command); + return jjtThis; + } +} + +SetCriteriaImpl setCriteria(BaseExpression expression, List values) #SetCriteriaImpl : +{ +} +{ + { + jjtThis.setExpression(expression); + jjtThis.setValues(values); + return jjtThis; + } +} + +/* +name=exists predicate +description=A test if rows exist. +example={code:sql}EXISTS (SELECT col FROM tbl){code} +*/ +ExistsCriteriaImpl existsCriteria(ParseInfo info) #ExistsCriteriaImpl : +{ + QueryCommandImpl subquery = null; + SubqueryHint hint = null; +} +{ + { hint = getSubqueryHint(getToken(1)); } + subquery = subquery(info) + + { + jjtThis.setCommand(subquery); + jjtThis.setSubqueryHint(hint); + return jjtThis; + } +} + +/* +name=group by clause +description=Defines the grouping columns +example={code:sql}GROUP BY col1, col2{code} +*/ +GroupByImpl groupBy(ParseInfo info) #GroupByImpl : +{ + List expressions = null; + boolean rollup = false; +} +{ + + ( + + expressions = expressionList(info) + + { + requiresVersionAtLeast(Version.TEIID_8_5); + rollup = true; + } + | + expressions = expressionList(info) + ) + + { + jjtThis.setSymbols(expressions); + jjtThis.setRollup(rollup); + return jjtThis; + } +} + +/* +name=having clause +description=Search condition applied after grouping. +example={code:sql}HAVING max(col1) = 5{code} +*/ +CriteriaImpl having(ParseInfo info) : +{ + CriteriaImpl criteria = null; +} +{ + + criteria = criteria(info) + { + return criteria; + } +} + +/* +name=order by clause +description=Specifices row ordering. +example={code:sql}ORDER BY x, y DESC{code} +*/ +OrderByImpl orderby(ParseInfo info) #OrderByImpl : +{ + OrderByItemImpl item = null; +} +{ + + item = sortSpecification(info) + { + jjtThis.getOrderByItems().add(item); + } + ( + item = sortSpecification(info) + { + jjtThis.getOrderByItems().add(item); + } + )* + { + return jjtThis; + } +} + +/* +name=sort specification +description=Defines how to sort on a particular expression +example={code:sql}col1 NULLS FIRST{code} +*/ +OrderByItemImpl sortSpecification(ParseInfo info) #OrderByItemImpl : +{ + BaseExpression ex = null; + boolean ascending = true; + NullOrdering nullOrdering = null; +} +{ + ex=sortKey(info) + [ | {ascending=false;}] + [ ( {nullOrdering=NullOrdering.FIRST;} | {nullOrdering=NullOrdering.LAST;})] + { + jjtThis.setSymbol(ex); + jjtThis.setAscending(ascending); + if (nullOrdering != null) { + jjtThis.setNullOrdering(nullOrdering); + } + return jjtThis; + } +} + +/* +name=sort key +description=A sort expression. +example={code:sql}col1{code} +*/ +BaseExpression sortKey(ParseInfo info) : +{ + BaseExpression ex = null; +} +{ + ex=expression(info) + { + //legacy support check for positional constants + if (ex instanceof ConstantImpl) { + boolean valid = false; + ConstantImpl c = (ConstantImpl)ex; + if (c.getValue() instanceof Integer) { + Integer val = (Integer)c.getValue(); + valid = val.intValue() > 0; + } + if (!valid) { + throw new ParseException(Messages.getString(Messages.TeiidParser.non_position_constant, ex)); + } + } + return ex; + } +} + +/* +name=integer parameter +description=A literal integer or parameter reference to an integer. +example={code:sql}?{code} +*/ +BaseExpression intParam(ParseInfo info) : +{ + BaseExpression ex = null; + Integer val = null; +} +{ + val = intVal() + { + return constant(val, DefaultDataTypeManager.DefaultDataTypes.INTEGER); + } + | + ex = unsignedValueExpressionPrimary(info) + { return ex; + } +} + +/* +name=limit clause +description=Limits and/or offsets the resultant rows. +example={code:sql}LIMIT 2{code} +*/ +LimitImpl limit(ParseInfo info) #LimitImpl : +{ + BaseExpression limit = null; + BaseExpression offset = null; + Token t = null; +} +{ + {t = getToken(1);} + (( offset = intParam(info) + [ limit = intParam(info)]) + { + if (limit == null) { + limit = offset; + offset = null; + } + } + | + ( offset = intParam(info) (|) + [limit = fetchLimitImpl(info)]) + | + (limit = fetchLimitImpl(info))) + { + jjtThis.setOffset(offset); + jjtThis.setRowLimit(limit); + jjtThis.setStrict(!isNonStrictHint(t)); + return jjtThis; + } +} + +/* +name=fetch clause +description=ANSI limit. +example={code:sql}FETCH FIRST 1 ROWS ONLY{code} +*/ +BaseExpression fetchLimitImpl(ParseInfo info) : +{ + BaseExpression limit = null; +} +{ + ( | ) [limit = intParam(info)] (|) + { + if (limit == null) { + return constant(1, DefaultDataTypeManager.DefaultDataTypes.INTEGER); + } + return limit; + } +} + +/* +name=option clause +description=Specifies query options. +example={code:sql}OPTION MAKEDEP tbl{code} +*/ +OptionImpl option(ParseInfo info) #OptionImpl : +{ + String id = null; + Token nocache = null; +} +{ +
] + procedureRsColumn(factory, proc) + ( procedureRsColumn(factory, proc))* + ) + | + returnDataType = parseDataType()) + ] + [ optionsClause(proc, factory) + { + setProcedureOptions(proc); + } + ] + [ { comment = getToken(1).specialToken; } + stmt = statement(info)]) + { + proc.setVirtual(virtual); + proc.setFunction(function); + if (stmt != null){ + if (function || !virtual) { + throw new ParseException(Messages.getString(Messages.TeiidParser.function_def, procName)); + } + proc.setQueryPlan((comment != null?comment.image+" ":"") + stmt.toString()); + } + + if (returnDataType != null){ + addProcColumn(factory, proc, "return", returnDataType, false); + } + if (function) { + replaceProcedureWithFunction(factory, proc); + } + return procCmd; + } +} + +/* +name=procedure parameter +description=A procedure or function parameter +example={code:sql}OUT x INTEGER{code} +*/ +void procedureParameter(MetadataFactory factory, Procedure proc) : +{ + String name = null; + ParsedDataType type = null; + ProcedureParameter.Type ppType = ProcedureParameter.Type.In; + ProcedureParameter param = null; + String defaultValue = null; + boolean notNull = false; + boolean vararg = false; +} +{ + [LOOKAHEAD(1) (( {ppType = ProcedureParameter.Type.In ;}) + |( {ppType = ProcedureParameter.Type.Out;}) + |( {ppType = ProcedureParameter.Type.InOut;}) + |( {ppType = ProcedureParameter.Type.In ; vararg = true;}))] + name = id(Boolean.TRUE) + type = parseDataType() + [ {notNull = true;}] + [ + { + if (ppType != ProcedureParameter.Type.Out) { + throw new ParseException(Messages.getString(Messages.TeiidParser.param_out, proc.getName(), name)); + } + ppType = ProcedureParameter.Type.ReturnValue; + } + ] + { + param = factory.addProcedureParameter(name, type.getType(), ppType, proc); + setTypeInfo(type, param); + if (notNull) { + param.setNullType(Column.NullType.No_Nulls); + } + if (vararg) { + param.setVarArg(vararg); + } + } + [ defaultValue = stringVal() {param.setDefaultValue(defaultValue);}] + [optionsClause(param, factory) + { + setColumnOptions(param); + } + ] +} + +/* +name=procedure result column +description=A procedure result column. +example={code:sql}x INTEGER{code} +*/ +void procedureRsColumn(MetadataFactory factory, Procedure proc) : +{ + String name = null; + ParsedDataType type = null; + boolean notNull = false; + BaseColumn column = null; +} +{ + name = id(Boolean.TRUE) + type = parseDataType() + { + column = addProcColumn(factory, proc, name, type, true); + } + [ {column.setNullType(Column.NullType.No_Nulls);}] + [optionsClause(column, factory) + { + setColumnOptions(column); + } + ] +} + +/* +name=create table +description=Defines a table or view. +example={code:sql}CREATE VIEW vw AS SELECT 1{code} +*/ +void createTable(MetadataFactory factory) : +{ + boolean view = false; + boolean globalTemp = false; + String tableName = null; + Table table = null; + Token comment = null; + CommandImpl query = null; +} +{ + ( + (
) | + ([] {view = true;}) | + (
{ requiresVersionAtLeast(Version.TEIID_8_5); globalTemp = true; view = true;}) + ) + + tableName = id(null) + { + table = factory.addTable(tableName); + table.setVirtual(view); + if (globalTemp) { + table.setTableType(Table.Type.TemporaryTable); + } + } + (createTableBody(table, factory) | [optionsClause(table, factory) + { + setTableOptions(table); + } + ]) + [ { comment = getToken(1).specialToken; } query = queryExpression(ParseInfo.DEFAULT_INSTANCE) + { + if (!view || globalTemp) { + throw new ParseException(Messages.getString(Messages.TeiidParser.view_def, table.getName())); + } + table.setSelectTransformation((comment != null?comment.image+" ":"") + query.toString()); + } + ] +} + +/* +name=create foreign temp table +description=Defines a foreign temp table +example={code:sql}CREATE FOREIGN TEMPORARY TABLE t (x string) ON z{code} +*/ +CreateImpl createForeignTempTable(ParseInfo info) : +{ + Table table = null; + String tableName = null; + String model = null; + MetadataFactory factory = getTempMetadataFactory(); +} +{ + []
+ tableName = id(null) + { + table = new Table(); + //need to set a dummy/stable uuid + table.setUUID("tid:0"); + table.setTableType(Table.Type.TemporaryTable); + table.setName(tableName); + } + createTableBody(table, factory) + model = id(null) + { + CreateImpl create = createASTNode(ASTNodes.CREATE); + create.setTableMetadata(table); + create.setOn(model); + return create; + } +} + +/* +name=create table body +description=Defines a table. +example={code:sql}(x string) OPTIONS (CARDINALITY 100){code} +*/ +void createTableBody(Table table, MetadataFactory factory) : +{ + String name = null; + AbstractMetadataRecord constraint = null; +} +{ + + createColumn(factory, table) + (LOOKAHEAD(3) + createColumn(factory, table) + )* + ({name=null;} [ name = id(null)] (constraint = primaryKey(factory, table, name) | constraint = constraint(factory, table, name, ParseInfo.DEFAULT_INSTANCE) | constraint = foreignKey(factory, table, name)) + [optionsClause(constraint, factory) + { + setCommonProperties(constraint, constraint.getProperties()); + } + ] + )* + + [optionsClause(table, factory) + { + setTableOptions(table); + } + ] + { + if (table.getColumns() != null && !table.supportsUpdate()) { + for (Column c : table.getColumns()) { + c.setUpdatable(false); + } + } + } +} + +/* +name=foreign key +description=Defines the foreign key referential constraint. +example={code:sql}FOREIGN KEY (a, b) REFERENCES tbl (x, y){code} +*/ +AbstractMetadataRecord foreignKey(MetadataFactory factory, Table table, String name) : +{ + List columnNames = null; + String viewName = null; + Table reference = null; + KeyRecord pk = null; + Column column = null; + List pkColumnNames = null; + KeyRecord key = null; +} +{ + + columnNames = columnList(true, false) + + viewName = id(null) + [pkColumnNames = columnList(true, false)] + { + return factory.addForiegnKey(name != null?name:("FK"+table.getForeignKeys().size()), columnNames, pkColumnNames, viewName, table); + } +} + +/* +name=primary key +description=Defines the primary key. +example={code:sql}PRIMARY KEY (a, b){code} +*/ +AbstractMetadataRecord primaryKey(MetadataFactory factory, Table table, String name) : +{ + List columnNames = null; + Column column = null; + KeyRecord key = null; +} +{ + + columnNames = columnList(true, false) + { + if (table.getPrimaryKey() != null){ + throw new ParseException(Messages.getString(Messages.TeiidParser.pk_exists, table.getName())); + } + return factory.addPrimaryKey(name!=null?name:"PK", columnNames, table); + } +} + +/* +name=other constraints +description=Defines ACCESSPATTERN and UNIQUE constraints and INDEXes. +example={code:sql}UNIQUE (a){code} +*/ +AbstractMetadataRecord constraint(MetadataFactory factory, Table table, String name, ParseInfo info) : +{ + KeyRecord keyrecord = null; + Column column = null; + List columnNames = null; + Token type = null; + KeyRecord key = null; + List expressions = null; +} +{ + (( type = | type = ) + columnNames = columnList(true, false) + { + if (type.image.equalsIgnoreCase("UNIQUE")) { + return factory.addIndex(name != null?name:("UNIQUE"+table.getUniqueKeys().size()), false, columnNames, table); + } else if (type.image.equalsIgnoreCase("ACCESSPATTERN")) { + return factory.addAccessPattern(name != null?name:("AP"+table.getAccessPatterns().size()), columnNames, table); + } + }) | ( + type = + + expressions = expressionList(info) + + { + return addFBI(factory, expressions, table, name); + } + ) +} + +/* +name=column list +description=A list of column names. +example={code:sql}(a, b){code} +*/ +List columnList(boolean validate, boolean asElementSymbols) : +{ + ArrayList list = new ArrayList(); + String id = null; +} +{ + + id = id(validate?Boolean.TRUE:null) + { + if (asElementSymbols) { + list.add(elementSymbol(id)); + } else { + list.add(id); + } + } + ( id = id(validate?Boolean.TRUE:null) + { + if (asElementSymbols) { + list.add(elementSymbol(id)); + } else { + list.add(id); + } + } + )* + + { + return list; + } +} + +/* +name=table element +description=Defines a table column. +example={code:sql}x INTEGER NOT NULL{code} +*/ +void createColumn(MetadataFactory factory, Table table) : +{ + String element = null; + ParsedDataType type = null; + boolean autoIncrement = false; + boolean notNull = false; + String defalt = null; + Column column = null; + List columnName = new ArrayList(); + boolean index = false; + boolean unique = false; + boolean pk = false; + Token word = null; +} +{ + element = id(Boolean.TRUE) + ( + + { + requiresVersionAtLeast(Version.TEIID_8_5); + type = new ParsedDataType("INTEGER"); + autoIncrement = true; + notNull = true; + } + | + ( + type = parseDataType() + [ { notNull = true; }] + [ { autoIncrement = true; }] + ) + { + column = factory.addColumn(element, type.getType(), table); + column.setUpdatable(true); + setTypeInfo(type, column); + columnName.add(element); + } + ) + + (( { pk = true; }) | ([ { unique = true; }] [ { index = true; }])) + [ defalt = stringVal() {column.setDefaultValue(defalt);}] + [optionsClause(column, factory) + { + setColumnOptions(column); + } + ] + { + if (index){ + factory.addIndex("INDEX"+table.getIndexes().size(), true, columnName, table); + } else if (unique){ + factory.addIndex("UNIQUE"+table.getIndexes().size(), false, columnName, table); + } else if (pk) { + if (table.getPrimaryKey() != null) { + throw new ParseException(Messages.getString(Messages.TeiidParser.pk_exists, table.getName())); + } + factory.addPrimaryKey("PK", columnName, table); + } + + if (notNull) { + column.setNullType(Column.NullType.No_Nulls); + } + column.setAutoIncremented(autoIncrement); + } +} + +/* +name=options clause +description=A list of statement options. +example={code:sql}OPTIONS ('x' 'y', 'a' 'b'){code} +*/ +void optionsClause(AbstractMetadataRecord record, MetadataFactory factory) : +{ +} +{ + + optionPair(record, factory) ( optionPair(record, factory))* + +} + +/* +name=option pair +description=An option key/value pair. +example={code:sql}'key' 'value'{code} +*/ +void optionPair(AbstractMetadataRecord record, MetadataFactory factory) : +{ + ConstantImpl value = null; + String key = null; + Token t = null; + String strVal = null; +} +{ + key = id(null) + (value = nonNumericLiteral() + | [strVal = plusMinus()] value = unsignedNumericLiteral(strVal)) + { + key = resolvePropertyKey(factory, key); + String val = null; + if (value.getValue() != null) { + val = value.getValue().toString(); + } + record.setProperty(key, val); + } +} + +/* +name=alter options +description=alters options of tables/procedure +example={code:sql}ALTER FOREIGN TABLE foo OPTIONS (ADD cardinality 100){code} +*/ +void alterStatement(MetadataFactory factory) : +{ + boolean table = false; + boolean proc = false; + boolean func = false; + String objectName = null; + AbstractMetadataRecord record = null; +} +{ + [ | ] (
{table = true;} | {table = true;} | {proc=true;}) + objectName = id(null) + { + if (table){ + record = factory.getSchema().getTable(objectName); + if (record == null){ + throw new ParseException(Messages.getString(Messages.TeiidParser.alter_table_doesnot_exist, objectName)); + } + } + if (proc){ + record = factory.getSchema().getProcedure(objectName); + if (record == null){ + throw new ParseException(Messages.getString(Messages.TeiidParser.alter_procedure_doesnot_exist, objectName)); + } + } + } + + (alterOptionsList(record, factory) | + alterColumn(record, factory)) +} + +/* +name=alter options list +description=a list of alterations to options +example={code:sql}OPTIONS (ADD updatable true){code} +*/ +void alterOptionsList(AbstractMetadataRecord record, MetadataFactory factory) : +{ + +} +{ + + (addSetOptionImpl(record, factory) | + dropOptionImpl(record)) + ( (addSetOptionImpl(record, factory) | + dropOptionImpl(record)))* + + { + setOptions(record); + } +} + +/* +name=drop option +description=drop option +example={code:sql}DROP updatable{code} +*/ +void dropOptionImpl(AbstractMetadataRecord record) : +{ + String key = null; +} +{ + key = id(null) + { + removeOption(key, record); + } +} + +/* +name=add set option +description=add or set an option pair +example={code:sql}ADD updatable true{code} +*/ +void addSetOptionImpl(AbstractMetadataRecord record, MetadataFactory factory) : +{ +} +{ + (|) optionPair(record, factory) +} + +/* +name=alter column options +description=alters a set of column options +example={code:sql}ALTER COLUMN bar OPTIONS (ADD updatable true){code} +*/ +void alterColumn(AbstractMetadataRecord parent, MetadataFactory factory) : +{ + boolean param = false; + String objectName = null; + AbstractMetadataRecord record = null; + String key = null; +} +{ + [|{param=true;}] + objectName = id(null) + { + record = getChild(objectName, parent, param); + } + alterOptionsList(record, factory) +} + +AssignmentStatementImpl assignmentStatement(ElementSymbolImpl elementSymbol, BaseLanguageObject value) #AssignmentStatementImpl : +{ +} +{ + { + jjtThis.setVariable(elementSymbol); + + if (value instanceof BaseExpression) + jjtThis.setExpression((BaseExpression) value); + else if (value instanceof QueryCommandImpl) + jjtThis.setExpression(scalarSubquery((QueryCommandImpl) value)); + else + jjtThis.setCommand((CommandImpl) value); + + return jjtThis; + } +} + +ScalarSubqueryImpl scalarSubquery(QueryCommandImpl queryCommand) #ScalarSubqueryImpl : +{ +} +{ + { + jjtThis.setCommand(queryCommand); + return jjtThis; + } +} + +GroupSymbolImpl groupSymbol(String... args) #GroupSymbolImpl : +{ +} +{ + { + /* + * Expectation is that group symbol args should be + * name then definition (or alias). + */ + jjtThis.setName(args[0]); + if (args.length == 2) + jjtThis.setDefinition(args[1]); + + return jjtThis; + } +} + +ConstantImpl constant(Object... args) #ConstantImpl : +{ +} +{ + { + if (args == null) + return jjtThis; + + /* + * Expectation is that constant args should be + * value of type Object and type of type Class. + */ + for (Object arg : args) { + if (arg instanceof Class) { + jjtThis.setType((Class) arg); + } else if (arg instanceof DefaultDataTypeManager.DefaultDataTypes) { + DefaultDataTypeManager.DefaultDataTypes dataType = (DefaultDataTypeManager.DefaultDataTypes) arg; + jjtThis.setType(dataType.getTypeClass()); + } else { + jjtThis.setValue(arg); + } + } + return jjtThis; + } +} + +ElementSymbolImpl elementSymbol(String name) #ElementSymbolImpl : +{ +} +{ + { + jjtThis.setName(name); + return jjtThis; + } +} + +BlockImpl block() #BlockImpl : +{ +} +{ + { + return jjtThis; + } +} + +BlockImpl asBlock(StatementImpl stmt) : +{ + BlockImpl b = null; +} +{ + { + if (stmt == null) + return null; + + if (stmt instanceof BlockImpl) + return (BlockImpl) stmt; + + b = block(); + b.addStatement(stmt); + return b; + } +} + +ExpressionCriteriaImpl expressionCriteria(BaseExpression expression) #ExpressionCriteriaImpl : +{ +} +{ + { + jjtThis.setExpression(expression); + return jjtThis; + } +} + +AliasSymbolImpl aliasSymbol(String alias, BaseExpression expression) #AliasSymbolImpl : +{ +} +{ + { + jjtThis.setName(alias); + jjtThis.setSymbol(expression); + return jjtThis; + } +} + +BaseAggregateSymbol newBaseAggregateSymbol(String name, boolean isDistinct, BaseExpression[] arguments) #BaseAggregateSymbol : +{ +} +{ + { + jjtThis.setName(name); + jjtThis.setDistinct(isDistinct); + jjtThis.setArgs(arguments); + return jjtThis; + } +} + +BaseWindowFunction windowFunction() #BaseWindowFunction : +{ +} +{ + { + return jjtThis; + } +} + +WindowSpecificationImpl newWindowSpecificationImpl() #WindowSpecificationImpl : +{ +} +{ + { + return jjtThis; + } +} + +TextLineImpl textLine() #TextLineImpl : +{ +} +{ + { + return jjtThis; + } +} + +AlterTriggerImpl alterTrigger() #AlterTriggerImpl : +{ +} +{ + { + return jjtThis; + } +} + +AlterProcedureImpl alterProcedure() #AlterProcedureImpl : +{ +} +{ + { + return jjtThis; + } +} + +AlterViewImpl alterView() #AlterViewImpl : +{ +} +{ + { + return jjtThis; + } +} + +ArraySymbolImpl array() #ArraySymbolImpl : +{ +} +{ + { + return jjtThis; + } +} \ No newline at end of file diff --git a/komodo-teiid-client/gen/org/teiid/query/parser/v7/.keep b/komodo-teiid-client/gen/org/teiid/query/parser/v7/.keep new file mode 100644 index 00000000..e69de29b diff --git a/komodo-teiid-client/gen/org/teiid/query/parser/v8/.keep b/komodo-teiid-client/gen/org/teiid/query/parser/v8/.keep new file mode 100644 index 00000000..e69de29b