--- /dev/null
+options\r
+{\r
+ STATIC = false;\r
+ LOOKAHEAD = 1;\r
+ DEBUG_PARSER = false;\r
+ DEBUG_LOOKAHEAD = false;\r
+ DEBUG_TOKEN_MANAGER = false;\r
+ ERROR_REPORTING = true;\r
+ USER_TOKEN_MANAGER = false;\r
+ USER_CHAR_STREAM = true;\r
+ COMMON_TOKEN_ACTION = true;\r
+ CACHE_TOKENS = true;\r
+ UNICODE_INPUT = true;\r
+}\r
+\r
+PARSER_BEGIN(SQLParser)\r
+\r
+/*\r
+\r
+ Derby - File org.apache.derby.impl.sql.compile.sqlgrammar.jj\r
+\r
+ Licensed to the Apache Software Foundation (ASF) under one or more\r
+ contributor license agreements. See the NOTICE file distributed with\r
+ this work for additional information regarding copyright ownership.\r
+ The ASF licenses this file to you under the Apache License, Version 2.0\r
+ (the "License"); you may not use this file except in compliance with\r
+ the License. You may obtain a copy of the License at\r
+\r
+ http://www.apache.org/licenses/LICENSE-2.0\r
+\r
+ Unless required by applicable law or agreed to in writing, software\r
+ distributed under the License is distributed on an "AS IS" BASIS,\r
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ See the License for the specific language governing permissions and\r
+ limitations under the License.\r
+\r
+*/\r
+\r
+package org.apache.derby.impl.sql.compile;\r
+\r
+import org.apache.derby.iapi.sql.Statement;\r
+import org.apache.derby.iapi.sql.StatementType;\r
+\r
+/* aggregates */\r
+import org.apache.derby.impl.sql.compile.CountAggregateDefinition;\r
+import org.apache.derby.impl.sql.compile.MaxMinAggregateDefinition;\r
+import org.apache.derby.impl.sql.compile.SumAvgAggregateDefinition;\r
+\r
+import org.apache.derby.impl.sql.compile.AggregateNode;\r
+import org.apache.derby.impl.sql.compile.BinaryOperatorNode;\r
+import org.apache.derby.impl.sql.compile.CallStatementNode;\r
+import org.apache.derby.impl.sql.compile.CharConstantNode;\r
+import org.apache.derby.impl.sql.compile.CastNode;\r
+import org.apache.derby.impl.sql.compile.ColumnDefinitionNode;\r
+import org.apache.derby.impl.sql.compile.ColumnReference;\r
+import org.apache.derby.impl.sql.compile.CursorNode;\r
+import org.apache.derby.impl.sql.compile.FromBaseTable;\r
+import org.apache.derby.impl.sql.compile.FromList;\r
+import org.apache.derby.impl.sql.compile.FromSubquery;\r
+import org.apache.derby.impl.sql.compile.FromTable;\r
+import org.apache.derby.impl.sql.compile.GroupByList;\r
+import org.apache.derby.impl.sql.compile.HasNodeVisitor;\r
+import org.apache.derby.impl.sql.compile.JavaToSQLValueNode;\r
+import org.apache.derby.impl.sql.compile.JoinNode;\r
+import org.apache.derby.impl.sql.compile.MethodCallNode;\r
+import org.apache.derby.impl.sql.compile.QueryTreeNode;\r
+import org.apache.derby.impl.sql.compile.ReplaceAggregatesWithCRVisitor;\r
+import org.apache.derby.impl.sql.compile.ResultColumnList;\r
+import org.apache.derby.impl.sql.compile.ResultColumn;\r
+import org.apache.derby.impl.sql.compile.OrderByList;\r
+import org.apache.derby.impl.sql.compile.OrderByColumn;\r
+import org.apache.derby.impl.sql.compile.ResultSetNode;\r
+import org.apache.derby.impl.sql.compile.SelectNode;\r
+import org.apache.derby.impl.sql.compile.SubqueryNode;\r
+import org.apache.derby.impl.sql.compile.TableName;\r
+import org.apache.derby.impl.sql.compile.TernaryOperatorNode;\r
+import org.apache.derby.impl.sql.compile.ParameterNode;\r
+import org.apache.derby.impl.sql.compile.PrivilegeNode;\r
+import org.apache.derby.impl.sql.compile.ConstraintDefinitionNode;\r
+import org.apache.derby.impl.sql.compile.DMLModStatementNode;\r
+import org.apache.derby.impl.sql.compile.RoutineDesignator;\r
+import org.apache.derby.impl.sql.compile.StatementNode;\r
+import org.apache.derby.impl.sql.compile.TableElementList;\r
+import org.apache.derby.impl.sql.compile.TableElementNode;\r
+import org.apache.derby.impl.sql.compile.TableOperatorNode;\r
+import org.apache.derby.impl.sql.compile.TablePrivilegesNode;\r
+import org.apache.derby.impl.sql.compile.TransactionStatementNode;\r
+import org.apache.derby.impl.sql.compile.TriggerReferencingStruct;\r
+import org.apache.derby.impl.sql.compile.UnionNode;\r
+import org.apache.derby.impl.sql.compile.IntersectOrExceptNode;\r
+import org.apache.derby.impl.sql.compile.UnaryOperatorNode;\r
+import org.apache.derby.impl.sql.compile.UntypedNullConstantNode;\r
+import org.apache.derby.impl.sql.compile.UpdateNode;\r
+import org.apache.derby.impl.sql.compile.UserTypeConstantNode;\r
+import org.apache.derby.impl.sql.compile.ValueNode;\r
+import org.apache.derby.impl.sql.compile.ValueNodeList;\r
+import org.apache.derby.impl.sql.compile.GroupByColumn;\r
+import org.apache.derby.impl.sql.compile.CurrentDatetimeOperatorNode;\r
+import org.apache.derby.impl.sql.compile.DDLStatementNode;\r
+import org.apache.derby.impl.sql.compile.AlterTableNode;\r
+\r
+import org.apache.derby.impl.sql.compile.ParseException;\r
+import org.apache.derby.impl.sql.compile.Token;\r
+import org.apache.derby.impl.sql.compile.TokenMgrError;\r
+import org.apache.derby.impl.sql.compile.SQLParserConstants;\r
+import org.apache.derby.impl.sql.compile.CharStream;\r
+import org.apache.derby.impl.sql.execute.TablePrivilegeInfo;\r
+import org.apache.derby.iapi.sql.dictionary.DataDictionary;\r
+import org.apache.derby.iapi.sql.dictionary.TableDescriptor;\r
+import org.apache.derby.iapi.sql.dictionary.TriggerDescriptor;\r
+import org.apache.derby.iapi.sql.dictionary.ViewDescriptor;\r
+import org.apache.derby.iapi.sql.dictionary.SchemaDescriptor;\r
+\r
+import org.apache.derby.iapi.sql.conn.Authorizer;\r
+import org.apache.derby.iapi.sql.execute.ConstantAction;\r
+import org.apache.derby.iapi.sql.execute.ExecutionContext;\r
+\r
+import org.apache.derby.iapi.types.DataTypeDescriptor;\r
+import org.apache.derby.iapi.types.TypeId;\r
+import org.apache.derby.iapi.sql.compile.TypeCompiler;\r
+import org.apache.derby.iapi.sql.conn.LanguageConnectionContext;\r
+\r
+import org.apache.derby.iapi.types.DateTimeDataValue;\r
+import org.apache.derby.iapi.types.DataTypeDescriptor;\r
+import org.apache.derby.iapi.types.DataTypeUtilities;\r
+import org.apache.derby.iapi.types.StringDataValue;\r
+import org.apache.derby.iapi.types.DataValueDescriptor;\r
+\r
+import org.apache.derby.iapi.error.StandardException;\r
+\r
+import org.apache.derby.iapi.reference.Property;\r
+import org.apache.derby.iapi.reference.SQLState;\r
+import org.apache.derby.iapi.reference.JDBC30Translation;\r
+import org.apache.derby.iapi.reference.Limits;\r
+\r
+import org.apache.derby.iapi.sql.compile.CompilerContext;\r
+import org.apache.derby.iapi.sql.compile.C_NodeTypes;\r
+\r
+import org.apache.derby.iapi.services.context.ContextManager;\r
+\r
+import org.apache.derby.iapi.sql.compile.NodeFactory;\r
+\r
+import org.apache.derby.iapi.services.sanity.SanityManager;\r
+\r
+import org.apache.derby.catalog.AliasInfo;\r
+import org.apache.derby.catalog.TypeDescriptor;\r
+import org.apache.derby.catalog.types.RoutineAliasInfo;\r
+\r
+import org.apache.derby.iapi.services.io.FormatableProperties;\r
+import org.apache.derby.iapi.services.io.StoredFormatIds;\r
+import org.apache.derby.iapi.util.ReuseFactory;\r
+import org.apache.derby.iapi.services.io.FormatableBitSet;\r
+import org.apache.derby.iapi.util.StringUtil;\r
+\r
+import java.sql.Types;\r
+import java.util.List;\r
+import java.util.ArrayList;\r
+import java.util.Hashtable;\r
+import java.util.Properties;\r
+import java.util.StringTokenizer;\r
+import java.util.Vector;\r
+import java.lang.Character;\r
+\r
+public class SQLParser\r
+{\r
+ private static final String[] SAVEPOINT_CLAUSE_NAMES = {"UNIQUE", "ON ROLLBACK RETAIN LOCKS", "ON ROLLBACK RETAIN CURSORS"};\r
+ private static final String[] ROUTINE_CLAUSE_NAMES =\r
+ {null, "SPECIFIC", "RESULT SET", "LANGUAGE", "EXTERNAL NAME", "PARAMETER STYLE", "SQL", "ON NULL INPUT"};\r
+ /**\r
+ Clauses required for Java routines. Numbers correspond\r
+ to offsets in ROUTINE_CLAUSE_NAMES.\r
+ 3 - "LANGUAGE"\r
+ 4 - "EXTERNAL NAME"\r
+ 5 - "PARAMETER STYLE"\r
+ */\r
+ private static final int[] JAVA_ROUTINE_CLAUSES = {3,4,5};\r
+ private static final String[] TEMPORARY_TABLE_CLAUSE_NAMES = {"NOT LOGGED", "ON COMMIT", "ON ROLLBACK"};\r
+ /* The default length of a char or bit if the length is omitted */\r
+ private static final int DEFAULT_STRING_COLUMN_LENGTH = 1;\r
+\r
+ // Defines for ON or USING clauses\r
+ private static final int ON_OR_USING_CLAUSE_SIZE = 2;\r
+ private static final int ON_CLAUSE = 0;\r
+ private static final int USING_CLAUSE = 1;\r
+\r
+ // Defines for optional table clauses\r
+ private static final int OPTIONAL_TABLE_CLAUSES_SIZE = 3;\r
+ private static final int OPTIONAL_TABLE_CLAUSES_TABLE_PROPERTIES = 0;\r
+ private static final int OPTIONAL_TABLE_CLAUSES_DERIVED_RCL = 1;\r
+ private static final int OPTIONAL_TABLE_CLAUSES_CORRELATION_NAME = 2;\r
+\r
+ // Define for UTF8 max\r
+ private static final int MAX_UTF8_LENGTH = 65535;\r
+\r
+ // Constants for set operator types\r
+ private static final int NO_SET_OP = 0;\r
+ private static final int UNION_OP = 1;\r
+ private static final int UNION_ALL_OP = 2;\r
+ private static final int EXCEPT_OP = 3;\r
+ private static final int EXCEPT_ALL_OP = 4;\r
+ private static final int INTERSECT_OP = 5;\r
+ private static final int INTERSECT_ALL_OP = 6;\r
+\r
+ private Object[] paramDefaults;\r
+ private String statementSQLText;\r
+ private NodeFactory nodeFactory;\r
+ private ContextManager cm;\r
+ private CompilerContext compilerContext;\r
+\r
+ /* The number of the next ? parameter */\r
+ private int parameterNumber;\r
+\r
+ /* The list of ? parameters */\r
+ private Vector parameterList;\r
+\r
+ /* Remember if the last identifier or keyword was a\r
+ * delimited identifier. This is used for remembering\r
+ * if the xxx in SERIALIZE(xxx) was a delimited identifier\r
+ * because we need to know whether or not we can convert\r
+ * xxx to upper case if we try to resolve it as a class\r
+ * alias at bind time.\r
+ */\r
+ private Boolean lastTokenDelimitedIdentifier = Boolean.FALSE;\r
+ private Boolean nextToLastTokenDelimitedIdentifier = Boolean.FALSE;\r
+\r
+\r
+ /*\r
+ ** Remember the last token we got that was an identifier\r
+ */ \r
+ private Token lastIdentifierToken;\r
+ private Token nextToLastIdentifierToken;\r
+\r
+ static final String SINGLEQUOTES = "\'\'";\r
+ static final String DOUBLEQUOTES = "\"\"";\r
+\r
+ static final String DEFAULT_INDEX_TYPE = "BTREE";\r
+\r
+ //the following 2 booleans are used to make sure only null or not null is\r
+ //defined for a column while creating a table or altering a table. Defining\r
+ //both at the same time will be an error case.\r
+ boolean explicitNotNull = false;\r
+ boolean explicitNull = false;\r
+\r
+ //this vector keeps a list of explicitly nullable columns, so that if they\r
+ //get used in the table level primary key constraint, it will result in an\r
+ //exception. \r
+ Vector explicitlyNullableColumnsList = new Vector();\r
+\r
+\r
+ final void setCompilerContext(CompilerContext cc) {\r
+ this.compilerContext = cc;\r
+ this.cm = cc.getContextManager();\r
+ }\r
+\r
+ /**\r
+ * Get the NodeFactory for this database.\r
+ *\r
+ * @return The NodeFactory for this database.\r
+ * @exception StandardException Thrown on error\r
+ */\r
+ private final NodeFactory getNodeFactory() throws StandardException\r
+ {\r
+ if ( nodeFactory == null )\r
+ {\r
+ nodeFactory = getCompilerContext().getNodeFactory();\r
+ }\r
+\r
+ return nodeFactory;\r
+ }\r
+\r
+ private final CompilerContext getCompilerContext()\r
+ { \r
+ return compilerContext; \r
+ }\r
+\r
+ private DataTypeDescriptor getDataTypeServices(int type, int precision, int scale,\r
+ int length)\r
+ {\r
+ return new DataTypeDescriptor(\r
+ TypeId.getBuiltInTypeId(type),\r
+ precision,\r
+ scale,\r
+ true, /* assume nullable for now, change it if not nullable */\r
+ length\r
+ );\r
+ }\r
+\r
+ private DataTypeDescriptor getJavaClassDataTypeDescriptor(String javaClassName) \r
+ {\r
+ return new DataTypeDescriptor(\r
+ TypeId.getUserDefinedTypeId(\r
+ javaClassName, \r
+ lastTokenDelimitedIdentifier.booleanValue()),\r
+ true);\r
+ }\r
+ private LanguageConnectionContext getLanguageConnectionContext()\r
+ {\r
+ return (LanguageConnectionContext) getContextManager().getContext(\r
+ LanguageConnectionContext.CONTEXT_ID);\r
+ }\r
+\r
+ /**\r
+ Utility method for checking that the underlying database has been\r
+ upgraded to the required level to use this functionality. Used to\r
+ disallow SQL statements that would leave on-disk formats that would\r
+ not be understood by a engine that matches the current upgrade level\r
+ of the database. Throws an exception if the database is not a the required level.\r
+ <P>\r
+ Typically used for CREATE statements at the parser level. Called usually just\r
+ before the node is created, or can be called in just a partial syntax fragment\r
+ \r
+ @param version Data Dictionary major version (DataDictionary.DD_ constant)\r
+ @param feature SQL Feature name, for error text.\r
+ */\r
+ private void checkVersion(int version, String feature) throws StandardException\r
+ {\r
+ getLanguageConnectionContext().getDataDictionary().checkVersion(\r
+ version, feature);\r
+ }\r
+\r
+ /**\r
+ Utility method for checking that the underlying database uses SQL standard\r
+ permission checking (GRANT/REVOKE).\r
+\r
+ @param command "GRANT" or "REVOKE"\r
+ */\r
+ private void checkSqlStandardAccess( String command) throws StandardException\r
+ {\r
+ if( getLanguageConnectionContext().usesSqlAuthorization())\r
+ return;\r
+\r
+ throw StandardException.newException(SQLState.LANG_GRANT_REVOKE_WITH_LEGACY_ACCESS,\r
+ command,\r
+ Property.SQL_AUTHORIZATION_PROPERTY,\r
+ "TRUE");\r
+ }\r
+\r
+\r
+ /**\r
+ Check that the current mode supports internal extensions.\r
+\r
+ @param feature Description of feature for exception.\r
+\r
+ @exception StandardException current mode does not support statement\r
+ */\r
+ private void checkInternalFeature(String feature) throws StandardException\r
+ {\r
+ CompilerContext cc = getCompilerContext();\r
+ if ((cc.getReliability() & CompilerContext.INTERNAL_SQL_ILLEGAL) != 0)\r
+ throw StandardException.newException(SQLState.LANG_SYNTAX_ERROR, feature);\r
+ }\r
+\r
+ /**\r
+ * check if the type length is ok for the given type.\r
+ */\r
+ private void checkTypeLimits(int type, int length)\r
+ throws StandardException\r
+ { \r
+ boolean valid = true;\r
+\r
+ \r
+ switch (type) {\r
+ case Types.BINARY:\r
+ case Types.CHAR:\r
+ if (length > Limits.DB2_CHAR_MAXWIDTH)\r
+ valid = false;\r
+ break;\r
+ \r
+ case Types.VARBINARY:\r
+ case Types.VARCHAR:\r
+ if (length > Limits.DB2_VARCHAR_MAXWIDTH)\r
+ valid = false;\r
+\r
+ break;\r
+ default:\r
+ break;\r
+ }\r
+ if (!valid) // If these limits are too big \r
+ {\r
+ DataTypeDescriptor charDTD = \r
+ DataTypeDescriptor.getBuiltInDataTypeDescriptor(type, length);\r
+ \r
+ throw StandardException.newException(SQLState.LANG_DB2_LENGTH_PRECISION_SCALE_VIOLATION, charDTD.getSQLstring());\r
+ } \r
+ }\r
+ \r
+ \r
+\r
+ // Get the current ContextManager\r
+ private final ContextManager getContextManager()\r
+ {\r
+ return cm;\r
+ }\r
+\r
+ /*\r
+ ** Compress 2 adjacent (single or double) quotes into a single (s or d) quote when\r
+ ** found in the middle of a String.\r
+ ** NOTE: """" or '''' will be compressed into "" or ''.\r
+ ** This function assumes that the leading and trailing quote from a\r
+ ** string or delimited identifier have already been removed.\r
+ */\r
+ private static String compressQuotes(String source, String quotes)\r
+ {\r
+ String result = source;\r
+ int index;\r
+ \r
+ /* Find the first occurrence of adjacent quotes. */\r
+ index = result.indexOf(quotes);\r
+\r
+ /* Replace each occurrence with a single quote and begin the\r
+ * search for the next occurrence from where we left off.\r
+ */\r
+ while (index != -1)\r
+ {\r
+ result = result.substring(0, index + 1) + result.substring(index + 2);\r
+\r
+ index = result.indexOf(quotes, index + 1);\r
+ }\r
+\r
+ return result;\r
+ }\r
+ \r
+ private static void verifyImageLength(String image) throws StandardException\r
+ {\r
+ // beetle 2758. For right now throw an error for literals > 64K\r
+ if (image.length() > MAX_UTF8_LENGTH)\r
+ {\r
+ throw StandardException.newException(SQLState.LANG_INVALID_LITERAL_LENGTH);\r
+ } \r
+ }\r
+\r
+ /*\r
+ ** Converts a delimited id to a canonical form.\r
+ ** Post process delimited identifiers to eliminate leading and\r
+ ** trailing " and convert all occurrences of "" to ".\r
+ */\r
+ private static String normalizeDelimitedID(String str)\r
+ {\r
+ str = compressQuotes(str, DOUBLEQUOTES);\r
+ return str;\r
+ }\r
+ private static boolean isDATETIME(int val)\r
+ {\r
+ if (val == DATE || val == TIME || val == TIMESTAMP)\r
+ return true;\r
+ else\r
+ return false;\r
+ }\r
+\r
+ /*\r
+ * Generate a multiplicative operator node, if necessary.\r
+ *\r
+ * If there are two operands, generate the multiplicative operator\r
+ * that corresponds to the multiplicativeOperator parameter. If there\r
+ * is no left operand, just return the right operand.\r
+ *\r
+ * @param leftOperand The left operand, null if no operator\r
+ * @param rightOperand The right operand\r
+ * @param multiplicativeOperator An identifier from BinaryOperatorNode\r
+ * telling what operator to generate.\r
+ *\r
+ * @return The multiplicative operator, or the right operand if there is\r
+ * no operator.\r
+ *\r
+ * @exception StandardException Thrown on error\r
+ */\r
+\r
+ ValueNode multOp(ValueNode leftOperand,\r
+ ValueNode rightOperand,\r
+ int multiplicativeOperator)\r
+ throws StandardException\r
+ {\r
+ if (leftOperand == null)\r
+ {\r
+ return rightOperand;\r
+ }\r
+\r
+ switch (multiplicativeOperator)\r
+ {\r
+ case BinaryOperatorNode.TIMES:\r
+ return (ValueNode) nodeFactory.getNode(\r
+ C_NodeTypes.BINARY_TIMES_OPERATOR_NODE,\r
+ leftOperand,\r
+ rightOperand, \r
+ getContextManager());\r
+\r
+ case BinaryOperatorNode.DIVIDE:\r
+ return (ValueNode) nodeFactory.getNode(\r
+ C_NodeTypes.BINARY_DIVIDE_OPERATOR_NODE,\r
+ leftOperand,\r
+ rightOperand,\r
+ getContextManager());\r
+ case BinaryOperatorNode.CONCATENATE:\r
+ return (ValueNode) nodeFactory.getNode(\r
+ C_NodeTypes.CONCATENATION_OPERATOR_NODE,\r
+ leftOperand,\r
+ rightOperand,\r
+ getContextManager());\r
+\r
+ default:\r
+ if (SanityManager.DEBUG)\r
+ SanityManager.THROWASSERT("Unexpected multiplicative operator " + \r
+ multiplicativeOperator);\r
+ return null;\r
+ }\r
+ }\r
+\r
+ /**\r
+ * Set up and like the parameters to the descriptors.\r
+ * Set all the ParameterNodes to point to the array of\r
+ * parameter descriptors.\r
+ * \r
+ * @exception StandardException\r
+ */\r
+ private void setUpAndLinkParameters()\r
+ throws StandardException\r
+ {\r
+ CompilerContext cc = getCompilerContext();\r
+ cc.setParameterList(parameterList);\r
+ /* Link the untyped parameters to the array of parameter descriptors */\r
+ \r
+ DataTypeDescriptor[] descriptors = cc.getParameterTypes();\r
+\r
+ ParameterNode newNode;\r
+ ParameterNode oldNode;\r
+ int paramCount;\r
+\r
+ /*\r
+ ** Iterate through the list of untyped parameter nodes, set each one\r
+ ** to point to the array of parameter descriptors.\r
+ */\r
+ paramCount = -1;\r
+ int plSize = parameterList.size();\r
+ for (int index = 0; index < plSize; index++)\r
+ {\r
+ paramCount++;\r
+\r
+ newNode = (ParameterNode) parameterList.elementAt(index);\r
+ newNode.setDescriptors(descriptors );\r
+ }\r
+ }\r
+\r
+ /**\r
+ * Initializes the list of unnamed parameters, i.e., "?" parameters\r
+ *\r
+ * Usually, this routine just gets an empty list for the unnamed parameters.\r
+ *\r
+ *\r
+ */\r
+ void initUnnamedParameterList()\r
+ {\r
+ parameterList = new Vector();\r
+ }\r
+\r
+ /**\r
+ * Makes a new unnamed ParameterNode and chains it onto parameterList.\r
+ *\r
+ * @return new unnamed parameter.\r
+ *\r
+ * @exception StandardException\r
+ */\r
+ ParameterNode makeParameterNode( )\r
+ throws StandardException\r
+ {\r
+ ParameterNode parm;\r
+ DataValueDescriptor sdv = null;\r
+\r
+ if ((paramDefaults != null) && (parameterNumber < paramDefaults.length))\r
+ {\r
+ sdv = (DataValueDescriptor) paramDefaults[parameterNumber];\r
+ }\r
+\r
+ parm = (ParameterNode) nodeFactory.getNode(\r
+ C_NodeTypes.PARAMETER_NODE,\r
+ ReuseFactory.getInteger(parameterNumber),\r
+ sdv,\r
+ getContextManager());\r
+\r
+ parameterNumber++;\r
+ parameterList.addElement(parm);\r
+\r
+ return parm;\r
+ }\r
+\r
+ /**\r
+ * Looks up an unnamed parameter given its parameter number.\r
+ *\r
+ * @param paramNumber Number of parameter in unnamed\r
+ * parameter list.\r
+ *\r
+ * @return corresponding unnamed parameter.\r
+ *\r
+ */\r
+ ParameterNode lookupUnnamedParameter( int paramNumber )\r
+ {\r
+ ParameterNode unnamedParameter;\r
+\r
+ unnamedParameter = (ParameterNode) parameterList.elementAt( paramNumber );\r
+ return unnamedParameter;\r
+ }\r
+\r
+ /**\r
+ * Translate a String containing a number into the appropriate type\r
+ * of Numeric node.\r
+ *\r
+ * @exception StandardException Thrown on error\r
+ */\r
+ ValueNode getNumericNode(String num) throws StandardException\r
+ {\r
+ ContextManager cm = getContextManager();\r
+\r
+ // first, see if it might be an integer\r
+ try\r
+ {\r
+ return (ValueNode) nodeFactory.getNode(\r
+ C_NodeTypes.INT_CONSTANT_NODE,\r
+ new Integer(num),\r
+ cm);\r
+ }\r
+ catch (NumberFormatException nfe)\r
+ {\r
+ // we catch because we want to continue on below\r
+ }\r
+\r
+ // next, see if it might be a long\r
+ try\r
+ {\r
+ return (ValueNode) nodeFactory.getNode(\r
+ C_NodeTypes.LONGINT_CONSTANT_NODE,\r
+ new Long(num),\r
+ cm);\r
+ }\r
+ catch (NumberFormatException nfe)\r
+ {\r
+ // we catch because we want to continue on below\r
+ }\r
+\r
+ return (ValueNode) nodeFactory.getNode(\r
+ C_NodeTypes.DECIMAL_CONSTANT_NODE,\r
+ num,\r
+ cm);\r
+ }\r
+ /**\r
+ * Determine whether the current token represents one of\r
+ * the built-in aliases.\r
+ *\r
+ * @return TRUE iff the current token names a built-in alias\r
+ */\r
+ private boolean isBuiltInAlias()\r
+ {\r
+ boolean retval = false;\r
+\r
+ switch (token.kind)\r
+ {\r
+ case UCASE:\r
+ case LCASE:\r
+ case SQRT:\r
+ case LOCATE:\r
+ case ABS:\r
+ case ABSVAL:\r
+ case SUBSTR:\r
+ case MOD:\r
+ retval = true;\r
+ break;\r
+\r
+ default:\r
+ retval = false;\r
+ break;\r
+ }\r
+\r
+\r
+ return retval;\r
+ }\r
+\r
+\r
+ /**\r
+ * Determine whether the next sequence of tokens represents one of\r
+ * the common (built-in) datatypes.\r
+ *\r
+ * @param checkFollowingToken true if additonal token for NATIONAL\r
+ * or LONG should be checked\r
+ * @return TRUE iff the next set of tokens names a common datatype\r
+ */\r
+ boolean commonDatatypeName(boolean checkFollowingToken)\r
+ {\r
+ return commonDatatypeName(1, checkFollowingToken);\r
+ }\r
+\r
+ /**\r
+ * Determine whether a sequence of tokens represents one of\r
+ * the common (built-in) datatypes.\r
+ *\r
+ * @param checkFollowingToken true if additonal token for NATIONAL\r
+ * or LONG should be checked\r
+ * @param start starting token index of the sequence\r
+ * @return TRUE iff the next set of tokens names a common datatype\r
+ */\r
+ boolean commonDatatypeName(int start, boolean checkFollowingToken)\r
+ {\r
+ boolean retval = false;\r
+\r
+ switch (getToken(start).kind)\r
+ {\r
+ case CHARACTER:\r
+ case CHAR:\r
+ case VARCHAR:\r
+ case NVARCHAR:\r
+ case NCHAR:\r
+ case BIT:\r
+ case NUMERIC:\r
+ case DECIMAL:\r
+ case DEC:\r
+ case INTEGER:\r
+ case INT:\r
+ case SMALLINT:\r
+ case LONGINT:\r
+ case FLOAT:\r
+ case REAL:\r
+ case DATE:\r
+ case TIME:\r
+ case TIMESTAMP:\r
+ case BOOLEAN:\r
+ case DOUBLE:\r
+ case BLOB:\r
+ case CLOB:\r
+ case NCLOB:\r
+ case BINARY: // LARGE OBJECT\r
+ case XML:\r
+ retval = true;\r
+ break;\r
+\r
+ case LONG:\r
+ if (checkFollowingToken == true)\r
+ {\r
+ switch (getToken(start+1).kind)\r
+ {\r
+ case VARCHAR:\r
+ case NVARCHAR:\r
+ case BINARY:\r
+ case VARBINARY:\r
+ case BIT:\r
+ retval = true;\r
+ break;\r
+ }\r
+ break;\r
+ }\r
+ else\r
+ {\r
+ retval = true;\r
+ break;\r
+ }\r
+\r
+ case NATIONAL:\r
+ if (checkFollowingToken == true)\r
+ {\r
+ switch (getToken(start+1).kind)\r
+ {\r
+ case CHAR:\r
+ case CHARACTER:\r
+ retval = true;\r
+ break;\r
+ }\r
+ break;\r
+ }\r
+ else\r
+ {\r
+ retval = true;\r
+ break;\r
+ }\r
+ }\r
+\r
+ return retval;\r
+ }\r
+\r
+ /**\r
+ * Get a DELETE node given the pieces.\r
+ *\r
+ *\r
+ * @exception StandardException\r
+ */\r
+ private StatementNode getDeleteNode(FromTable fromTable,\r
+ TableName tableName,\r
+ ValueNode whereClause)\r
+ throws StandardException\r
+ {\r
+ FromList fromList = (FromList) nodeFactory.getNode(\r
+ C_NodeTypes.FROM_LIST,\r
+ getContextManager());\r
+\r
+ fromList.addFromTable(fromTable);\r
+\r
+ SelectNode resultSet = (SelectNode) nodeFactory.getNode(\r
+ C_NodeTypes.SELECT_NODE,\r
+ null,\r
+ null, /* AGGREGATE list */\r
+ fromList, /* FROM list */\r
+ whereClause, /* WHERE clause */\r
+ null, /* GROUP BY list */\r
+ null, /* having clause */\r
+ getContextManager());\r
+\r
+ StatementNode retval =\r
+ (StatementNode) nodeFactory.getNode(\r
+ C_NodeTypes.DELETE_NODE,\r
+ tableName,\r
+ resultSet,\r
+ getContextManager());\r
+\r
+ setUpAndLinkParameters();\r
+\r
+ return retval;\r
+ }\r
+\r
+ /**\r
+ * Get an UPDATE node given the pieces.\r
+ *\r
+ *\r
+ * @exception StandardException\r
+ */\r
+ private StatementNode getUpdateNode(FromTable fromTable,\r
+ TableName tableName,\r
+ ResultColumnList setClause,\r
+ ValueNode whereClause)\r
+ throws StandardException\r
+ {\r
+ FromList fromList = (FromList) nodeFactory.getNode(\r
+ C_NodeTypes.FROM_LIST,\r
+ getContextManager());\r
+\r
+ fromList.addFromTable(fromTable);\r
+\r
+ SelectNode resultSet = (SelectNode) nodeFactory.getNode(\r
+ C_NodeTypes.SELECT_NODE,\r
+ setClause,\r
+ null, /* AGGREGATE list */\r
+ fromList, /* FROM list */\r
+ whereClause, /* WHERE clause */\r
+ null, /* GROUP BY list */\r
+ null, /* having clause */\r
+ getContextManager());\r
+\r
+ StatementNode retval =\r
+ (StatementNode) nodeFactory.getNode(\r
+ C_NodeTypes.UPDATE_NODE,\r
+ tableName,\r
+ resultSet,\r
+ getContextManager());\r
+\r
+ setUpAndLinkParameters();\r
+\r
+ return retval;\r
+ }\r
+\r
+ /**\r
+ * Generate a trim operator node\r
+ * @param trimSpec one of Leading, Trailing or Both.\r
+ * @param trimChar the character to trim. Can be null in which case it defaults\r
+ * to ' '.\r
+ * @param trimSource expression to be trimmed.\r
+ */\r
+ private ValueNode getTrimOperatorNode(Integer trimSpec, ValueNode trimChar,\r
+ ValueNode trimSource, ContextManager cm) throws StandardException\r
+ {\r
+ if (trimChar == null)\r
+ {\r
+ trimChar = (CharConstantNode) nodeFactory.getNode(\r
+ C_NodeTypes.CHAR_CONSTANT_NODE,\r
+ " ",\r
+ getContextManager());\r
+ }\r
+ return (ValueNode) nodeFactory.getNode(\r
+ C_NodeTypes.TRIM_OPERATOR_NODE,\r
+ trimSource, // receiver\r
+ trimChar, // leftOperand.\r
+ null,\r
+ ReuseFactory.getInteger(TernaryOperatorNode.TRIM),\r
+ trimSpec,\r
+ cm == null ? getContextManager() : cm);\r
+ }\r
+\r
+ private boolean ansiTrimSpecFollows()\r
+ {\r
+ return (getToken(2).kind == LEADING || getToken(2).kind == TRAILING\r
+ || getToken(2).kind == BOTH);\r
+ }\r
+ \r
+ /**\r
+ * Determine whether the next sequence of tokens can be the beginning\r
+ * of a remainingPredicate() rule.\r
+ *\r
+ * @return TRUE iff the next set of tokens is the beginning of a\r
+ * remainingPredicate()\r
+ */\r
+ private boolean remainingPredicateFollows()\r
+ {\r
+ boolean retval = false;\r
+\r
+ switch (getToken(1).kind)\r
+ {\r
+ case EQUALS_OPERATOR:\r
+ case NOT_EQUALS_OPERATOR:\r
+ case NOT_EQUALS_OPERATOR2: // !=\r
+ case LESS_THAN_OPERATOR:\r
+ case GREATER_THAN_OPERATOR:\r
+ case LESS_THAN_OR_EQUALS_OPERATOR:\r
+ case GREATER_THAN_OR_EQUALS_OPERATOR:\r
+ case IN:\r
+ case LIKE:\r
+ case BETWEEN:\r
+ retval = true;\r
+ break;\r
+\r
+ case NOT:\r
+ switch (getToken(2).kind)\r
+ {\r
+ case IN:\r
+ case LIKE:\r
+ case BETWEEN:\r
+ retval = true;\r
+ }\r
+ break;\r
+ }\r
+\r
+ return retval;\r
+ }\r
+\r
+\r
+ /**\r
+ * Determine whether the next token is a DROP\r
+ *\r
+ * @return TRUE iff the next token is DROP\r
+ */\r
+ private boolean dropFollows()\r
+ {\r
+ if (getToken(1).kind == DROP)\r
+ { return true; }\r
+ else { return false; }\r
+ }\r
+\r
+ /**\r
+ * Determine whether the next sequence of tokens can be the beginning\r
+ * of a escapedValueFunction().\r
+ *\r
+ * We check only for the punctuation here, because identifiers are\r
+ * very hard to check for in semantic lookahead.\r
+ *\r
+ * @return TRUE iff the next set of tokens is the beginning of a\r
+ * escapedValueFunction()\r
+ */\r
+ private boolean escapedValueFunctionFollows()\r
+ {\r
+ if (getToken(1).kind != LEFT_BRACE)\r
+ {\r
+ return false;\r
+ }\r
+\r
+ return getToken(2).kind == FN;\r
+ }\r
+ \r
+\r
+ /**\r
+ List of JDBC escape functions that map directly onto\r
+ a function in the SYSFUN schema.\r
+ */\r
+ private static final String[] ESCAPED_SYSFUN_FUNCTIONS =\r
+ {"ACOS", "ASIN", "ATAN", "COS", "SIN", "TAN", "PI",\r
+ "DEGREES", "RADIANS", "EXP", "LOG", "LOG10", "CEILING", "FLOOR",\r
+ "SIGN", "RAND", "COT" };\r
+ \r
+ /**\r
+ Convert a JDBC escaped function name to a function\r
+ name in the SYSFUC schema. Returns null if no such\r
+ function exists.\r
+ */ \r
+ private String getEscapedSYSFUN(String name)\r
+ {\r
+ name = StringUtil.SQLToUpperCase(name);\r
+ \r
+ for (int i = 0; i < ESCAPED_SYSFUN_FUNCTIONS.length; i++)\r
+ {\r
+ if (ESCAPED_SYSFUN_FUNCTIONS[i].equals(name))\r
+ return name;\r
+ }\r
+ return null;\r
+ }\r
+\r
+ /**\r
+ * Determine whether the next sequence of tokens can be the beginning\r
+ * of a columnInvocation() rule. columnInvocations start with\r
+ * [ [ id . ] id . ] id . id (\r
+ *\r
+ * We check only for the punctuation here, because identifiers are\r
+ * very hard to check for in semantic lookahead.\r
+ *\r
+ * @return TRUE iff the next set of tokens is the beginning of a\r
+ * columnInvocation()\r
+ */\r
+ private boolean columnMethodInvocationFollows()\r
+ {\r
+ int tokKind;\r
+\r
+ // First token must not be a built-in function name that can be\r
+ // followed immediately by a PERIOD. There are only a few of\r
+ // these - most built-in functions have a LEFT_PAREN following\r
+ // the function name.\r
+\r
+ // if we run out of token, it's probably a syntax error, \r
+ // in fact\r
+ tokKind = getToken(1).kind;\r
+ if ( tokKind == EOF ) { return false; } \r
+ \r
+ // disambiguate from named parameter reference\r
+ if ( getToken(1).image.charAt(0) == '?' ) { return false; }\r
+\r
+ if (tokKind == CURRENT_DATE ||\r
+ tokKind == CURRENT_TIME ||\r
+ tokKind == CURRENT_TIMESTAMP ||\r
+ tokKind == CURRENT && (isDATETIME(getToken(2).kind)) )\r
+ {\r
+ return false;\r
+ }\r
+\r
+ // Second token must be a PERIOD\r
+ if (getToken(2).kind != PERIOD)\r
+ {\r
+ return false;\r
+ }\r
+\r
+ // We have established that we start with " id . "\r
+ tokKind = getToken(4).kind;\r
+ if (tokKind == LEFT_PAREN)\r
+ {\r
+ // id.id(\r
+ return true;\r
+ }\r
+\r
+ // Not id.id(, so 4th token must be PERIOD\r
+ if (tokKind != PERIOD)\r
+ {\r
+ return false;\r
+ }\r
+\r
+ tokKind = getToken(6).kind;\r
+ if (tokKind == LEFT_PAREN)\r
+ {\r
+ // id.id.id(\r
+ return true;\r
+ }\r
+\r
+ // Not id.id.id(, so 6th token must be PERIOD\r
+ if (tokKind != PERIOD)\r
+ {\r
+ return false;\r
+ }\r
+\r
+ tokKind = getToken(8).kind;\r
+ if (tokKind == LEFT_PAREN)\r
+ {\r
+ // id.id.id.id(\r
+ return true;\r
+ }\r
+\r
+ return false;\r
+ }\r
+\r
+ /**\r
+ * Determine whether the next sequence of tokens can be the beginning\r
+ * of an aggregateNode()() rule. aggregateNodes() start with one\r
+ * of the built-in aggregate names, or with an identifier followed\r
+ * by "( DISTINCT". A non-distinct user-defined aggregate invocation\r
+ * is treated as a staticMethodInvocationAlias() by the parser,\r
+ * and the binding phase figures out what it really is by looking\r
+ * at the data dictionary.\r
+ *\r
+ * We check only for the punctuation here, because identifiers are\r
+ * very hard to check for in semantic lookahead.\r
+ *\r
+ * @return TRUE iff the next set of tokens is the beginning of a\r
+ * aggregateNode()\r
+ */\r
+ private boolean aggregateFollows()\r
+ {\r
+ boolean retval = false;\r
+\r
+ switch (getToken(1).kind)\r
+ {\r
+ case MAX:\r
+ case AVG:\r
+ case MIN:\r
+ case SUM:\r
+ // This is a built-in aggregate\r
+ retval = true;\r
+ break;\r
+\r
+ case COUNT:\r
+ // COUNT is not a reserved word\r
+ // This may eclipse use of COUNT as a function or a procedure that is probably what we want\r
+ if (getToken(2).kind == LEFT_PAREN)\r
+ retval = true;\r
+ default:\r
+ // Not a built-in aggregate - assume the first token is an\r
+ // identifier, and see whether it is followed by " ( DISTINCT "\r
+ if (getToken(2).kind == LEFT_PAREN && getToken(3).kind == DISTINCT)\r
+ retval = true;\r
+ break;\r
+ }\r
+\r
+ return retval;\r
+ }\r
+\r
+ /**\r
+ * Determine whether the next sequence of tokens can be the beginning\r
+ * of a miscBuiltins().\r
+ *\r
+ * We check only for the punctuation here, because identifiers are\r
+ * very hard to check for in semantic lookahead.\r
+ *\r
+ * @return TRUE iff the next set of tokens is the beginning of a\r
+ * aggregateNode()\r
+ */\r
+ private boolean miscBuiltinFollows()\r
+ {\r
+ boolean retval = false;\r
+ int tokKind = getToken(1).kind;\r
+ \r
+ if (getToken(0).kind == CALL) \r
+ retval = true;\r
+\r
+ switch (tokKind)\r
+ {\r
+ case GET_CURRENT_CONNECTION:\r
+ case CURRENT_DATE:\r
+ case CURRENT_TIME:\r
+ case CURRENT_TIMESTAMP:\r
+ retval = true;\r
+ break;\r
+\r
+ case CURRENT:\r
+ if (isDATETIME(getToken(2).kind)) \r
+ retval = true;\r
+ break;\r
+ \r
+ case CAST:\r
+ case LEFT_PAREN:\r
+ retval = false;\r
+ break;\r
+\r
+ default:\r
+ if (getToken(2).kind == LEFT_PAREN)\r
+ retval = true;\r
+ break;\r
+ }\r
+\r
+ return retval;\r
+ }\r
+\r
+ /**\r
+ * Determine whether the next sequence of tokens can be the beginning\r
+ * of a subquery. A subquery can begin with an arbitrary number of\r
+ * left parentheses, followed by either SELECT or VALUES.\r
+ *\r
+ * @return TRUE iff the next set of tokens is the beginning of a\r
+ * subquery.\r
+ */\r
+ private boolean subqueryFollows()\r
+ {\r
+ int tokKind;\r
+ boolean retval = false;\r
+\r
+ for (int i = 1; true; i++)\r
+ {\r
+ tokKind = getToken(i).kind;\r
+ if (tokKind == LEFT_PAREN)\r
+ {\r
+ // A subquery can start with an arbitrary number of left\r
+ // parentheses.\r
+ continue;\r
+ }\r
+ else if (tokKind == SELECT || tokKind == VALUES)\r
+ {\r
+ // If the first token we find after all the left parentheses\r
+ // is SELECT or VALUES, it's a subquery.\r
+ retval = true;\r
+ break;\r
+ }\r
+ else\r
+ {\r
+ // If the first token we find after all the left parentheses\r
+ // is neither SELECT nor VALUES, it's not a subquery.\r
+ break;\r
+ }\r
+ }\r
+\r
+ return retval;\r
+ }\r
+\r
+\r
+ /**\r
+ * Determine whether the next sequence of tokens can be the beginning\r
+ * of a rowValueConstructorList. A rowValueConstructorList is a comma-\r
+ * separated list of expressions enclosed in parentheses. This presents\r
+ * special problems, because an expression be nested within an\r
+ * arbitrary number of parentheses. To determine whether a left\r
+ * parenthesis introduces a rowValueConstructorList or an expression,\r
+ * we need to find the closing parenthesis, and determine whether\r
+ * the next token is a comma.\r
+ *\r
+ * For example, the following is a rowValueConstructorList:\r
+ *\r
+ * (((1)), 2)\r
+ *\r
+ * and the following is just an expression:\r
+ *\r
+ * (((1)))\r
+ *\r
+ * @return TRUE iff the next set of tokens is the beginning of a\r
+ * subquery.\r
+ */\r
+ private boolean rowValueConstructorListFollows()\r
+ {\r
+ int nesting;\r
+ boolean retval = false;\r
+\r
+ // A rowValueConstructorList starts with a left parenthesis\r
+ if (getToken(1).kind == LEFT_PAREN)\r
+ {\r
+ // Keep track of the nesting of parens while looking ahead\r
+ nesting = 1;\r
+ for (int i = 2; true; i++)\r
+ {\r
+ int tokKind = getToken(i).kind;\r
+\r
+ // Special case for NULL/DEFAULT because they are not allowed in\r
+ // a parenthesized expression, so (null)/(default) must be seen\r
+ // as a rowValueConstructorList with one element.\r
+ if (i == 2 && (tokKind == NULL || tokKind == _DEFAULT))\r
+ {\r
+ retval = true;\r
+ break;\r
+ }\r
+\r
+ // There must be a COMMA at nesting level 1 (i.e. outside of\r
+ // the first expression) for it to be a rowValueConstructorList\r
+ if (nesting == 1 && tokKind == COMMA)\r
+ {\r
+ retval = true;\r
+ break;\r
+ }\r
+\r
+ // If we run out of tokens before finding the last closing\r
+ // parenthesis, it's not a rowValueConstructorList (it's\r
+ // probably a syntax error, in fact)\r
+ if (tokKind == EOF)\r
+ {\r
+ break;\r
+ }\r
+\r
+ // Increase the nesting for each (, and decrease it for each )\r
+ if (tokKind == LEFT_PAREN)\r
+ {\r
+ nesting++;\r
+ }\r
+ else if (tokKind == RIGHT_PAREN)\r
+ {\r
+ nesting--;\r
+ }\r
+\r
+ // Don't look any farther than the last closing parenthesis\r
+ if (nesting == 0)\r
+ {\r
+ break;\r
+ }\r
+ }\r
+ }\r
+\r
+ return retval;\r
+ }\r
+\r
+ /**\r
+ * Determine whether the next token is the beginning of a propertyList(). \r
+ * A properties list is the comment "--derby-properties" followed by a \r
+ * dot-separated list, followed by an =, followed by a value all on that \r
+ * comment line. This means that the comment should start with the word\r
+ * "derby-properties".\r
+ *\r
+ * @return TRUE iff the next token is derby-properties \r
+ */\r
+ private boolean derbyPropertiesListFollows()\r
+ {\r
+ return \r
+ getToken(1).kind == DERBYDASHPROPERTIES;\r
+ }\r
+\r
+ /**\r
+ * Determine whether the next sequence of tokens can be the beginning\r
+ * of a newInvocation(). A newInvocation() begins with the word "new"\r
+ * followed by a dot-separated list of identifiers, followed\r
+ * by a left parenthesis.\r
+ *\r
+ * @param startToken Token to look for new at\r
+ *\r
+ * @return TRUE iff the next set of tokens is the beginning of a\r
+ * newInvocation().\r
+ */\r
+ private boolean newInvocationFollows(int startToken)\r
+ {\r
+ boolean retval = false;\r
+\r
+ // newInvocation() starts with the word "new"\r
+ if (getToken(startToken).kind == NEW)\r
+ {\r
+ // Look at every other token. Ignore the identifiers, because\r
+ // they are hard to test for.\r
+ for (int i = 2 + startToken; true; i += 2)\r
+ {\r
+ int tokKind = getToken(i).kind;\r
+\r
+ // If we find a left parenthesis without any intervening\r
+ // cruft, we have found a newInvocation()\r
+ if (tokKind == LEFT_PAREN)\r
+ {\r
+ retval = true;\r
+ break;\r
+ }\r
+ else if (tokKind != PERIOD)\r
+ {\r
+ // Anything other than a PERIOD is "cruft"\r
+ break;\r
+ }\r
+ }\r
+ }\r
+\r
+ return retval;\r
+ }\r
+ /**\r
+ * Determine whether the next sequence of tokens is a class name\r
+ *\r
+ * @return TRUE iff the next set of tokens is the java class name\r
+ */\r
+ boolean javaClassFollows()\r
+ {\r
+ boolean retval = false;\r
+\r
+ // Look at every other token. Ignore the identifiers, because\r
+ // they are hard to test for.\r
+ for (int i = 2; true; i += 2)\r
+ {\r
+ int tokKind = getToken(i).kind;\r
+\r
+ // If we find a '::' without any intervening\r
+ // cruft, we have found a javaClass\r
+ if (tokKind == DOUBLE_COLON)\r
+ {\r
+ retval = true;\r
+ break;\r
+ }\r
+ else if (tokKind != PERIOD)\r
+ {\r
+ // Anything other than a PERIOD is "cruft"\r
+ break;\r
+ }\r
+ }\r
+\r
+ return retval;\r
+ }\r
+\r
+ /**\r
+ * Determine whether the next sequence of tokens can be the beginning\r
+ * of a FROM newInvocation(). A FROM newInvocation() begins with the words "from new"\r
+ * followed by a dot-separated list of identifiers, followed\r
+ * by a left parenthesis.\r
+ *\r
+ * @return TRUE iff the next set of tokens is the beginning of a\r
+ * FROM newInvocation().\r
+ */\r
+ private boolean fromNewInvocationFollows()\r
+ {\r
+ boolean retval = false;\r
+\r
+ // FROM newInvocation() starts with the words "from new"\r
+ return (getToken(1).kind == FROM && newInvocationFollows(2));\r
+ }\r
+\r
+ /**\r
+ * Determine whether the next sequence of tokens can be the beginning\r
+ * of a joinedTableExpression(). A joinedTableExpression() begins\r
+ * with one of:\r
+ *\r
+ * JOIN\r
+ * INNER JOIN\r
+ * LEFT OUTER JOIN\r
+ * RIGHT OUTER JOIN\r
+ *\r
+ * @return TRUE iff the next set of tokens is the beginning of a\r
+ * joinedTableExpression().\r
+ */\r
+ private boolean joinedTableExpressionFollows()\r
+ {\r
+ boolean retval = false;\r
+\r
+ int tokKind1 = getToken(1).kind;\r
+ int tokKind2 = getToken(2).kind;\r
+\r
+ if (tokKind1 == JOIN)\r
+ {\r
+ retval = true;\r
+ }\r
+ else if (tokKind1 == INNER && tokKind2 == JOIN)\r
+ {\r
+ retval = true;\r
+ }\r
+ else if ((tokKind1 == LEFT || tokKind1 == RIGHT) && tokKind2 == OUTER)\r
+ {\r
+ if (getToken(3).kind == JOIN)\r
+ {\r
+ retval = true;\r
+ }\r
+ }\r
+ else if ((tokKind1 == LEFT || tokKind1 == RIGHT) && tokKind2 == JOIN)\r
+ {\r
+ retval = true;\r
+ }\r
+\r
+ return retval;\r
+ }\r
+\r
+ /**\r
+ * Translate a token for the name of a built-in aggregate to a String\r
+ * containing an aggregate name.\r
+ */\r
+ private static String aggName(Token token)\r
+ {\r
+ String retval = null;\r
+\r
+ switch (token.kind)\r
+ {\r
+ case MAX:\r
+ retval = "MAX";\r
+ break;\r
+\r
+ case AVG:\r
+ retval = "AVG";\r
+ break;\r
+\r
+ case MIN:\r
+ retval = "MIN";\r
+ break;\r
+\r
+ case SUM:\r
+ retval = "SUM";\r
+ break;\r
+\r
+ case COUNT:\r
+ retval = "COUNT";\r
+ break;\r
+\r
+ default:\r
+ if (SanityManager.DEBUG)\r
+ {\r
+ SanityManager.THROWASSERT("Unexpected token type in aggName: " +\r
+ token.kind);\r
+ }\r
+ break;\r
+ }\r
+\r
+ return retval;\r
+ }\r
+\r
+ /**\r
+ * Translate a token for the name of a built-in aggregate to an\r
+ * aggregate definition class.\r
+ */\r
+ private static Class aggClass(Token token)\r
+ {\r
+ Class retval = null;\r
+\r
+ switch (token.kind)\r
+ {\r
+ case MAX:\r
+ case MIN:\r
+ retval = MaxMinAggregateDefinition.class;\r
+ break;\r
+\r
+ case AVG:\r
+ case SUM:\r
+ retval = SumAvgAggregateDefinition.class;\r
+ break;\r
+\r
+ case COUNT:\r
+ retval = CountAggregateDefinition.class;\r
+ break;\r
+\r
+ default:\r
+ if (SanityManager.DEBUG)\r
+ {\r
+ SanityManager.THROWASSERT("Unexpected token type in aggClass: "\r
+ + token.kind);\r
+ }\r
+ break;\r
+ }\r
+\r
+ return retval;\r
+ }\r
+\r
+ /**\r
+ * Determine whether the next sequence of tokens can be the beginning\r
+ * of another element in a PROPERTY list. These elements are of the\r
+ * form:\r
+ *\r
+ * COMMA dot.separated.list = ...\r
+ *\r
+ * Look for the COMMA, the dots in the dot-separated list, and the =\r
+ *\r
+ * @return TRUE iff the next set of tokens is the beginning of a\r
+ * another element in a PROPERTY list.\r
+ */\r
+ private boolean anotherPropertyFollows()\r
+ {\r
+ boolean retval = false;\r
+\r
+ // Element must start with COMMA\r
+ if (getToken(1).kind == COMMA)\r
+ {\r
+ // Rest of element is dot-separated list with = at end\r
+ int i = 3;\r
+ int tokKind;\r
+ do\r
+ {\r
+ tokKind = getToken(i).kind;\r
+\r
+ // If we've found nothing but PERIODs until the EQUALS_OPERATOR\r
+ // it is the beginning of another property list element.\r
+ if (tokKind == EQUALS_OPERATOR)\r
+ {\r
+ retval = true;\r
+ break;\r
+ }\r
+\r
+ i += 2;\r
+ } while (tokKind == PERIOD);\r
+ }\r
+\r
+ return retval;\r
+ }\r
+\r
+ /**\r
+ * Get one of the several types of create alias nodes.\r
+ *\r
+ * @param aliasName The name of the alias\r
+ * @param fullStaticMethodName The full path/method name\r
+ * @param aliasSpecificInfo Information specific to the type of alias being created.\r
+ * @param aliasType The type of alias to create\r
+ * @param delimitedIdentifier Whether or not to treat the class name\r
+ * as a delimited identifier if trying to\r
+ * resolve it as a class alias.\r
+ *\r
+ * @return A CreateAliasNode matching the given parameters\r
+ *\r
+ * @exception StandardException Thrown on error\r
+ */\r
+ StatementNode\r
+ getCreateAliasNode(\r
+ Object aliasName,\r
+ String fullStaticMethodName,\r
+ Object aliasSpecificInfo,\r
+ char aliasType,\r
+ Boolean delimitedIdentifier)\r
+ throws StandardException\r
+ {\r
+\r
+ StatementNode aliasNode = (StatementNode) getNodeFactory().getCreateAliasNode\r
+ (\r
+ aliasName,\r
+ fullStaticMethodName,\r
+ aliasSpecificInfo,\r
+ aliasType,\r
+ delimitedIdentifier,\r
+ getContextManager()\r
+ );\r
+\r
+ return aliasNode;\r
+ }\r
+\r
+ /**\r
+ Create a node for the drop alias/procedure call.\r
+ */\r
+ StatementNode\r
+ dropAliasNode(Object aliasName, char type) throws StandardException\r
+ {\r
+\r
+ StatementNode stmt = (StatementNode) nodeFactory.getNode(\r
+ C_NodeTypes.DROP_ALIAS_NODE,\r
+ aliasName,\r
+ new Character(type),\r
+ getContextManager());\r
+\r
+ return stmt;\r
+ }\r
+\r
+ /**\r
+ * Get a substring node from\r
+ * - the string\r
+ * - the start position\r
+ * - the length\r
+ * - a boolean values for specifying the kind of substring function\r
+ * @exception StandardException Thrown on error\r
+ */\r
+ ValueNode getSubstringNode( ValueNode stringValue, ValueNode startPosition, \r
+ ValueNode length, Boolean boolVal ) throws StandardException\r
+ {\r
+ return (ValueNode) nodeFactory.getNode(\r
+ C_NodeTypes.SUBSTRING_OPERATOR_NODE,\r
+ stringValue,\r
+ startPosition,\r
+ length,\r
+ ReuseFactory.getInteger(TernaryOperatorNode.SUBSTRING),\r
+ null,\r
+ getContextManager());\r
+ }\r
+\r
+ final public TableName\r
+ qualifiedName(int id_length_limit) throws ParseException, StandardException\r
+ {\r
+ return qualifiedName( C_NodeTypes.TABLE_NAME, id_length_limit);\r
+ }\r
+\r
+ private void initStatement( String statementSQLText, Object[] paramDefaults)\r
+ throws StandardException\r
+ {\r
+ /* Do per-statement initialization here */\r
+ parameterNumber = 0;\r
+ this.statementSQLText = statementSQLText;\r
+ this.paramDefaults = paramDefaults;\r
+ nodeFactory = getNodeFactory();\r
+ initUnnamedParameterList();\r
+ } // End of initStatement\r
+\r
+ private void checkIdentifierLengthLimit( String identifier, int identifier_length_limit) \r
+ throws StandardException\r
+ {\r
+ if (identifier.length() > identifier_length_limit)\r
+ throw StandardException.newException(SQLState.LANG_IDENTIFIER_TOO_LONG, identifier, String.valueOf(identifier_length_limit));\r
+ }\r
+\r
+ private ValueNode getJdbcIntervalNode( int intervalType) throws StandardException\r
+ {\r
+ return (ValueNode) nodeFactory.getNode( C_NodeTypes.INT_CONSTANT_NODE,\r
+ ReuseFactory.getInteger( intervalType),\r
+ getContextManager());\r
+ }\r
+ \r
+ private void checkAuthorizationLength( String authorization)\r
+ throws StandardException\r
+ {\r
+ checkIdentifierLengthLimit( authorization, Limits.DB2_MAX_USERID_LENGTH);\r
+ }\r
+\r
+ /**\r
+ Check to see if the required claues have been added\r
+ to a procedure or function defintion.\r
+ \r
+ @param required int array of require clauses\r
+ @param clauses the array of declared clauses.\r
+ */\r
+ void checkRequiredRoutineClause(int[] required, Object[] clauses)\r
+ throws StandardException\r
+ {\r
+ for (int i = 0; i < required.length; i++)\r
+ {\r
+ int re = required[i];\r
+ if (clauses[re] == null)\r
+ {\r
+ throw StandardException.newException(SQLState.LANG_SYNTAX_ERROR,\r
+ ROUTINE_CLAUSE_NAMES[re]);\r
+ }\r
+ }\r
+ }\r
+}\r
+\r
+PARSER_END(SQLParser)\r
+\r
+TOKEN_MGR_DECLS :\r
+{\r
+ void CommonTokenAction(Token t)\r
+ {\r
+ t.beginOffset = input_stream.getBeginOffset();\r
+ t.endOffset = input_stream.getEndOffset();\r
+ }\r
+}\r
+\r
+SKIP :\r
+{ /* white space */\r
+ " "\r
+ | "\t"\r
+ | "\n"\r
+ | "\r"\r
+}\r
+\r
+SKIP :\r
+{ /* comments */\r
+ "--" : IN_COMMENT\r
+}\r
+\r
+<IN_COMMENT> SKIP :\r
+{ /* white space */\r
+ " "\r
+ | "\t"\r
+}\r
+\r
+/*\r
+ Check if the comment characters -- are followed by DERBY-PROPERTIES\r
+ token. \r
+\r
+ If yes, then this comment is providing user-supplied optimizer \r
+ overrides. There should be keyname=value [,keyname=value] pairs\r
+ after -- DERBY-PROPERTIES otherwise throw an exception. These\r
+ optimier overrides should be used in correct context only, \r
+ otherwise, the parser will throw an exception.\r
+\r
+ If this comment does not start with DERBY-PROPERTOIES, then it is \r
+ just a regular comment. Skip the comment and move on to the next line.\r
+ */\r
+<IN_COMMENT> MORE [IGNORE_CASE]:\r
+{\r
+"D" : LOOKFOR_DE\r
+|\r
+<("\n"|"\r"|"\r\n")?> : DEFAULT\r
+|\r
+<NOT_D : (~["D"])> : IT_IS_NOT_DERBYPROPERTIES_COMMENT\r
+}\r
+\r
+<LOOKFOR_DE> MORE [IGNORE_CASE]:\r
+{\r
+"E" : LOOKFOR_DER\r
+|\r
+<("\n"|"\r"|"\r\n")?> : DEFAULT\r
+|\r
+<NOT_DE : (~["E"])> : IT_IS_NOT_DERBYPROPERTIES_COMMENT\r
+}\r
+\r
+<LOOKFOR_DER> MORE [IGNORE_CASE]:\r
+{\r
+"R" : LOOKFOR_DERB\r
+|\r
+<("\n"|"\r"|"\r\n")?> : DEFAULT\r
+|\r
+<NOT_DER : (~["R"])> : IT_IS_NOT_DERBYPROPERTIES_COMMENT\r
+}\r
+\r
+<LOOKFOR_DERB> MORE [IGNORE_CASE]:\r
+{\r
+"B" : LOOKFOR_DERBY\r
+|\r
+<("\n"|"\r"|"\r\n")?> : DEFAULT\r
+|\r
+<NOT_DERB : (~["B"])> : IT_IS_NOT_DERBYPROPERTIES_COMMENT\r
+}\r
+\r
+<LOOKFOR_DERBY> MORE [IGNORE_CASE]:\r
+{\r
+"Y" : LOOKFOR_DERBYDASH\r
+|\r
+<("\n"|"\r"|"\r\n")?> : DEFAULT\r
+|\r
+<NOT_DERBY : (~["Y"])> : IT_IS_NOT_DERBYPROPERTIES_COMMENT\r
+}\r
+\r
+<LOOKFOR_DERBYDASH> MORE [IGNORE_CASE]:\r
+{\r
+"-" : LOOKFOR_DERBYDASHP\r
+|\r
+<("\n"|"\r"|"\r\n")?> : DEFAULT\r
+|\r
+<NOT_DERBYDASH : (~["-"])> : IT_IS_NOT_DERBYPROPERTIES_COMMENT\r
+}\r
+\r
+<LOOKFOR_DERBYDASHP> MORE [IGNORE_CASE]:\r
+{\r
+"P" : LOOKFOR_DERBYDASHPR\r
+|\r
+<("\n"|"\r"|"\r\n")?> : DEFAULT\r
+|\r
+<NOT_DERBYDASHP : (~["P"])> : IT_IS_NOT_DERBYPROPERTIES_COMMENT\r
+}\r
+\r
+<LOOKFOR_DERBYDASHPR> MORE [IGNORE_CASE]:\r
+{\r
+"R" : LOOKFOR_DERBYDASHPRO\r
+|\r
+<("\n"|"\r"|"\r\n")?> : DEFAULT\r
+|\r
+<NOT_DERBYDASHPR : (~["R"])> : IT_IS_NOT_DERBYPROPERTIES_COMMENT\r
+}\r
+\r
+<LOOKFOR_DERBYDASHPRO> MORE [IGNORE_CASE]:\r
+{\r
+"O" : LOOKFOR_DERBYDASHPROP\r
+|\r
+<("\n"|"\r"|"\r\n")?> : DEFAULT\r
+|\r
+<NOT_DERBYDASHPRO : (~["O"])> : IT_IS_NOT_DERBYPROPERTIES_COMMENT\r
+}\r
+\r
+<LOOKFOR_DERBYDASHPROP> MORE [IGNORE_CASE]:\r
+{\r
+"P" : LOOKFOR_DERBYDASHPROPE\r
+|\r
+<("\n"|"\r"|"\r\n")?> : DEFAULT\r
+|\r
+<NOT_DERBYDASHPROP : (~["P"])> : IT_IS_NOT_DERBYPROPERTIES_COMMENT\r
+}\r
+\r
+<LOOKFOR_DERBYDASHPROPE> MORE [IGNORE_CASE]:\r
+{\r
+"E" : LOOKFOR_DERBYDASHPROPER\r
+|\r
+<("\n"|"\r"|"\r\n")?> : DEFAULT\r
+|\r
+<NOT_DERBYDASHPROPE : (~["E"])> : IT_IS_NOT_DERBYPROPERTIES_COMMENT\r
+}\r
+\r
+<LOOKFOR_DERBYDASHPROPER> MORE [IGNORE_CASE]:\r
+{\r
+"R" : LOOKFOR_DERBYDASHPROPERT\r
+|\r
+<("\n"|"\r"|"\r\n")?> : DEFAULT\r
+|\r
+<NOT_DERBYDASHPROPER : (~["R"])> : IT_IS_NOT_DERBYPROPERTIES_COMMENT\r
+}\r
+\r
+<LOOKFOR_DERBYDASHPROPERT> MORE [IGNORE_CASE]:\r
+{\r
+"T" : LOOKFOR_DERBYDASHPROPERTI\r
+|\r
+<("\n"|"\r"|"\r\n")?> : DEFAULT\r
+|\r
+<NOT_DERBYDASHPROPERT : (~["T"])> : IT_IS_NOT_DERBYPROPERTIES_COMMENT\r
+}\r
+\r
+<LOOKFOR_DERBYDASHPROPERTI> MORE [IGNORE_CASE]:\r
+{\r
+"I" : LOOKFOR_DERBYDASHPROPERTIE\r
+|\r
+<("\n"|"\r"|"\r\n")?> : DEFAULT\r
+|\r
+<NOT_DERBYDASHPROPERTI : (~["I"])> : IT_IS_NOT_DERBYPROPERTIES_COMMENT\r
+}\r
+\r
+<LOOKFOR_DERBYDASHPROPERTIE> MORE [IGNORE_CASE]:\r
+{\r
+"E" : LOOKFOR_DERBYDASHPROPERTIES\r
+|\r
+<("\n"|"\r"|"\r\n")?> : DEFAULT\r
+|\r
+<NOT_DERBYDASHPROPERTIE : (~["E"])> : IT_IS_NOT_DERBYPROPERTIES_COMMENT\r
+}\r
+\r
+<LOOKFOR_DERBYDASHPROPERTIES> TOKEN [IGNORE_CASE] :\r
+{ \r
+ <DERBYDASHPROPERTIES : "DERBYDASHPROPERTIES"> \r
+}\r
+\r
+//once we find comment starting with -- DERBY-PROPERTIES, we want to switch \r
+//from SKIP mode to the TOKEN mode in the parser so the rest of the characters \r
+//on the comment line can be treated as part of one big token so we can get \r
+//keyname=value pairs from that token. The reason for treating them as one big\r
+//token is that the existing code in parser allows newline characters between\r
+//individual token but with optimizer overrides, all the properties have to\r
+//be specified on the -- DERBY-PROPERTIES comment line. \r
+<LOOKFOR_DERBYDASHPROPERTIES> TOKEN [IGNORE_CASE]:\r
+{\r
+"S" { matchedToken.kind = DERBYDASHPROPERTIES; } : PROPERTIES_LIST\r
+}\r
+\r
+//We found -- DERBY-PROPERTIE? where ? is a character other than S\r
+//and hence we should the rest of the characters on this line as \r
+//a regular comment\r
+<LOOKFOR_DERBYDASHPROPERTIES> SKIP :\r
+{\r
+<("\n"|"\r"|"\r\n")?> : DEFAULT\r
+|\r
+<NOT_PROPERTIES : (~["S","s"])> : IT_IS_NOT_DERBYPROPERTIES_COMMENT\r
+}\r
+\r
+<IT_IS_NOT_DERBYPROPERTIES_COMMENT> SKIP :\r
+{\r
+ <SINGLE_LINE_SQLCOMMENT: (~["\n","\r"])* ("\n"|"\r"|"\r\n")?> : DEFAULT\r
+}\r
+\r
+//found -- DERBY-PROPERTIES. Treat rest of the characters on the line\r
+//as one big token and then fetch keyname=value pairs from that token.\r
+<PROPERTIES_LIST> TOKEN :\r
+{\r
+ <CHECK_PROPERTIES: (~["\n","\r"])* ("\n"|"\r"|"\r\n")?> : DEFAULT\r
+}\r
+\r
+/*\r
+ This list should contain only and all SQL92 keywords that are reserved.\r
+ Reserved keywords can be used as identifiers in the language only\r
+ as delimited identifiers.\r
+ */\r
+/* NOTE - If you add a keyword, then you must add it to reservedKeyword()\r
+ * or nonReservedKeyword() as well!\r
+ */\r
+TOKEN [IGNORE_CASE] :\r
+{ /* SQL92 reserved Keywords */\r
+ <ADD: "add">\r
+| <ALL: "all">\r
+| <ALLOCATE: "allocate">\r
+| <ALTER: "alter">\r
+| <AND: "and">\r
+| <ANY: "any">\r
+| <ARE: "are">\r
+| <AS: "as">\r
+| <ASC: "asc">\r
+| <ASSERTION: "assertion">\r
+| <AT: "at">\r
+| <AUTHORIZATION: "authorization">\r
+| <AVG: "avg">\r
+| <BEGIN: "begin">\r
+| <BETWEEN: "between">\r
+| <BINARY: "binary">\r
+| <BIT: "bit">\r
+| <BOTH: "both">\r
+| <BY: "by">\r
+| <CASCADE: "cascade">\r
+| <CASCADED: "cascaded">\r
+| <CASE: "case">\r
+| <CAST: "cast">\r
+| <CHAR: "char">\r
+| <CHARACTER: "character">\r
+| <CHARACTER_LENGTH: "character_length">\r
+| <CHECK: "check">\r
+| <CLOSE: "close">\r
+| <COALESCE: "coalesce">\r
+| <COLLATE: "collate">\r
+| <COLLATION: "collation">\r
+| <COLUMN: "column">\r
+| <COMMIT: "commit">\r
+| <CONNECT: "connect">\r
+| <CONNECTION: "connection">\r
+| <CONSTRAINT: "constraint">\r
+| <CONSTRAINTS: "constraints">\r
+| <CONTINUE: "continue">\r
+| <CONVERT: "convert">\r
+| <CORRESPONDING: "corresponding">\r
+| <COUNT: "count">\r
+| <CREATE: "create">\r
+| <CURRENT: "current">\r
+| <CURRENT_DATE: "current_date">\r
+| <CURRENT_TIME: "current_time">\r
+| <CURRENT_TIMESTAMP: "current_timestamp">\r
+| <CURRENT_USER: "current_user">\r
+| <CURSOR: "cursor">\r
+| <D: "d">\r
+| <DEALLOCATE: "deallocate">\r
+| <DEC: "dec">\r
+| <DECIMAL: "decimal">\r
+| <DECLARE: "declare">\r
+| <_DEFAULT: "default">\r
+| <DEFERRABLE: "deferrable">\r
+| <DEFERRED: "deferred">\r
+| <DELETE: "delete">\r
+| <DESC: "desc">\r
+| <DESCRIBE: "describe">\r
+| <DIAGNOSTICS: "diagnostics">\r
+| <DISCONNECT: "disconnect">\r
+| <DISTINCT: "distinct">\r
+| <DOUBLE: "double">\r
+| <DROP: "drop">\r
+| <ELSE: "else">\r
+| <END: "end">\r
+| <ENDEXEC: "end-exec">\r
+| <ESCAPE: "escape">\r
+| <EXCEPT: "except">\r
+| <EXCEPTION: "exception">\r
+| <EXEC: "exec">\r
+| <EXECUTE: "execute">\r
+| <EXISTS: "exists">\r
+| <EXTERNAL: "external">\r
+| <FALSE: "false">\r
+| <FETCH: "fetch">\r
+| <FIRST: "first">\r
+| <FLOAT: "float">\r
+| <FOR: "for">\r
+| <FOREIGN: "foreign">\r
+| <FOUND: "found">\r
+| <FROM: "from">\r
+| <FULL: "full">\r
+| <FUNCTION: "function">\r
+| <GET: "get">\r
+| <GLOBAL: "global">\r
+| <GO: "go">\r
+| <GOTO: "goto">\r
+| <GRANT: "grant">\r
+| <GROUP: "group">\r
+| <HAVING: "having">\r
+| <HOUR: "hour">\r
+| <IDENTITY: "identity">\r
+| <IMMEDIATE: "immediate">\r
+| <IN: "in">\r
+| <INDICATOR: "indicator">\r
+| <INITIALLY: "initially">\r
+| <INNER: "inner">\r
+| <INPUT: "input">\r
+| <INSENSITIVE: "insensitive">\r
+| <INSERT: "insert">\r
+| <INT: "int">\r
+| <INTEGER: "integer">\r
+| <INTERSECT: "intersect">\r
+| <INTO: "into">\r
+| <IS: "is">\r
+| <ISOLATION: "isolation">\r
+| <JOIN: "join">\r
+| <KEY: "key">\r
+| <LAST: "last">\r
+| <LEADING: "leading">\r
+| <LEFT: "left">\r
+| <LIKE: "like">\r
+| <LOWER: "lower">\r
+| <MATCH: "match">\r
+| <MAX: "max">\r
+| <MIN: "min">\r
+| <MINUTE: "minute">\r
+| <MODULE: "module">\r
+| <NATIONAL: "national">\r
+| <NATURAL: "natural">\r
+| <NCHAR: "nchar">\r
+| <NEXT: "next">\r
+| <NO: "no">\r
+| <NOT: "not">\r
+| <NULL: "null">\r
+| <NULLIF: "nullif">\r
+| <NUMERIC: "numeric">\r
+| <OF: "of">\r
+| <ON: "on">\r
+| <ONLY: "only">\r
+| <OPEN: "open">\r
+| <OPTION: "option">\r
+| <OR: "or">\r
+| <ORDER: "order">\r
+| <OUTER: "outer">\r
+| <OUTPUT: "output">\r
+| <OVERLAPS: "overlaps">\r
+| <PAD: "pad">\r
+| <PARTIAL: "partial">\r
+| <PREPARE: "prepare">\r
+| <PRESERVE: "preserve">\r
+| <PRIMARY: "primary">\r
+| <PRIOR: "prior">\r
+| <PRIVILEGES: "privileges">\r
+| <PROCEDURE: "procedure">\r
+| <PUBLIC: "public">\r
+| <READ: "read">\r
+| <REAL: "real">\r
+| <REFERENCES: "references">\r
+| <RELATIVE: "relative">\r
+| <RESTRICT: "restrict">\r
+| <REVOKE: "revoke">\r
+| <RIGHT: "right">\r
+| <ROLLBACK: "rollback">\r
+| <ROWS: "rows">\r
+| <SCHEMA: "schema">\r
+| <SCROLL: "scroll">\r
+| <SECOND: "second">\r
+| <SELECT: "select">\r
+| <SESSION_USER: "session_user">\r
+| <SET: "set">\r
+| <SMALLINT: "smallint">\r
+| <SOME: "some">\r
+| <SPACE: "space">\r
+| <SQL: "sql">\r
+| <SQLCODE: "sqlcode">\r
+| <SQLERROR: "sqlerror">\r
+| <SQLSTATE: "sqlstate">\r
+| <SUBSTRING: "substring">\r
+| <SUM: "sum">\r
+| <SYSTEM_USER: "system_user">\r
+| <T: "t">\r
+| <TABLE: "table">\r
+| <TEMPORARY: "temporary">\r
+| <TIMEZONE_HOUR: "timezone_hour">\r
+| <TIMEZONE_MINUTE: "timezone_minute">\r
+| <TO: "to">\r
+| <TRANSACTION: "transaction">\r
+| <TRANSLATE: "translate">\r
+| <TRANSLATION: "translation">\r
+| <TRAILING: "trailing">\r
+| <TRIM: "trim">\r
+| <TRUE: "true">\r
+| <TS: "ts">\r
+| <UNION: "union">\r
+| <UNIQUE: "unique">\r
+| <UNKNOWN: "unknown">\r
+| <UPDATE: "update">\r
+| <UPPER: "upper">\r
+| <USER: "user">\r
+| <USING: "using">\r
+| <VALUE: "value">\r
+| <VALUES: "values">\r
+| <VARBINARY: "varbinary">\r
+| <VARCHAR: "varchar">\r
+| <VARYING: "varying">\r
+| <VIEW: "view">\r
+| <WHENEVER: "whenever">\r
+| <WHERE: "where">\r
+| <WITH: "with">\r
+| <WORK: "work">\r
+| <WRITE: "write">\r
+| <YEAR: "year">\r
+}\r
+\r
+/*\r
+ This list should contain only and all SQL92 keywords that are non-reserved.\r
+ Non-reserved keywords can be used as identifiers in the language.\r
+ To make that happen, the individual tokens have to be repeated in\r
+ the nonReservedKeyword() rule -- unless there's some other JavaCC shorthand?\r
+\r
+ NOTE: I've commented out most of these because we won't be using them\r
+ right away and the grammar is taking forever to process.\r
+ */\r
+/* NOTE - If you add a keyword, then you must add it to reservedKeyword()\r
+ * or nonReservedKeyword() as well!\r
+ */\r
+TOKEN [IGNORE_CASE] :\r
+{ /* SQL92 non-reserved Keywords */\r
+ <ABS: "abs">\r
+| <ABSVAL: "absval">\r
+| <ACTION: "action">\r
+| <ALWAYS: "always">\r
+| <BLOB: "blob">\r
+ | <C: "c">\r
+ | <CALLED: "called">\r
+| <CLOB: "clob">\r
+ | <COBOL: "cobol">\r
+| <COMMITTED: "committed">\r
+| <CONCAT: "concat">\r
+| <CONTAINS: "contains">\r
+| <DATA: "data">\r
+| <DATE: "date">\r
+| <DAY: "day">\r
+| <DEFINER: "definer">\r
+| <DYNAMIC: "dynamic">\r
+| <FORTRAN: "fortran">\r
+| <GENERATED: "generated">\r
+| <IDENTITY_VAL_LOCAL: "identity_val_local">\r
+| <INCREMENT: "increment">\r
+| <INITIAL: "initial">\r
+| <INOUT: "inout">\r
+| <INTERVAL: "interval">\r
+| <INVOKER: "invoker">\r
+| <LANGUAGE: "language">\r
+| <LARGE: "large">\r
+| <LENGTH: "length">\r
+| <LEVEL: "level">\r
+| <LOCKS: "locks">\r
+| <LOCKSIZE: "locksize">\r
+| <LOGGED: "logged">\r
+| <MOD: "mod">\r
+| <MODIFIES: "modifies">\r
+| <MODIFY: "modify">\r
+| <MONTH: "month">\r
+| <_MORE: "more">\r
+| <MUMPS: "mumps">\r
+| <NAME: "name">\r
+| <NCLOB: "nclob">\r
+| <NULLABLE: "nullable">\r
+| <NUMBER: "number">\r
+| <OBJECT: "object">\r
+| <PASCAL: "pascal">\r
+| <PLI: "pli">\r
+| <PRECISION: "precision">\r
+| <RELEASE: "release">\r
+| <REPEATABLE: "repeatable">\r
+| <RESTART: "restart">\r
+| <RETURNS: "returns">\r
+| <ROW: "row">\r
+| <SAVEPOINT: "savepoint">\r
+| <SCALE: "scale">\r
+| <SECURITY: "security">\r
+| <SERIALIZABLE: "serializable">\r
+| <SQL_TSI_FRAC_SECOND: "sql_tsi_frac_second">\r
+| <SQL_TSI_SECOND: "sql_tsi_second">\r
+| <SQL_TSI_MINUTE: "sql_tsi_minute">\r
+| <SQL_TSI_HOUR: "sql_tsi_hour">\r
+| <SQL_TSI_DAY: "sql_tsi_day">\r
+| <SQL_TSI_WEEK: "sql_tsi_week">\r
+| <SQL_TSI_MONTH: "sql_tsi_month">\r
+| <SQL_TSI_QUARTER: "sql_tsi_quarter">\r
+| <SQL_TSI_YEAR: "sql_tsi_year">\r
+| <START: "start">\r
+| <STATEMENT: "statement">\r
+| <SYNONYM: "synonym">\r
+| <THEN: "then">\r
+| <TIME: "time">\r
+| <TIMESTAMP: "timestamp">\r
+| <TIMESTAMPADD: "timestampadd">\r
+| <TIMESTAMPDIFF: "timestampdiff">\r
+| <TRUNCATE: "truncate">\r
+| <TYPE: "type">\r
+| <UNCOMMITTED: "uncommitted">\r
+| <USAGE: "usage">\r
+| <WHEN: "when">\r
+}\r
+\r
+/*\r
+ The next lists should contain non-SQL92 keywords, and should\r
+ specify whether their keywords are reserved or non-reserved.\r
+ If they are non-reserved, they need to be added to the identifier() rule.\r
+\r
+ NOTE: XML, XMLPARSE, XMLSERIALIZE, and XMLEXISTS are considered reserved\r
+ words to comply with the SQL/XML (2003) standard, section 5.1. Similarly,\r
+ XMLQUERY is a reserved word per SQL/XML (2006).\r
+ */\r
+\r
+/* NOTE - If you add a keyword, then you must add it to reservedKeyword()\r
+ * or nonReservedKeyword() as well!\r
+ */\r
+TOKEN [IGNORE_CASE] :\r
+{ /* Additional JSQL reserved keywords -- non-SQL92 reserved Keywords */\r
+ <BOOLEAN: "boolean">\r
+| <CALL: "call">\r
+| <CURDATE: "curdate">\r
+| <CURTIME: "curtime">\r
+| <DATABASE: "database">\r
+| <GET_CURRENT_CONNECTION: "getCurrentConnection">\r
+| <EXPLAIN: "explain">\r
+| <LONGINT: "bigint">\r
+| <LONG: "long">\r
+| <LTRIM: "ltrim">\r
+| <RTRIM: "rtrim">\r
+| <SUBSTR: "substr">\r
+| <XML: "xml">\r
+| <XMLEXISTS: "xmlexists">\r
+| <XMLPARSE: "xmlparse">\r
+| <XMLQUERY: "xmlquery">\r
+| <XMLSERIALIZE: "xmlserialize">\r
+}\r
+\r
+/* NOTE - If you add a keyword, then you must add it to reservedKeyword()\r
+ * or nonReservedKeyword() as well!\r
+ *\r
+ * NOTE: CONTENT, DOCUMENT, STRIP, WHITESPACE and PASSING are considered NON-\r
+ * reserved words to comply with the SQL/XML (2003) standard, section 5.1.\r
+ * Similarly, EMPTY, RETURNING, and SEQUENCE are all considered NON-reserved\r
+ * words per SQL/XML (2006). PRESERVE is also listed as non-reserved in the\r
+ * SQL/XML spec, but since that word is already reserved, we leave it alone.\r
+ */\r
+TOKEN [IGNORE_CASE] :\r
+{ /* Additional JSQL keywords -- non-SQL92 non-reserved Keywords */\r
+ <AFTER: "after">\r
+| <BEFORE: "before">\r
+| <CLASS: "class">\r
+| <COMPRESS: "compress">\r
+| <CONTENT: "content">\r
+| <CS: "cs">\r
+| <CURSORS: "cursors">\r
+| <DB2SQL: "db2sql">\r
+| <DIRTY: "dirty">\r
+| <DOCUMENT: "document">\r
+| <EACH: "each">\r
+| <EMPTY: "empty">\r
+| <EXCLUSIVE: "exclusive">\r
+| <FN: "fn">\r
+| <INDEX: "index">\r
+| <JAVA: "java">\r
+| <LCASE: "lcase">\r
+| <LOCATE: "locate">\r
+| <LOCK: "lock">\r
+| <MESSAGE_LOCALE: "message_locale">\r
+| <METHOD: "method">\r
+| <MODE: "mode">\r
+| <NEW: "new">\r
+| <NEW_TABLE: "new_table">\r
+| <NVARCHAR: "nvarchar"> \r
+| <OJ: "oj">\r
+| <OFF: "off">\r
+| <OLD: "old">\r
+| <OLD_TABLE: "old_table">\r
+| <OUT: "out">\r
+| <PARAMETER: "parameter">\r
+| <PASSING: "passing">\r
+| <PROPERTIES: "properties">\r
+| <READS: "reads">\r
+| <REF: "ref">\r
+| <REFERENCING: "referencing">\r
+| <RENAME: "rename">\r
+| <RESET: "reset">\r
+| <RESULT: "result">\r
+| <RETAIN: "retain">\r
+| <RETURNING: "returning">\r
+| <RR: "rr">\r
+| <RS: "rs">\r
+| <SEQUENCE: "sequence">\r
+| <SEQUENTIAL: "sequential">\r
+| <SETS: "sets">\r
+| <SHARE: "share">\r
+| <SQLID: "sqlid">\r
+| <SPECIFIC: "specific">\r
+| <SQRT: "sqrt">\r
+| <STABILITY: "stability">\r
+| <STRIP: "strip">\r
+| <STYLE: "style">\r
+| <TRIGGER: "trigger">\r
+| <UCASE: "ucase">\r
+| <UR: "ur">\r
+| <WHITESPACE: "whitespace">\r
+}\r
+\r
+TOKEN :\r
+{ /* Operators and punctuation */\r
+ <DOUBLE_QUOTE: "\"">\r
+| <PERCENT: "%">\r
+| <AMPERSAND: "&">\r
+| <QUOTE: "'">\r
+| <LEFT_BRACE: "{">\r
+| <RIGHT_BRACE: "}">\r
+| <LEFT_PAREN: "(">\r
+| <RIGHT_PAREN: ")">\r
+| <ASTERISK: "*">\r
+| <PLUS_SIGN: "+">\r
+| <COMMA: ",">\r
+| <MINUS_SIGN: "-">\r
+| <PERIOD: ".">\r
+| <SOLIDUS: "/">\r
+| <COLON: ":">\r
+| <DOUBLE_COLON: "::">\r
+| <SEMICOLON: ";">\r
+| <LESS_THAN_OPERATOR: "<">\r
+| <LESS_THAN_OR_EQUALS_OPERATOR: "<=">\r
+| <EQUALS_OPERATOR: "=">\r
+| <NOT_EQUALS_OPERATOR: "<>">\r
+| <NOT_EQUALS_OPERATOR2: "!=">\r
+| <GREATER_THAN_OPERATOR: ">">\r
+| <GREATER_THAN_OR_EQUALS_OPERATOR: ">=">\r
+| <QUESTION_MARK: "?">\r
+| <UNDERSCORE: "_">\r
+| <VERTICAL_BAR: "|">\r
+| <LEFT_BRACKET: "[">\r
+| <RIGHT_BRACKET: "]">\r
+| <CONCATENATION_OPERATOR: "||">\r
+| <FIELD_REFERENCE: "->">\r
+}\r
+\r
+TOKEN :\r
+{ /* Identifiers */\r
+ <IDENTIFIER: ( <LETTER> ) (<LETTER> | "_" | <DIGIT>)* >\r
+}\r
+\r
+TOKEN: { <K: "K" > }\r
+TOKEN: { <M: "M" > }\r
+TOKEN: { <G: "G" > }\r
+\r
+TOKEN:\r
+{\r
+ <#LETTER: [\r
+ "a"-"z",\r
+ "A"-"Z",\r
+ "\u00aa",\r
+ "\u00b5",\r
+ "\u00ba",\r
+ "\u00c0" - "\u00d6",\r
+ "\u00d8" - "\u00f6",\r
+ "\u00f8" - "\u01f5",\r
+ "\u01fa" - "\u0217",\r
+ "\u0250" - "\u02a8",\r
+ "\u02b0" - "\u02b8",\r
+ "\u02bb" - "\u02c1",\r
+ "\u02d0" - "\u02d1",\r
+ "\u02e0" - "\u02e4",\r
+ "\u037a",\r
+ "\u0386",\r
+ "\u0388" - "\u038a",\r
+ "\u038c",\r
+ "\u038e" - "\u03a1",\r
+ "\u03a3" - "\u03ce",\r
+ "\u03d0" - "\u03d6",\r
+ "\u03da",\r
+ "\u03dc",\r
+ "\u03de",\r
+ "\u03e0",\r
+ "\u03e2" - "\u03f3",\r
+ "\u0401" - "\u040c",\r
+ "\u040e" - "\u044f",\r
+ "\u0451" - "\u045c",\r
+ "\u045e" - "\u0481",\r
+ "\u0490" - "\u04c4",\r
+ "\u04c7" - "\u04c8",\r
+ "\u04cb" - "\u04cc",\r
+ "\u04d0" - "\u04eb",\r
+ "\u04ee" - "\u04f5",\r
+ "\u04f8" - "\u04f9",\r
+ "\u0531" - "\u0556",\r
+ "\u0559",\r
+ "\u0561" - "\u0587",\r
+ "\u05d0" - "\u05ea",\r
+ "\u05f0" - "\u05f2",\r
+ "\u0621" - "\u063a",\r
+ "\u0640" - "\u064a",\r
+ "\u0671" - "\u06b7",\r
+ "\u06ba" - "\u06be",\r
+ "\u06c0" - "\u06ce",\r
+ "\u06d0" - "\u06d3",\r
+ "\u06d5",\r
+ "\u06e5" - "\u06e6",\r
+ "\u0905" - "\u0939",\r
+ "\u093d",\r
+ "\u0958" - "\u0961",\r
+ "\u0985" - "\u098c",\r
+ "\u098f" - "\u0990",\r
+ "\u0993" - "\u09a8",\r
+ "\u09aa" - "\u09b0",\r
+ "\u09b2",\r
+ "\u09b6" - "\u09b9",\r
+ "\u09dc" - "\u09dd",\r
+ "\u09df" - "\u09e1",\r
+ "\u09f0" - "\u09f1",\r
+ "\u0a05" - "\u0a0a",\r
+ "\u0a0f" - "\u0a10",\r
+ "\u0a13" - "\u0a28",\r
+ "\u0a2a" - "\u0a30",\r
+ "\u0a32" - "\u0a33",\r
+ "\u0a35" - "\u0a36",\r
+ "\u0a38" - "\u0a39",\r
+ "\u0a59" - "\u0a5c",\r
+ "\u0a5e",\r
+ "\u0a72" - "\u0a74",\r
+ "\u0a85" - "\u0a8b",\r
+ "\u0a8d",\r
+ "\u0a8f" - "\u0a91",\r
+ "\u0a93" - "\u0aa8",\r
+ "\u0aaa" - "\u0ab0",\r
+ "\u0ab2" - "\u0ab3",\r
+ "\u0ab5" - "\u0ab9",\r
+ "\u0abd",\r
+ "\u0ae0",\r
+ "\u0b05" - "\u0b0c",\r
+ "\u0b0f" - "\u0b10",\r
+ "\u0b13" - "\u0b28",\r
+ "\u0b2a" - "\u0b30",\r
+ "\u0b32" - "\u0b33",\r
+ "\u0b36" - "\u0b39",\r
+ "\u0b3d",\r
+ "\u0b5c" - "\u0b5d",\r
+ "\u0b5f" - "\u0b61",\r
+ "\u0b85" - "\u0b8a",\r
+ "\u0b8e" - "\u0b90",\r
+ "\u0b92" - "\u0b95",\r
+ "\u0b99" - "\u0b9a",\r
+ "\u0b9c",\r
+ "\u0b9e" - "\u0b9f",\r
+ "\u0ba3" - "\u0ba4",\r
+ "\u0ba8" - "\u0baa",\r
+ "\u0bae" - "\u0bb5",\r
+ "\u0bb7" - "\u0bb9",\r
+ "\u0c05" - "\u0c0c",\r
+ "\u0c0e" - "\u0c10",\r
+ "\u0c12" - "\u0c28",\r
+ "\u0c2a" - "\u0c33",\r
+ "\u0c35" - "\u0c39",\r
+ "\u0c60" - "\u0c61",\r
+ "\u0c85" - "\u0c8c",\r
+ "\u0c8e" - "\u0c90",\r
+ "\u0c92" - "\u0ca8",\r
+ "\u0caa" - "\u0cb3",\r
+ "\u0cb5" - "\u0cb9",\r
+ "\u0cde",\r
+ "\u0ce0" - "\u0ce1",\r
+ "\u0d05" - "\u0d0c",\r
+ "\u0d0e" - "\u0d10",\r
+ "\u0d12" - "\u0d28",\r
+ "\u0d2a" - "\u0d39",\r
+ "\u0d60" - "\u0d61",\r
+ "\u0e01" - "\u0e2e",\r
+ "\u0e30",\r
+ "\u0e32" - "\u0e33",\r
+ "\u0e40" - "\u0e46",\r
+ "\u0e81" - "\u0e82",\r
+ "\u0e84",\r
+ "\u0e87" - "\u0e88",\r
+ "\u0e8a",\r
+ "\u0e8d",\r
+ "\u0e94" - "\u0e97",\r
+ "\u0e99" - "\u0e9f",\r
+ "\u0ea1" - "\u0ea3",\r
+ "\u0ea5",\r
+ "\u0ea7",\r
+ "\u0eaa" - "\u0eab",\r
+ "\u0ead" - "\u0eae",\r
+ "\u0eb0",\r
+ "\u0eb2" - "\u0eb3",\r
+ "\u0ebd",\r
+ "\u0ec0" - "\u0ec4",\r
+ "\u0ec6",\r
+ "\u0edc" - "\u0edd",\r
+ "\u0f40" - "\u0f47",\r
+ "\u0f49" - "\u0f69",\r
+ "\u10a0" - "\u10c5",\r
+ "\u10d0" - "\u10f6",\r
+ "\u1100" - "\u1159",\r
+ "\u115f" - "\u11a2",\r
+ "\u11a8" - "\u11f9",\r
+ "\u1e00" - "\u1e9b",\r
+ "\u1ea0" - "\u1ef9",\r
+ "\u1f00" - "\u1f15",\r
+ "\u1f18" - "\u1f1d",\r
+ "\u1f20" - "\u1f45",\r
+ "\u1f48" - "\u1f4d",\r
+ "\u1f50" - "\u1f57",\r
+ "\u1f59",\r
+ "\u1f5b",\r
+ "\u1f5d",\r
+ "\u1f5f" - "\u1f7d",\r
+ "\u1f80" - "\u1fb4",\r
+ "\u1fb6" - "\u1fbc",\r
+ "\u1fbe",\r
+ "\u1fc2" - "\u1fc4",\r
+ "\u1fc6" - "\u1fcc",\r
+ "\u1fd0" - "\u1fd3",\r
+ "\u1fd6" - "\u1fdb",\r
+ "\u1fe0" - "\u1fec",\r
+ "\u1ff2" - "\u1ff4",\r
+ "\u1ff6" - "\u1ffc",\r
+ "\u207f",\r
+ "\u2102",\r
+ "\u2107",\r
+ "\u210a" - "\u2113",\r
+ "\u2115",\r
+ "\u2118" - "\u211d",\r
+ "\u2124",\r
+ "\u2126",\r
+ "\u2128",\r
+ "\u212a" - "\u2131",\r
+ "\u2133" - "\u2138",\r
+ "\u3005",\r
+ "\u3031" - "\u3035",\r
+ "\u3041" - "\u3094",\r
+ "\u309b" - "\u309e",\r
+ "\u30a1" - "\u30fa",\r
+ "\u30fc" - "\u30fe",\r
+ "\u3105" - "\u312c",\r
+ "\u3131" - "\u318e",\r
+ "\u4e00" - "\u9fa5",\r
+ "\uac00" - "\ud7a3",\r
+ "\uf900" - "\ufa2d",\r
+ "\ufb00" - "\ufb06",\r
+ "\ufb13" - "\ufb17",\r
+ "\ufb1f" - "\ufb28",\r
+ "\ufb2a" - "\ufb36",\r
+ "\ufb38" - "\ufb3c",\r
+ "\ufb3e",\r
+ "\ufb40" - "\ufb41",\r
+ "\ufb43" - "\ufb44",\r
+ "\ufb46" - "\ufbb1",\r
+ "\ufbd3" - "\ufd3d",\r
+ "\ufd50" - "\ufd8f",\r
+ "\ufd92" - "\ufdc7",\r
+ "\ufdf0" - "\ufdfb",\r
+ "\ufe70" - "\ufe72",\r
+ "\ufe74",\r
+ "\ufe76" - "\ufefc",\r
+ "\uff21" - "\uff3a",\r
+ "\uff41" - "\uff5a",\r
+ "\uff66" - "\uffbe",\r
+ "\uffc2" - "\uffc7",\r
+ "\uffca" - "\uffcf",\r
+ "\uffd2" - "\uffd7",\r
+ "\uffda" - "\uffdc"\r
+ ]>\r
+}\r
+\r
+TOKEN :\r
+{\r
+ <#DIGIT: [\r
+ "0" - "9",\r
+ "\u0660" - "\u0669",\r
+ "\u06f0" - "\u06f9",\r
+ "\u0966" - "\u096f",\r
+ "\u09e6" - "\u09ef",\r
+ "\u0a66" - "\u0a6f",\r
+ "\u0ae6" - "\u0aef",\r
+ "\u0b66" - "\u0b6f",\r
+ "\u0be7" - "\u0bef",\r
+ "\u0c66" - "\u0c6f",\r
+ "\u0ce6" - "\u0cef",\r
+ "\u0d66" - "\u0d6f",\r
+ "\u0e50" - "\u0e59",\r
+ "\u0ed0" - "\u0ed9",\r
+ "\u0f20" - "\u0f29",\r
+ "\uff10" - "\uff19"\r
+ ]>\r
+}\r
+\r
+TOKEN :\r
+{ /* Delimited Identifiers - NOTE: this does not allow zero-length identifiers */\r
+ <DELIMITED_IDENTIFIER: "\""\r
+ (\r
+ ("\"\"") |\r
+ (~["\""])\r
+ ) +\r
+ "\"">\r
+}\r
+\r
+TOKEN :\r
+{ /* Literals */\r
+ <EXACT_NUMERIC: ( <UINT> ( "." ( <UINT> )? )? | "." <UINT> )>\r
+| <UINT: (["0" - "9"])+ >/* This is for an unsigned exact numeric */\r
+| <LENGTH_MODIFIER: ( <UINT> ["K","M","G","k","m","g"] )>\r
+| <STRING: "'"\r
+ (\r
+ "''" |\r
+ ~["'"]\r
+ ) *\r
+ "'">\r
+| <HEX_STRING: ["X","x"] "'" (["0"-"9","a"-"f","A"-"F"])*"'"> /* RESOLVE: does not allow separators */\r
+| <APPROXIMATE_NUMERIC: <EXACT_NUMERIC> ["e","E"] ( ("+" | "-") )? ( ["0" - "9"] )+ >\r
+/*****\r
+ The tokenizer can't handle the date/time literals because\r
+ they are constructed of two tokens with arbitrary whitespace between them.\r
+ INTERVAL_LITERAL will also have to be upgraded at some point.\r
+| <DATE_LITERAL: "DATE" "'" <DATE_VALUE> "'" >\r
+| <#DATE_VALUE: <UINT> "-" <UINT> "-" <UINT> >\r
+| <TIME_LITERAL: "TIME" "'" <TIME_VALUE> ( <TIMEZONE_INTERVAL> ) ? "'" >\r
+| <#TIME_VALUE: <UINT> ":" <UINT> ":" <SECONDS_VALUE> >\r
+| <#TIMEZONE_INTERVAL: ("+" | "-") <UINT> ":" <UINT> >\r
+| <TIMESTAMP_LITERAL: "TIMESTAMP" "'" <DATE_VALUE> " " <TIME_VALUE> ( <TIMEZONE_INTERVAL> ) ? "'" >\r
+*****/\r
+| <INTERVAL_LITERAL: "INTERVAL" "'" (["+","-"])? <INTERVAL_STRING> <INTERVAL_QUALIFIER> >\r
+| <#INTERVAL_STRING: "'" ( <YEAR_MONTH_LITERAL> | <DAY_TIME_LITERAL> ) "'" >\r
+| <#INTERVAL_QUALIFIER: <SINGLE_DATETIME_FIELD> | ( <START_FIELD> <TO> <END_FIELD> ) >\r
+| <#SINGLE_DATETIME_FIELD: <NON_SECOND_DATETIME_FIELD> ( <LEFT_PAREN> <UINT> <RIGHT_PAREN> ) ? >\r
+| <#START_FIELD: <NON_SECOND_DATETIME_FIELD> ( <LEFT_PAREN> <UINT> <RIGHT_PAREN> ) ? >\r
+| <#END_FIELD: <NON_SECOND_DATETIME_FIELD> >\r
+| <#NON_SECOND_DATETIME_FIELD: <YEAR> | <MONTH> | <DAY> | <HOUR> | <MINUTE> >\r
+| <#YEAR_MONTH_LITERAL: (<UINT> | ( <UINT> "-" ) )? <UINT> >\r
+| <#DAY_TIME_LITERAL: ( <DAY_TIME_INTERVAL> | <TIME_INTERVAL> ) >\r
+| <#DAY_TIME_INTERVAL: <UINT> ( " " <UINT> ( ":" <UINT> ( ":" <SECONDS_VALUE> ) ? ) ? ) ? >\r
+| <#SECONDS_VALUE: <UINT> ( "." ( <UINT> ) ? ) ? >\r
+| <#TIME_INTERVAL: <UINT> ( ":" <UINT> ( ":" <SECONDS_VALUE> ) ? ) ?\r
+ | <UINT> ( ":" <SECONDS_VALUE> ) ?\r
+ | <SECONDS_VALUE> >\r
+}\r
+\r
+\r
+\r
+/*\r
+ * <A NAME="Statement">Statement</A>\r
+ */\r
+StatementNode\r
+Statement( String statementSQLText, Object[] paramDefaults) throws StandardException :\r
+{\r
+ StatementNode statementNode;\r
+\r
+ initStatement(statementSQLText, paramDefaults);\r
+}\r
+{\r
+ statementNode = StatementPart(null) <EOF>\r
+ {\r
+ return statementNode;\r
+ }\r
+}\r
+\r
+StatementNode \r
+proceduralStatement(Token[] tokenHolder) throws StandardException : \r
+{\r
+ StatementNode statementNode;\r
+ tokenHolder[0] = getToken(1);\r
+} \r
+{ \r
+(\r
+ statementNode = insertStatement()\r
+| \r
+ statementNode = preparableUpdateStatement()\r
+|\r
+ statementNode = preparableDeleteStatement()\r
+|\r
+ statementNode = preparableSelectStatement(true) \r
+|\r
+ statementNode = callStatement() \r
+)\r
+ {\r
+ return statementNode;\r
+ } \r
+}\r
+\r
+/*\r
+ * <A NAME="StatementPart">StatementPart</A>\r
+ * \r
+ * @param tokenHolder returns the token that starts\r
+ * the statement. If null, ignored.\r
+ */\r
+StatementNode\r
+StatementPart(Token[] tokenHolder) throws StandardException :\r
+{\r
+ StatementNode statementNode;\r
+ //before starting new statements, initialize this variables. Otherwise, the left\r
+ //over values from previously failed sql will affect the next sql. \r
+ explicitNotNull = false;\r
+ explicitNull = false;\r
+ explicitlyNullableColumnsList = new Vector();\r
+\r
+ /*\r
+ ** Grab the token preceding this production\r
+ */\r
+ if (tokenHolder != null) \r
+ {\r
+ tokenHolder[0] = getToken(1);\r
+ }\r
+}\r
+{\r
+ /*\r
+ * The present method of invoking the parser is\r
+ * via JDBC, which uses preparable SQL statements only.\r
+ * the only place this makes a difference from other\r
+ * flavors of SQL (direct SQL, embedded SQL, dynamic SQL)\r
+ * is in the select and positioned update/delete statements,\r
+ * and in whether transaction and connection statements are\r
+ * allowed.\r
+ *\r
+ * When it becomes necessary to differentiate, we should\r
+ * define a way to put the parser into different modes\r
+ * (preparable SQL, dynamic SQL, direct SQL, embedded SQL, etc.)\r
+ * and have it accept/reject statements based on the mode\r
+ * it is in.\r
+ */\r
+ (\r
+ statementNode = spsRenameStatement() |\r
+ // statementNode = SQLTransactionStatement() |\r
+ statementNode = lockStatement()\r
+ )\r
+ {\r
+ return statementNode;\r
+ }\r
+| (\r
+ statementNode = createStatements() |\r
+ statementNode = dropStatements() |\r
+ statementNode = spsAlterStatement() |\r
+ statementNode = globalTemporaryTableDeclaration() |\r
+ statementNode = preparableSQLDataStatement() |\r
+ statementNode = spsSetStatement() |\r
+ statementNode = truncateTableStatement() |\r
+ statementNode = grantStatement() |\r
+ statementNode = revokeStatement() |\r
+ statementNode = execStatement()\r
+ // statementNode = SQLTransactionStatement()\r
+ )\r
+ {\r
+ return statementNode;\r
+ }\r
+}\r
+\r
+/*\r
+ * <A NAME="createStatements">spsCreateStatement</A>\r
+ */\r
+StatementNode\r
+createStatements() throws StandardException :\r
+{\r
+ StatementNode statementNode;\r
+ Token beginToken;\r
+ int tokKind;\r
+}\r
+{\r
+ beginToken = <CREATE> (\r
+ (\r
+ statementNode = schemaDefinition() |\r
+ statementNode = viewDefinition(beginToken) |\r
+ statementNode = triggerDefinition() |\r
+ statementNode = synonymDefinition()\r
+ )\r
+ {\r
+ }\r
+| statementNode = tableDefinition()\r
+ {\r
+ }\r
+| statementNode = procedureDefinition()\r
+| statementNode = functionDefinition()\r
+|\r
+ statementNode = indexDefinition()\r
+ {\r
+ }\r
+ )\r
+ {\r
+ return statementNode;\r
+ }\r
+\r
+}\r
+\r
+/*\r
+ * <A NAME="dropStatements">spsDropStatement</A>\r
+ */\r
+StatementNode\r
+dropStatements() throws StandardException :\r
+{\r
+ StatementNode statementNode;\r
+}\r
+{\r
+ <DROP>\r
+ (\r
+ statementNode = dropSchemaStatement() |\r
+ statementNode = dropTableStatement() |\r
+ statementNode = dropIndexStatement() |\r
+ statementNode = dropAliasStatement() |\r
+ statementNode = dropViewStatement() |\r
+ statementNode = dropTriggerStatement() \r
+ )\r
+ {\r
+ return statementNode;\r
+ }\r
+}\r
+\r
+/*\r
+ * <A NAME="spsAlterStatement">spsAlterStatement</A>\r
+ */\r
+StatementNode\r
+spsAlterStatement() throws StandardException :\r
+{\r
+ StatementNode statementNode;\r
+}\r
+{\r
+ <ALTER>\r
+ (\r
+ statementNode = alterTableStatement()\r
+ )\r
+ {\r
+ return statementNode;\r
+ }\r
+}\r
+\r
+/*\r
+ * <A NAME="spsSetStatement">spsSetStatement</A>\r
+ */\r
+StatementNode\r
+spsSetStatement() throws StandardException :\r
+{\r
+ StatementNode statementNode;\r
+}\r
+{\r
+ LOOKAHEAD ( { getToken(1).kind == SET && getToken(2).kind != CURRENT } )\r
+ <SET>\r
+ (\r
+ statementNode = setIsolationStatement() |\r
+ statementNode = setSchemaStatement() |\r
+ statementNode = setMessageLocaleStatement()\r
+ )\r
+ {\r
+ return statementNode;\r
+ }\r
+|\r
+ LOOKAHEAD ( { getToken(1).kind == SET && getToken(2).kind == CURRENT } )\r
+ <SET>\r
+ (\r
+ statementNode = setSchemaStatement() |\r
+ statementNode = setIsolationStatement()\r
+\r
+ )\r
+ {\r
+ return statementNode;\r
+ }\r
+}\r
+ \r
+/*\r
+ * <A NAME="preparableSQLDataStatement">preparableSQLDataStatement</A>\r
+ *\r
+ * preparableSQLDataStatement differs from\r
+ * directSQLDataStatement in that it\r
+ * supports positioned update and delete\r
+ * and a preparable select (with FOR UPDATE)\r
+ * instead of a direct select (without FOR UPDATE)\r
+ */\r
+StatementNode\r
+preparableSQLDataStatement() throws StandardException :\r
+{\r
+ StatementNode dmlStatement;\r
+}\r
+{\r
+ /*\r
+ ** RESOLVE: Ignoring temporary table declarations for now.\r
+ */\r
+ dmlStatement = preparableDeleteStatement()\r
+ {\r
+ return dmlStatement;\r
+ }\r
+|\r
+ dmlStatement = preparableSelectStatement(true)\r
+ {\r
+ return dmlStatement;\r
+ }\r
+|\r
+ dmlStatement = insertStatement()\r
+ {\r
+ return dmlStatement;\r
+ }\r
+|\r
+ dmlStatement = preparableUpdateStatement()\r
+ {\r
+ return dmlStatement;\r
+ }\r
+|\r
+ dmlStatement = callStatement()\r
+ {\r
+ return dmlStatement;\r
+ }\r
+|\r
+ dmlStatement = savepointStatement()\r
+ {\r
+ return dmlStatement;\r
+ }\r
+}\r
+\r
+/*\r
+ * <A NAME="preparableDeleteStatement">preparableDeleteStatement</A>\r
+ *\r
+ * This may be a search or positioned delete statement.\r
+ */\r
+StatementNode\r
+preparableDeleteStatement() throws StandardException :\r
+{\r
+ StatementNode qtn;\r
+}\r
+{\r
+ <DELETE> qtn = deleteBody()\r
+ {\r
+ return qtn;\r
+ }\r
+}\r
+\r
+StatementNode\r
+deleteBody() throws StandardException :\r
+{\r
+ JavaToSQLValueNode javaToSQLNode = null;\r
+ String correlationName = null;\r
+ TableName tableName = null;\r
+ ValueNode whereClause = null;\r
+ FromTable fromTable = null;\r
+ QueryTreeNode retval;\r
+ Properties targetProperties = null;\r
+ Token whereToken = null;\r
+}\r
+{\r
+ LOOKAHEAD( { fromNewInvocationFollows() } ) \r
+ <FROM> javaToSQLNode = newInvocation()\r
+ [ whereToken = <WHERE> whereClause = whereClause(whereToken) ]\r
+ {\r
+ fromTable = (FromTable) nodeFactory.getNode(\r
+ C_NodeTypes.FROM_VTI,\r
+ javaToSQLNode.getJavaValueNode(), \r
+ (String) null,\r
+ null, \r
+ (Properties) null,\r
+ getContextManager()); \r
+\r
+ return getDeleteNode(fromTable, tableName, whereClause);\r
+ }\r
+|\r
+ <FROM> tableName = qualifiedName(Limits.MAX_IDENTIFIER_LENGTH) \r
+ [ \r
+ LOOKAHEAD\r
+ ( { (getToken(1).kind != EOF) && (getToken(1).kind != WHERE) && !derbyPropertiesListFollows() } )\r
+ [ <AS> ] correlationName = identifier(Limits.MAX_IDENTIFIER_LENGTH, true) \r
+ ]\r
+ [targetProperties = propertyList(false) <CHECK_PROPERTIES>] \r
+ [ \r
+ whereToken = <WHERE>\r
+ (\r
+ //need LOOKAHEAD here to decide between CURRENT in class name\r
+ //and CURRENT in CURRENT OF\r
+ LOOKAHEAD ( \r
+ {\r
+ (getToken(1).kind == CURRENT) &&\r
+ (getToken(2).kind == OF) \r
+ }\r
+ ) \r
+ fromTable = currentOfClause( correlationName ) |\r
+ whereClause = whereClause(whereToken)\r
+ )\r
+ ]\r
+ {\r
+ /* Fabricate a ResultSetNode (SelectNode) under the DeleteNode.\r
+ * For a searched delete,\r
+ * The FromList is simply the table that we are deleting from.\r
+ * (NOTE - we mark the table as the one that we are deleting from.)\r
+ * For a positioned delete,\r
+ * the FromList is a CurrentOfNode holding the cursor name.\r
+ * The select list will be null for now. We will generate it at\r
+ * bind time, in keeping with the design decision that the parser's\r
+ * output should look like the language.\r
+ */\r
+ if (fromTable == null)\r
+ fromTable = (FromTable) nodeFactory.getNode(\r
+ C_NodeTypes.FROM_BASE_TABLE,\r
+ tableName,\r
+ correlationName,\r
+ ReuseFactory.getInteger(\r
+ FromBaseTable.DELETE),\r
+ null,\r
+ getContextManager());\r
+\r
+ /* Update the FromTable with any properties, if non-null */\r
+ if (targetProperties != null)\r
+ {\r
+ if (SanityManager.DEBUG)\r
+ {\r
+ if (((FromBaseTable) fromTable).getProperties() != null)\r
+ {\r
+ SanityManager.THROWASSERT(\r
+ "Overwriting existing properties");\r
+ }\r
+ }\r
+ ((FromBaseTable) fromTable).setTableProperties(targetProperties);\r
+ }\r
+\r
+ return getDeleteNode(fromTable, tableName, whereClause);\r
+ }\r
+}\r
+\r
+/*\r
+ * <A NAME="currentOfClause">currentOfClause</A>\r
+ */\r
+FromTable\r
+currentOfClause( String correlationName ) throws StandardException :\r
+{\r
+ String cursorName = null;\r
+}\r
+{\r
+ <CURRENT> <OF> cursorName = identifier(Limits.MAX_IDENTIFIER_LENGTH, true)\r
+ { \r
+ return (FromTable) nodeFactory.getNode(\r
+ C_NodeTypes.CURRENT_OF_NODE,\r
+ correlationName,\r
+ cursorName,\r
+ null,\r
+ getContextManager());\r
+ }\r
+}\r
+\r
+\r
+/*\r
+ * <A NAME="preparableSelectStatement">preparableSelectStatement</A>\r
+ *\r
+ *\r
+ * The preparable select statement is a superset of\r
+ * the directSelectStatementMultipleRows in that it\r
+ * allows both the preparable single row select statement\r
+ * (a query expression that returns one row, although it\r
+ * is also handled like a cursor) and the preparable\r
+ * multiple row select statement, which allows not only\r
+ * an order by clause but also a for update clause.\r
+ */\r
+CursorNode\r
+preparableSelectStatement(boolean checkParams) throws StandardException :\r
+{\r
+ ResultSetNode queryExpression;\r
+ Vector updateColumns = new Vector();\r
+ int forUpdateState = CursorNode.UNSPECIFIED;\r
+ int isolationLevel = ExecutionContext.UNSPECIFIED_ISOLATION_LEVEL;\r
+ CursorNode retval;\r
+ OrderByList orderCols = null;\r
+}\r
+{\r
+ queryExpression = queryExpression(null, NO_SET_OP) \r
+ [ orderCols = orderByClause() ]\r
+ [ <FOR> forUpdateState = forUpdateClause(updateColumns) ]\r
+ [ isolationLevel = atIsolationLevel() ]\r
+ {\r
+ // Note: if order by is specified, the for update clause\r
+ // must be READ ONLY or empty, and the cursor\r
+ // is implicitly READ_ONLY.\r
+\r
+ retval = (CursorNode) nodeFactory.getNode(\r
+ C_NodeTypes.CURSOR_NODE,\r
+ "SELECT",\r
+ queryExpression,\r
+ null,\r
+ orderCols,\r
+ ReuseFactory.getInteger(forUpdateState),\r
+ (forUpdateState == CursorNode.READ_ONLY ? null : updateColumns ),\r
+ getContextManager());\r
+\r
+ if (checkParams)\r
+ {\r
+ setUpAndLinkParameters();\r
+ }\r
+\r
+ /* Set the isolation levels for the scans if specified */\r
+ if (isolationLevel != ExecutionContext.UNSPECIFIED_ISOLATION_LEVEL)\r
+ {\r
+ getCompilerContext().setScanIsolationLevel(isolationLevel);\r
+ }\r
+\r
+ return retval;\r
+ }\r
+}\r
+\r
+/*\r
+ * <A NAME="insertStatement">insertStatement</A>\r
+ */\r
+StatementNode\r
+insertStatement() throws StandardException :\r
+{\r
+ StatementNode insertNode;\r
+ QueryTreeNode targetTable;\r
+}\r
+{\r
+ <INSERT> <INTO> targetTable = targetTable()\r
+ insertNode = insertColumnsAndSource(targetTable)\r
+ {\r
+ setUpAndLinkParameters();\r
+\r
+ return insertNode;\r
+ }\r
+}\r
+\r
+QueryTreeNode\r
+targetTable() throws StandardException :\r
+{\r
+ JavaToSQLValueNode javaToSQLNode = null;\r
+ String correlationName = null;\r
+ TableName tableName;\r
+}\r
+{\r
+ /* NOTE: this rule has to come first in order to avoid making NEW\r
+ * a reserved word.\r
+ */\r
+ /* identifier() used to be correlationName() */\r
+ LOOKAHEAD( { newInvocationFollows(1) } )\r
+ javaToSQLNode = newInvocation()\r
+ {\r
+ return nodeFactory.getNode(\r
+ C_NodeTypes.FROM_VTI,\r
+ javaToSQLNode.getJavaValueNode(), \r
+ correlationName,\r
+ null, \r
+ (Properties) null,\r
+ getContextManager()); \r
+ }\r
+|\r
+ tableName = qualifiedName(Limits.MAX_IDENTIFIER_LENGTH) \r
+ {\r
+ return tableName;\r
+ }\r
+}\r
+\r
+/*\r
+ * <A NAME="preparableUpdateStatement">preparableUpdateStatement</A>\r
+ */\r
+StatementNode\r
+preparableUpdateStatement() throws StandardException :\r
+{\r
+ StatementNode qtn;\r
+}\r
+{\r
+ // NOTE: It only makes sense to have a property list if there is a\r
+ // table name, so I moved it into the [] for qualifiedName(). \r
+\r
+ <UPDATE> qtn = updateBody()\r
+ {\r
+ return qtn;\r
+ }\r
+\r
+}\r
+\r
+boolean\r
+tableOrIndex() :\r
+{\r
+}\r
+{\r
+ <TABLE>\r
+ {\r
+ return true;\r
+ }\r
+|\r
+ <INDEX>\r
+ {\r
+ return false;\r
+ }\r
+}\r
+\r
+StatementNode\r
+updateBody() throws StandardException :\r
+{\r
+ ResultColumnList columnList;\r
+ String correlationName = null;\r
+ JavaToSQLValueNode javaToSQLNode = null;\r
+ TableName tableName = null;\r
+ ValueNode whereClause = null;\r
+ FromTable fromTable = null;\r
+ Properties targetProperties = null;\r
+ Token whereToken = null;\r
+}\r
+{\r
+ LOOKAHEAD( { newInvocationFollows(1) } ) \r
+ javaToSQLNode = newInvocation()\r
+ <SET> columnList = setClauseList()\r
+ [ whereToken = <WHERE> whereClause = whereClause(whereToken) ]\r
+ {\r
+ fromTable = (FromTable) nodeFactory.getNode(\r
+ C_NodeTypes.FROM_VTI,\r
+ javaToSQLNode.getJavaValueNode(), \r
+ (String) null,\r
+ null, \r
+ (Properties) null,\r
+ getContextManager()); \r
+\r
+ return getUpdateNode(fromTable, tableName, columnList, whereClause);\r
+ }\r
+|\r
+ tableName = qualifiedName(Limits.MAX_IDENTIFIER_LENGTH)\r
+ [\r
+ LOOKAHEAD( { (getToken(1).kind != SET) && !derbyPropertiesListFollows() } )\r
+ [ <AS> ] correlationName = identifier(Limits.MAX_IDENTIFIER_LENGTH, true) \r
+ ]\r
+ [\r
+ targetProperties = propertyList(false) <CHECK_PROPERTIES>\r
+ ] \r
+ <SET> columnList = setClauseList()\r
+ [ \r
+ whereToken = <WHERE>\r
+ (\r
+ whereClause = whereClause(whereToken) |\r
+ fromTable = currentOfClause( correlationName )\r
+ )\r
+ ]\r
+ {\r
+ /* Fabricate a ResultSetNode (SelectNode) under the UpdateNode.\r
+ * For a searched update,\r
+ * The FromList is simply the table that we are updating.\r
+ * For a positioned update,\r
+ * the FromList is a CurrentOfNode holding the cursor name.\r
+ * (NOTE - we mark the table as the one that we are updating.)\r
+ * The select list is the columns in the SET clause. At bind time,\r
+ * we will prepend the CurrentRowLocation() in keeping with the design \r
+ * decision that the parser's output should look like the language.\r
+ */\r
+ if (fromTable == null)\r
+ fromTable = (FromTable) nodeFactory.getNode(\r
+ C_NodeTypes.FROM_BASE_TABLE,\r
+ tableName,\r
+ correlationName,\r
+ ReuseFactory.getInteger(\r
+ FromBaseTable.UPDATE),\r
+ null,\r
+ getContextManager());\r
+\r
+ /* Update the FromTable with any properties, if non-null */\r
+ if (targetProperties != null)\r
+ {\r
+ if (SanityManager.DEBUG)\r
+ {\r
+ if (((FromBaseTable) fromTable).getProperties() != null)\r
+ {\r
+ SanityManager.THROWASSERT(\r
+ "Overwriting existing properties");\r
+ }\r
+ }\r
+ ((FromBaseTable) fromTable).setTableProperties(targetProperties);\r
+ }\r
+ return getUpdateNode(fromTable, tableName, columnList, whereClause);\r
+ }\r
+}\r
+\r
+/*\r
+ * <A NAME="callStatement">callStatement</A>\r
+ */\r
+StatementNode\r
+callStatement() throws StandardException :\r
+{\r
+ StatementNode retval;\r
+}\r
+{\r
+ (\r
+ retval = bareCallStatement() |\r
+ <LEFT_BRACE> retval = bareCallStatement() <RIGHT_BRACE>\r
+ )\r
+ {\r
+ return retval;\r
+ }\r
+}\r
+\r
+/*\r
+ * <A NAME="bareCallStatement">baseCallStatement</A>\r
+ */\r
+StatementNode\r
+bareCallStatement() throws StandardException :\r
+{\r
+ ParameterNode returnParam;\r
+\r
+ ValueNode value;\r
+\r
+ ResultSetNode resultSetNode;\r
+}\r
+{\r
+ <CALL> value = primaryExpression( true )\r
+ {\r
+ if (! (value instanceof JavaToSQLValueNode) ||\r
+ ! (((JavaToSQLValueNode) value).getJavaValueNode() instanceof MethodCallNode))\r
+ {\r
+ throw StandardException.newException(SQLState.LANG_INVALID_CALL_STATEMENT);\r
+ }\r
+\r
+ StatementNode callStatement =\r
+ (StatementNode) nodeFactory.getNode(\r
+ C_NodeTypes.CALL_STATEMENT_NODE,\r
+ value,\r
+ getContextManager());\r
+\r
+ setUpAndLinkParameters();\r
+\r
+ return callStatement;\r
+ }\r
+\r
+ // ? = CALL method()\r
+| returnParam = dynamicParameterSpecification()\r
+ {\r
+ getCompilerContext().setReturnParameterFlag(); //bug4450\r
+ }\r
+ <EQUALS_OPERATOR> <CALL> resultSetNode = rowValueConstructor(null)\r
+ {\r
+ // validate that we have something that is an appropriate call statement\r
+ ResultColumnList rcl = resultSetNode.getResultColumns();\r
+\r
+ // we can have only 1 return value/column\r
+ if (rcl == null || rcl.size() > 1)\r
+ {\r
+ throw StandardException.newException(SQLState.LANG_INVALID_CALL_STATEMENT);\r
+ }\r
+\r
+ // we must have a method call node\r
+ value = ((ResultColumn) rcl.elementAt(0)).getExpression();\r
+ if (! (value instanceof JavaToSQLValueNode) ||\r
+ ! (((JavaToSQLValueNode) value).getJavaValueNode() instanceof MethodCallNode))\r
+ {\r
+ throw StandardException.newException(SQLState.LANG_INVALID_CALL_STATEMENT);\r
+ }\r
+\r
+ // wrap the row result set in a cursor node\r
+ StatementNode cursorNode =\r
+ (StatementNode) nodeFactory.getNode(\r
+ C_NodeTypes.CURSOR_NODE,\r
+ "SELECT",\r
+ resultSetNode,\r
+ null,\r
+ null,\r
+ ReuseFactory.getInteger(CursorNode.READ_ONLY),\r
+ null,\r
+ getContextManager());\r
+\r
+ // set the 0th param to be a RETURN param\r
+ returnParam.setReturnOutputParam(value);\r
+\r
+ setUpAndLinkParameters();\r
+\r
+ return cursorNode;\r
+ }\r
+}\r
+\r
+/*\r
+ * <A NAME="primaryExpression">primaryExpression</A>\r
+ * \r
+ * @param inSelectClause will be true if this method got called while parsing the select or values clause\r
+ * If in select or values clause, we do not want to allow boolean values.\r
+ */\r
+ValueNode primaryExpression( boolean inSelectClause ) throws StandardException :\r
+{\r
+ ValueNode value = null;\r
+}\r
+{\r
+ LOOKAHEAD\r
+ ( {\r
+ getToken(2).kind == PERIOD &&\r
+ getToken(4).kind == LEFT_PAREN\r
+ }\r
+ )\r
+ value = routineInvocation()\r
+ {\r
+ return value;\r
+ }\r
+|\r
+ value = primaryExpressionXX( inSelectClause )\r
+ {\r
+ return value;\r
+ }\r
+}\r
+\r
+/* \r
+ * <A NAME="savepointStatement">savepointStatement</A>\r
+\r
+ savepointStatementClauses contains the UNIQUE, ON ROLLBACK RETAIN LOCKS, ON ROLLBACK RETAIN CURSORS clauses.\r
+\r
+ 0 - Boolean - UNIQUE clause\r
+ 1 - Boolean - ON ROLLBACK RETAIN LOCKS clause\r
+ 2 - Boolean - ON ROLLBACK RETAIN CURSORS clause\r
+ */\r
+StatementNode\r
+savepointStatement() throws StandardException :\r
+{\r
+ String savepointName = null;\r
+ int savepointStatementType;\r
+ Object[] savepointStatementClauses = new Object[3];\r
+}\r
+{\r
+ (\r
+ <SAVEPOINT> savepointName = identifier(Limits.MAX_IDENTIFIER_LENGTH, true) (savepointStatementClause(savepointStatementClauses))+\r
+ {\r
+ //ON ROLLBACK RETAIN CURSORS is mandatory\r
+ if (savepointStatementClauses[2] == null)\r
+ throw StandardException.newException(SQLState.LANG_SYNTAX_ERROR, "MISSING ON ROLLBACK RETAIN CURSORS");\r
+ savepointStatementType = 1;\r
+ }\r
+| <ROLLBACK> [ <WORK> ] <TO> <SAVEPOINT> [ savepointName = identifier(Limits.MAX_IDENTIFIER_LENGTH, true) ]\r
+ {\r
+ savepointStatementType = 2;\r
+ }\r
+| <RELEASE> [ <TO> ] <SAVEPOINT> savepointName = identifier(Limits.MAX_IDENTIFIER_LENGTH, true)\r
+ {\r
+ savepointStatementType = 3;\r
+ }\r
+ )\r
+ {\r
+ return (StatementNode) nodeFactory.getNode(\r
+ C_NodeTypes.SAVEPOINT_NODE,\r
+ savepointName,\r
+ ReuseFactory.getInteger(savepointStatementType),\r
+ getContextManager());\r
+ }\r
+}\r
+\r
+void savepointStatementClause(Object[] savepointStatementClauses) throws StandardException :\r
+{\r
+ int clausePosition = -1;\r
+}\r
+{\r
+ (\r
+ <UNIQUE> {clausePosition = 0;}\r
+ |\r
+ <ON> <ROLLBACK> <RETAIN> (clausePosition = LocksOrCursors())\r
+ )\r
+ {\r
+ if (clausePosition != -1) {\r
+ // check for repeated clause\r
+ if (savepointStatementClauses[clausePosition] != null) {\r
+\r
+ String which = SAVEPOINT_CLAUSE_NAMES[clausePosition];\r
+ throw StandardException.newException(SQLState.LANG_DB2_MULTIPLE_ELEMENTS, which);\r
+ }\r
+ \r
+ savepointStatementClauses[clausePosition] = Boolean.TRUE;\r
+ }\r
+ }\r
+}\r
+\r
+/*\r
+ * <A NAME="LocksOrCursors">LocksOrCursors</A>\r
+ */\r
+int\r
+LocksOrCursors() :\r
+{\r
+}\r
+{\r
+ <LOCKS>\r
+ {\r
+ return (1);\r
+ }\r
+|\r
+ <CURSORS>\r
+ {\r
+ return (2);\r
+ }\r
+}\r
+\r
+/* \r
+ * <A NAME="globalTemporaryTableDeclaration">globalTemporaryTableDeclaration</A>\r
+\r
+ declareTableClauses contains the NOT LOGGED, on commit and on rollback clauses.\r
+\r
+ 0 - Boolean - NOT LOGGED clause\r
+ 1 - Boolean - on commit behavior\r
+ 2 - Boolean - on rollback behavior\r
+ */\r
+StatementNode\r
+globalTemporaryTableDeclaration() throws StandardException :\r
+{\r
+ TableName tableName;\r
+ TableElementList tableElementList;\r
+ Object[] declareTableClauses = new Object[3];\r
+}\r
+{ \r
+ <DECLARE> <GLOBAL> <TEMPORARY> <TABLE> tableName = qualifiedName(Limits.MAX_IDENTIFIER_LENGTH)\r
+ tableElementList = tableElementList()\r
+ ( declareTableClause(declareTableClauses) ) +\r
+ {\r
+ // NOT LOGGED is mandatory\r
+ if (declareTableClauses[0] == null)\r
+ throw StandardException.newException(SQLState.LANG_SYNTAX_ERROR, "MISSING NOT LOGGED");\r
+ // if ON COMMIT behavior not explicitly specified in DECLARE command, resort to default ON COMMIT DELETE ROWS\r
+ if (declareTableClauses[1] == null)\r
+ declareTableClauses[1] = Boolean.TRUE;\r
+ // if ON ROLLBACK behavior not explicitly specified in DECLARE command, resort to default ON ROLLBACK DELETE ROWS\r
+ if (declareTableClauses[2] == null)\r
+ declareTableClauses[2] = Boolean.TRUE;\r
+ return (StatementNode) nodeFactory.getNode(\r
+ C_NodeTypes.CREATE_TABLE_NODE,\r
+ tableName,\r
+ tableElementList,\r
+ (Properties)null,\r
+ (Boolean) declareTableClauses[1],\r
+ (Boolean) declareTableClauses[2],\r
+ getContextManager());\r
+ }\r
+}\r
+\r
+void declareTableClause(Object[] declareTableClauses) throws StandardException :\r
+{\r
+ int clausePosition = -1;\r
+ Object clauseValue = null;\r
+}\r
+{\r
+ (\r
+ <NOT> <LOGGED> {clauseValue = Boolean.TRUE; clausePosition = 0;}\r
+ |\r
+ LOOKAHEAD( {getToken(1).kind == ON && getToken(2).kind == COMMIT} )\r
+ <ON> <COMMIT> ( clauseValue = onCommit() ) <ROWS> { clausePosition = 1;} \r
+ |\r
+ LOOKAHEAD( {getToken(1).kind == ON && getToken(2).kind == ROLLBACK} )\r
+ <ON> <ROLLBACK> <DELETE> <ROWS> { clauseValue = Boolean.TRUE; clausePosition = 2;} \r
+ )\r
+\r
+\r
+ {\r
+ if (clausePosition != -1) {\r
+ // check for repeated clause\r
+ if (declareTableClauses[clausePosition] != null) {\r
+\r
+ String which = TEMPORARY_TABLE_CLAUSE_NAMES[clausePosition];\r
+ throw StandardException.newException(SQLState.LANG_DB2_MULTIPLE_ELEMENTS, which);\r
+ }\r
+ \r
+ declareTableClauses[clausePosition] = clauseValue;\r
+ }\r
+ }\r
+}\r
+\r
+/*\r
+ * <A NAME="onCommit">onCommit</A>\r
+ */\r
+Boolean\r
+onCommit() :\r
+{\r
+}\r
+{\r
+ <PRESERVE>\r
+ {\r
+ return (Boolean.FALSE);\r
+ }\r
+|\r
+ <DELETE>\r
+ {\r
+ return (Boolean.TRUE);\r
+ }\r
+}\r
+\r
+/*\r
+ * <A NAME="tableElementList">tableElementList</A>\r
+ */\r
+TableElementList\r
+tableElementList() throws StandardException :\r
+{\r
+ TableElementList tableElementList =\r
+ (TableElementList) nodeFactory.getNode(\r
+ C_NodeTypes.TABLE_ELEMENT_LIST,\r
+ getContextManager());\r
+}\r
+{\r
+ <LEFT_PAREN> tableElement(tableElementList)\r
+ ( <COMMA> tableElement(tableElementList) ) * <RIGHT_PAREN>\r
+ {\r
+ return tableElementList;\r
+ }\r
+}\r
+\r
+/*\r
+ * <A NAME="tableElement">tableElement</A>\r
+ */\r
+void\r
+tableElement(TableElementList tableElementList) throws StandardException :\r
+{\r
+ TableElementNode tableElement;\r
+ //initialize following two booleans for every new table element so that the\r
+ //values from previous tableElement doesn't impact the next tableElement\r
+ explicitNotNull = false;\r
+ explicitNull = false;\r
+\r
+}\r
+{\r
+ tableElement = columnDefinition(tableElementList)\r
+ {\r
+ tableElementList.addTableElement(tableElement);\r
+ }\r
+|\r
+ tableElement = tableConstraintDefinition()\r
+ {\r
+ tableElementList.addTableElement(tableElement);\r
+ }\r
+}\r
+\r
+/*\r
+ * <A NAME="columnDefinition">columnDefinition</A>\r
+ */\r
+TableElementNode\r
+columnDefinition(TableElementList tableElementList) throws StandardException :\r
+{\r
+ DataTypeDescriptor typeDescriptor = null;\r
+ ValueNode defaultNode = null;\r
+ String columnName;\r
+ long[] autoIncrementInfo = new long[4];\r
+}\r
+{\r
+ /*\r
+ ** RESOLVE: We are ignoring domains and collation.\r
+ */\r
+\r
+ /* identifier() used to be columnName() */\r
+ columnName = identifier(Limits.MAX_IDENTIFIER_LENGTH, true) \r
+ ( typeDescriptor = dataTypeDDL() \r
+ )\r
+ [ defaultNode = defaultAndConstraints(typeDescriptor, tableElementList, columnName, autoIncrementInfo) ]\r
+ {\r
+ // Only pass autoincrement info for autoincrement columns\r
+ if (autoIncrementInfo[QueryTreeNode.AUTOINCREMENT_IS_AUTOINCREMENT_INDEX] == 0)\r
+ {\r
+ autoIncrementInfo = null;\r
+ }\r
+\r
+ return (TableElementNode) nodeFactory.getNode(\r
+ C_NodeTypes.COLUMN_DEFINITION_NODE,\r
+ columnName,\r
+ defaultNode,\r
+ typeDescriptor,\r
+ autoIncrementInfo,\r
+ getContextManager());\r
+ }\r
+}\r
+\r
+\r
+/*\r
+ * <A NAME="defaultAndConstraints">defaultAndConstraints</A>\r
+ */\r
+ValueNode\r
+defaultAndConstraints(DataTypeDescriptor typeDescriptor,\r
+ TableElementList tableElementList,\r
+ String columnName,\r
+ long[] autoIncrementInfo) throws StandardException :\r
+{\r
+ ValueNode defaultNode = null;\r
+}\r
+{ // compatible with db2 syntax\r
+ columnConstraintDefinition(typeDescriptor, tableElementList, columnName) ( columnConstraintDefinition(typeDescriptor, tableElementList, columnName)) *\r
+ [ defaultNode = defaultClause(autoIncrementInfo, columnName) ( columnConstraintDefinition(typeDescriptor, tableElementList, columnName) )* ]\r
+ {\r
+ return defaultNode;\r
+ }\r
+|\r
+ defaultNode = defaultClause(autoIncrementInfo, columnName)\r
+ ( columnConstraintDefinition(typeDescriptor, tableElementList, columnName) ) *\r
+ {\r
+ return defaultNode;\r
+ }\r
+}\r
+\r
+/*\r
+ * <A NAME="dataTypeDDL">dataTypeDDL</A>\r
+ */\r
+DataTypeDescriptor\r
+dataTypeDDL() throws StandardException :\r
+{\r
+ DataTypeDescriptor typeDescriptor;\r
+}\r
+{\r
+ LOOKAHEAD( { commonDatatypeName(false) } )\r
+ typeDescriptor = dataTypeCommon()\r
+ {\r
+ return typeDescriptor;\r
+ }\r
+}\r
+\r
+\r
+/*\r
+ * <A NAME="dataTypeCast">dataTypeCast</A>\r
+ */\r
+DataTypeDescriptor\r
+dataTypeCast() throws StandardException :\r
+{\r
+ DataTypeDescriptor typeDescriptor;\r
+}\r
+{\r
+ // This lookahead is required because the names of the built-in\r
+ // datatypes are not reserved words\r
+ LOOKAHEAD( { commonDatatypeName(true) } )\r
+ typeDescriptor = dataTypeCommon()\r
+ {\r
+ return typeDescriptor;\r
+ }\r
+}\r
+\r
+/*\r
+ * <A NAME="dataTypeCommon">dataTypeCommon</A>\r
+ */\r
+DataTypeDescriptor\r
+dataTypeCommon() throws StandardException :\r
+{\r
+ DataTypeDescriptor typeDescriptor;\r
+ boolean checkCS = false;\r
+}\r
+{\r
+(\r
+ /* RESOLVE: Ignoring decimal, numeric, long */\r
+\r
+ /*\r
+ ** We are not planning to support character sets, so I commented\r
+ ** out characterSetSpecification().\r
+ */\r
+ ( LOOKAHEAD({getToken(2).kind != LARGE})\r
+ typeDescriptor = characterStringType()\r
+ )\r
+ /* [ <CHARACTER> <SET> characterSetSpecification() ] */\r
+|\r
+ ( LOOKAHEAD({getToken(3).kind != LARGE})\r
+ typeDescriptor = nationalCharacterStringType()\r
+ )\r
+|\r
+ typeDescriptor = numericType()\r
+|\r
+ typeDescriptor = datetimeType()\r
+| <BOOLEAN>\r
+{\r
+ checkInternalFeature(TypeId.BOOLEAN_NAME);\r
+ typeDescriptor = new DataTypeDescriptor(TypeId.BOOLEAN_ID, true);\r
+}\r
+|\r
+ typeDescriptor = longType()\r
+|\r
+ typeDescriptor = LOBType()\r
+|\r
+ typeDescriptor = XMLType()\r
+ )\r
+ {\r
+ return typeDescriptor;\r
+ }\r
+}\r
+\r
+/*\r
+ * <A NAME="characterStringType">characterStringType</A>\r
+ */\r
+DataTypeDescriptor\r
+characterStringType() throws StandardException :\r
+{\r
+ int length = DEFAULT_STRING_COLUMN_LENGTH;\r
+ Token varyingToken = null;\r
+ int type;\r
+}\r
+{\r
+ (\r
+ (\r
+ <VARCHAR> length = charLength()\r
+ )\r
+ {\r
+ type = Types.VARCHAR;\r
+ }\r
+|\r
+ charOrCharacter()\r
+ (\r
+ // Length is optional for CHARACTER, not for plain CHARACTER VARYING\r
+ varyingToken = <VARYING> length = charLength() |\r
+ [ length = charLength() ]\r
+ )\r
+ {\r
+ // If the user says CHARACTER VARYING, it's really VARCHAR\r
+ type = (varyingToken == null ? Types.CHAR : Types.VARCHAR);\r
+ }\r
+ ) [ type = forBitData(type) ]\r
+\r
+ {\r
+ checkTypeLimits(type,length);\r
+ DataTypeDescriptor charDTD = DataTypeDescriptor.getBuiltInDataTypeDescriptor(type, length);\r
+ return charDTD;\r
+ }\r
+}\r
+\r
+\r
+/*\r
+ * <A NAME="charOrCharacter">charOrCharacter</A>\r
+ */\r
+void\r
+charOrCharacter() :\r
+{\r
+}\r
+{\r
+ <CHAR> | <CHARACTER>\r
+}\r
+\r
+/*\r
+ * <A NAME="charType">charType</A>\r
+ */\r
+int\r
+charLength() throws StandardException :\r
+{\r
+ int length;\r
+}\r
+{\r
+ <LEFT_PAREN> length = length() <RIGHT_PAREN>\r
+ {\r
+ return length;\r
+ }\r
+}\r
+\r
+/*\r
+** <A NAME="forBitData">forBitData</A>\r
+*/\r
+\r
+int\r
+forBitData(int charType) :\r
+{\r
+}\r
+{\r
+ <FOR> <BIT> <DATA>\r
+ {\r
+ if (charType == Types.CHAR)\r
+ charType = Types.BINARY;\r
+ else if (charType == Types.VARCHAR)\r
+ charType = Types.VARBINARY;\r
+ else if (charType == Types.LONGVARCHAR)\r
+ charType = Types.LONGVARBINARY;\r
+\r
+ return charType;\r
+ }\r
+}\r
+\r
+/*\r
+ * <A NAME="nationalCharacterStringType">nationalCharacterStringType</A>\r
+ */\r
+DataTypeDescriptor\r
+nationalCharacterStringType() throws StandardException :\r
+{\r
+ DataTypeDescriptor dataTypeDescriptor;\r
+ int length = DEFAULT_STRING_COLUMN_LENGTH;\r
+ String type = null;\r
+ Token varyingToken = null;\r
+}\r
+{\r
+(\r
+ <NATIONAL> charOrCharacter() \r
+ (\r
+ // Length is optional for NATIONAL CHARACTER , not for NATIONAL CHARACTER VARYING\r
+ varyingToken = <VARYING> length = charLength() |\r
+ [ length = charLength() ]\r
+ )\r
+ {\r
+\r
+ // If the user says NATIONAL CHARACTER VARYING, it's really NATIONALVARCHAR\r
+ type = (varyingToken == null ? TypeId.NATIONAL_CHAR_NAME : \r
+ TypeId.NATIONAL_VARCHAR_NAME);\r
+ }\r
+|\r
+ <NCHAR> \r
+ (\r
+ // Length is optional for NCHAR, not for NCHAR VARYING\r
+ varyingToken = <VARYING> length = charLength() |\r
+ [ length = charLength() ]\r
+ )\r
+ {\r
+ // If the user says NCHAR VARYING, it's really NATIONALVARCHAR\r
+ type = (varyingToken == null ? TypeId.NATIONAL_CHAR_NAME : \r
+ TypeId.NATIONAL_VARCHAR_NAME);\r
+\r
+ }\r
+|\r
+ <NVARCHAR> \r
+ (\r
+ length = charLength()\r
+ )\r
+ {\r
+ type = TypeId.NATIONAL_VARCHAR_NAME;\r
+ }\r
+)\r
+\r
+ {\r
+ // need to re-enable according to SQL standard\r
+ throw StandardException.newException(SQLState.NOT_IMPLEMENTED, type);\r
+ // return DataTypeDescriptor.getBuiltInDataTypeDescriptor(type, length);\r
+ } \r
+}\r
+\r
+/*\r
+ * <A NAME="LOBType">lobType</A>\r
+ */\r
+DataTypeDescriptor\r
+LOBType() throws StandardException :\r
+{\r
+ int length = 2147483647; // default to 2GB-1 if no length specified\r
+ String type;\r
+}\r
+{\r
+ (\r
+ <BLOB> [ length = lengthAndModifier() ]\r
+ {\r
+ type = TypeId.BLOB_NAME;\r
+ }\r
+ |\r
+ <CLOB> [ length = lengthAndModifier() ]\r
+ {\r
+ type = TypeId.CLOB_NAME;\r
+ }\r
+ |\r
+ <NCLOB> length = lengthAndModifier()\r
+ {\r
+ type = TypeId.NCLOB_NAME;\r
+ // need to re-enable according to SQL standard\r
+ throw StandardException.newException(SQLState.NOT_IMPLEMENTED, type);\r
+ }\r
+ |\r
+ <BINARY> <LARGE> <OBJECT> [ length = lengthAndModifier() ]\r
+ {\r
+ type = TypeId.BLOB_NAME;\r
+ }\r
+ |\r
+ charOrCharacter() <LARGE> <OBJECT> [ length = lengthAndModifier() ]\r
+ {\r
+ type = TypeId.CLOB_NAME;\r
+ }\r
+ |\r
+ <NATIONAL> <CHARACTER> <LARGE> <OBJECT> length = lengthAndModifier()\r
+ {\r
+ type = TypeId.NCLOB_NAME;\r
+ // need to re-enable according to SQL standard\r
+ throw StandardException.newException(SQLState.NOT_IMPLEMENTED, type);\r
+ }\r
+ )\r
+ {\r
+ DataTypeDescriptor dtd = DataTypeDescriptor.getBuiltInDataTypeDescriptor(type, length);\r
+\r
+ return dtd;\r
+ }\r
+}\r
+\r
+/*\r
+ * <A NAME="numericType">numericType</A>\r
+ */\r
+DataTypeDescriptor\r
+numericType() throws StandardException :\r
+{\r
+ DataTypeDescriptor typeDescriptor;\r
+}\r
+{\r
+ typeDescriptor = exactNumericType()\r
+ {\r
+ return typeDescriptor;\r
+ }\r
+|\r
+ typeDescriptor = approximateNumericType()\r
+ {\r
+ return typeDescriptor;\r
+ }\r
+}\r
+\r
+/*\r
+ * <A NAME="exactNumericType">exactNumericType</A>\r
+ */\r
+DataTypeDescriptor\r
+exactNumericType() throws StandardException :\r
+{\r
+ int precision = TypeCompiler.DEFAULT_DECIMAL_PRECISION;\r
+ int scale = TypeCompiler.DEFAULT_DECIMAL_SCALE;\r
+ int type = Types.DECIMAL;\r
+ String typeStr = "DECIMAL";\r
+ int maxWidth;\r
+ DataTypeDescriptor dtd = null;\r
+}\r
+{\r
+ ( <NUMERIC> \r
+ {\r
+ type = Types.NUMERIC;\r
+ typeStr = "NUMERIC";\r
+ }\r
+ | <DECIMAL> | <DEC> )\r
+ [ <LEFT_PAREN> precision = precision() [ <COMMA> scale = scale() ] <RIGHT_PAREN> ]\r
+ {\r
+ if ((precision <= 0) || \r
+ (precision > TypeCompiler.MAX_DECIMAL_PRECISION_SCALE))\r
+ {\r
+ throw StandardException.newException(SQLState.LANG_INVALID_PRECISION, \r
+ typeStr, String.valueOf(precision));\r
+ } \r
+ else if ((scale < 0) || \r
+ (scale > TypeCompiler.MAX_DECIMAL_PRECISION_SCALE))\r
+ {\r
+ throw StandardException.newException(SQLState.LANG_INVALID_DECIMAL_SCALE, \r
+ typeStr, String.valueOf(scale));\r
+ }\r
+ else if (scale > precision)\r
+ {\r
+ throw StandardException.newException(SQLState.LANG_INVALID_DECIMAL_PRECISION_SCALE, \r
+ String.valueOf(scale),\r
+ String.valueOf(precision));\r
+ }\r
+ /*\r
+ ** If we have a decimal point, need to count it\r
+ ** towards maxwidth. Max width needs to account\r
+ ** for the possible leading '0' and '-' and the\r
+ ** decimal point. e.g., DEC(1,1) has a maxwidth\r
+ ** of 4 (to handle "-0.1").\r
+ */\r
+ maxWidth = DataTypeUtilities.computeMaxWidth( precision, scale);\r
+ return getDataTypeServices(type, precision, scale, maxWidth);\r
+ }\r
+ |\r
+ dtd = exactIntegerType()\r
+ {\r
+ return dtd;\r
+ }\r
+}\r
+\r
+/*\r
+ * <A NAME="exactNumericType">exactNumericType</A>\r
+ */\r
+DataTypeDescriptor\r
+exactIntegerType() throws StandardException :\r
+{\r
+\r
+}\r
+{\r
+ (<INTEGER> | <INT>)\r
+ {\r
+ return DataTypeDescriptor.getBuiltInDataTypeDescriptor(Types.INTEGER);\r
+ }\r
+|\r
+ <SMALLINT>\r
+ {\r
+ return DataTypeDescriptor.getBuiltInDataTypeDescriptor(Types.SMALLINT);\r
+ }\r
+|\r
+ <LONGINT>\r
+ {\r
+ return DataTypeDescriptor.getBuiltInDataTypeDescriptor(Types.BIGINT);\r
+ }\r
+}\r
+\r
+/*\r
+ * <A NAME="approximateNumericType">approximateNumericType</A>\r
+ */\r
+DataTypeDescriptor\r
+approximateNumericType() throws StandardException :\r
+{\r
+ int type = 0, scale = 0, width = 0;\r
+ int prec = -1;\r
+ DataTypeDescriptor dts = null;\r
+}\r
+{\r
+ <FLOAT> [ <LEFT_PAREN> prec = precision() <RIGHT_PAREN> ]\r
+ {\r
+ /*\r
+ When not specified, default is DOUBLE_PRECISION\r
+ */\r
+ if (prec == -1)\r
+ prec = TypeId.DOUBLE_PRECISION;\r
+\r
+ if (prec > 0 && prec <= TypeId.REAL_PRECISION)\r
+ {\r
+ type = Types.REAL;\r
+ prec = TypeId.REAL_PRECISION;\r
+ scale = TypeId.REAL_SCALE;\r
+ width = TypeId.REAL_MAXWIDTH;\r
+ }\r
+ else if (prec > TypeId.REAL_PRECISION &&\r
+ prec <= TypeId.DOUBLE_PRECISION)\r
+ {\r
+ type = Types.DOUBLE;\r
+ prec = TypeId.DOUBLE_PRECISION;\r
+ scale = TypeId.DOUBLE_SCALE;\r
+ width = TypeId.DOUBLE_MAXWIDTH;\r
+ }\r
+ else\r
+ throw StandardException.newException(SQLState.LANG_INVALID_PRECISION, "FLOAT", String.valueOf(prec));\r
+\r
+ /*\r
+ REMIND: this is a slight hack, in that exacting reading of\r
+ the InformationSchema requires that the type the user typed\r
+ in be visible to them in the InformationSchema views. But\r
+ most implementations use synonyms or mappings at some point,\r
+ and this is one of those places, for us.\r
+ */\r
+ return getDataTypeServices(type, prec, scale, width);\r
+ }\r
+| \r
+ <REAL>\r
+ {\r
+ return DataTypeDescriptor.getBuiltInDataTypeDescriptor(Types.REAL);\r
+ }\r
+|\r
+ dts = doubleType()\r
+ {\r
+ return dts;\r
+ }\r
+}\r
+\r
+/*\r
+ * <A NAME="doubleType">doubleType</A>\r
+ */\r
+DataTypeDescriptor\r
+doubleType() throws StandardException :\r
+\r
+{\r
+\r
+}\r
+{\r
+ ( LOOKAHEAD({getToken(2).kind == PRECISION}) <DOUBLE> <PRECISION> | <DOUBLE> )\r
+ {\r
+ return DataTypeDescriptor.getBuiltInDataTypeDescriptor(Types.DOUBLE);\r
+ }\r
+}\r
+\r
+\r
+/*\r
+ * <A NAME="longType">longType</A>\r
+ */\r
+DataTypeDescriptor\r
+longType() throws StandardException :\r
+{\r
+ DataTypeDescriptor dataTypeDescriptor;\r
+}\r
+{\r
+ <LONG> dataTypeDescriptor = longSubType()\r
+ {\r
+ return dataTypeDescriptor;\r
+ }\r
+}\r
+\r
+\r
+DataTypeDescriptor\r
+longSubType() throws StandardException :\r
+{\r
+ int lvcType = Types.LONGVARCHAR;\r
+}\r
+{\r
+ <VARCHAR> [ lvcType = forBitData(lvcType) ]\r
+ {\r
+ return DataTypeDescriptor.getBuiltInDataTypeDescriptor(lvcType);\r
+ }\r
+|\r
+ <NVARCHAR> \r
+ {\r
+ // need to re-enable according to SQL standard\r
+ throw StandardException.newException(SQLState.NOT_IMPLEMENTED, TypeId.NATIONAL_LONGVARCHAR_NAME);\r
+ // return DataTypeDescriptor.getBuiltInDataTypeDescriptor(TypeId.NATIONAL_LONGVARCHAR_NAME);\r
+ }\r
+}\r
+\r
+/*\r
+ * <A NAME="XMLType">XMLType</A>\r
+ */\r
+DataTypeDescriptor\r
+XMLType() throws StandardException :\r
+{\r
+ DataTypeDescriptor value;\r
+}\r
+{\r
+ <XML>\r
+ {\r
+ checkVersion(DataDictionary.DD_VERSION_DERBY_10_1, "XML");\r
+ return DataTypeDescriptor.getBuiltInDataTypeDescriptor(\r
+ StoredFormatIds.XML_TYPE_ID);\r
+ }\r
+}\r
+\r
+/*\r
+ * <A NAME="xmlDocOrContent">xmlDocOrContent</A>\r
+ *\r
+ * Parse the XML keywords DOCUMENT and CONTENT. We don't\r
+ * support CONTENT yet, so we throw an appropriate error\r
+ * if we see it.\r
+ *\r
+ */\r
+void\r
+xmlDocOrContent() throws StandardException :\r
+{\r
+}\r
+{\r
+ LOOKAHEAD({ (getToken(1).kind != DOCUMENT) &&\r
+ (getToken(1).kind != CONTENT) })\r
+ {\r
+ throw StandardException.newException(\r
+ SQLState.LANG_XML_KEYWORD_MISSING, "DOCUMENT",\r
+ ReuseFactory.getInteger(getToken(1).beginLine),\r
+ ReuseFactory.getInteger(getToken(1).beginColumn));\r
+ }\r
+|\r
+ LOOKAHEAD({ getToken(1).kind == CONTENT }) <CONTENT>\r
+ {\r
+ throw StandardException.newException(\r
+ SQLState.LANG_UNSUPPORTED_XML_FEATURE, "CONTENT");\r
+ }\r
+|\r
+ LOOKAHEAD({ getToken(1).kind == DOCUMENT }) <DOCUMENT>\r
+ {\r
+ return;\r
+ }\r
+}\r
+\r
+/*\r
+ * <A NAME="javaType">javaType</A>\r
+ */\r
+DataTypeDescriptor\r
+javaType() throws StandardException :\r
+{\r
+ String javaClassName;\r
+}\r
+{\r
+ javaClassName = javaClassName() \r
+ {\r
+ return getJavaClassDataTypeDescriptor(javaClassName);\r
+ }\r
+}\r
+\r
+/*\r
+ * <A NAME = "javaDSL">javaDSL</A>\r
+ *\r
+ * A Java dot-separated list.\r
+ */\r
+String\r
+javaDSL() :\r
+{\r
+ String dotSeparatedList;\r
+}\r
+{\r
+ dotSeparatedList = caseSensitiveIdentifierPlusReservedWords()\r
+ ( dotSeparatedList = javaDSLNameExtender(dotSeparatedList) ) *\r
+ {\r
+ return dotSeparatedList;\r
+ }\r
+}\r
+\r
+\r
+/*\r
+ * <A NAME="javaClassName">javaClassName</A>\r
+ */\r
+String\r
+javaClassName() :\r
+{\r
+ String javaClassName;\r
+}\r
+{\r
+ javaClassName = javaDSL()\r
+ {\r
+ return javaClassName;\r
+ }\r
+}\r
+\r
+/*\r
+ * <A NAME="javaDSLNameExtender">javaDSLNameExtender</A>\r
+ */\r
+String\r
+javaDSLNameExtender(String dotSeparatedList) :\r
+{\r
+ String extender;\r
+}\r
+{\r
+ <PERIOD> extender = caseSensitiveIdentifierPlusReservedWords()\r
+ {\r
+ return dotSeparatedList + "." + extender;\r
+ }\r
+}\r
+\r
+/*\r
+ * <A NAME="length">lengthAndModifier</A>\r
+ */\r
+int\r
+lengthAndModifier() throws StandardException :\r
+{\r
+ Token tok;\r
+ Token tokmod = null;\r
+}\r
+{\r
+ <LEFT_PAREN> \r
+ // we have essentially 3 different ways of specifying the length of a LOB\r
+ ( tok = <LENGTH_MODIFIER> // LOB(33K)\r
+ | tok = <EXACT_NUMERIC> [ tokmod = <IDENTIFIER> ] ) // LOB(33) or LOB(33 K)\r
+ <RIGHT_PAREN>\r
+ {\r
+ String s = tok.image + (tokmod==null ? "" : tokmod.image); // colapse cases;\r
+ try\r
+ {\r
+ char modifier = s.charAt(s.length()-1);\r
+ String number = s.substring(0, s.length()-1); // in case of ending w. letter\r
+ long mul;\r
+ switch (modifier) {\r
+ case 'G': \r
+ case 'g':\r
+ mul =1073741824L; //1 Giga\r
+ break;\r
+ case 'M':\r
+ case 'm':\r
+ mul=1048576L; // 1 Mega\r
+ break;\r
+ case 'K':\r
+ case 'k':\r
+ mul=1024L; // 1 Kilo\r
+ break;\r
+ default:\r
+ mul=1;\r
+ number = s; // no letter in end, need whole string\r
+ break;\r
+ }\r
+ long specifiedLength = Long.parseLong(number) * mul;\r
+ \r
+ // match DB2 limits of 1 to 2147483647\r
+ if ((specifiedLength > 0L) && \r
+ (specifiedLength <= Limits.DB2_LOB_MAXWIDTH))\r
+ {\r
+ return (int)specifiedLength;\r
+ }\r
+\r
+ // DB2 allows 2G or 2048M or 2097152k that calculate out to \r
+ // 2147483648, but sets the length to be one less.\r
+ if (mul != 1 && specifiedLength == 2147483648L)\r
+ return Limits.DB2_LOB_MAXWIDTH;\r
+ \r
+ }\r
+ catch (NumberFormatException nfe)\r
+ {\r
+ }\r
+\r
+ throw StandardException.newException(\r
+ SQLState.LANG_INVALID_COLUMN_LENGTH, s);\r
+ }\r
+}\r
+\r
+/*\r
+ * <A NAME="length">length</A>\r
+ */\r
+int\r
+length() throws StandardException :\r
+{\r
+ Token tok;\r
+ int retval;\r
+}\r
+{\r
+ tok = <EXACT_NUMERIC>\r
+ {\r
+ try\r
+ {\r
+ retval = Integer.parseInt(tok.image);\r
+\r
+ if (retval > 0)\r
+ return retval;\r
+ }\r
+ catch (NumberFormatException nfe)\r
+ {\r
+ }\r
+ throw StandardException.newException(SQLState.LANG_INVALID_COLUMN_LENGTH, tok.image);\r
+ }\r
+}\r
+\r
+\r
+/*\r
+ * <A NAME="exactNumber">exactNumber</A>\r
+*/\r
+long\r
+exactNumber() throws StandardException :\r
+{\r
+ Token longToken;\r
+ String sign = "";\r
+}\r
+{\r
+ [ sign = sign() ] longToken = <EXACT_NUMERIC>\r
+ {\r
+ try \r
+ {\r
+ /*\r
+ * Note that it's important to re-concatenate\r
+ * the - sign (if present) into the number\r
+ * before converting it to a long value so\r
+ * that we can successfully handle any value\r
+ * in the range Long.MIN_VALUE ... Long.MAX_VALUE.\r
+ * Unfortunately, we can't simply do:\r
+ * return Long.parseLong(sign+longToken.image);\r
+ * because Long.parseLong() doesn't accept a\r
+ * leading + sign.\r
+ */\r
+\r
+ if (sign.equals("-"))\r
+ {\r
+ return Long.parseLong("-"+longToken.image);\r
+ }\r
+ else\r
+ {\r
+ return Long.parseLong(longToken.image);\r
+ }\r
+ }\r
+ catch (NumberFormatException nfe)\r
+ {\r
+ throw\r
+ StandardException.newException(\r
+ SQLState.LANG_INVALID_INTEGER_LITERAL, longToken.image);\r
+ }\r
+ }\r
+}\r
+/*\r
+ * <A NAME="precision">precision</A>\r
+ */\r
+int\r
+precision() throws StandardException :\r
+{\r
+ int uintValue;\r
+}\r
+{\r
+ uintValue = uint_value()\r
+ {\r
+ return uintValue;\r
+ }\r
+}\r
+\r
+/*\r
+ * <A NAME="uint_value">uint_value</A>\r
+ */\r
+int \r
+uint_value() throws StandardException :\r
+{\r
+ Token uintToken;\r
+}\r
+{\r
+ /*\r
+ because the parser won't match to UINT, we use EXACT_NUMERIC.\r
+ */\r
+ uintToken = <EXACT_NUMERIC>\r
+ {\r
+ try {\r
+ return Integer.parseInt(uintToken.image);\r
+ } catch (NumberFormatException nfe) {\r
+ throw StandardException.newException(SQLState.LANG_INVALID_INTEGER_LITERAL, uintToken.image);\r
+ }\r
+ }\r
+}\r
+\r
+/*\r
+ * <A NAME="scale">scale</A>\r
+ */\r
+int\r
+scale() throws StandardException :\r
+{\r
+ int uintValue;\r
+}\r
+{\r
+ uintValue = uint_value()\r
+ {\r
+ return uintValue;\r
+ }\r
+}\r
+\r
+\r
+/*\r
+ * <A NAME="datetimeType">datetimeType</A>\r
+ */\r
+DataTypeDescriptor\r
+datetimeType() throws StandardException :\r
+{\r
+ Token tzTok = null;\r
+ int prec = -1; // know the value back is positive and in range\r
+}\r
+{\r
+ <DATE> \r
+ {\r
+ return DataTypeDescriptor.getBuiltInDataTypeDescriptor(Types.DATE);\r
+ }\r
+|\r
+ <TIME> \r
+ {\r
+\r
+ /*\r
+ We do not try to set up a precision for time/timestamp\r
+ values because this field gets mapped to the precision\r
+ field in the JDBC driver that is for the number of\r
+ decimal digits in the value. Precision for time is\r
+ actually the scale of the seconds value.\r
+\r
+ If/when precision for times is supported, we may need\r
+ to migrate the system catalog information to fill in\r
+ the default values appropriately (the default for\r
+ time is 0, fortunately; but for timestamp it is\r
+ actually 9 due to java.sql.Timestamp's precision).\r
+ */\r
+ return DataTypeDescriptor.getBuiltInDataTypeDescriptor(Types.TIME);\r
+ }\r
+|\r
+ <TIMESTAMP> \r
+ {\r
+\r
+ return DataTypeDescriptor.getBuiltInDataTypeDescriptor(Types.TIMESTAMP);\r
+ }\r
+}\r
+\r
+/*\r
+ * <A NAME="timePrecision">timePrecision</A>\r
+ */\r
+\r
+void\r
+qualifiedNameList(Vector list, int id_length_limit) throws StandardException :\r
+{\r
+}\r
+{\r
+ qualifiedNameElement(list, id_length_limit) ( <COMMA> qualifiedNameElement(list, id_length_limit) ) *\r
+}\r
+\r
+void \r
+qualifiedNameElement(Vector list, int id_length_limit) throws StandardException :\r
+{\r
+ TableName qualifiedName = null;\r
+}\r
+{\r
+ qualifiedName = qualifiedName(id_length_limit)\r
+ {\r
+ list.addElement(qualifiedName);\r
+ }\r
+}\r
+\r
+/*\r
+ * <A NAME="qualifiedName">qualifiedName</A>\r
+ */\r
+TableName\r
+qualifiedName( int nodeType, int id_length_limit) throws StandardException :\r
+{\r
+ //String catalogName = null;\r
+ String schemaName = null;\r
+ String qualifiedId;\r
+ String firstName = null;\r
+ String secondName = null;\r
+}\r
+{\r
+ firstName = identifier(Limits.MAX_IDENTIFIER_LENGTH, false)\r
+ [\r
+ // This LOOKAHEAD is necessary because a selectSublist()\r
+ // can be a qualifiedName.*. Make sure that the token after\r
+ // the PERIOD is not an ASTERISK before committing to this\r
+ // optional element.\r
+ LOOKAHEAD( {getToken(1).kind == PERIOD &&\r
+ getToken(2).kind != ASTERISK} )\r
+ <PERIOD> secondName = identifier(Limits.MAX_IDENTIFIER_LENGTH, false)\r
+ ]\r
+ {\r
+ if (secondName == null)\r
+ {\r
+ qualifiedId = firstName;\r
+ }\r
+ else\r
+ {\r
+ schemaName = firstName;\r
+ qualifiedId = secondName;\r
+ }\r
+\r
+ //limit the qualifiedId to the id length limit passed to this method\r
+ checkIdentifierLengthLimit(qualifiedId, id_length_limit);\r
+ if (schemaName != null)\r
+ checkIdentifierLengthLimit(schemaName, Limits.MAX_IDENTIFIER_LENGTH);\r
+\r
+ return (TableName) nodeFactory.getNode(\r
+ nodeType,\r
+ schemaName,\r
+ qualifiedId,\r
+ new Integer(lastIdentifierToken.beginOffset),\r
+ new Integer(lastIdentifierToken.endOffset),\r
+ getContextManager());\r
+ }\r
+}\r
+\r
+/*\r
+ * <A NAME="queryExpression">queryExpression</A>\r
+ *\r
+ * We have to be carefull to get the associativity correct. According to the SQL spec\r
+ * <non-join query expression> ::=\r
+ * <non-join query term>\r
+ * | <query expression body> UNION [ ALL ] <query term>\r
+ * | <query expression body> EXCEPT [ ALL ] <query term>\r
+ * Meaning that\r
+ * t1 UNION ALL t2 UNION t3\r
+ * is equivalent to\r
+ * (t1 UNION ALL t2) UNION t3\r
+ * However recursive descent parsers want recursion to be on the right, so this kind of associativity is unnatural\r
+ * for our parser. The queryExpression method must know whether it is being called as the right hand side of a\r
+ * set operator to produce a query tree with the correct associativity.\r
+ */\r
+ResultSetNode\r
+queryExpression(ResultSetNode leftSide, int operatorType) throws StandardException :\r
+{\r
+ ResultSetNode term;\r
+}\r
+{\r
+ term = nonJoinQueryTerm(leftSide, operatorType) [ term = unionOrExcept(term) ]\r
+ {\r
+ return term;\r
+ }\r
+}\r
+\r
+/*\r
+ * <A NAME="unionOrExcept">unionOrExcept</A>\r
+ */\r
+ResultSetNode\r
+unionOrExcept(ResultSetNode term) throws StandardException :\r
+{\r
+ ResultSetNode expression;\r
+ Token tok = null;\r
+}\r
+{\r
+ <UNION> [ tok = <ALL> | <DISTINCT> ] expression =\r
+ queryExpression(term,\r
+ (tok != null) ? UNION_ALL_OP : UNION_OP)\r
+ {\r
+ return expression;\r
+ }\r
+|\r
+ <EXCEPT> [ tok = <ALL> | <DISTINCT> ] expression =\r
+ queryExpression(term,\r
+ (tok != null) ? EXCEPT_ALL_OP : EXCEPT_OP)\r
+ {\r
+ return expression;\r
+ }\r
+}\r
+\r
+\r
+/*\r
+ * <A NAME="nonJoinQueryTerm">nonJoinQueryTerm</A>\r
+ *\r
+ * Be careful with the associativity of INTERSECT. According to the SQL spec\r
+ * t1 INTERSECT t2 INTERSECT ALL t3\r
+ * is equivalent to\r
+ * (t1 INTERSECT t2) INTERSECT ALL t3\r
+ * which is not the same as\r
+ * t1 INTERSECT (t2 INTERSECT ALL t3)\r
+ * See the comment on queryExpression.\r
+ */\r
+ResultSetNode\r
+nonJoinQueryTerm(ResultSetNode leftSide, int operatorType) throws StandardException :\r
+{\r
+ ResultSetNode term;\r
+}\r
+{\r
+ term = nonJoinQueryPrimary() [ term = intersect( term) ]\r
+ {\r
+ switch( operatorType)\r
+ {\r
+ case NO_SET_OP:\r
+ return term;\r
+\r
+ case UNION_OP:\r
+ return (ResultSetNode) nodeFactory.getNode(\r
+ C_NodeTypes.UNION_NODE,\r
+ leftSide,\r
+ term,\r
+ Boolean.FALSE,\r
+ Boolean.FALSE,\r
+ null,\r
+ getContextManager());\r
+\r
+ case UNION_ALL_OP:\r
+ return (ResultSetNode) nodeFactory.getNode(\r
+ C_NodeTypes.UNION_NODE,\r
+ leftSide,\r
+ term,\r
+ Boolean.TRUE,\r
+ Boolean.FALSE,\r
+ null,\r
+ getContextManager());\r
+\r
+ case EXCEPT_OP:\r
+ return (ResultSetNode) nodeFactory.getNode(\r
+ C_NodeTypes.INTERSECT_OR_EXCEPT_NODE,\r
+ ReuseFactory.getInteger( IntersectOrExceptNode.EXCEPT_OP),\r
+ leftSide,\r
+ term,\r
+ Boolean.FALSE,\r
+ null,\r
+ getContextManager());\r
+\r
+ case EXCEPT_ALL_OP:\r
+ return (ResultSetNode) nodeFactory.getNode(\r
+ C_NodeTypes.INTERSECT_OR_EXCEPT_NODE,\r
+ ReuseFactory.getInteger( IntersectOrExceptNode.EXCEPT_OP),\r
+ leftSide,\r
+ term,\r
+ Boolean.TRUE,\r
+ null,\r
+ getContextManager());\r
+\r
+ case INTERSECT_OP:\r
+ return (ResultSetNode) nodeFactory.getNode(\r
+ C_NodeTypes.INTERSECT_OR_EXCEPT_NODE,\r
+ ReuseFactory.getInteger( IntersectOrExceptNode.INTERSECT_OP),\r
+ leftSide,\r
+ term,\r
+ Boolean.FALSE,\r
+ null,\r
+ getContextManager());\r
+\r
+ case INTERSECT_ALL_OP:\r
+ return (ResultSetNode) nodeFactory.getNode(\r
+ C_NodeTypes.INTERSECT_OR_EXCEPT_NODE,\r
+ ReuseFactory.getInteger( IntersectOrExceptNode.INTERSECT_OP),\r
+ leftSide,\r
+ term,\r
+ Boolean.TRUE,\r
+ null,\r
+ getContextManager());\r
+\r
+\r
+ default:\r
+ if (SanityManager.DEBUG)\r
+ {\r
+ SanityManager.THROWASSERT( "Invalid set operator type: " + operatorType);\r
+ }\r
+ return null;\r
+ }\r
+ }\r
+}\r
+\r
+/*\r
+ * <A NAME="intersect">intersect</A>\r
+ */\r
+ResultSetNode\r
+intersect(ResultSetNode term) throws StandardException :\r
+{\r
+ ResultSetNode expression;\r
+ Token tok = null;\r
+}\r
+{\r
+ <INTERSECT> [ tok = <ALL> | <DISTINCT> ] expression =\r
+ nonJoinQueryTerm(term, (tok != null) ? INTERSECT_ALL_OP : INTERSECT_OP)\r
+ {\r
+ return expression;\r
+ }\r
+}\r
+\r
+/*\r
+ * <A NAME="nonJoinQueryPrimary">nonJoinQueryPrimary</A>\r
+ */\r
+ResultSetNode\r
+nonJoinQueryPrimary() throws StandardException :\r
+{\r
+ ResultSetNode primary;\r
+}\r
+{\r
+ primary = simpleTable()\r
+ {\r
+ return primary;\r
+ }\r
+|\r
+ <LEFT_PAREN> primary = queryExpression(null, NO_SET_OP) <RIGHT_PAREN>\r
+ {\r
+ return primary;\r
+ }\r
+}\r
+\r
+/*\r
+ * <A NAME="simpleTable">simpleTable</A>\r
+ */\r
+ResultSetNode\r
+simpleTable() throws StandardException :\r
+{\r
+ ResultSetNode resultSetNode;\r
+}\r
+{\r
+ resultSetNode = querySpecification()\r
+ {\r
+ return resultSetNode;\r
+ }\r
+|\r
+ resultSetNode = tableValueConstructor()\r
+ {\r
+ return resultSetNode;\r
+ }\r
+}\r
+\r
+/*\r
+ * <A NAME="querySpecification">querySpecification</A>\r
+ */\r
+ResultSetNode\r
+querySpecification() throws StandardException :\r
+{\r
+ ResultColumnList selectList;\r
+ SelectNode selectNode;\r
+ boolean isDistinct = false;\r
+}\r
+{\r
+ <SELECT> [ isDistinct = setQuantifier() ]\r
+ selectList = selectList()\r
+ selectNode = tableExpression(selectList)\r
+ {\r
+ if (isDistinct) selectNode.makeDistinct();\r
+ return selectNode;\r
+ }\r
+}\r
+\r
+/*\r
+ * <A NAME="setQuantifier">setQuantifier</A>\r
+ */\r
+boolean\r
+setQuantifier() :\r
+{}\r
+{\r
+ // This lookahead is required to distinquish distinct from\r
+ // a class which starts with distinct (e.g., distinct::)\r
+ LOOKAHEAD\r
+ (\r
+ {\r
+ getToken(1).kind == DISTINCT &&\r
+ !(\r
+ getToken(2).kind == PERIOD ||\r
+ getToken(2).kind == DOUBLE_COLON\r
+ )\r
+ }\r
+ )\r
+ <DISTINCT>\r
+ {\r
+ return true;\r
+ }\r
+|\r
+ // This lookahead is required to distinquish all from\r
+ // a class which starts with all (e.g., all::)\r
+ LOOKAHEAD\r
+ (\r
+ {\r
+ getToken(1).kind == ALL &&\r
+ !(\r
+ getToken(2).kind == PERIOD ||\r
+ getToken(2).kind == DOUBLE_COLON\r
+ )\r
+ }\r
+ )\r
+ <ALL>\r
+ {\r
+ return false;\r
+ }\r
+}\r
+\r
+/*\r
+ * <A NAME="selectList">selectList</A>\r
+ */\r
+ResultColumnList\r
+selectList() throws StandardException :\r
+{\r
+ ResultColumn allResultColumn;\r
+ ResultColumnList resultColumns = (ResultColumnList) nodeFactory.getNode(\r
+ C_NodeTypes.RESULT_COLUMN_LIST,\r
+ getContextManager());\r
+}\r
+{\r
+ <ASTERISK>\r
+ {\r
+ allResultColumn = (ResultColumn) nodeFactory.getNode(\r
+ C_NodeTypes.ALL_RESULT_COLUMN,\r
+ null,\r
+ getContextManager());\r
+ /* Add the new AllResultColumn to the end of the list */\r
+ resultColumns.addResultColumn(allResultColumn);\r
+ return resultColumns;\r
+ }\r
+|\r
+ selectColumnList(resultColumns)\r
+ {\r
+ return resultColumns;\r
+ }\r
+}\r
+\r
+void\r
+selectColumnList(ResultColumnList resultColumns) throws StandardException :\r
+{\r
+}\r
+{\r
+ selectSublist(resultColumns) ( <COMMA> selectSublist(resultColumns) ) *\r
+}\r
+\r
+/*\r
+ * <A NAME="selectSublist">selectSublist</A>\r
+ */\r
+void\r
+selectSublist(ResultColumnList resultColumns) throws StandardException :\r
+{\r
+ ResultColumn resultColumn;\r
+ ResultColumn allResultColumn;\r
+ TableName tableName;\r
+}\r
+{\r
+ // This LOOKAHEAD is required because both a qualifiedName() and a\r
+ // derivedColumn() can start with an identifier(). So, the two cases\r
+ // we check for are x.* and x.y.*\r
+ //\r
+ // NOTE: It is hard to check for an identifier() using semantic lookahead.\r
+ LOOKAHEAD\r
+ (\r
+ {\r
+ getToken(2).kind == PERIOD &&\r
+ (\r
+ getToken(3).kind == ASTERISK ||\r
+ (getToken(4).kind == PERIOD && getToken(5).kind == ASTERISK)\r
+ )\r
+ }\r
+ )\r
+ tableName = qualifiedName(Limits.MAX_IDENTIFIER_LENGTH) <PERIOD> <ASTERISK>\r
+ {\r
+ allResultColumn = (ResultColumn) nodeFactory.getNode(\r
+ C_NodeTypes.ALL_RESULT_COLUMN,\r
+ tableName,\r
+ getContextManager());\r
+ /* Add the new AllResultColumn to the end of the list */\r
+ resultColumns.addResultColumn(allResultColumn);\r
+ }\r
+|\r
+ resultColumn = derivedColumn(resultColumns)\r
+ {\r
+ /* Add the new ResultColumn to the end of the list */\r
+ resultColumns.addResultColumn(resultColumn);\r
+ }\r
+}\r
+\r
+/*\r
+ * <A NAME="derivedColumn">derivedColumn</A>\r
+ */\r
+ResultColumn\r
+derivedColumn(ResultColumnList resultColumns) throws StandardException :\r
+{\r
+ ValueNode columnExpression;\r
+ String columnName = null;\r
+}\r
+{\r
+ //true to additiveExpression ensures that for the derived columns, we will not allow boolean values inside (), \r
+ //eg (2 > 1) should be disallowed in the select clause\r
+ columnExpression = additiveExpression(null, 0, true) \r
+ [ columnName = asClause() ]\r
+ { \r
+ /*\r
+ ** If there is no AS clause, and the expression is a simple\r
+ ** column, use the name of the column as the result column\r
+ ** name.\r
+ */\r
+ if ((columnName == null) && (columnExpression instanceof ColumnReference))\r
+ {\r
+ columnName = ((ColumnReference) columnExpression).columnName;\r
+ }\r
+\r
+ return (ResultColumn) nodeFactory.getNode(\r
+ C_NodeTypes.RESULT_COLUMN,\r
+ columnName,\r
+ columnExpression,\r
+ getContextManager());\r
+ }\r
+}\r
+\r
+/*\r
+ * <A NAME="asClause">asClause</A>\r
+ */\r
+String\r
+asClause() throws StandardException :\r
+{\r
+ String columnName;\r
+}\r
+{\r
+ /* identifier() used to be columnName() */\r
+ [ <AS> ] columnName = identifier(Limits.MAX_IDENTIFIER_LENGTH, true)\r
+ {\r
+ return columnName;\r
+ }\r
+}\r
+\r
+/*\r
+ * <A NAME="valueExpression">valueExpression</A>\r
+ * \r
+ * @param inSelectClause will be true if this method got called while parsing the select or values clause\r
+ * If in select or values clause, we do not want to allow boolean values.\r
+ */\r
+ValueNode\r
+valueExpression( boolean inSelectClause ) throws StandardException :\r
+{\r
+ ValueNode leftOperand;\r
+}\r
+{\r
+ leftOperand = orExpression(null, inSelectClause)\r
+ (<OR> leftOperand = orExpression(leftOperand, inSelectClause) ) *\r
+ {\r
+\r
+ return leftOperand;\r
+ }\r
+}\r
+ \r
+/*\r
+ * <A NAME="orExpression">orExpression</A>\r
+ * \r
+ * @param inSelectClause will be true if this method got called while parsing the select or values clause\r
+ * If in select or values clause, we do not want to allow boolean values.\r
+ */\r
+ValueNode\r
+orExpression(ValueNode farLeftOperand, boolean inSelectClause) throws StandardException :\r
+{\r
+ ValueNode leftOperand;\r
+}\r
+{\r
+ leftOperand = andExpression(null, inSelectClause)\r
+ (<AND> leftOperand = andExpression(leftOperand, inSelectClause)) *\r
+ {\r
+ if (farLeftOperand == null)\r
+ {\r
+ return leftOperand;\r
+ }\r
+ else\r
+ {\r
+ return (ValueNode) nodeFactory.getNode(\r
+ C_NodeTypes.OR_NODE,\r
+ farLeftOperand,\r
+ leftOperand,\r
+ getContextManager());\r
+ }\r
+ }\r
+}\r
+\r
+/*\r
+ * <A NAME="andExpression">andExpression</A>\r
+ * \r
+ * @param inSelectClause will be true if this method got called while parsing the select or values clause\r
+ * If in select or values clause, we do not want to allow boolean values.\r
+ */\r
+ValueNode\r
+andExpression(ValueNode farLeftOperand, boolean inSelectClause) throws StandardException :\r
+{\r
+ Token tok = null;\r
+ ValueNode test;\r
+}\r
+{\r
+ //LOOKAHEAD required to tell that NOT is not part of a class name\r
+ [ LOOKAHEAD({getToken(1).kind == NOT && !(getToken(2).kind == PERIOD ||\r
+ getToken(2).kind == DOUBLE_COLON)}) tok = <NOT> ] test = isSearchCondition(inSelectClause) \r
+ {\r
+ /* Put the NOT on top of test */\r
+ if (tok != null)\r
+ {\r
+ test = (ValueNode) nodeFactory.getNode(\r
+ C_NodeTypes.NOT_NODE,\r
+ test,\r
+ getContextManager());\r
+ }\r
+\r
+ if (farLeftOperand != null)\r
+ {\r
+ test = (ValueNode) nodeFactory.getNode(\r
+ C_NodeTypes.AND_NODE,\r
+ farLeftOperand,\r
+ test,\r
+ getContextManager());\r
+ }\r
+ return test;\r
+ }\r
+}\r
+\r
+/*\r
+ * <A NAME="isSearchCondition">isSearchCondition</A>\r
+ * \r
+ * @param inSelectClause will be true if this method got called while parsing the select or values clause\r
+ * If in select or values clause, we do not want to allow boolean values.\r
+ */\r
+ValueNode\r
+isSearchCondition( boolean inSelectClause ) throws StandardException :\r
+{\r
+ ValueNode result;\r
+ ValueNode booleanPrimary;\r
+ Token isToken = null;\r
+ Token notToken = null;\r
+ Token truthValue = null;\r
+}\r
+{\r
+ booleanPrimary = booleanPrimary(inSelectClause)\r
+ [\r
+ isToken = <IS> [ notToken = <NOT> ] <NULL>\r
+ ]\r
+ {\r
+ if ( isToken != null )\r
+ {\r
+ result = (ValueNode) nodeFactory.getNode(\r
+ C_NodeTypes.IS_NULL_NODE,\r
+ booleanPrimary,\r
+ getContextManager());\r
+ \r
+ /* Put the NOT on top of the tree */\r
+ if (notToken != null)\r
+ {\r
+ result = (ValueNode) nodeFactory.getNode(\r
+ C_NodeTypes.NOT_NODE,\r
+ result,\r
+ getContextManager());\r
+ }\r
+ }\r
+ else { result = booleanPrimary; }\r
+\r
+ return result;\r
+ }\r
+}\r
+\r
+/*\r
+ * <A NAME="booleanPrimary">booleanPrimary</A>\r
+ * \r
+ * @param inSelectClause will be true if this method got called while parsing the select or values clause\r
+ * If in select or values clause, we do not want to allow boolean values.\r
+ */\r
+ValueNode\r
+booleanPrimary(boolean inSelectClause) throws StandardException :\r
+{\r
+ ValueNode primary;\r
+ ValueNode searchCondition;\r
+}\r
+{\r
+ primary = predicate(inSelectClause)\r
+ {\r
+ return primary;\r
+ }\r
+}\r
+\r
+/*\r
+ * <A NAME="predicate">predicate</A>\r
+ * \r
+ * @param inSelectClause will be true if this method got called while parsing the select or values clause\r
+ * If in select or values clause, we do not want to allow boolean values.\r
+ */\r
+ValueNode\r
+predicate( boolean inSelectClause ) throws StandardException :\r
+{\r
+ ValueNode value;\r
+}\r
+{\r
+ (\r
+ value = additiveExpression(null, 0, inSelectClause) |\r
+ value = existsExpression()\r
+ )\r
+ (\r
+ // This LOOKAHEAD is necessary because remainingPredicate() can\r
+ // start with NOT, and what follows a predicate() can also start\r
+ // with NOT\r
+ LOOKAHEAD( { remainingPredicateFollows() } )\r
+ value = remainingPredicate(value, inSelectClause)\r
+ )*\r
+ {\r
+ return value;\r
+ }\r
+/*\r
+** RESOLVE: overlapsExpression commented out for the time being to avoid\r
+** a left recursion. An OVERLAPS expression is defined as taking row\r
+** constructors as parameters. A row constructor contains a valueExpression\r
+** as its first element, so it can't return be the first element in a\r
+** valueExpression.\r
+\r
+|\r
+ overlapsExpression()\r
+ {\r
+ return null;\r
+ }\r
+*/\r
+}\r
+\r
+/*\r
+ * <A NAME="remainingPredicates">remainingPredicates</A>\r
+ * \r
+ * @param inSelectClause will be true if this method got called while parsing the select or values clause\r
+ * If in select or values clause, we do not want to allow boolean values.\r
+ */\r
+ValueNode\r
+remainingPredicate(ValueNode value, boolean inSelectClause) throws StandardException :\r
+{\r
+ Token tok = null;\r
+}\r
+{\r
+ value = remainingNonNegatablePredicate(value, inSelectClause)\r
+ {\r
+ return value;\r
+ }\r
+|\r
+ [ tok = <NOT> ] value = remainingNegatablePredicate(value, inSelectClause)\r
+ {\r
+ /* Put the NOT on top of the tree */\r
+ if (tok != null)\r
+ {\r
+ value = (ValueNode) nodeFactory.getNode(\r
+ C_NodeTypes.NOT_NODE,\r
+ value,\r
+ getContextManager());\r
+ }\r
+\r
+ return value;\r
+ }\r
+}\r
+\r
+/*\r
+ * <A NAME="remainingNonNegatablePredicate">remainingNonNegatablePredicate</A>\r
+ * \r
+ * @param inSelectClause will be true if this method got called while parsing the select or values clause\r
+ * If in select or values clause, we do not want to allow boolean values.\r
+ */\r
+ValueNode \r
+remainingNonNegatablePredicate(ValueNode leftOperand, boolean inSelectClause) throws StandardException :\r
+{\r
+ int operator;\r
+ String javaClassName;\r
+ Token tok = null;\r
+ ValueNode tree = null;\r
+ ValueNode likePattern;\r
+ ValueNode betweenLeft;\r
+ ValueNode betweenRight;\r
+}\r
+{\r
+ operator = compOp()\r
+ (\r
+ // Lookahead required here to tell ALL, ANY or SOME from a \r
+ // class which starts with these words (e.g., ALL::)\r
+ LOOKAHEAD({(getToken(1).kind == ALL || getToken(1).kind == ANY || \r
+ getToken(1).kind == SOME) && getToken(2).kind == LEFT_PAREN})\r
+ (\r
+ operator = quantifier(operator)\r
+ <LEFT_PAREN>\r
+ leftOperand = tableSubquery(operator, leftOperand)\r
+ <RIGHT_PAREN>\r
+ )\r
+ |\r
+ (\r
+ leftOperand = additiveExpression(leftOperand, operator, inSelectClause)\r
+ )\r
+ )\r
+ {\r
+ return leftOperand;\r
+ }\r
+}\r
+\r
+/*\r
+ * <A NAME="remainingNegatablePredicate">remainingNegatablePredicate</A>\r
+ * \r
+ * @param inSelectClause will be true if this method got called while parsing the select or values clause\r
+ * If in select or values clause, we do not want to allow boolean values.\r
+ */\r
+ValueNode \r
+remainingNegatablePredicate(ValueNode leftOperand, boolean inSelectClause) throws StandardException :\r
+{\r
+ ValueNode tree = null;\r
+ ValueNode likePattern;\r
+ ValueNode betweenLeft;\r
+ ValueNode betweenRight;\r
+ ValueNode escapeValue = null;\r
+}\r
+{\r
+ <IN> tree = inPredicateValue(leftOperand)\r
+ {\r
+ return tree;\r
+ }\r
+|\r
+ <LIKE> likePattern = additiveExpression(null, 0, inSelectClause)\r
+ [\r
+ <ESCAPE> escapeValue = additiveExpression(null, 0, inSelectClause) |\r
+ <LEFT_BRACE> <ESCAPE> escapeValue = additiveExpression(null, 0, inSelectClause) <RIGHT_BRACE>\r
+ ]\r
+ {\r
+ tree = (ValueNode) nodeFactory.getNode(\r
+ C_NodeTypes.LIKE_OPERATOR_NODE,\r
+ leftOperand,\r
+ likePattern,\r
+ escapeValue,\r
+ getContextManager());\r
+ \r
+ return tree;\r
+ }\r
+|\r
+ <BETWEEN> betweenLeft = additiveExpression(null, 0, inSelectClause) <AND>\r
+ betweenRight = additiveExpression(null, 0, inSelectClause)\r
+ {\r
+ ValueNodeList betweenList = (ValueNodeList) nodeFactory.getNode(\r
+ C_NodeTypes.VALUE_NODE_LIST,\r
+ getContextManager());\r
+ betweenList.addElement(betweenLeft);\r
+ betweenList.addElement(betweenRight);\r
+ tree = (ValueNode) nodeFactory.getNode(\r
+ C_NodeTypes.BETWEEN_OPERATOR_NODE,\r
+ leftOperand,\r
+ betweenList,\r
+ getContextManager());\r
+ \r
+ return tree;\r
+ }\r
+}\r
+\r
+/*\r
+ * <A NAME="compOp">compOp</A>\r
+ */\r
+int\r
+compOp() throws StandardException :\r
+{}\r
+{\r
+ <EQUALS_OPERATOR>\r
+ {\r
+ return BinaryOperatorNode.EQ;\r
+ }\r
+|\r
+ <NOT_EQUALS_OPERATOR>\r
+ {\r
+ return BinaryOperatorNode.NE;\r
+ }\r
+|\r
+ <NOT_EQUALS_OPERATOR2>\r
+ {\r
+ return BinaryOperatorNode.NE;\r
+ }\r
+|\r
+ <LESS_THAN_OPERATOR>\r
+ {\r
+ return BinaryOperatorNode.LT;\r
+ }\r
+|\r
+ <GREATER_THAN_OPERATOR>\r
+ {\r
+ return BinaryOperatorNode.GT;\r
+ }\r
+|\r
+ <LESS_THAN_OR_EQUALS_OPERATOR>\r
+ {\r
+ return BinaryOperatorNode.LE;\r
+ }\r
+|\r
+ <GREATER_THAN_OR_EQUALS_OPERATOR>\r
+ {\r
+ return BinaryOperatorNode.GE;\r
+ }\r
+}\r
+\r
+/*\r
+ * <A NAME="additiveExpression">additiveExpression</A>\r
+ * \r
+ * @param inSelectClause will be true if this method got called while parsing the select or values clause\r
+ * If in select or values clause, we do not want to allow boolean values.\r
+ */\r
+ValueNode\r
+additiveExpression(ValueNode farLeftOperand, int compOp, boolean inSelectClause) throws StandardException :\r
+{\r
+ ValueNode leftOperand;\r
+ int operator;\r
+ int nodeType;\r
+}\r
+{\r
+ leftOperand = multiplicativeExpression(null, 0, inSelectClause) \r
+ (operator = additiveOperator() \r
+ leftOperand = multiplicativeExpression(leftOperand, operator, inSelectClause) )*\r
+ {\r
+ if (farLeftOperand == null)\r
+ return leftOperand;\r
+\r
+ switch (compOp)\r
+ {\r
+ case BinaryOperatorNode.EQ:\r
+ nodeType = C_NodeTypes.BINARY_EQUALS_OPERATOR_NODE;\r
+ break;\r
+\r
+ case BinaryOperatorNode.NE:\r
+ nodeType = C_NodeTypes.BINARY_NOT_EQUALS_OPERATOR_NODE;\r
+ break;\r
+\r
+ case BinaryOperatorNode.LT:\r
+ nodeType = C_NodeTypes.BINARY_LESS_THAN_OPERATOR_NODE;\r
+ break;\r
+\r
+ case BinaryOperatorNode.GT:\r
+ nodeType = C_NodeTypes.BINARY_GREATER_THAN_OPERATOR_NODE;\r
+ break;\r
+\r
+ case BinaryOperatorNode.LE:\r
+ nodeType = C_NodeTypes.BINARY_LESS_EQUALS_OPERATOR_NODE;\r
+ break;\r
+\r
+ case BinaryOperatorNode.GE:\r
+ nodeType = C_NodeTypes.BINARY_GREATER_EQUALS_OPERATOR_NODE;\r
+ break;\r
+\r
+ default:\r
+ if (SanityManager.DEBUG)\r
+ SanityManager.THROWASSERT("Unknown comparison operator " + compOp);\r
+ nodeType = 0;\r
+ break;\r
+ }\r
+\r
+ return (ValueNode) nodeFactory.getNode(\r
+ nodeType,\r
+ farLeftOperand,\r
+ leftOperand,\r
+ getContextManager());\r
+ }\r
+}\r
+\r
+/*\r
+ * <A NAME="additiveOperator">additiveOperator</A>\r
+ */\r
+int\r
+additiveOperator() throws StandardException :\r
+{\r
+ Token tok;\r
+}\r
+{ tok = <PLUS_SIGN> \r
+ {\r
+ return BinaryOperatorNode.PLUS;\r
+ }\r
+|\r
+ tok = <MINUS_SIGN>\r
+ {\r
+ return BinaryOperatorNode.MINUS;\r
+ }\r
+}\r
+\r
+/*\r
+ * <A NAME="multiplicativeExpression">multiplicativeExpression</A>\r
+ * \r
+ * @param inSelectClause will be true if this method got called while parsing the select or values clause\r
+ * If in select or values clause, we do not want to allow boolean values.\r
+ */\r
+ValueNode\r
+multiplicativeExpression(ValueNode farLeftOperand, int additiveOperator, boolean inSelectClause) throws StandardException :\r
+{\r
+ ValueNode leftOperand;\r
+ int multOp;\r
+}\r
+{\r
+ leftOperand = unaryExpression(null, 0, inSelectClause) \r
+ (multOp = multiplicativeOperator() \r
+ leftOperand = unaryExpression(leftOperand, multOp, inSelectClause) )*\r
+ {\r
+ if (farLeftOperand == null)\r
+ return leftOperand;\r
+\r
+ switch (additiveOperator)\r
+ {\r
+ case BinaryOperatorNode.PLUS:\r
+ return (ValueNode) nodeFactory.getNode(\r
+ C_NodeTypes.BINARY_PLUS_OPERATOR_NODE,\r
+ farLeftOperand,\r
+ leftOperand,\r
+ getContextManager()\r
+ );\r
+\r
+ case BinaryOperatorNode.MINUS:\r
+ return (ValueNode) nodeFactory.getNode(\r
+ C_NodeTypes.BINARY_MINUS_OPERATOR_NODE,\r
+ farLeftOperand,\r
+ leftOperand,\r
+ getContextManager()\r
+ );\r
+\r
+ default:\r
+ if (SanityManager.DEBUG)\r
+ SanityManager.THROWASSERT(\r
+ "Unexpected operator value of " + additiveOperator);\r
+ return null;\r
+ }\r
+ }\r
+}\r
+\r
+/*\r
+ * <A NAME="multiplicativeOperator">multiplicativeOperator</A>\r
+ */\r
+int\r
+multiplicativeOperator() throws StandardException :\r
+{ }\r
+{ <ASTERISK> \r
+ {\r
+ return BinaryOperatorNode.TIMES;\r
+ }\r
+|\r
+ <SOLIDUS>\r
+ {\r
+ return BinaryOperatorNode.DIVIDE;\r
+ }\r
+|\r
+ <CONCATENATION_OPERATOR>\r
+ {\r
+ return BinaryOperatorNode.CONCATENATE;\r
+ }\r
+}\r
+\r
+/*\r
+ * <A NAME="unaryExpression">unaryExpression</A>\r
+ * \r
+ * @param inSelectClause will be true if this method got called while parsing the select or values clause\r
+ * If in select or values clause, we do not want to allow boolean values.\r
+ */\r
+ValueNode\r
+unaryExpression(ValueNode farLeftOperand, int multiplicativeOperator, boolean inSelectClause) throws StandardException :\r
+{\r
+ ValueNode value;\r
+ String sign = null;\r
+ int tokKind1;\r
+ int tokKind2;\r
+}\r
+{\r
+ [\r
+ // This LOOKAHEAD is required because a + or - sign can come before\r
+ // any expression, and also can be part of a literal. If it comes\r
+ // before a number, we want it to be considered part of the literal,\r
+ // because the literal() rule knows how to handle the minimum value\r
+ // for an int without changing it to a long.\r
+ LOOKAHEAD( {\r
+ ( (tokKind1 = getToken(1).kind) == PLUS_SIGN ||\r
+ tokKind1 == MINUS_SIGN )\r
+ &&\r
+ ( (tokKind2 = getToken(2).kind) != EXACT_NUMERIC &&\r
+ tokKind2 != APPROXIMATE_NUMERIC)\r
+ } )\r
+ sign = sign()\r
+ ]\r
+ value = primaryExpression(inSelectClause)\r
+ {\r
+ if ("-".equals(sign))\r
+ {\r
+ value = (ValueNode) nodeFactory.getNode(\r
+ C_NodeTypes.UNARY_MINUS_OPERATOR_NODE,\r
+ value,\r
+ getContextManager());\r
+ }\r
+ else if ("+".equals(sign))\r
+ {\r
+ value = (ValueNode) nodeFactory.getNode(\r
+ C_NodeTypes.UNARY_PLUS_OPERATOR_NODE,\r
+ value,\r
+ getContextManager());\r
+ }\r
+ else if (SanityManager.DEBUG)\r
+ {\r
+ if (sign != null)\r
+ {\r
+ SanityManager.THROWASSERT("Unknown unary operator '"\r
+ + sign\r
+ + "'");\r
+ }\r
+ }\r
+\r
+ return multOp(farLeftOperand, value, multiplicativeOperator);\r
+ }\r
+}\r
+\r
+\r
+/*\r
+ * <A NAME="sign">sign</A>\r
+ */\r
+String\r
+sign() :\r
+{\r
+ Token s;\r
+}\r
+{\r
+ s = <PLUS_SIGN>\r
+ {\r
+ return s.image;\r
+ }\r
+|\r
+ s = <MINUS_SIGN>\r
+ {\r
+ return s.image;\r
+ }\r
+}\r
+\r
+/*\r
+ * <A NAME="primaryExpressionXX">primaryExpressionXX</A>\r
+ * \r
+ * @param inSelectClause will be true if this method got called while parsing the select or values clause\r
+ * If in select or values clause, we do not want to allow boolean values.\r
+ */\r
+ValueNode\r
+primaryExpressionXX( boolean inSelectClause ) throws StandardException :\r
+{\r
+ ValueNode value;\r
+}\r
+{\r
+ value = primary(inSelectClause)\r
+ ( value = nonStaticMethodCallOrFieldAccess(value)) * \r
+ {\r
+ return value;\r
+ }\r
+}\r
+\r
+ValueNode\r
+nonStaticMethodCallOrFieldAccess(ValueNode receiver) throws StandardException :\r
+{\r
+ ValueNode value;\r
+}\r
+{\r
+ value = nonStaticMethodInvocation(receiver)\r
+ {\r
+ return value;\r
+ }\r
+}\r
+\r
+/*\r
+ * <A NAME="nonStaticMethodInvocation">nonStaticMethodInvocation</A>\r
+ */\r
+ValueNode\r
+nonStaticMethodInvocation(ValueNode receiver) throws StandardException :\r
+{\r
+ Vector parameterList = new Vector();\r
+ MethodCallNode methodNode;\r
+ ParameterNode parameterNode;\r
+}\r
+{\r
+ LOOKAHEAD\r
+ ( {\r
+ getToken(3).kind == LEFT_PAREN\r
+ }\r
+ )\r
+\r
+ ( <FIELD_REFERENCE> | <PERIOD> )\r
+ methodNode = methodName(receiver) methodCallParameterList(parameterList)\r
+\r
+ {\r
+\r
+ /*\r
+ ** ? parameters are not allowed for the receiver --\r
+ ** unless the receiver is standing in for a named parameter,\r
+ ** whose type is therefore known.\r
+ */\r
+ if (receiver instanceof ParameterNode)\r
+ {\r
+ throw StandardException.newException(SQLState.LANG_PARAMETER_RECEIVER,\r
+ methodNode.getMethodName());\r
+ }\r
+\r
+ methodNode.addParms(parameterList);\r
+\r
+ /*\r
+ ** Assume this is being returned to the SQL domain. If it turns\r
+ ** out that this is being returned to the Java domain, we will\r
+ ** get rid of this node.\r
+ */\r
+ return (ValueNode) nodeFactory.getNode(\r
+ C_NodeTypes.JAVA_TO_SQL_VALUE_NODE,\r
+ methodNode,\r
+ getContextManager());\r
+ }\r
+|\r
+ <PERIOD> methodNode = methodName(receiver)\r
+ {\r
+ /*\r
+ ** ? parameters are not allowed for the receiver --\r
+ ** unless the receiver is standing in for a named parameter,\r
+ ** whose type is therefore known.\r
+ */\r
+ if (receiver instanceof ParameterNode)\r
+ {\r
+ throw StandardException.newException(SQLState.LANG_PARAMETER_RECEIVER,\r
+ methodNode.getMethodName());\r
+ }\r
+\r
+ methodNode.addParms(parameterList);\r
+\r
+ /*\r
+ ** Assume this is being returned to the SQL domain. If it turns\r
+ ** out that this is being returned to the Java domain, we will\r
+ ** get rid of this node.\r
+ */\r
+ return (ValueNode) nodeFactory.getNode(\r
+ C_NodeTypes.JAVA_TO_SQL_VALUE_NODE,\r
+ methodNode,\r
+ getContextManager());\r
+ }\r
+\r
+\r
+}\r
+\r
+/*\r
+ * <A NAME="methodName">methodName</A>\r
+ */\r
+MethodCallNode\r
+methodName(ValueNode receiver) throws StandardException :\r
+{\r
+ String methodName;\r
+}\r
+{\r
+ /*\r
+ ** NOTE: allowing a delimited identifier as a method name is necessary,\r
+ ** because Java is case-sensitive. But this also allows identifiers that\r
+ ** do not match Java syntax. This will probably not cause a problem\r
+ ** in later phases, like binding and code generation.\r
+ */\r
+ methodName = caseSensitiveIdentifierPlusReservedWords()\r
+ {\r
+ return (MethodCallNode) nodeFactory.getNode(\r
+ C_NodeTypes.NON_STATIC_METHOD_CALL_NODE,\r
+ methodName,\r
+ receiver,\r
+ getContextManager());\r
+ }\r
+}\r
+\r
+/*\r
+ * <A NAME="staticMethodName">staticMethodName</A>\r
+ */\r
+MethodCallNode\r
+staticMethodName(String javaClassName) throws StandardException :\r
+{\r
+ String methodName;\r
+}\r
+{\r
+ /*\r
+ ** NOTE: allowing a delimited identifier as a method name is necessary,\r
+ ** because Java is case-sensitive. But this also allows identifiers that\r
+ ** do not match Java syntax. This will probably not cause a problem\r
+ ** in later phases, like binding and code generation.\r
+ */\r
+ methodName = caseSensitiveIdentifierPlusReservedWords()\r
+ {\r
+ return (MethodCallNode) nodeFactory.getNode(\r
+ C_NodeTypes.STATIC_METHOD_CALL_NODE,\r
+ methodName,\r
+ javaClassName,\r
+ getContextManager());\r
+ }\r
+}\r
+\r
+/*\r
+ * <A NAME="methodParameter">methodParameter</A>\r
+ */\r
+void\r
+methodParameter(Vector parameterList) throws StandardException :\r
+{\r
+ ValueNode parameter;\r
+}\r
+{\r
+ parameter = additiveExpression(null,0, false)\r
+ {\r
+ parameterList.addElement(parameter);\r
+ }\r
+|\r
+ parameter = nullSpecification()\r
+ {\r
+ parameterList.addElement(parameter);\r
+ }\r
+}\r
+\r
+\r
+/*\r
+ * <A NAME="primary">primary</A>\r
+ * \r
+ * @param inSelectClause will be true if this method got called while parsing the select or values clause\r
+ * If in select or values clause, we do not want to allow boolean values.\r
+ */\r
+ValueNode\r
+primary(boolean inSelectClause) throws StandardException :\r
+{\r
+ String javaClassName;\r
+ ValueNode value;\r
+}\r
+{\r
+ \r
+ //Look ahead required here to tell a java class from a identifier\r
+ LOOKAHEAD( { javaClassFollows() } )\r
+ value = staticClassReference()\r
+ {\r
+ return value;\r
+ }\r
+|\r
+ value = valueExpressionPrimary(inSelectClause)\r
+ {\r
+ return value;\r
+ }\r
+}\r
+\r
+/*\r
+ * <A NAME="staticClassReference">staticClassReference</A>\r
+ */\r
+ValueNode\r
+staticClassReference() throws StandardException :\r
+{\r
+ String javaClassName;\r
+ ValueNode value;\r
+}\r
+{\r
+ javaClassName = javaClass() <DOUBLE_COLON> value = staticClassReferenceType(javaClassName)\r
+ {\r
+ return value;\r
+ }\r
+}\r
+\r
+/*\r
+ * <A NAME="staticClassReferenceType">staticClassReferenceType</A>\r
+ */\r
+ValueNode\r
+staticClassReferenceType(String javaClassName) throws StandardException :\r
+{\r
+ ValueNode value;\r
+}\r
+{\r
+ //Look ahead required here to tell method from field reference\r
+ LOOKAHEAD({(getToken(2).kind == LEFT_PAREN)})\r
+ value = staticMethodInvocation(javaClassName) \r
+ {\r
+ return value;\r
+ }\r
+|\r
+ value = staticClassFieldReference(javaClassName) \r
+ {\r
+ return value;\r
+ }\r
+}\r
+\r
+/*\r
+ * <A NAME="staticClassFieldReference">staticClassFieldReference</A>\r
+ */\r
+ValueNode\r
+staticClassFieldReference(String javaClassName) throws StandardException :\r
+{\r
+ String fieldName = null;\r
+}\r
+{\r
+ fieldName = caseSensitiveIdentifierPlusReservedWords() \r
+ {\r
+ return (ValueNode) nodeFactory.getNode(\r
+ C_NodeTypes.JAVA_TO_SQL_VALUE_NODE,\r
+ nodeFactory.getNode(\r
+ C_NodeTypes.STATIC_CLASS_FIELD_REFERENCE_NODE,\r
+ javaClassName,\r
+ fieldName,\r
+ nextToLastTokenDelimitedIdentifier,\r
+ getContextManager()),\r
+ getContextManager());\r
+ }\r
+}\r
+\r
+/*\r
+ * <A NAME="nonSecondDatetimeField">nonSecondDatetimeField</A>\r
+ */\r
+int\r
+nonSecondDatetimeField() :\r
+{}\r
+{\r
+ <YEAR> \r
+ {\r
+ return DateTimeDataValue.YEAR_FIELD;\r
+ }\r
+|\r
+ <MONTH> \r
+ {\r
+ return DateTimeDataValue.MONTH_FIELD;\r
+ }\r
+|\r
+ <DAY> \r
+ {\r
+ return DateTimeDataValue.DAY_FIELD;\r
+ }\r
+|\r
+ <HOUR> \r
+ {\r
+ return DateTimeDataValue.HOUR_FIELD;\r
+ }\r
+|\r
+ <MINUTE>\r
+ {\r
+ return DateTimeDataValue.MINUTE_FIELD;\r
+ }\r
+}\r
+\r
+\r
+ValueNode\r
+escapedValueFunction() throws StandardException :\r
+{\r
+ ValueNode value;\r
+ ValueNode str1;\r
+ ValueNode str2;\r
+ ValueNode startPosition;\r
+ ValueNode length = null;\r
+}\r
+{\r
+ value = miscBuiltinsCore( true /* is JDBC escape */)\r
+ {\r
+ return value;\r
+ }\r
+|\r
+ /* Escaped function substring() */\r
+ <SUBSTRING> <LEFT_PAREN> value = additiveExpression(null, 0, false) <COMMA> startPosition = additiveExpression(null, 0, false) [ <COMMA> length = additiveExpression(null, 0, false) ] <RIGHT_PAREN>\r
+ {\r
+ return getSubstringNode(value, startPosition, length, Boolean.FALSE);\r
+ }\r
+|\r
+ /* CURDATE() is an escaped function supported by JCC 2.2 or higher */\r
+ <CURDATE> <LEFT_PAREN> <RIGHT_PAREN>\r
+ {\r
+ return (ValueNode) nodeFactory.getNode(\r
+ C_NodeTypes.CURRENT_DATETIME_OPERATOR_NODE,\r
+ ReuseFactory.getInteger(\r
+ CurrentDatetimeOperatorNode.CURRENT_DATE),\r
+ getContextManager());\r
+ }\r
+|\r
+ /* CURTIME() is an escaped function supported by JCC 2.2 or higher */\r
+ <CURTIME> <LEFT_PAREN> <RIGHT_PAREN>\r
+ {\r
+ return (ValueNode) nodeFactory.getNode(\r
+ C_NodeTypes.CURRENT_DATETIME_OPERATOR_NODE,\r
+ ReuseFactory.getInteger(\r
+ CurrentDatetimeOperatorNode.CURRENT_TIME),\r
+ getContextManager());\r
+ }\r
+|\r
+ /* CONCAT( string1, string2 )\r
+ * CONCAT is not a reserved word.\r
+ */\r
+ <CONCAT> <LEFT_PAREN> str1 = additiveExpression(null,0, false) <COMMA> \r
+ str2 = additiveExpression(null,0, false) <RIGHT_PAREN>\r
+ {\r
+ return (ValueNode) nodeFactory.getNode(\r
+ C_NodeTypes.CONCATENATION_OPERATOR_NODE,\r
+ str1,\r
+ str2,\r
+ getContextManager());\r
+ }\r
+|\r
+ /* Method versions of USER special registers\r
+ * are ODBC remnants. Only supported\r
+ * when escaped.\r
+ */\r
+ value = userNode() <LEFT_PAREN> <RIGHT_PAREN>\r
+ {\r
+ return value;\r
+ }\r
+|\r
+ value = timestampArithmeticFuncion()\r
+ {\r
+ return value;\r
+ }\r
+ \r
+| \r
+ LOOKAHEAD({ getEscapedSYSFUN(getToken(1).image) != null }) \r
+ value = escapedSYSFUNFunction()\r
+ {\r
+ return value;\r
+ }\r
+\r
+ \r
+}\r
+\r
+/*\r
+ * <A NAME="numericValueFunction">numericValueFunction</A>\r
+ */\r
+ValueNode\r
+escapedSYSFUNFunction() throws StandardException :\r
+{\r
+ Vector parameterList = new Vector();\r
+ Token tok;\r
+}\r
+{\r
+ tok = <IDENTIFIER> methodCallParameterList(parameterList)\r
+ {\r
+ String sysFunName = getEscapedSYSFUN(tok.image);\r
+ \r
+ TableName functionName = (TableName) nodeFactory.getNode(\r
+ C_NodeTypes.TABLE_NAME,\r
+ SchemaDescriptor.IBM_SYSTEM_FUN_SCHEMA_NAME,\r
+ sysFunName,\r
+ new Integer(0),\r
+ new Integer(0),\r
+ getContextManager());\r
+ \r
+ MethodCallNode methodNode = (MethodCallNode) nodeFactory.getNode(\r
+ C_NodeTypes.STATIC_METHOD_CALL_NODE,\r
+ functionName,\r
+ null,\r
+ getContextManager());\r
+\r
+ methodNode.addParms(parameterList);\r
+\r
+ /*\r
+ ** Assume this is being returned to the SQL domain. If it turns\r
+ ** out that this is being returned to the Java domain, we will\r
+ ** get rid of this node.\r
+ */\r
+ return (ValueNode) nodeFactory.getNode(\r
+ C_NodeTypes.JAVA_TO_SQL_VALUE_NODE,\r
+ methodNode,\r
+ getContextManager());\r
+ }\r
+}\r
+\r
+\r
+/*\r
+ * <A NAME="timestampArithmeticFuncion">timestampArithmeticFuncion</A>\r
+ */\r
+ValueNode\r
+timestampArithmeticFuncion() throws StandardException :\r
+{\r
+ ValueNode intervalType;\r
+ ValueNode tstamp1;\r
+ ValueNode tstamp2;\r
+ ValueNode count;\r
+}\r
+{\r
+ <TIMESTAMPADD> <LEFT_PAREN> intervalType = jdbcIntervalType() <COMMA>\r
+ count = additiveExpression(null,0,false) <COMMA>\r
+ tstamp1 = additiveExpression(null,0,false) <RIGHT_PAREN>\r
+ {\r
+ return (ValueNode) nodeFactory.getNode( C_NodeTypes.TIMESTAMP_ADD_FN_NODE,\r
+ tstamp1,\r
+ intervalType,\r
+ count,\r
+ ReuseFactory.getInteger( TernaryOperatorNode.TIMESTAMPADD),\r
+ null,\r
+ getContextManager());\r
+ }\r
+|\r
+ <TIMESTAMPDIFF> <LEFT_PAREN> intervalType = jdbcIntervalType() <COMMA>\r
+ tstamp1 = additiveExpression(null,0,false) <COMMA>\r
+ tstamp2 = additiveExpression(null,0,false) <RIGHT_PAREN>\r
+ {\r
+ return (ValueNode) nodeFactory.getNode( C_NodeTypes.TIMESTAMP_DIFF_FN_NODE,\r
+ tstamp2,\r
+ intervalType,\r
+ tstamp1,\r
+ ReuseFactory.getInteger( TernaryOperatorNode.TIMESTAMPDIFF),\r
+ null,\r
+ getContextManager());\r
+ }\r
+} \r
+\r
+/*\r
+ * <A NAME="jdbcIntervalType">jdbcIntervalType</A>\r
+ */\r
+ValueNode jdbcIntervalType() throws StandardException :\r
+{\r
+}\r
+{\r
+ <SQL_TSI_FRAC_SECOND>\r
+ {\r
+ return getJdbcIntervalNode( DateTimeDataValue.FRAC_SECOND_INTERVAL);\r
+ }\r
+|\r
+ <SQL_TSI_SECOND>\r
+ {\r
+ return getJdbcIntervalNode( DateTimeDataValue.SECOND_INTERVAL);\r
+ }\r
+|\r
+ <SQL_TSI_MINUTE>\r
+ {\r
+ return getJdbcIntervalNode( DateTimeDataValue.MINUTE_INTERVAL);\r
+ }\r
+|\r
+ <SQL_TSI_HOUR>\r
+ {\r
+ return getJdbcIntervalNode( DateTimeDataValue.HOUR_INTERVAL);\r
+ }\r
+|\r
+ <SQL_TSI_DAY>\r
+ {\r
+ return getJdbcIntervalNode( DateTimeDataValue.DAY_INTERVAL);\r
+ }\r
+|\r
+ <SQL_TSI_WEEK>\r
+ {\r
+ return getJdbcIntervalNode( DateTimeDataValue.WEEK_INTERVAL);\r
+ }\r
+|\r
+ <SQL_TSI_MONTH>\r
+ {\r
+ return getJdbcIntervalNode( DateTimeDataValue.MONTH_INTERVAL);\r
+ }\r
+|\r
+ <SQL_TSI_QUARTER>\r
+ {\r
+ return getJdbcIntervalNode( DateTimeDataValue.QUARTER_INTERVAL);\r
+ }\r
+|\r
+ <SQL_TSI_YEAR>\r
+ {\r
+ return getJdbcIntervalNode( DateTimeDataValue.YEAR_INTERVAL);\r
+ }\r
+}\r
+\r
+/*\r
+ * <A NAME="numericValueFunction">numericValueFunction</A>\r
+ */\r
+ValueNode\r
+numericValueFunction() throws StandardException :\r
+{\r
+ ValueNode value;\r
+ int field;\r
+}\r
+{\r
+ /*\r
+ * NOTE: If you add a new rule here, you must add the appropriate\r
+ * LOOKAHEAD rule to miscBuiltins().\r
+ */\r
+\r
+ <ABS> value = absFunction()\r
+ {\r
+ return value;\r
+ }\r
+|\r
+ <ABSVAL> value = absFunction()\r
+ {\r
+ return value;\r
+ }\r
+|\r
+ <SQRT> <LEFT_PAREN> value = additiveExpression(null,0,false) <RIGHT_PAREN>\r
+ {\r
+ return (ValueNode)nodeFactory.getNode(\r
+ C_NodeTypes.SQRT_OPERATOR_NODE,\r
+ value,\r
+ getContextManager());\r
+ }\r
+|\r
+ /* MOD(int, int)\r
+ */\r
+ <MOD> value = modFunction()\r
+ {\r
+ return value;\r
+ }\r
+|\r
+ <IDENTITY_VAL_LOCAL> <LEFT_PAREN> <RIGHT_PAREN>\r
+ {\r
+ return (ValueNode) nodeFactory.getNode(\r
+ C_NodeTypes.IDENTITY_VAL_NODE,\r
+ getContextManager());\r
+ }\r
+}\r
+\r
+/*\r
+ * <A NAME="coalesceFunction">coalesceFunction</A>\r
+ */\r
+ValueNode\r
+coalesceFunction(String coalesceOrValue) throws StandardException :\r
+{\r
+ ValueNodeList expressionList = (ValueNodeList) nodeFactory.getNode(\r
+ C_NodeTypes.VALUE_NODE_LIST,\r
+ getContextManager());\r
+}\r
+{\r
+ <LEFT_PAREN>\r
+ coalesceExpression(expressionList)\r
+ ( <COMMA> coalesceExpression(expressionList) )* \r
+ <RIGHT_PAREN>\r
+ {\r
+ return (ValueNode)nodeFactory.getNode(\r
+ C_NodeTypes.COALESCE_FUNCTION_NODE,\r
+ coalesceOrValue,\r
+ expressionList,\r
+ getContextManager());\r
+ }\r
+}\r
+\r
+/*\r
+ * <A NAME="coalesceExpression">coalesceExpression</A>\r
+ */\r
+void\r
+coalesceExpression(ValueNodeList expressionList) throws StandardException :\r
+{\r
+ ValueNode expression;\r
+}\r
+{\r
+ expression = additiveExpression(null,0,false)\r
+ {\r
+ expressionList.addElement(expression);\r
+ }\r
+}\r
+\r
+/*\r
+ * <A NAME="absFunction">absFunction</A>\r
+ */\r
+ValueNode\r
+absFunction() throws StandardException :\r
+{\r
+ ValueNode value;\r
+}\r
+{\r
+ <LEFT_PAREN> value = additiveExpression(null,0, false) <RIGHT_PAREN>\r
+ {\r
+ return (ValueNode)nodeFactory.getNode(\r
+ C_NodeTypes.ABSOLUTE_OPERATOR_NODE,\r
+ value,\r
+ getContextManager());\r
+ }\r
+}\r
+/*\r
+ * <A NAME="modFunction">modFunction</A>\r
+ */\r
+ValueNode\r
+modFunction() throws StandardException :\r
+{\r
+ ValueNode int1;\r
+ ValueNode int2;\r
+}\r
+{\r
+ <LEFT_PAREN> int1 = additiveExpression(null,0,false) <COMMA> \r
+ int2 = additiveExpression(null,0,false) <RIGHT_PAREN>\r
+ {\r
+ return (ValueNode)nodeFactory.getNode(\r
+ C_NodeTypes.MOD_OPERATOR_NODE,\r
+ int1, int2,\r
+ getContextManager());\r
+ }\r
+}\r
+\r
+/*\r
+ * <A NAME="datetimeField">datetimeField</A>\r
+ */\r
+int\r
+datetimeField() :\r
+{\r
+ int field;\r
+}\r
+{\r
+ field = nonSecondDatetimeField() \r
+ {\r
+ return field;\r
+ }\r
+|\r
+ <SECOND>\r
+ {\r
+ return DateTimeDataValue.SECOND_FIELD;\r
+ }\r
+}\r
+\r
+\r
+ValueNode\r
+characterValueFunction() throws StandardException :\r
+{\r
+ ValueNode value = null;\r
+ ValueNode str1;\r
+ ValueNode str2;\r
+ Token upperTok = null;\r
+ Token lowerTok = null;\r
+ ValueNode startPosition;\r
+ ValueNode length = null;\r
+}\r
+{\r
+ <SUBSTR> <LEFT_PAREN> value = additiveExpression(null,0,false) <COMMA> startPosition = additiveExpression(null,0,false) [ <COMMA> length = additiveExpression(null,0,false) ] <RIGHT_PAREN>\r
+ {\r
+ return getSubstringNode( value, startPosition, length, Boolean.FALSE );\r
+ }\r
+|\r
+ ( upperTok = <UPPER> | lowerTok = <LOWER> ) <LEFT_PAREN> value = additiveExpression(null,0,false) <RIGHT_PAREN>\r
+ {\r
+ return (ValueNode) nodeFactory.getNode(\r
+ C_NodeTypes.SIMPLE_STRING_OPERATOR_NODE,\r
+ value,\r
+ (upperTok != null) ? "upper" : "lower",\r
+ getContextManager());\r
+ }\r
+|\r
+ ( upperTok = <UCASE> | lowerTok = <LCASE> ) <LEFT_PAREN> value = additiveExpression(null,0,false) <RIGHT_PAREN>\r
+ {\r
+ return (ValueNode) nodeFactory.getNode(\r
+ C_NodeTypes.SIMPLE_STRING_OPERATOR_NODE,\r
+ value,\r
+ (upperTok != null) ? "upper" : "lower",\r
+ getContextManager());\r
+ }\r
+|\r
+ value = trimFunction()\r
+ {\r
+ return value;\r
+ }\r
+|\r
+ /* LOCATE( string1, string2[, start] )\r
+ * LOCATE is a SQLJ reserved word.\r
+ */\r
+ <LOCATE> <LEFT_PAREN> str1 = additiveExpression(null,0,false) <COMMA>\r
+ str2 = additiveExpression(null,0,false)\r
+ [ <COMMA> value = additiveExpression(null,0,false) ]\r
+ <RIGHT_PAREN>\r
+ {\r
+ // if start is missing, start is equal to 1\r
+ return (ValueNode) nodeFactory.getNode(\r
+ C_NodeTypes.LOCATE_FUNCTION_NODE,\r
+ str1,\r
+ str2,\r
+ (value == null) ? getNodeFactory().getNode(\r
+ C_NodeTypes.INT_CONSTANT_NODE, \r
+ ReuseFactory.getInteger(1), \r
+ getContextManager() )\r
+ : value,\r
+ ReuseFactory.getInteger(TernaryOperatorNode.LOCATE),\r
+ null,\r
+ getContextManager());\r
+ }\r
+}\r
+\r
+\r
+ValueNode\r
+trimFunction() throws StandardException :\r
+{\r
+ ValueNode source;\r
+ Integer trimType;\r
+ ValueNode ansiTrimNode;\r
+}\r
+{\r
+ trimType = trimType() <LEFT_PAREN> source = additiveExpression(null,0,false) <RIGHT_PAREN>\r
+ {\r
+ return getTrimOperatorNode(trimType, null, source, null);\r
+ }\r
+|\r
+ <TRIM> ansiTrimNode = ansiTrim()\r
+ {\r
+ return ansiTrimNode;\r
+ }\r
+\r
+}\r
+\r
+\r
+ValueNode\r
+ansiTrim() throws StandardException :\r
+{\r
+ Integer trimSpec = ReuseFactory.getInteger(StringDataValue.BOTH);\r
+ ValueNode trimChar = null;\r
+ ValueNode trimSource = null;\r
+}\r
+{\r
+ LOOKAHEAD ({ansiTrimSpecFollows()})\r
+ <LEFT_PAREN> trimSpec = ansiTrimSpec()\r
+ (\r
+ // LEADING FROM <source>\r
+ LOOKAHEAD(<FROM>)\r
+ <FROM> trimSource = additiveExpression(null,0,false) <RIGHT_PAREN>\r
+ {\r
+ return getTrimOperatorNode(trimSpec, trimChar, trimSource, null);\r
+ }\r
+ |\r
+ // LEADING <char> FROM <source>\r
+ trimChar = additiveExpression(null,0,false) <FROM> trimSource = additiveExpression(null,0,false) <RIGHT_PAREN>\r
+ {\r
+ return getTrimOperatorNode(trimSpec, trimChar, trimSource, null);\r
+ }\r
+ )\r
+|\r
+ LOOKAHEAD ({!ansiTrimSpecFollows()})\r
+ <LEFT_PAREN> trimChar = additiveExpression(null,0,false)\r
+ (\r
+ <FROM> trimSource = additiveExpression(null,0,false) <RIGHT_PAREN>\r
+ {\r
+ return getTrimOperatorNode(trimSpec, trimChar, trimSource, null);\r
+ }\r
+ |\r
+ <RIGHT_PAREN>\r
+ {\r
+ // expr was trim(e)-- we assigned e to trimChar but it is really the trimSource\r
+ return getTrimOperatorNode(trimSpec, null, trimChar, null);\r
+ }\r
+ )\r
+}\r
+\r
+Integer\r
+ansiTrimSpec() :\r
+{\r
+}\r
+{\r
+ <TRAILING>\r
+ {\r
+ return ReuseFactory.getInteger(StringDataValue.TRAILING);\r
+ }\r
+|\r
+ <LEADING>\r
+ {\r
+ return ReuseFactory.getInteger(StringDataValue.LEADING);\r
+ }\r
+|\r
+ <BOTH>\r
+ {\r
+ return ReuseFactory.getInteger(StringDataValue.BOTH);\r
+ }\r
+}\r
+\r
+\r
+Integer\r
+trimType() :\r
+{\r
+}\r
+{\r
+ <RTRIM>\r
+ {\r
+ return ReuseFactory.getInteger(StringDataValue.TRAILING);\r
+ }\r
+|\r
+ <LTRIM>\r
+ {\r
+ return ReuseFactory.getInteger(StringDataValue.LEADING);\r
+ }\r
+}\r
+\r
+/*\r
+ * <A NAME="valueExpressionPrimary">valueExpressionPrimary</A>\r
+ * \r
+ * @param inSelectClause will be true if this method got called while parsing the select or values clause\r
+ * If in select or values clause, we do not want to allow boolean values.\r
+ */\r
+ValueNode\r
+valueExpressionPrimary(boolean inSelectClause) throws StandardException :\r
+{\r
+ ValueNode value;\r
+ int tokKind;\r
+}\r
+{\r
+ /* This LOOKAHEAD is required to distinguish \r
+ * a escapedValueFunction() from other escaped \r
+ * clauses. The former always has an FN as its \r
+ * second token.\r
+ */\r
+ LOOKAHEAD( { escapedValueFunctionFollows() } )\r
+ <LEFT_BRACE> <FN> value = escapedValueFunction() <RIGHT_BRACE>\r
+ {\r
+ return value;\r
+ }\r
+|\r
+ LOOKAHEAD({getToken(2).kind == SCHEMA || getToken(2).kind == SQLID}) \r
+ <CURRENT> (<SCHEMA> | <SQLID>)\r
+ {\r
+ return (ValueNode) nodeFactory.getNode(\r
+ C_NodeTypes.CURRENT_SCHEMA_NODE,\r
+ getContextManager());\r
+ }\r
+|\r
+ LOOKAHEAD({getToken(2).kind == ISOLATION}) \r
+ <CURRENT> <ISOLATION>\r
+ {\r
+ return (ValueNode) nodeFactory.getNode(\r
+ C_NodeTypes.CURRENT_ISOLATION_NODE,\r
+ getContextManager());\r
+ }\r
+|\r
+ /* Omitted "case_expression" */\r
+ value = valueSpecification()\r
+ {\r
+ return value;\r
+ }\r
+|\r
+ // This LOOKAHEAD is required to distinguish a newInvocation() from\r
+ // an aggregateNode() and a columnReference(). It is necessary because\r
+ // NEW is not a reserved word.\r
+ LOOKAHEAD( { newInvocationFollows(1) } )\r
+ value = newInvocation()\r
+ {\r
+ return value;\r
+ }\r
+|\r
+ // This LOOKAHEAD is required to distinguish an aggregateNode from\r
+ // miscBuiltins(). Both can start with an identifier.\r
+ LOOKAHEAD( { aggregateFollows() } )\r
+ value = aggregateNode()\r
+ {\r
+ return value;\r
+ }\r
+|\r
+ // This LOOKAHEAD is required because both miscBuiltins() and\r
+ // columnReference can start with an identifier()\r
+ LOOKAHEAD( { miscBuiltinFollows() } )\r
+ value = miscBuiltins()\r
+ {\r
+ return value;\r
+ }\r
+|\r
+ value = columnReference()\r
+ {\r
+ return value;\r
+ }\r
+|\r
+ <LEFT_PAREN>\r
+ (\r
+ // This LOOKAHEAD is required because a subquery can have\r
+ // queryExpressions nested arbitrarily deep inside of parentheses,\r
+ // so both subquery() and valueExpression() can start with\r
+ // LEFT_PAREN. We disambiguate this case by only considering it\r
+ // to be a subquery if it starts with SELECT or VALUES, which\r
+ // are the first tokens to come after the LEFT_PAREN in a subquery.\r
+ LOOKAHEAD( {getToken(1).kind == SELECT || getToken(1).kind == VALUES} )\r
+ value = subquery(SubqueryNode.EXPRESSION_SUBQUERY, null)\r
+ |\r
+ /*\r
+ ** NOTE: The optional intervalQualfier() here makes sense only for\r
+ ** the MINUS operator. We will have to add a semantic check that the\r
+ ** valueExpression() here is a MINUS operator if the intervalQualifier\r
+ ** is supplied.\r
+ */\r
+ // without the following check, select/values (c1>c2) will not be caught\r
+ LOOKAHEAD({inSelectClause})\r
+ value = additiveExpression(null,0, inSelectClause)\r
+ | //following will happen if we are not coming here for select/values clause\r
+ value = valueExpression(inSelectClause)\r
+ )\r
+ <RIGHT_PAREN>\r
+ {\r
+ return value;\r
+ }\r
+|\r
+ value = castSpecification()\r
+ {\r
+ return value;\r
+ }\r
+}\r
+\r
+/*\r
+ * <A NAME="miscBuiltins">miscBuiltins</A>\r
+ */\r
+ValueNode\r
+miscBuiltins() throws StandardException :\r
+{\r
+ ValueNode value;\r
+}\r
+{\r
+ /*\r
+ * If you add rule to miscBuiltinsCore(), you must add the appropriate \r
+ * LOOKAHEAD rule here.\r
+ * SQRT and LOCATE are non-reserved keywords, so we need to disambiguate\r
+ * the grammar: "SQRT(" and "LOCATE(" introduce the SQRT and LOCATE\r
+ * built-in functions, not a static method invocation alias.\r
+ */\r
+ LOOKAHEAD( {\r
+ ( (getToken(1).kind == GET_CURRENT_CONNECTION ||\r
+ getToken(1).kind == ABS ||\r
+ getToken(1).kind == ABSVAL ||\r
+ getToken(1).kind == SQRT ||\r
+ getToken(1).kind == MOD ||\r
+ getToken(1).kind == COALESCE ||\r
+ getToken(1).kind == VALUE ||\r
+ getToken(1).kind == IDENTITY_VAL_LOCAL ||\r
+ getToken(1).kind == SUBSTRING ||\r
+ getToken(1).kind == SUBSTR ||\r
+ getToken(1).kind == UPPER ||\r
+ getToken(1).kind == LOWER ||\r
+ getToken(1).kind == UCASE ||\r
+ getToken(1).kind == LCASE ||\r
+ getToken(1).kind == LTRIM ||\r
+ getToken(1).kind == RTRIM ||\r
+ getToken(1).kind == TRIM ||\r
+ getToken(1).kind == DATE ||\r
+ getToken(1).kind == TIME ||\r
+ getToken(1).kind == TIMESTAMP ||\r
+ getToken(1).kind == DOUBLE ||\r
+ getToken(1).kind == CHAR ||\r
+ getToken(1).kind == VARCHAR ||\r
+ getToken(1).kind == INTEGER ||\r
+ getToken(1).kind == INT || \r
+ getToken(1).kind == SMALLINT ||\r
+ getToken(1).kind == LONGINT ||\r
+ getToken(1).kind == YEAR ||\r
+ getToken(1).kind == MONTH ||\r
+ getToken(1).kind == DAY ||\r
+ getToken(1).kind == HOUR ||\r
+ getToken(1).kind == MINUTE ||\r
+ getToken(1).kind == SECOND ||\r
+ getToken(1).kind == LENGTH ||\r
+ getToken(1).kind == LOCATE ||\r
+ getToken(1).kind == XMLPARSE ||\r
+ getToken(1).kind == XMLSERIALIZE ||\r
+ getToken(1).kind == XMLEXISTS ||\r
+ getToken(1).kind == XMLQUERY ) &&\r
+ getToken(2).kind == LEFT_PAREN\r
+ )\r
+ } )\r
+ /* miscBuiltins() are composed of the core\r
+ * system, string and numeric functions,\r
+ * date functions\r
+ * and static method calls.\r
+ */\r
+ value = miscBuiltinsCore( false /* not JDBC escape */)\r
+ {\r
+ return value;\r
+ }\r
+|\r
+ value = datetimeValueFunction()\r
+ {\r
+ return value;\r
+ }\r
+| \r
+ /* This is where we build a node for static method aliases */\r
+ value = routineInvocation()\r
+ {\r
+ return value;\r
+ }\r
+}\r
+\r
+ValueNode\r
+miscBuiltinsCore( boolean isJDBCEscape) throws StandardException :\r
+{\r
+ ValueNode value;\r
+}\r
+{\r
+ /* miscBuiltinsCore() are the core\r
+ * system, string and numeric functions.\r
+ * NOTE: date functions not currently considered\r
+ * core for purposes of the grammar since\r
+ * they can only be escaped when they appear\r
+ * as functions (not special registers).\r
+ *\r
+ * NOTE: If you add a new rule here, you must add the appropriate\r
+ * LOOKAHEAD rule to miscBuiltins().\r
+ */\r
+\r
+ <GET_CURRENT_CONNECTION> <LEFT_PAREN> <RIGHT_PAREN>\r
+ {\r
+ checkInternalFeature("GETCURRENTCONNECTION()");\r
+ return (ValueNode) nodeFactory.getNode(\r
+ C_NodeTypes.JAVA_TO_SQL_VALUE_NODE,\r
+ nodeFactory.getNode(\r
+ C_NodeTypes.GET_CURRENT_CONNECTION_NODE,\r
+ getContextManager()),\r
+ getContextManager());\r
+ }\r
+|\r
+ value = numericValueFunction() \r
+ {\r
+ return value;\r
+ }\r
+|\r
+ value = characterValueFunction()\r
+ {\r
+ return value;\r
+ }\r
+|\r
+ value = dataTypeScalarFunction()\r
+ {\r
+ return value;\r
+ }\r
+|\r
+ <COALESCE> value = coalesceFunction("COALESCE")\r
+ {\r
+ return value;\r
+ }\r
+|\r
+ <VALUE> value = coalesceFunction("VALUE")\r
+ {\r
+ return value;\r
+ }\r
+|\r
+ <LENGTH> <LEFT_PAREN> value = additiveExpression(null,0, false) <RIGHT_PAREN>\r
+ {\r
+ ContextManager localCM = getContextManager();\r
+ if( isJDBCEscape)\r
+ return (ValueNode) nodeFactory.getNode(\r
+ C_NodeTypes.CHAR_LENGTH_OPERATOR_NODE,\r
+ getTrimOperatorNode(\r
+ ReuseFactory.getInteger(StringDataValue.TRAILING),\r
+ null,\r
+ value,\r
+ localCM),\r
+ localCM);\r
+ return (ValueNode) nodeFactory.getNode(\r
+ C_NodeTypes.DB2_LENGTH_OPERATOR_NODE,\r
+ value,\r
+ localCM);\r
+ }\r
+|\r
+ value = xmlFunction()\r
+ {\r
+ return value;\r
+ }\r
+}\r
+\r
+\r
+/*\r
+ * <A NAME="dataTypeScalarFunction">dataTypeScalarFunction</A>\r
+ */\r
+ValueNode\r
+ dataTypeScalarFunction() throws StandardException :\r
+{\r
+ DataTypeDescriptor dts;\r
+ ValueNode value; //converted result\r
+ ValueNode operand;\r
+ int charType;\r
+ int length = -1;\r
+}\r
+{\r
+ //Note: When you add a new data type function, in addition to adding it \r
+ // here, you need to add it to miscBuiltins()\r
+ value = dateTimeScalarFunction()\r
+ {\r
+ return value;\r
+ }\r
+ |\r
+ dts = numericFunctionType() <LEFT_PAREN> operand = additiveExpression(null,0, false) <RIGHT_PAREN>\r
+ {\r
+ value = (ValueNode) nodeFactory.getNode(\r
+ C_NodeTypes.CAST_NODE,\r
+ operand,\r
+ dts,\r
+ getContextManager());\r
+ ((CastNode) value).setForDataTypeFunction(true);\r
+ ((CastNode) value).setForExternallyGeneratedCASTnode();\r
+\r
+ return value;\r
+ }\r
+ | charType = charOrVarchar() <LEFT_PAREN> operand = additiveExpression(null,0, false) [ <COMMA> length = length() ] <RIGHT_PAREN>\r
+ {\r
+ // Always check db2 limits for this function. It's new\r
+ checkTypeLimits(charType,length);\r
+ value = (ValueNode) nodeFactory.getNode(\r
+ C_NodeTypes.CAST_NODE,\r
+ operand,\r
+ new Integer(charType),\r
+ new Integer(length),\r
+ getContextManager());\r
+\r
+ ((CastNode) value).setForDataTypeFunction(true);\r
+ ((CastNode) value).setForExternallyGeneratedCASTnode();\r
+ return value;\r
+ }\r
+}\r
+ \r
+/*\r
+ * <A NAME="xmlFunction">xmlFunction</A>\r
+ *\r
+ * This method parses the built-in functions used with\r
+ * the XML datatype.\r
+ *\r
+ */\r
+ValueNode\r
+ xmlFunction() throws StandardException :\r
+{\r
+ ValueNode value;\r
+ checkVersion(DataDictionary.DD_VERSION_DERBY_10_1, "XML");\r
+\r
+ // We only allow XML operations if the classpath has all\r
+ // of the required external classes (namley, JAXP and Xalan).\r
+ org.apache.derby.iapi.types.XML.checkXMLRequirements();\r
+}\r
+{\r
+ <XMLPARSE> <LEFT_PAREN>\r
+ xmlDocOrContent() value = xmlParseValue() <RIGHT_PAREN>\r
+ {\r
+ return value;\r
+ }\r
+|\r
+ <XMLSERIALIZE> <LEFT_PAREN> value = xmlSerializeValue() <RIGHT_PAREN>\r
+ {\r
+ return value;\r
+ }\r
+|\r
+ <XMLEXISTS> <LEFT_PAREN> value = xmlQueryValue(true) <RIGHT_PAREN>\r
+ {\r
+ return value;\r
+ }\r
+|\r
+ <XMLQUERY> <LEFT_PAREN> value = xmlQueryValue(false) <RIGHT_PAREN>\r
+ {\r
+ return value;\r
+ }\r
+}\r
+\r
+/*\r
+ * <A NAME="xmlParseValue">xmlParseValue</A>\r
+ *\r
+ * Syntax is as follows:\r
+ *\r
+ * XMLPARSE( DOCUMENT <string-value-expression> PRESERVE WHITESPACE )\r
+ *\r
+ * The result of this operation will be an XML value, which can either\r
+ * be used transiently or else can be stored persistently in a table that\r
+ * has an XML column. For example:\r
+ *\r
+ * ij> CREATE TABLE x_table (id INT, xdoc XML);\r
+ * 0 rows inserted/updated/deleted\r
+ * ij> INSERT INTO x_table VALUES (1, XMLPARSE(DOCUMENT '<simp> doc </simp>'\r
+ * PRESERVE WHITESPACE));\r
+ * 1 row inserted/updated/deleted\r
+ *\r
+ * We only allow XML documents (as opposed to XML content) to be\r
+ * parsed into XML values. Note that we require the "PRESERVE WHITESPACE"\r
+ * keyword to be explicit; this is because the SQL/XML (2003) spec says that\r
+ * if no whitespace option is given, the default is "STRIP WHITESPACE", which\r
+ * we don't support (yet).\r
+ *\r
+ * By the time we get to this method, the "DOCUMENT" keyword has already\r
+ * been parsed.\r
+ *\r
+ */\r
+ValueNode\r
+ xmlParseValue() throws StandardException :\r
+{\r
+ ValueNode value;\r
+ boolean wsOption;\r
+}\r
+{\r
+ value = additiveExpression(null,0,false) wsOption = xmlPreserveWhitespace() {\r
+ return (ValueNode) nodeFactory.getNode(\r
+ C_NodeTypes.XML_PARSE_OPERATOR_NODE,\r
+ value,\r
+ ReuseFactory.getInteger(UnaryOperatorNode.XMLPARSE_OP),\r
+ new Object[] {(wsOption ? Boolean.TRUE : Boolean.FALSE)},\r
+ getContextManager());\r
+ }\r
+}\r
+\r
+/*\r
+ * <A NAME="xmlPreserveWhitespace">xmlPreserveWhitespace</A>\r
+ *\r
+ * For now, we only support the PRESERVE WHITESPACE option.\r
+ *\r
+ */\r
+boolean\r
+ xmlPreserveWhitespace() throws StandardException :\r
+{\r
+}\r
+{\r
+ LOOKAHEAD({ (getToken(1).kind != STRIP) &&\r
+ (getToken(1).kind != PRESERVE) })\r
+ {\r
+ throw StandardException.newException(\r
+ SQLState.LANG_XML_KEYWORD_MISSING, "PRESERVE WHITESPACE",\r
+ ReuseFactory.getInteger(getToken(1).beginLine),\r
+ ReuseFactory.getInteger(getToken(1).beginColumn));\r
+ }\r
+|\r
+ <STRIP> <WHITESPACE>\r
+ { // don't preserve whitespace.\r
+ throw StandardException.newException(\r
+ SQLState.LANG_UNSUPPORTED_XML_FEATURE, "STRIP WHITESPACE");\r
+ }\r
+|\r
+ <PRESERVE> <WHITESPACE>\r
+ { // must preserve whitespace.\r
+ return true;\r
+ }\r
+}\r
+\r
+/*\r
+ * <A NAME="xmlSerializeValue">xmlSerializeValue</A>\r
+ *\r
+ * Syntax is as follows:\r
+ *\r
+ * XMLSERIALIZE( <xml-value-expression> AS <string-data-type> )\r
+ *\r
+ * The result of this operation will be a string value with the type specified\r
+ * by the user. For example:\r
+ *\r
+ * ij> SELECT id, XMLSERIALIZE(xdoc AS varchar(30)) FROM x_table;\r
+ * ID |2\r
+ * ------------------------------------------\r
+ * 1 |<simp> doc </simp>\r
+ *\r
+ */\r
+ValueNode\r
+ xmlSerializeValue() throws StandardException :\r
+{\r
+ ValueNode value;\r
+ DataTypeDescriptor targetType;\r
+}\r
+{\r
+ value = additiveExpression(null,0,false)\r
+ targetType = xmlSerializeTargetType()\r
+ {\r
+ return (ValueNode) nodeFactory.getNode(\r
+ C_NodeTypes.XML_SERIALIZE_OPERATOR_NODE,\r
+ value,\r
+ ReuseFactory.getInteger(UnaryOperatorNode.XMLSERIALIZE_OP),\r
+ new Object[] {targetType},\r
+ getContextManager());\r
+ }\r
+}\r
+\r
+/*\r
+ * <A NAME="xmlSerializeTargetType">xmlSerializeTargetType</A>\r
+ *\r
+ * Parse the target type of an XMLSERIALIZE operation.\r
+ *\r
+ */\r
+DataTypeDescriptor xmlSerializeTargetType() throws StandardException :\r
+{\r
+ DataTypeDescriptor targetType;\r
+}\r
+{\r
+ LOOKAHEAD({ (getToken(1).kind != AS) })\r
+ {\r
+ throw StandardException.newException(\r
+ SQLState.LANG_XML_KEYWORD_MISSING, "AS",\r
+ ReuseFactory.getInteger(getToken(1).beginLine),\r
+ ReuseFactory.getInteger(getToken(1).beginColumn));\r
+ }\r
+|\r
+ <AS> targetType = dataTypeDDL()\r
+ {\r
+ return targetType;\r
+ }\r
+}\r
+\r
+/*\r
+ * <A NAME="xmlQueryValue">xmlQueryValue</A>\r
+ *\r
+ * This method is used for parsing the XMLEXISTS and XMLQUERY operators\r
+ * (which operator depends on the received boolean parameter).\r
+ *\r
+ * For XMLEXISTS, the syntax is as follows:\r
+ *\r
+ * XMLEXISTS( <xpath-expression> PASSING BY REF <xml-value-expression> )\r
+ *\r
+ * The result of this operation will be a boolean true/false/unknown value:\r
+ * -- Unknown if either <xquery-expression> or <xml-value-expression> is null;\r
+ * -- True if evaluation of the given query expression against the\r
+ * given xml-value returns at least one node.\r
+ * -- False otherwise.\r
+ *\r
+ * For example:\r
+ *\r
+ * ij> SELECT id FROM x_table WHERE XMLEXISTS('/simple' PASSING BY REF xdoc);\r
+ * ID\r
+ * -----------\r
+ * 1\r
+ *\r
+ * ====\r
+ *\r
+ * For XMLQUERY, the syntax is as follows:\r
+ *\r
+ * XMLQUERY( <xquery-expression>\r
+ * PASSING BY REF <xml-value-expression>\r
+ * [ RETURNING SEQUENCE [ BY REF ] ]\r
+ * EMPTY ON EMPTY\r
+ * )\r
+ *\r
+ * The result of this operation will be an XMLDataValue.\r
+ *\r
+ * For example:\r
+ *\r
+ * ij> SELECT XMLSERIALIZE(\r
+ * XMLQUERY('/simple' PASSING BY REF xdoc EMPTY ON EMPTY) AS CHAR(100));\r
+ * ID\r
+ * -----------\r
+ * <simp> doc </simp>\r
+ *\r
+ */\r
+ValueNode\r
+ xmlQueryValue(boolean existsOnly) throws StandardException :\r
+{\r
+ // The query expression (currently must be an expression\r
+ // supported by Xalan--i.e. XPath only).\r
+ ValueNode xqueryExpr = null;\r
+\r
+ // Context item for the query; not required by SQL/XML spec,\r
+ // but required by Derby for now.\r
+ ValueNode xmlValue = null;\r
+\r
+ // User-specified default passing mechanism. Since Derby only\r
+ // supports one type of passing mechanism--BY REF--this value\r
+ // isn't currently used.\r
+ short defaultPassingMech = -1;\r
+}\r
+{\r
+ xqueryExpr = additiveExpression(null, 0, false)\r
+ <PASSING> defaultPassingMech = xmlPassingMechanism()\r
+ xmlValue = xqVarList()\r
+ (\r
+ LOOKAHEAD( { !existsOnly } )\r
+ [ xqReturningClause() [ xmlPassingMechanism() ] ]\r
+ xqEmptyHandlingClause()\r
+ { /* Right now, we only support one kind of returning clause\r
+ * (RETURNING SEQUENCE) and one kind of handling clause\r
+ * (EMPTY ON EMPTY), so there's nothing more to do here--\r
+ * we just needed to check the syntax. In the future\r
+ * we may need to add more logic here to support the\r
+ * other options. Note: if no returning clause is\r
+ * specified, RETURNING SEQUENCE is implied (because\r
+ * that's all we support).\r
+ */\r
+ }\r
+ |\r
+ LOOKAHEAD( { existsOnly } )\r
+ { /* For XMLEXISTS there's nothing more to parse. We need\r
+ * this LOOKAHEAD in order to tell the parser that we're\r
+ * done parsing and thus it shouldn't look for (nor allow)\r
+ * any more tokens (neither xqReturningClause() nor\r
+ * xqEmptyHandlingClause() is allowed for the XMLEXISTS\r
+ * operator).\r
+ */\r
+ }\r
+ )\r
+ {\r
+ ValueNode vNode = (ValueNode) nodeFactory.getNode(\r
+ (existsOnly\r
+ ? C_NodeTypes.XML_EXISTS_OPERATOR_NODE\r
+ : C_NodeTypes.XML_QUERY_OPERATOR_NODE),\r
+ xqueryExpr,\r
+ xmlValue,\r
+ (existsOnly\r
+ ? ReuseFactory.getInteger(BinaryOperatorNode.XMLEXISTS_OP)\r
+ : ReuseFactory.getInteger(BinaryOperatorNode.XMLQUERY_OP)),\r
+ getContextManager());\r
+\r
+ return vNode;\r
+ }\r
+}\r
+\r
+/**\r
+ * <A NAME="xqVarList">xqVarList</A>\r
+ *\r
+ * Parse a list of XML query variables, which can include at most one\r
+ * XML value to be used as the "context item" for the query. If\r
+ * such a context item was found, return that item; for all other\r
+ * variable declarations we currently throw a "not supported" error\r
+ * because Xalan doesn't allowing binding of variables.\r
+ */\r
+\r
+ValueNode xqVarList()\r
+ throws StandardException :\r
+{\r
+ // Placeholder for the XML context item as we parse the\r
+ // argument list.\r
+ ValueNode [] xmlValue = new ValueNode [] { (ValueNode)null };\r
+}\r
+{\r
+ xqVariable(xmlValue)\r
+ ( <COMMA> xqVariable(xmlValue) )*\r
+ {\r
+ return xmlValue[0];\r
+ }\r
+}\r
+\r
+/**\r
+ * <A NAME="xqVariable">xqVariable</A>\r
+ *\r
+ * Parse an XML query variable. If the argument is an XML value\r
+ * to be used as the "context item" for a query, then store the\r
+ * value in the first slot of the received ValueNode array;\r
+ * otherwise, throw a "not supported" errror (for now).\r
+ */\r
+\r
+void xqVariable(ValueNode [] xmlVal) throws StandardException :\r
+{\r
+ ValueNode curVal;\r
+ String varName = null;\r
+ short passingMech = -1;\r
+}\r
+{\r
+ curVal = additiveExpression(null,0, false)\r
+ [\r
+ LOOKAHEAD( { getToken(1).kind == AS } )\r
+ <AS> varName = identifier(Limits.MAX_IDENTIFIER_LENGTH, true)\r
+ {\r
+ /* From XQuery 1.0: "The <identifier> I contained in XQV\r
+ * shall be an XML 1.1 NCName." From XML 1.1:\r
+ *\r
+ * [4] NCName ::= (Letter | '_') (NCNameChar)*\r
+ * [5] NCNameChar ::= Letter | Digit | '.' | '-' | '_' |\r
+ * CombiningChar | Extender\r
+ *\r
+ * Since Derby's definition of an "identifier" is a subset\r
+ * of NCName, we just use Derby's definition. This means\r
+ * that some valid NCNames won't be recognized by Derby--\r
+ * but since the ones we _do_ recognize are all still valid\r
+ * NCNames, we're not breaking any rules.\r
+ */\r
+\r
+ /* All of that said, since we use Xalan as the underlying\r
+ * query engine and Xalan doesn't support variable binding,\r
+ * there's no point in letting the user specify variables\r
+ * right now. So we disallow it. In the future we'll have\r
+ * to add logic here to store the variables and pass them\r
+ * to the correct operator for binding/execution.\r
+ */\r
+ throw StandardException.newException(\r
+ SQLState.LANG_UNSUPPORTED_XML_FEATURE, "PASSING ... AS");\r
+ }\r
+ ] \r
+ (\r
+ [ passingMech = xmlPassingMechanism() ]\r
+ {\r
+ if (varName == null)\r
+ {\r
+ /* We get here if we just parsed an XML context item.\r
+ * That said, if we already have one (xmlVal[0] is not\r
+ * null) then we can't allow second one, per SQL/XML[2006]\r
+ * (6.17: Syntax Rules:5.b.i): "XMQ shall contain exactly\r
+ * one <XML query context item> XQCI."\r
+ */\r
+ if (xmlVal[0] != null)\r
+ {\r
+ throw StandardException.newException(\r
+ SQLState.LANG_MULTIPLE_XML_CONTEXT_ITEMS);\r
+ }\r
+\r
+ xmlVal[0] = curVal;\r
+\r
+ /* Note: It's possible that a passing mechanism was\r
+ * specified for the context item; if so its value is\r
+ * stored in passingMech. However, we don't actually\r
+ * store that passing mechanism anywhere because we\r
+ * (currently) only support BY REF, so we know what\r
+ * it has to be. If we add support for other passing\r
+ * mechanisms (namely, BY VALUE) in the future, we'll\r
+ * have to store the passing mechanism provided by\r
+ * the user and process it at compilation/execution\r
+ * time.\r
+ */\r
+ }\r
+ }\r
+ )\r
+ { // By this time we've parsed everything we need so there's nothing\r
+ // more to do. The reason we're left with this empty block is\r
+ // is that most of the syntax is optional. We end up here if\r
+ // none of the optional syntax was given, in which case all we\r
+ // need to do is store curVal--and we already did that.\r
+ }\r
+}\r
+\r
+/*\r
+ * <A NAME="xmlPassingMechanism">xmlPassingMechanism</A>\r
+ *\r
+ * For now, we only support the BY REF option because\r
+ * that gives us better performance (allows us to avoid\r
+ * performing potentially deep copies of XML nodes). This\r
+ * means that if the same XML value is passed BY REF into\r
+ * two different XML arguments for a single operator, then\r
+ * every node in the first XML argument must have an\r
+ * identical node in the second XML argument, and the\r
+ * ids for both nodes must be the same. That said,\r
+ * since we don't support variable binding yet, this\r
+ * becomes a non-issue because we can't pass XML values.\r
+ * In the future, though, we may choose to support the\r
+ * passing/binding of variables (the only reason we\r
+ * don't now is because Xalan doesn't support it) and\r
+ * if we do, BY REF should provide better performance\r
+ * due to lack of deep copying.\r
+ */\r
+short\r
+ xmlPassingMechanism() throws StandardException :\r
+{\r
+}\r
+{\r
+ LOOKAHEAD( { getToken(2).kind == REF })\r
+ <BY> <REF>\r
+ { // pass the XML value by reference\r
+ return org.apache.derby.iapi.types.XML.XQ_PASS_BY_REF;\r
+ }\r
+|\r
+ <BY> <VALUE>\r
+ { // pass a 'copy' of the XML value.\r
+ throw StandardException.newException(\r
+ SQLState.LANG_UNSUPPORTED_XML_FEATURE, "BY VALUE");\r
+ }\r
+}\r
+\r
+/*\r
+ * <A NAME="xqReturningClause">xqReturningClause</A>\r
+ *\r
+ * For now we only support "RETURNING SEQUENCE". The reason\r
+ * is that this applies to the XMLQUERY operator and the\r
+ * results of evaluating a query expression in Xalan against\r
+ * an XML value can be an arbritary sequence of items--including\r
+ * atomic values. For simplicity we just return the values\r
+ * as they are, without doing any further work. SQL/XML[2006]\r
+ * says that if we supported RETURNING CONTENT then we'd have\r
+ * to construct an XQuery document from the results--but we don't\r
+ * do that extra work for now, so we just say that we return\r
+ * SEQUENCE.\r
+ *\r
+ * NOTE: This means that we may not be able to store the results\r
+ * of an XMLQUERY operation into a Derby XML column. Right now\r
+ * an XML column can only hold valid DOCUMENT nodes, which we\r
+ * we define as an XML value whose serialized form can be parsed\r
+ * by a JAXP DocumentBuilder (because that's what Derby's XMLPARSE\r
+ * operator uses and the result is always a Document node).\r
+ * Internally this means that we can only store a sequence if it\r
+ * contains exactly one org.w3c.dom.Node that is an instance of\r
+ * org.w3c.dom.Document. If the result of an XMLQUERY operation\r
+ * does not fit this criteria then it will *not* be storable into\r
+ * Derby XML columns.\r
+ */\r
+short\r
+ xqReturningClause() throws StandardException :\r
+{\r
+}\r
+{\r
+ LOOKAHEAD( { getToken(2).kind == SEQUENCE } )\r
+ <RETURNING> <SEQUENCE>\r
+ { // XMLQUERY should return result as a sequence.\r
+ // NOTE: since Derby XML columns only allow DOCUMENT(UNTYPED),\r
+ // the result of an XMLQUERY operator that returns SEQUENCE\r
+ // might not be storable into an XML column.\r
+ return org.apache.derby.iapi.types.XML.XQ_RETURN_SEQUENCE;\r
+ }\r
+|\r
+ <RETURNING> <CONTENT>\r
+ { // XMLQUERY should return 'content'.\r
+ throw StandardException.newException(\r
+ SQLState.LANG_UNSUPPORTED_XML_FEATURE, "RETURNING CONTENT");\r
+ }\r
+}\r
+\r
+/*\r
+ * <A NAME="xqEmptyHandlingClause">xqEmptyHandlingClause</A>\r
+ *\r
+ * Defines what the behavior should be when an XMLQUERY operator\r
+ * results in an empty sequence. For now we just return the\r
+ * empty sequence.\r
+ */\r
+short\r
+ xqEmptyHandlingClause() throws StandardException :\r
+{\r
+}\r
+{\r
+ LOOKAHEAD( { getToken(1).kind == EMPTY })\r
+ <EMPTY> <ON> <EMPTY>\r
+ { // XMLQUERY should return an empty sequence when result of\r
+ // the query is an empty sequence (i.e. when there are no\r
+ // results).\r
+ return org.apache.derby.iapi.types.XML.XQ_EMPTY_ON_EMPTY;\r
+ }\r
+|\r
+ <NULL> <ON> <EMPTY>\r
+ { // XMLQUERY should return a null XML value when result of\r
+ // the query is an empty sequence (i.e. when there are no\r
+ // results).\r
+ throw StandardException.newException(\r
+ SQLState.LANG_UNSUPPORTED_XML_FEATURE, "NULL ON EMPTY");\r
+ }\r
+}\r
+\r
+/*\r
+ * <A NAME="numericFunctionType">numericFunctionType</A>\r
+ */\r
+DataTypeDescriptor\r
+numericFunctionType() throws StandardException :\r
+\r
+{\r
+ DataTypeDescriptor dts;\r
+}\r
+{\r
+ dts = doubleType()\r
+ {\r
+ return dts;\r
+ }\r
+ |\r
+ dts = exactIntegerType()\r
+ {\r
+ return dts;\r
+ }\r
+}\r
+\r
+/*\r
+ * <A NAME="dateTimeScalarFunction">dateTimeScalarFunction</A>\r
+ */\r
+ValueNode\r
+dateTimeScalarFunction() throws StandardException :\r
+{\r
+ ValueNode value;\r
+ ValueNode timestampNode;\r
+ int field;\r
+}\r
+{\r
+ /*\r
+ * NOTE: If you add a new rule here, you must add the appropriate\r
+ * LOOKAHEAD rule to miscBuiltins().\r
+ */\r
+ <TIME> <LEFT_PAREN> value = additiveExpression(null,0, false) <RIGHT_PAREN>\r
+ {\r
+ ValueNode castValue = (ValueNode) nodeFactory.getNode(\r
+ C_NodeTypes.CAST_NODE,\r
+ value,\r
+ DataTypeDescriptor.getBuiltInDataTypeDescriptor( Types.TIME),\r
+ getContextManager());\r
+ ((CastNode) castValue).setForExternallyGeneratedCASTnode();\r
+ return castValue;\r
+ }\r
+|\r
+ <DATE> <LEFT_PAREN> value = additiveExpression(null,0, false) <RIGHT_PAREN>\r
+ {\r
+ return (ValueNode) nodeFactory.getNode(\r
+ C_NodeTypes.UNARY_DATE_TIMESTAMP_OPERATOR_NODE,\r
+ value,\r
+ DataTypeDescriptor.getBuiltInDataTypeDescriptor( Types.DATE),\r
+ getContextManager());\r
+ }\r
+|\r
+ <TIMESTAMP> <LEFT_PAREN> value = additiveExpression(null,0, false) timestampNode = timestampFunctionCompletion( value)\r
+ {\r
+ return timestampNode;\r
+ }\r
+|\r
+ field = datetimeField() <LEFT_PAREN> value = additiveExpression(null,0, false) <RIGHT_PAREN>\r
+ {\r
+ return (ValueNode) nodeFactory.getNode(\r
+ C_NodeTypes.EXTRACT_OPERATOR_NODE,\r
+ ReuseFactory.getInteger(field),\r
+ value,\r
+ getContextManager());\r
+ }\r
+}\r
+\r
+\r
+/*\r
+ * <A NAME="timestampFunctionCompletion">timestampFunctionCompletion</A>\r
+ */\r
+ValueNode\r
+timestampFunctionCompletion( ValueNode firstArg) throws StandardException :\r
+{\r
+ ValueNode timeValue;\r
+}\r
+{\r
+ <RIGHT_PAREN>\r
+ {\r
+ return (ValueNode) nodeFactory.getNode(\r
+ C_NodeTypes.UNARY_DATE_TIMESTAMP_OPERATOR_NODE,\r
+ firstArg,\r
+ DataTypeDescriptor.getBuiltInDataTypeDescriptor( Types.TIMESTAMP),\r
+ getContextManager());\r
+ }\r
+|\r
+ <COMMA> timeValue = additiveExpression(null,0, false) <RIGHT_PAREN>\r
+ {\r
+ return (ValueNode) nodeFactory.getNode(\r
+ C_NodeTypes.TIMESTAMP_OPERATOR_NODE,\r
+ firstArg,\r
+ timeValue,\r
+ getContextManager());\r
+ }\r
+}\r
+\r
+/*\r
+ * <A NAME="booleanLiteral">booleanLiteral</A>\r
+ */\r
+Token\r
+booleanLiteral() :\r
+{\r
+ Token tok;\r
+}\r
+{\r
+ tok = <TRUE>\r
+ {\r
+ return tok;\r
+ }\r
+|\r
+ tok = <FALSE>\r
+ {\r
+ return tok;\r
+ }\r
+}\r
+\r
+/*\r
+ * <A NAME="generalValueSpecification">generalValueSpecification</A>\r
+ */\r
+ValueNode\r
+generalValueSpecification() throws StandardException :\r
+{\r
+ ValueNode parm;\r
+}\r
+{\r
+ parm = dynamicParameterSpecification()\r
+ {\r
+ return parm;\r
+ }\r
+|\r
+ parm = userNode()\r
+ {\r
+ return parm;\r
+ }\r
+}\r
+\r
+ValueNode\r
+userNode() throws StandardException :\r
+{\r
+}\r
+{\r
+ <USER>\r
+ {\r
+ return (ValueNode) nodeFactory.getNode(\r
+ C_NodeTypes.USER_NODE,\r
+ getContextManager());\r
+ }\r
+|\r
+ <CURRENT_USER>\r
+ {\r
+ return (ValueNode) nodeFactory.getNode(\r
+ C_NodeTypes.CURRENT_USER_NODE,\r
+ getContextManager());\r
+ }\r
+|\r
+ <SESSION_USER>\r
+ {\r
+ return (ValueNode) nodeFactory.getNode(\r
+ C_NodeTypes.SESSION_USER_NODE,\r
+ getContextManager());\r
+ }\r
+}\r
+\r
+\r
+\r
+\r
+/*\r
+ * <A NAME="newInvocation">newInvocation</A>\r
+ */\r
+JavaToSQLValueNode\r
+newInvocation() throws StandardException :\r
+{\r
+ QueryTreeNode newNode;\r
+ Vector parameterList = new Vector();\r
+ String javaClassName;\r
+}\r
+{\r
+ <NEW> javaClassName = javaClassName() methodCallParameterList(parameterList)\r
+ { \r
+ if (!javaClassName.startsWith("org.apache.derby.diag.") && !javaClassName.startsWith("org.apache.derby.catalog.") && !javaClassName.startsWith("com.ibm.db2j."))\r
+ {\r
+ checkInternalFeature(javaClassName);\r
+ }\r
+ newNode = nodeFactory.getNode(C_NodeTypes.NEW_INVOCATION_NODE,\r
+ javaClassName,\r
+ parameterList, \r
+ lastTokenDelimitedIdentifier,\r
+ getContextManager());\r
+\r
+ /*\r
+ ** Assume this is being returned to the SQL domain. If it turns\r
+ ** out that this is being returned to the Java domain, we will\r
+ ** get rid of this node.\r
+ */\r
+ return (JavaToSQLValueNode) nodeFactory.getNode(\r
+ C_NodeTypes.JAVA_TO_SQL_VALUE_NODE,\r
+ newNode,\r
+ getContextManager());\r
+ }\r
+}\r
+\r
+/*\r
+ * <A NAME="vtiTableConstruct">vtiTableConstruct</A>\r
+ *\r
+ * Parse a TABLE() constructor that corresponds to an internal\r
+ * VTI invocation. For example:\r
+ *\r
+ * TABLE ( <qualifiedName> (arg1, arg2, ...) )\r
+ *\r
+ * where <qualifiedName> is a table name that Derby will map internally\r
+ * to a VTI (ex. "SYSCS_DIAG.SPACE_TABLE"). The list of arguments\r
+ * will then be passed to the VTI when it is invoked (DERBY-2152).\r
+ *\r
+ * An example query where this might occur is as follows:\r
+ *\r
+ * SELECT * FROM TABLE(SYSCS_DIAG.SPACE_TABLE('APP', 'T1')) x\r
+ *\r
+ * in which case SYSCS_DIAG.SPACE_TABLE will be mapped (internally)\r
+ * to the "org.apache.derby.diag.SpaceTable" diagnostic VTI. Thus\r
+ * the equivalent call prior to DERBY-2152 would have been:\r
+ *\r
+ * SELECT * FROM NEW org.apache.derby.diag.SpaceTable('APP', 'T1')) x\r
+ *\r
+ * Note that this latter syntax is still supported.\r
+ */\r
+JavaToSQLValueNode\r
+vtiTableConstruct() throws StandardException :\r
+{\r
+ QueryTreeNode newNode = null;\r
+ Vector parameterList = new Vector();\r
+ TableName vtiTableName = null;\r
+}\r
+{\r
+ <TABLE> <LEFT_PAREN>\r
+ vtiTableName = qualifiedName(Limits.MAX_IDENTIFIER_LENGTH)\r
+ methodCallParameterList(parameterList)\r
+ <RIGHT_PAREN>\r
+ {\r
+ /* The fact that we pass a NULL table descriptor to the\r
+ * following call is an indication that we are mapping to a\r
+ * VTI table function (i.e. one that accepts arguments).\r
+ * Since we have the table name we do not need to pass in a\r
+ * TableDescriptor--we'll just create one from the table\r
+ * name. See NewInvocationNode for more.\r
+ */\r
+ newNode = nodeFactory.getNode(C_NodeTypes.NEW_INVOCATION_NODE,\r
+ vtiTableName, // TableName\r
+ null, // TableDescriptor\r
+ parameterList, \r
+ lastTokenDelimitedIdentifier,\r
+ getContextManager());\r
+\r
+ /*\r
+ ** Assume this is being returned to the SQL domain. If it turns\r
+ ** out that this is being returned to the Java domain, we will\r
+ ** get rid of this node.\r
+ */\r
+ return (JavaToSQLValueNode) nodeFactory.getNode(\r
+ C_NodeTypes.JAVA_TO_SQL_VALUE_NODE,\r
+ newNode,\r
+ getContextManager());\r
+ }\r
+}\r
+\r
+/*\r
+ * <A NAME="staticMethodInvocation">staticMethodInvocation</A>\r
+ */\r
+ValueNode\r
+staticMethodInvocation(String javaClassName) throws StandardException :\r
+{\r
+ Vector parameterList = new Vector();\r
+ MethodCallNode methodNode;\r
+}\r
+{\r
+ methodNode = staticMethodName(javaClassName) methodCallParameterList(parameterList)\r
+ {\r
+ methodNode.addParms(parameterList);\r
+\r
+ /*\r
+ ** Assume this is being returned to the SQL domain. If it turns\r
+ ** out that this is being returned to the Java domain, we will\r
+ ** get rid of this node.\r
+ */\r
+ return (ValueNode) nodeFactory.getNode(\r
+ C_NodeTypes.JAVA_TO_SQL_VALUE_NODE,\r
+ methodNode,\r
+ getContextManager());\r
+ }\r
+}\r
+\r
+/**\r
+ * <A NAME="methodCallParameterList">methodCallParameterList</A>\r
+*/\r
+\r
+void methodCallParameterList(Vector parameterList) throws StandardException :\r
+{\r
+}\r
+{\r
+ <LEFT_PAREN>\r
+ [ methodParameter(parameterList)\r
+ ( <COMMA> methodParameter(parameterList) )* ]\r
+ <RIGHT_PAREN>\r
+}\r
+\r
+/*\r
+ * <A NAME="routineInvocation">routineInvocation</A>\r
+ */\r
+ValueNode\r
+routineInvocation() throws StandardException :\r
+{\r
+ Vector parameterList = new Vector();\r
+ TableName routineName;\r
+ MethodCallNode methodNode;\r
+}\r
+{\r
+ routineName = qualifiedName(Limits.MAX_IDENTIFIER_LENGTH)\r
+ methodCallParameterList(parameterList)\r
+ {\r
+\r
+ methodNode = (MethodCallNode) nodeFactory.getNode(\r
+ C_NodeTypes.STATIC_METHOD_CALL_NODE,\r
+ routineName,\r
+ null,\r
+ getContextManager());\r
+\r
+ methodNode.addParms(parameterList);\r
+\r
+ /*\r
+ ** Assume this is being returned to the SQL domain. If it turns\r
+ ** out that this is being returned to the Java domain, we will\r
+ ** get rid of this node.\r
+ */\r
+ return (ValueNode) nodeFactory.getNode(\r
+ C_NodeTypes.JAVA_TO_SQL_VALUE_NODE,\r
+ methodNode,\r
+ getContextManager());\r
+ }\r
+}\r
+\r
+/*\r
+ * <A NAME="javaClass">javaClass</A>\r
+ */\r
+\r
+String\r
+javaClass() throws StandardException :\r
+{\r
+ String javaClassName;\r
+}\r
+{\r
+ javaClassName = javaClassName() \r
+ {\r
+ return javaClassName;\r
+ }\r
+}\r
+\r
+/*\r
+ * <A NAME="columnMethodInvocation">columnMethodInvocation</A>\r
+ */\r
+ValueNode\r
+columnMethodInvocation() throws StandardException :\r
+{\r
+ ValueNode columnReference;\r
+ ValueNode methodNode;\r
+}\r
+{\r
+ columnReference = columnNameForInvocation()\r
+ methodNode = nonStaticMethodInvocation(columnReference)\r
+ {\r
+ return methodNode;\r
+ }\r
+}\r
+\r
+/*\r
+ * <A NAME="columnNameForInvocation">columnNameForInvocation</A>\r
+ */\r
+ValueNode\r
+columnNameForInvocation() throws StandardException :\r
+{\r
+ String firstName;\r
+ String secondName = null;\r
+ String thirdName = null;\r
+ String columnName = null;\r
+ String tableName = null;\r
+ String schemaName = null;\r
+ TableName tabName = null;\r
+ ValueNode retval;\r
+}\r
+{\r
+ firstName = identifier(Limits.MAX_IDENTIFIER_LENGTH, true)\r
+ [\r
+ // This LOOKAHEAD is required because we have the following cases:\r
+ // schema.table.column.method()\r
+ // table.column.method()\r
+ // column.method()\r
+ //\r
+ // We have to look ahead to ensure that there is at least one more\r
+ // PERIOD after the current one, so that we don't consider the\r
+ // method name to be a table or column name\r
+ LOOKAHEAD( {\r
+ getToken(1).kind == PERIOD &&\r
+ getToken(3).kind == PERIOD\r
+ } )\r
+ <PERIOD> secondName = identifier(Limits.MAX_IDENTIFIER_LENGTH, true)\r
+ [\r
+ // See above: we don't want to mistake the method name for a\r
+ // column name.\r
+ LOOKAHEAD( {\r
+ getToken(1).kind == PERIOD &&\r
+ getToken(3).kind == PERIOD\r
+ } )\r
+ <PERIOD> thirdName = identifier(Limits.MAX_IDENTIFIER_LENGTH, true)\r
+ ]\r
+ ]\r
+ {\r
+ // Figure out what each identifier stands for\r
+ if (thirdName == null)\r
+ {\r
+ if (secondName == null)\r
+ {\r
+ // There's only one identifier, so it must be a column name\r
+ columnName = firstName;\r
+ }\r
+ else\r
+ {\r
+ // There are two identifiers, so they are table and column names\r
+ tableName = firstName;\r
+ columnName = secondName;\r
+ }\r
+ }\r
+ else\r
+ {\r
+ // There are three identifiers,\r
+ // so they are schema, table, and column names\r
+ schemaName = firstName;\r
+ tableName = secondName;\r
+ columnName = thirdName;\r
+ }\r
+\r
+ if (tableName != null)\r
+ {\r
+ // There is a table name, so get a TableName node\r
+ tabName =\r
+ (TableName) nodeFactory.getNode(\r
+ C_NodeTypes.TABLE_NAME,\r
+ schemaName,\r
+ tableName,\r
+ new Integer(nextToLastIdentifierToken.beginOffset),\r
+ new Integer(nextToLastIdentifierToken.endOffset),\r
+ getContextManager());\r
+ }\r
+\r
+ // Get the column reference\r
+ retval = (ValueNode) nodeFactory.getNode(\r
+ C_NodeTypes.COLUMN_REFERENCE,\r
+ columnName,\r
+ tabName,\r
+ new Integer(lastIdentifierToken.beginOffset),\r
+ new Integer(lastIdentifierToken.endOffset),\r
+ getContextManager());\r
+\r
+ return retval;\r
+ }\r
+}\r
+\r
+/*\r
+ * <A NAME="columnReference">columnReference</A>\r
+ */\r
+ColumnReference\r
+columnReference() throws StandardException :\r
+{\r
+ String firstName;\r
+ String secondName = null;\r
+ String thirdName = null;\r
+ String columnName = null;\r
+ String tableName = null;\r
+ String schemaName = null;\r
+ TableName tabName = null;\r
+}\r
+{\r
+ firstName = identifier(Limits.MAX_IDENTIFIER_LENGTH, false)\r
+ [\r
+ // This LOOKAHEAD is needed to ensure that, if the identifier\r
+ // after the PERIOD is a method name , we\r
+ // don't treat it as part of the column reference.\r
+ LOOKAHEAD( {\r
+ getToken(1).kind == PERIOD &&\r
+ getToken(3).kind != LEFT_PAREN\r
+ } )\r
+ <PERIOD> secondName = identifier(Limits.MAX_IDENTIFIER_LENGTH, false)\r
+ [\r
+ // This LOOKAHEAD is needed to ensure that, if the identifier\r
+ // after the PERIOD is a method name , we\r
+ // don't treat it as part of the column reference.\r
+ LOOKAHEAD( {\r
+ getToken(1).kind == PERIOD &&\r
+ getToken(3).kind != LEFT_PAREN\r
+ } )\r
+ <PERIOD> thirdName = identifier(Limits.MAX_IDENTIFIER_LENGTH, false)\r
+ ]\r
+ ]\r
+ {\r
+ // Figure out what each name stands for\r
+ if (thirdName == null)\r
+ {\r
+ if (secondName == null)\r
+ {\r
+ // Only one name, must be column name\r
+ columnName = firstName;\r
+ }\r
+ else\r
+ {\r
+ // Two names: table.column\r
+ tableName = firstName;\r
+ columnName = secondName;\r
+ }\r
+ }\r
+ else\r
+ {\r
+ // Three names: schema.table.column\r
+ schemaName = firstName;\r
+ tableName = secondName;\r
+ columnName = thirdName;\r
+ }\r
+\r
+ checkIdentifierLengthLimit(columnName, Limits.MAX_IDENTIFIER_LENGTH);\r
+ if (schemaName != null)\r
+ checkIdentifierLengthLimit(schemaName, Limits.MAX_IDENTIFIER_LENGTH);\r
+ if (tableName != null)\r
+ checkIdentifierLengthLimit(tableName, Limits.MAX_IDENTIFIER_LENGTH);\r
+\r
+ if (tableName != null)\r
+ {\r
+ tabName = (TableName) nodeFactory.getNode(\r
+ C_NodeTypes.TABLE_NAME,\r
+ schemaName,\r
+ tableName,\r
+ new Integer(nextToLastIdentifierToken.beginOffset),\r
+ new Integer(nextToLastIdentifierToken.endOffset),\r
+ getContextManager());\r
+ }\r
+\r
+ return (ColumnReference) nodeFactory.getNode(\r
+ C_NodeTypes.COLUMN_REFERENCE,\r
+ columnName,\r
+ tabName,\r
+ new Integer(lastIdentifierToken.beginOffset),\r
+ new Integer(lastIdentifierToken.endOffset),\r
+ getContextManager());\r
+ }\r
+}\r
+\r
+/*\r
+void\r
+columnReference() throws StandardException :\r
+{}\r
+{\r
+ /*\r
+ **\r
+ ** I re-wrote the above rule because it caused a grammar ambiguitity.\r
+ ** The problem is that we are parsing a dot-separated list of identifiers,\r
+ ** and the grammar doesn't know what the identifiers stand for, but the\r
+ ** syntax assumed that it did. For example, in schema.table.column,\r
+ ** the grammar doesn't know when it parses the first identifier whether\r
+ ** it will be a catalog name, schema name, table name, or column name.\r
+ **\r
+ ** I think this problem could be solved by increasing the lookahead.\r
+ ** I will try that solution next. I like that solution better because,\r
+ ** if it works, it will be easier for the grammar to figure out what\r
+ ** each identifier stands for.\r
+ **\r
+\r
+ [ <MODULE> <PERIOD> <IDENTIFIER> |\r
+ [ [ [ <IDENTIFIER> <PERIOD> ] <IDENTIFIER> <PERIOD> ] <IDENTIFIER> <PERIOD> ]\r
+ ]\r
+ <IDENTIFIER>\r
+}\r
+*/\r
+\r
+OrderByList\r
+orderByClause() throws StandardException :\r
+{\r
+ OrderByList orderCols;\r
+}\r
+{\r
+ <ORDER> <BY> orderCols = sortSpecificationList()\r
+ {\r
+ return orderCols;\r
+ }\r
+}\r
+\r
+int\r
+atIsolationLevel() throws StandardException :\r
+{\r
+ int isolationLevel;\r
+}\r
+{\r
+ <WITH> isolationLevel = isolationLevelDB2Abbrev()\r
+ {\r
+ return isolationLevel;\r
+ }\r
+\r
+}\r
+\r
+OrderByList\r
+sortSpecificationList() throws StandardException :\r
+{ \r
+ OrderByList orderCols = (OrderByList) nodeFactory.getNode(\r
+ C_NodeTypes.ORDER_BY_LIST,\r
+ getContextManager()); \r
+}\r
+{\r
+ sortSpecification(orderCols) ( <COMMA> sortSpecification(orderCols) ) *\r
+ {\r
+ return orderCols;\r
+ }\r
+}\r
+\r
+void\r
+sortSpecification(OrderByList orderCols) throws StandardException :\r
+{ OrderByColumn orderCol; }\r
+{\r
+ orderCol = sortKey() /* [ collateClause() ] */ [ orderingSpecification(orderCol) ]\r
+ {\r
+ orderCols.addOrderByColumn(orderCol);\r
+ } \r
+}\r
+\r
+OrderByColumn\r
+sortKey() throws StandardException :\r
+{\r
+ ValueNode columnExpression;\r
+} \r
+{\r
+ columnExpression = additiveExpression(null,0,true)\r
+ {\r
+ return (OrderByColumn) nodeFactory.getNode(\r
+ C_NodeTypes.ORDER_BY_COLUMN,\r
+ columnExpression,\r
+ getContextManager());\r
+ }\r
+}\r
+\r
+\r
+\r
+void\r
+orderingSpecification(OrderByColumn orderCol) :\r
+{}\r
+{\r
+ <ASC> \r
+|\r
+ <DESC>\r
+ {\r
+ orderCol.setDescending();\r
+ }\r
+}\r
+\r
+/*\r
+ * <A NAME="forUpdateClause">forUpdateClause</A>\r
+ */\r
+int\r
+forUpdateClause(Vector columnList) throws StandardException :\r
+{\r
+ int retval;\r
+}\r
+{\r
+ <UPDATE> [ <OF> forUpdateColumnList(columnList) ]\r
+ {\r
+ return CursorNode.UPDATE;\r
+ }\r
+|\r
+ <READ> <ONLY>\r
+ {\r
+ return CursorNode.READ_ONLY;\r
+ }\r
+|\r
+ <FETCH> <ONLY>\r
+ {\r
+ return CursorNode.READ_ONLY;\r
+ }\r
+}\r
+\r
+/*\r
+ * <A NAME="forUpdateColumnList">forUpdateColumnList</A>\r
+ */\r
+void\r
+forUpdateColumnList(Vector columnList) throws StandardException :\r
+{\r
+}\r
+{\r
+ forUpdateColumn(columnList) ( <COMMA> forUpdateColumn(columnList) ) *\r
+}\r
+\r
+/*\r
+ * <A NAME="forUpdateColumn">forUpdateColumn</A>\r
+ */\r
+void\r
+forUpdateColumn(Vector columnList) throws StandardException :\r
+{\r
+ String columnName;\r
+}\r
+{\r
+ /* identifier() used to be columnName() */\r
+ columnName = identifier(Limits.MAX_IDENTIFIER_LENGTH, true)\r
+ {\r
+ columnList.addElement(columnName);\r
+ }\r
+}\r
+\r
+/*\r
+ * <A NAME="setClauseList">setClauseList</A>\r
+ */\r
+ResultColumnList\r
+setClauseList() throws StandardException :\r
+{\r
+ ResultColumnList columnList = (ResultColumnList) nodeFactory.getNode(\r
+ C_NodeTypes.RESULT_COLUMN_LIST,\r
+ getContextManager());\r
+}\r
+{\r
+ setClause(columnList) ( <COMMA> setClause(columnList) ) *\r
+ {\r
+ return columnList;\r
+ }\r
+}\r
+\r
+/*\r
+ * <A NAME="setClause">setClause</A>\r
+ */\r
+void\r
+setClause(ResultColumnList columnList) throws StandardException :\r
+{\r
+ ResultColumn resultColumn;\r
+ ColumnReference columnName;\r
+ ValueNode valueNode;\r
+}\r
+{\r
+ /* identifier() used to be objectColumn() */\r
+ /*\r
+ SQL92 only wants identifiers here (column names)\r
+ but JBuilder expects table.column, so we allow the\r
+ general form.\r
+ */\r
+ columnName = columnReference() <EQUALS_OPERATOR> valueNode = updateSource(columnName.getColumnName())\r
+ {\r
+ resultColumn = (ResultColumn) nodeFactory.getNode(\r
+ C_NodeTypes.RESULT_COLUMN,\r
+ columnName,\r
+ valueNode,\r
+ getContextManager());\r
+ columnList.addResultColumn(resultColumn);\r
+ }\r
+}\r
+\r
+/*\r
+ * <A NAME="updateSource">updateSource</A>\r
+ */\r
+ValueNode\r
+updateSource(String columnName) throws StandardException :\r
+{\r
+ ValueNode valueNode;\r
+}\r
+{\r
+ valueNode = additiveExpression(null,0, false) \r
+ {\r
+ return valueNode;\r
+ }\r
+|\r
+ valueNode = nullSpecification() \r
+ {\r
+ return valueNode;\r
+ }\r
+|\r
+ <_DEFAULT>\r
+ {\r
+ return (ValueNode) nodeFactory.getNode(\r
+ C_NodeTypes.DEFAULT_NODE,\r
+ columnName,\r
+ getContextManager());\r
+ }\r
+}\r
+\r
+/*\r
+ * <A NAME="nullSpecification">nullSpecification</A>\r
+ */\r
+ValueNode\r
+nullSpecification() throws StandardException :\r
+{}\r
+{\r
+ <NULL>\r
+ {\r
+ return (ValueNode) nodeFactory.getNode(\r
+ C_NodeTypes.UNTYPED_NULL_CONSTANT_NODE,\r
+ getContextManager());\r
+ }\r
+}\r
+\r
+\r
+/*\r
+ * <A NAME="insertColumnsAndSource">insertColumnsAndSource</A>\r
+ */\r
+StatementNode\r
+insertColumnsAndSource(QueryTreeNode targetTable) \r
+ throws StandardException :\r
+{\r
+ Properties targetProperties = null;\r
+ ResultSetNode queryExpression;\r
+ ResultColumnList columnList = null;\r
+}\r
+{\r
+ [\r
+ // This LOOKAHEAD is required because a query expression can\r
+ // be a SELECT or VALUES nested arbitrarily deep in parentheses\r
+ // (which looks like a subquery). So, to be sure that a left\r
+ // parenthesis introduces an insertColumnList(), we have to\r
+ // be sure it doesn't introduce a subquery.\r
+ LOOKAHEAD( { getToken(1).kind == LEFT_PAREN && ! subqueryFollows() } )\r
+ <LEFT_PAREN> columnList = insertColumnList() <RIGHT_PAREN>\r
+ ]\r
+ [ targetProperties = propertyList(false) <CHECK_PROPERTIES>]\r
+ queryExpression = queryExpression(null, NO_SET_OP)\r
+ {\r
+ return (StatementNode) nodeFactory.getNode(\r
+ C_NodeTypes.INSERT_NODE,\r
+ targetTable,\r
+ columnList,\r
+ queryExpression,\r
+ targetProperties,\r
+ getContextManager());\r
+ }\r
+ /* RESOLVE: Ignoring default values for now\r
+|\r
+ [ targetProperties = propertyList(false) <CHECK_PROPERTIES>]\r
+ <_DEFAULT> <VALUES>\r
+ {\r
+ return null;\r
+ }\r
+ */\r
+}\r
+\r
+/*\r
+ * <A NAME="insertColumnList">insertColumnList</A>\r
+ */\r
+ResultColumnList\r
+insertColumnList() throws StandardException :\r
+{\r
+ ResultColumnList columnList = (ResultColumnList) nodeFactory.getNode(\r
+ C_NodeTypes.RESULT_COLUMN_LIST,\r
+ getContextManager());\r
+}\r
+{\r
+ columnQualifiedNameList(columnList)\r
+ {\r
+ return columnList;\r
+ }\r
+}\r
+\r
+/*\r
+ * <A NAME="columnQualifiedNameList">columnQualifiedNameList</A>\r
+ */\r
+void\r
+columnQualifiedNameList(ResultColumnList columnList) throws StandardException :\r
+{}\r
+{\r
+ columnQualifiedNameItem(columnList) ( <COMMA> columnQualifiedNameItem(columnList) ) *\r
+}\r
+\r
+/*\r
+ * <A NAME="columnQualifiedNameItem">columnQualifiedNameItem</A>\r
+ */\r
+void\r
+columnQualifiedNameItem(ResultColumnList columnList) throws StandardException :\r
+{\r
+ ColumnReference columnRef;\r
+ ResultColumn resultColumn;\r
+}\r
+{\r
+ /*\r
+ SQL92 only wants identifiers here (column names)\r
+ but JBuilder expects table.column, so we allow the\r
+ general form.\r
+ */\r
+ columnRef = columnReference()\r
+ {\r
+ /*\r
+ ** Store the column names for the result columns in the\r
+ ** result column list. We don't know yet what valueNodes\r
+ ** should be hooked up to each result column, so set that\r
+ ** to null for now.\r
+ */\r
+ resultColumn = (ResultColumn) nodeFactory.getNode(\r
+ C_NodeTypes.RESULT_COLUMN,\r
+ columnRef,\r
+ null,\r
+ getContextManager());\r
+ columnList.addResultColumn(resultColumn);\r
+ }\r
+}\r
+\r
+/*\r
+ * <A NAME="rowValueConstructor">rowValueConstructor</A>\r
+ */\r
+ResultSetNode\r
+rowValueConstructor(ResultSetNode leftRSN) throws StandardException :\r
+{\r
+ ResultColumnList resultColumns = (ResultColumnList) nodeFactory.getNode(\r
+ C_NodeTypes.RESULT_COLUMN_LIST,\r
+ getContextManager());\r
+ ResultSetNode newRSN;\r
+}\r
+{\r
+ // This LOOKAHEAD is required because a rowValueConstructorList is\r
+ // nested in parentheses, and each element of the list can also be\r
+ // nested in an arbitrary number of parentheses.\r
+ LOOKAHEAD( { rowValueConstructorListFollows() } )\r
+ <LEFT_PAREN> rowValueConstructorList(resultColumns) <RIGHT_PAREN>\r
+ {\r
+ /* If leftRSN is null, simply return the newRSN, else generate and\r
+ * return a UNION ALL above the 2 RSNs, after verifying that the size()\r
+ * of both RSNs RCLs is the same.\r
+ */\r
+ newRSN = (ResultSetNode) nodeFactory.getNode(\r
+ C_NodeTypes.ROW_RESULT_SET_NODE,\r
+ resultColumns,\r
+ null,\r
+ getContextManager());\r
+ if (leftRSN != null)\r
+ {\r
+ if (leftRSN.getResultColumns().size() !=\r
+ newRSN.getResultColumns().size())\r
+ {\r
+ throw StandardException.newException(SQLState.LANG_ROW_VALUE_CONSTRUCTOR_UNMATCHED_COLUMNS);\r
+ }\r
+\r
+ newRSN = (ResultSetNode) nodeFactory.getNode( \r
+ C_NodeTypes.UNION_NODE,\r
+ leftRSN,\r
+ newRSN,\r
+ Boolean.TRUE,\r
+ Boolean.TRUE,\r
+ null,\r
+ getContextManager());\r
+ }\r
+ return newRSN;\r
+ \r
+ }\r
+|\r
+ rowValueConstructorElement(resultColumns)\r
+ {\r
+ /* If leftRSN is null, simply return the newRSN, else generate and\r
+ * return a UNION ALL above the 2 RSNs, after verifying that the size()\r
+ * of both RSNs RCLs is the same.\r
+ */\r
+ newRSN = (ResultSetNode) nodeFactory.getNode(\r
+ C_NodeTypes.ROW_RESULT_SET_NODE,\r
+ resultColumns,\r
+ null,\r
+ getContextManager());\r
+ if (leftRSN != null)\r
+ {\r
+ if (leftRSN.getResultColumns().size() !=\r
+ newRSN.getResultColumns().size())\r
+ {\r
+ throw StandardException.newException(SQLState.LANG_ROW_VALUE_CONSTRUCTOR_UNMATCHED_COLUMNS);\r
+ }\r
+\r
+ newRSN = (ResultSetNode) nodeFactory.getNode(\r
+ C_NodeTypes.UNION_NODE,\r
+ leftRSN,\r
+ newRSN,\r
+ Boolean.TRUE,\r
+ Boolean.TRUE,\r
+ null,\r
+ getContextManager());\r
+ }\r
+ return newRSN;\r
+ }\r
+}\r
+\r
+/*\r
+ * <A NAME="rowValueConstructorElement">rowValueConstructorElement</A>\r
+ */\r
+void\r
+rowValueConstructorElement(ResultColumnList resultColumns) throws StandardException :\r
+{\r
+ ValueNode value;\r
+}\r
+{\r
+ value = additiveExpression(null, 0, true)\r
+ {\r
+ resultColumns.addResultColumn(\r
+ (ResultColumn) nodeFactory.getNode(\r
+ C_NodeTypes.RESULT_COLUMN,\r
+ null,\r
+ value,\r
+ getContextManager())\r
+ );\r
+ }\r
+|\r
+ value = nullSpecification()\r
+ {\r
+ resultColumns.addResultColumn(\r
+ (ResultColumn) nodeFactory.getNode(\r
+ C_NodeTypes.RESULT_COLUMN,\r
+ null,\r
+ value,\r
+ getContextManager())\r
+ );\r
+ }\r
+|\r
+ <_DEFAULT>\r
+ {\r
+ resultColumns.addResultColumn(\r
+ (ResultColumn) nodeFactory.getNode(\r
+ C_NodeTypes.RESULT_COLUMN,\r
+ null,\r
+ (ValueNode) nodeFactory.getNode(\r
+ C_NodeTypes.DEFAULT_NODE,\r
+ null,\r
+ getContextManager()),\r
+ getContextManager())\r
+ );\r
+ }\r
+|\r
+ {\r
+ throw StandardException.newException(SQLState.LANG_EMPTY_VALUES_CLAUSE);\r
+ }\r
+}\r
+\r
+/*\r
+ * <A NAME="rowValueConstructorList">rowValueConstructorList</A>\r
+ */\r
+void\r
+rowValueConstructorList(ResultColumnList resultColumns) throws StandardException :\r
+{}\r
+{\r
+ rowValueConstructorElement(resultColumns)\r
+ ( <COMMA> rowValueConstructorElement(resultColumns) ) *\r
+}\r
+\r
+\r
+/*\r
+ * <A NAME="tableSubquery">tableSubquery</A>\r
+ */\r
+SubqueryNode\r
+tableSubquery(int subqueryType, ValueNode leftOperand) throws StandardException :\r
+{\r
+ SubqueryNode subqueryNode;\r
+}\r
+{\r
+ subqueryNode = subquery(subqueryType, leftOperand)\r
+ {\r
+ return subqueryNode;\r
+ }\r
+}\r
+\r
+\r
+/*\r
+ * <A NAME="subquery">subquery</A>\r
+ */\r
+SubqueryNode\r
+subquery(int subqueryType, ValueNode leftOperand) throws StandardException :\r
+{\r
+ ResultSetNode queryExpression;\r
+ SubqueryNode subqueryNode;\r
+}\r
+{\r
+ queryExpression = queryExpression(null, NO_SET_OP)\r
+ {\r
+ subqueryNode = (SubqueryNode) nodeFactory.getNode(\r
+ C_NodeTypes.SUBQUERY_NODE,\r
+ queryExpression, \r
+ ReuseFactory.getInteger(subqueryType),\r
+ leftOperand,\r
+ getContextManager());\r
+ return subqueryNode;\r
+ }\r
+}\r
+\r
+/*\r
+ * <A NAME="inPredicateValue">inPredicateValue</A>\r
+ */\r
+ValueNode\r
+inPredicateValue(ValueNode leftOperand) throws StandardException :\r
+{\r
+ ValueNode retval;\r
+ int tokKind;\r
+}\r
+{\r
+ <LEFT_PAREN>\r
+ (\r
+ // This LOOKAHEAD is necessary because both a subquery and an\r
+ // inValueList can be nested arbitrarily deep in parentheses,\r
+ // so both can start with LEFT_PAREN. To disambiguate, we only\r
+ // consider it a subquery if the first token that comes after\r
+ // all the LEFT_PARENS is either a SELECT or a VALUES.\r
+ LOOKAHEAD( { subqueryFollows() } )\r
+ retval = tableSubquery(SubqueryNode.IN_SUBQUERY, leftOperand)\r
+ |\r
+ retval = inValueList(leftOperand)\r
+ )\r
+ <RIGHT_PAREN>\r
+ {\r
+ return retval;\r
+ }\r
+}\r
+\r
+/*\r
+ * <A NAME="inValueList">inValueList</A>\r
+ */\r
+ValueNode\r
+inValueList(ValueNode leftOperand) throws StandardException:\r
+{\r
+ ValueNodeList inList = (ValueNodeList) nodeFactory.getNode(\r
+ C_NodeTypes.VALUE_NODE_LIST,\r
+ getContextManager());\r
+}\r
+{\r
+ inElement(inList) ( <COMMA> inElement(inList) ) *\r
+ {\r
+ return (ValueNode) nodeFactory.getNode(\r
+ C_NodeTypes.IN_LIST_OPERATOR_NODE,\r
+ leftOperand,\r
+ inList,\r
+ getContextManager());\r
+ }\r
+}\r
+\r
+/*\r
+ * <A NAME="inElement">inElement</A>\r
+ */\r
+void\r
+inElement(ValueNodeList inList) throws StandardException :\r
+{\r
+ ValueNode valueNode;\r
+}\r
+{\r
+ valueNode = additiveExpression(null, 0, false)\r
+ {\r
+ inList.addElement(valueNode);\r
+ }\r
+}\r
+\r
+\r
+/*\r
+ * <A NAME="quantifier">quantifier</A>\r
+ */\r
+int\r
+quantifier(int opType) throws StandardException :\r
+{\r
+ int retval = 0;\r
+}\r
+{\r
+ <ALL> \r
+ {\r
+ switch (opType)\r
+ {\r
+ case BinaryOperatorNode.EQ:\r
+ retval = SubqueryNode.EQ_ALL_SUBQUERY;\r
+ break;\r
+\r
+ case BinaryOperatorNode.NE:\r
+ retval = SubqueryNode.NE_ALL_SUBQUERY;\r
+ break;\r
+\r
+ case BinaryOperatorNode.LE:\r
+ retval = SubqueryNode.LE_ALL_SUBQUERY;\r
+ break;\r
+\r
+ case BinaryOperatorNode.LT:\r
+ retval = SubqueryNode.LT_ALL_SUBQUERY;\r
+ break;\r
+\r
+ case BinaryOperatorNode.GE:\r
+ retval = SubqueryNode.GE_ALL_SUBQUERY;\r
+ break;\r
+\r
+ case BinaryOperatorNode.GT:\r
+ retval = SubqueryNode.GT_ALL_SUBQUERY;\r
+ break;\r
+\r
+ default:\r
+ if (SanityManager.DEBUG)\r
+ SanityManager.THROWASSERT(\r
+ "Invalid value for opType (" + opType +\r
+ ") passed to quantifier()");\r
+ }\r
+ return retval;\r
+ }\r
+|\r
+ some()\r
+ {\r
+ switch (opType)\r
+ {\r
+ case BinaryOperatorNode.EQ:\r
+ retval = SubqueryNode.EQ_ANY_SUBQUERY;\r
+ break;\r
+\r
+ case BinaryOperatorNode.NE:\r
+ retval = SubqueryNode.NE_ANY_SUBQUERY;\r
+ break;\r
+\r
+ case BinaryOperatorNode.LE:\r
+ retval = SubqueryNode.LE_ANY_SUBQUERY;\r
+ break;\r
+\r
+ case BinaryOperatorNode.LT:\r
+ retval = SubqueryNode.LT_ANY_SUBQUERY;\r
+ break;\r
+\r
+ case BinaryOperatorNode.GE:\r
+ retval = SubqueryNode.GE_ANY_SUBQUERY;\r
+ break;\r
+\r
+ case BinaryOperatorNode.GT:\r
+ retval = SubqueryNode.GT_ANY_SUBQUERY;\r
+ break;\r
+\r
+ default:\r
+ if (SanityManager.DEBUG)\r
+ SanityManager.THROWASSERT(\r
+ "Invalid value for opType (" + opType +\r
+ ") passed to quantifier()");\r
+ }\r
+ return retval;\r
+ }\r
+}\r
+\r
+/*\r
+ * <A NAME="some">some</A>\r
+ */\r
+void\r
+some() throws StandardException :\r
+{}\r
+{\r
+ <SOME> |\r
+ <ANY>\r
+}\r
+\r
+/*\r
+ * <A NAME="existsExpression">existsExpression</A>\r
+ */\r
+SubqueryNode\r
+existsExpression() throws StandardException :\r
+{\r
+ SubqueryNode subqueryNode;\r
+}\r
+{\r
+ <EXISTS> <LEFT_PAREN>\r
+ subqueryNode = tableSubquery(SubqueryNode.EXISTS_SUBQUERY, null)\r
+ <RIGHT_PAREN>\r
+ {\r
+ return subqueryNode;\r
+ }\r
+}\r
+\r
+/*\r
+ * <A NAME="tableExpression">tableExpression</A>\r
+ */\r
+SelectNode\r
+tableExpression(ResultColumnList selectList) throws StandardException :\r
+{\r
+ SelectNode selectNode;\r
+ FromList fromList;\r
+ ValueNode whereClause = null;\r
+ GroupByList groupByList = null;\r
+ ValueNode havingClause = null;\r
+ Token whereToken;\r
+}\r
+{\r
+ fromList = fromClause()\r
+ [ whereToken = <WHERE> whereClause = whereClause(whereToken) ]\r
+ [ groupByList = groupByClause() ]\r
+ [ havingClause = havingClause() ]\r
+ {\r
+ \r
+ // fix for HAVING without GROUP BY, makes sure we get one\r
+ // aggregate operator by adding a count(*), this fixes beetle 5853, 5890\r
+ if (havingClause != null && groupByList == null) {\r
+ ValueNode vn = (ValueNode) nodeFactory.getNode(\r
+ C_NodeTypes.AGGREGATE_NODE,\r
+ null,\r
+ org.apache.derby.impl.sql.compile.CountAggregateDefinition.class,\r
+ Boolean.FALSE, // distinct Boolean.TRUE?\r
+ "COUNT(*)",\r
+ getContextManager());\r
+ AggregateNode n = (AggregateNode) vn;\r
+ n.replaceAggregatesWithColumnReferences(selectList, 0); \r
+ }\r
+ \r
+ selectNode = (SelectNode) nodeFactory.getNode(\r
+ C_NodeTypes.SELECT_NODE,\r
+ selectList,\r
+ null, /* AGGREGATE list */\r
+ fromList,\r
+ whereClause,\r
+ groupByList,\r
+ havingClause,\r
+ getContextManager());\r
+\r
+ return selectNode;\r
+ }\r
+}\r
+\r
+\r
+\r
+/*\r
+ * <A NAME="fromClause">fromClause</A>\r
+ */\r
+FromList\r
+fromClause() throws StandardException :\r
+{\r
+ FromList fromList = (FromList) nodeFactory.getNode(\r
+ C_NodeTypes.FROM_LIST,\r
+ getNodeFactory().doJoinOrderOptimization(),\r
+ getContextManager());\r
+ int tokKind;\r
+ Token beginToken;\r
+ Token endToken;\r
+}\r
+{\r
+ <FROM> {beginToken = getToken(1);}\r
+ [\r
+ fromListProperties(fromList)\r
+ ]\r
+ dummyTableReferenceRule(fromList)\r
+ ( <COMMA> dummyTableReferenceRule(fromList) ) * {endToken = getToken(0);}\r
+\r
+ {\r
+ fromList.setBeginOffset( beginToken.beginOffset);\r
+ fromList.setEndOffset( endToken.endOffset);\r
+ return fromList;\r
+ }\r
+}\r
+\r
+/*\r
+ * <A NAME="fromListProperties">fromListProperties</A>\r
+ */\r
+void\r
+fromListProperties(FromList fromList) throws StandardException :\r
+{\r
+ Properties properties;\r
+}\r
+{\r
+ properties = propertyList(true) <CHECK_PROPERTIES>\r
+ {\r
+ fromList.setProperties(properties);\r
+ }\r
+}\r
+\r
+/* This rule created simply as a way to add the result of tableReference()\r
+ * to the fromList.\r
+ */\r
+void\r
+dummyTableReferenceRule(FromList fromList) throws StandardException :\r
+{\r
+ FromTable tableReference;\r
+}\r
+{\r
+ /* If we have a table constructor and the expression is a SELECT\r
+ * query or a VALUES query then we read the <TABLE> keyword;\r
+ * otherwise we leave the <TABLE> token in the queue and let\r
+ * other types of expressions (namely, vtiTableConstruct())\r
+ * deal with it accordingly. DERBY-2152.\r
+ */\r
+ LOOKAHEAD({ getToken(1).kind == TABLE &&\r
+ getToken(2).kind == LEFT_PAREN &&\r
+ (\r
+ getToken(3).kind == SELECT ||\r
+ getToken(3).kind == VALUES\r
+ )\r
+ }) <TABLE>\r
+ tableReference = tableReferenceTypes(false)\r
+ {\r
+ fromList.addFromTable(tableReference);\r
+ }\r
+|\r
+ tableReference = tableReferenceTypes(false)\r
+ {\r
+ fromList.addFromTable(tableReference);\r
+ }\r
+}\r
+\r
+FromTable\r
+tableReferenceTypes(boolean nestedInParens) throws StandardException :\r
+{\r
+ FromTable tableReference;\r
+}\r
+{\r
+ tableReference = tableReference(nestedInParens)\r
+ {\r
+ return tableReference ;\r
+ }\r
+|\r
+ <LEFT_BRACE> <OJ> tableReference = tableReference(nestedInParens) <RIGHT_BRACE>\r
+ {\r
+ return tableReference;\r
+ }\r
+}\r
+\r
+Object[]\r
+optionalTableClauses() throws StandardException :\r
+{\r
+ Object[] otc = null;\r
+ Properties tableProperties = null;\r
+ ResultColumnList derivedRCL = null;\r
+ String correlationName = null;\r
+}\r
+{\r
+ otc = optionalTableProperties() \r
+ {\r
+ otc[OPTIONAL_TABLE_CLAUSES_DERIVED_RCL] = derivedRCL;\r
+ otc[OPTIONAL_TABLE_CLAUSES_CORRELATION_NAME] = correlationName;\r
+ return otc;\r
+ }\r
+|\r
+ [ [ <AS> ] \r
+ correlationName = identifier(Limits.MAX_IDENTIFIER_LENGTH, true)\r
+ [ <LEFT_PAREN> derivedRCL = derivedColumnList() <RIGHT_PAREN> ] \r
+ [tableProperties = propertyList(true) <CHECK_PROPERTIES>] ]\r
+ {\r
+ otc = new Object[OPTIONAL_TABLE_CLAUSES_SIZE];\r
+ otc[OPTIONAL_TABLE_CLAUSES_TABLE_PROPERTIES] = tableProperties;\r
+ otc[OPTIONAL_TABLE_CLAUSES_DERIVED_RCL] = derivedRCL;\r
+ otc[OPTIONAL_TABLE_CLAUSES_CORRELATION_NAME] = correlationName;\r
+ return otc;\r
+ }\r
+}\r
+\r
+Object[]\r
+optionalTableProperties() throws StandardException :\r
+{\r
+ Object[] otc = null;\r
+ Properties tableProperties = null;\r
+}\r
+{\r
+ tableProperties = propertyList(true) <CHECK_PROPERTIES> \r
+ {\r
+ otc = new Object[OPTIONAL_TABLE_CLAUSES_SIZE];\r
+ otc[OPTIONAL_TABLE_CLAUSES_TABLE_PROPERTIES] = tableProperties;\r
+ return otc;\r
+ }\r
+}\r
+\r
+/*\r
+ * <A NAME="tableReference">tableReference</A>\r
+ */\r
+FromTable\r
+tableReference(boolean nestedInParens) throws StandardException :\r
+{\r
+ JavaToSQLValueNode javaToSQLNode = null;\r
+ TableName tableName;\r
+ String correlationName = null;\r
+ ResultColumnList derivedRCL = null;\r
+ FromTable fromTable;\r
+ TableOperatorNode joinTable = null;\r
+ FromTable tableReference;\r
+ Object[] optionalTableClauses = new Object[OPTIONAL_TABLE_CLAUSES_SIZE];\r
+ Properties tableProperties = null;\r
+ ResultSetNode derivedTable;\r
+}\r
+{\r
+ /* NOTE: this rule has to come first in order to avoid making NEW\r
+ * a reserved word.\r
+ */\r
+ /* identifier() used to be correlationName() */\r
+ (LOOKAHEAD({ newInvocationFollows(1) }) javaToSQLNode = newInvocation()\r
+ | javaToSQLNode = vtiTableConstruct()\r
+ )\r
+ [ <AS> ] correlationName = identifier(Limits.MAX_IDENTIFIER_LENGTH, true)\r
+ [ <LEFT_PAREN> derivedRCL = derivedColumnList() <RIGHT_PAREN> ]\r
+ [ optionalTableClauses = optionalTableProperties() ]\r
+ (LOOKAHEAD( { joinedTableExpressionFollows() } )\r
+ joinTable = joinedTableExpression(\r
+ (joinTable != null) ?\r
+ joinTable :\r
+ (FromTable) nodeFactory.getNode(\r
+ C_NodeTypes.FROM_VTI,\r
+ javaToSQLNode.getJavaValueNode(), \r
+ correlationName,\r
+ derivedRCL, \r
+ ((optionalTableClauses != null) ? \r
+ (Properties) optionalTableClauses[OPTIONAL_TABLE_CLAUSES_TABLE_PROPERTIES] :\r
+ (Properties) null),\r
+ getContextManager()),\r
+ nestedInParens)) *\r
+ {\r
+ /* Build a derived table if not a join expression */\r
+ if (joinTable == null)\r
+ {\r
+ fromTable = (FromTable) nodeFactory.getNode(\r
+ C_NodeTypes.FROM_VTI,\r
+ javaToSQLNode.getJavaValueNode(), \r
+ correlationName,\r
+ derivedRCL, \r
+ ((optionalTableClauses != null) ? \r
+ (Properties) optionalTableClauses[OPTIONAL_TABLE_CLAUSES_TABLE_PROPERTIES] :\r
+ (Properties) null),\r
+ getContextManager()); \r
+ }\r
+ else\r
+ {\r
+ fromTable = joinTable;\r
+ }\r
+\r
+ return fromTable;\r
+ }\r
+|\r
+ /* identifier() used to be correlationName() */\r
+ tableName = qualifiedName(Limits.MAX_IDENTIFIER_LENGTH) \r
+ optionalTableClauses = optionalTableClauses()\r
+ (LOOKAHEAD( { joinedTableExpressionFollows() } )\r
+ joinTable = joinedTableExpression(\r
+ (joinTable != null) ?\r
+ joinTable :\r
+ (FromTable) nodeFactory.getNode(\r
+ C_NodeTypes.FROM_BASE_TABLE,\r
+ tableName,\r
+ (String) optionalTableClauses[OPTIONAL_TABLE_CLAUSES_CORRELATION_NAME],\r
+ (ResultColumnList) optionalTableClauses[OPTIONAL_TABLE_CLAUSES_DERIVED_RCL],\r
+ (Properties) optionalTableClauses[OPTIONAL_TABLE_CLAUSES_TABLE_PROPERTIES],\r
+ getContextManager()), \r
+ nestedInParens)) *\r
+ {\r
+ /* Build a from table if not a join expression */\r
+ if (joinTable == null)\r
+ {\r
+ fromTable = (FromTable) nodeFactory.getNode(\r
+ C_NodeTypes.FROM_BASE_TABLE,\r
+ tableName,\r
+ (String) optionalTableClauses[OPTIONAL_TABLE_CLAUSES_CORRELATION_NAME],\r
+ (ResultColumnList) optionalTableClauses[OPTIONAL_TABLE_CLAUSES_DERIVED_RCL],\r
+ (Properties) optionalTableClauses[OPTIONAL_TABLE_CLAUSES_TABLE_PROPERTIES],\r
+ getContextManager());\r
+ }\r
+ else\r
+ { \r
+ fromTable = joinTable;\r
+ }\r
+ return fromTable;\r
+ }\r
+|\r
+ // There is a grammar ambiguity with nested parentheses here.\r
+ // A series of left parentheses could introduce either a table\r
+ // reference or a derived table. For example:\r
+ //\r
+ // (((select c from t) a inner join (select d from s) b ))\r
+ //\r
+ // and:\r
+ //\r
+ // (((select c from t) a)))\r
+ //\r
+ // To distinguish these two cases, we consider anything that starts\r
+ // with a single parenthesis and either SELECT or VALUES to be\r
+ // a derived table, and anything else to be a table reference.\r
+ // Note that we can't use the subqueryFollows() lookahead method,\r
+ // because it skips over all leading left parentheses to decide\r
+ // whether a subquery follows.\r
+ LOOKAHEAD( {\r
+ getToken(1).kind == LEFT_PAREN &&\r
+ (\r
+ getToken(2).kind == SELECT ||\r
+ getToken(2).kind == VALUES\r
+ )\r
+ } )\r
+ derivedTable = derivedTable() [ <AS> ] correlationName = identifier(Limits.MAX_IDENTIFIER_LENGTH, true)\r
+ [ <LEFT_PAREN> derivedRCL = derivedColumnList() <RIGHT_PAREN> ]\r
+ [ optionalTableClauses = optionalTableProperties() ]\r
+ ( LOOKAHEAD( { joinedTableExpressionFollows() } )\r
+ joinTable = joinedTableExpression(\r
+ (joinTable != null) ?\r
+ joinTable :\r
+ (FromTable) nodeFactory.getNode(\r
+ C_NodeTypes.FROM_SUBQUERY,\r
+ derivedTable, \r
+ correlationName,\r
+ derivedRCL,\r
+ ((optionalTableClauses != null) ?\r
+ (Properties) optionalTableClauses[OPTIONAL_TABLE_CLAUSES_TABLE_PROPERTIES] :\r
+ (Properties) null),\r
+ getContextManager()),\r
+ nestedInParens)) *\r
+ {\r
+ /* Build a derived table if not a join expression */\r
+ if (joinTable == null)\r
+ {\r
+ fromTable = (FromTable) nodeFactory.getNode(\r
+ C_NodeTypes.FROM_SUBQUERY,\r
+ derivedTable, \r
+ correlationName,\r
+ derivedRCL,\r
+ ((optionalTableClauses != null) ?\r
+ (Properties) optionalTableClauses[OPTIONAL_TABLE_CLAUSES_TABLE_PROPERTIES] :\r
+ (Properties) null),\r
+ getContextManager()); \r
+ }\r
+ else\r
+ {\r
+ fromTable = joinTable;\r
+ }\r
+\r
+ return fromTable;\r
+ }\r
+|\r
+ <LEFT_PAREN> tableReference = tableReferenceTypes(true) <RIGHT_PAREN>\r
+ ( LOOKAHEAD( { joinedTableExpressionFollows() } )\r
+ joinTable = joinedTableExpression(\r
+ (joinTable != null) ?\r
+ joinTable :\r
+ tableReference,\r
+ nestedInParens)) *\r
+ {\r
+ if (joinTable == null)\r
+ {\r
+ fromTable = tableReference; \r
+ }\r
+ else\r
+ {\r
+ fromTable = joinTable;\r
+ }\r
+\r
+ return fromTable;\r
+ }\r
+}\r
+\r
+/*\r
+ * <A NAME="derivedColumnList">derivedColumnList</A>\r
+ */\r
+ResultColumnList\r
+derivedColumnList() throws StandardException :\r
+{\r
+ ResultColumnList resultColumns =\r
+ (ResultColumnList) nodeFactory.getNode(\r
+ C_NodeTypes.RESULT_COLUMN_LIST,\r
+ getContextManager());\r
+}\r
+{\r
+ columnNameList(resultColumns)\r
+ {\r
+ return resultColumns;\r
+ }\r
+}\r
+\r
+/*\r
+ * <A NAME="columnNameList">columnNameList</A>\r
+ */\r
+void\r
+columnNameList(ResultColumnList columnList) throws StandardException :\r
+{}\r
+{\r
+ columnNameItem(columnList) ( <COMMA> columnNameItem(columnList) ) *\r
+}\r
+\r
+/*\r
+ * <A NAME="columnNameItem">columnNameItem</A>\r
+ */\r
+void\r
+columnNameItem(ResultColumnList columnList) throws StandardException :\r
+{\r
+ String columnName;\r
+ ResultColumn resultColumn;\r
+}\r
+{\r
+ /* identifier() used to be columnName() */\r
+ columnName = identifier(Limits.MAX_IDENTIFIER_LENGTH, true)\r
+ {\r
+ /*\r
+ ** Store the column names for the result columns in the\r
+ ** result column list. We don't know yet what valueNodes\r
+ ** should be hooked up to each result column, so set that\r
+ ** to null for now.\r
+ */\r
+ resultColumn = (ResultColumn) nodeFactory.getNode(\r
+ C_NodeTypes.RESULT_COLUMN,\r
+ columnName,\r
+ null,\r
+ getContextManager());\r
+ columnList.addResultColumn(resultColumn);\r
+ }\r
+}\r
+\r
+/*\r
+ * <A NAME="indexColumnList">indexColumnList</A>\r
+ */\r
+void\r
+indexColumnList(Vector columnList) throws StandardException :\r
+{}\r
+{\r
+ indexColumnItem(columnList) ( <COMMA> indexColumnItem(columnList) ) *\r
+}\r
+\r
+/*\r
+ * <A NAME="indexColumnItem">indexColumnItem</A>\r
+ */\r
+void\r
+indexColumnItem(Vector columnList) throws StandardException :\r
+{\r
+ String columnName;\r
+}\r
+{\r
+ /* identifier never ends with a space; appending a space meaning desc */\r
+ columnName = identifier(Limits.MAX_IDENTIFIER_LENGTH, true) [<ASC> | <DESC> {columnName = columnName + ' ';}]\r
+ {\r
+ /*\r
+ ** Store the column names for the index columns in the\r
+ ** index column list.\r
+ */\r
+ columnList.addElement(columnName);\r
+ }\r
+}\r
+\r
+/*\r
+ * <A NAME="derivedTable">derivedTable</A>\r
+ */\r
+ResultSetNode\r
+derivedTable() throws StandardException :\r
+{\r
+ SubqueryNode tableSubquery;\r
+}\r
+{\r
+ <LEFT_PAREN>\r
+ tableSubquery = tableSubquery(SubqueryNode.FROM_SUBQUERY, null)\r
+ <RIGHT_PAREN>\r
+ {\r
+ return tableSubquery.getResultSet();\r
+ }\r
+}\r
+\r
+TableOperatorNode\r
+joinedTableExpression(ResultSetNode leftRSN, boolean nestedInParens) throws StandardException :\r
+{\r
+ TableOperatorNode joinNode;\r
+}\r
+{\r
+ joinNode = qualifiedJoin(leftRSN, nestedInParens) \r
+ {\r
+ return joinNode;\r
+ }\r
+}\r
+\r
+TableOperatorNode\r
+qualifiedJoin(ResultSetNode leftRSN, boolean nestedInParens) throws StandardException :\r
+{\r
+ int joinType = JoinNode.INNERJOIN;\r
+ ResultSetNode rightRSN;\r
+ TableOperatorNode ton = null;\r
+ Object[] onOrUsingClause = null;\r
+ ResultColumnList usingClause = null;\r
+ ValueNode onClause;\r
+}\r
+{\r
+ /* RESOLVE - If we ever support NATURAL JOIN then we will need to break up\r
+ * this rule. Right now the joinSpecification() is non-optional. This\r
+ * allows us to build the Join tree from left to right. With NATURAL JOINS\r
+ * there is no joinSpecification() and we would want to build the tree from\r
+ * right to left.\r
+ */\r
+ //[ <NATURAL> ] \r
+ [ joinType = joinType() ] <JOIN>\r
+ rightRSN = tableReferenceTypes(nestedInParens) \r
+ onOrUsingClause = joinSpecification(leftRSN, rightRSN)\r
+ {\r
+ /* If NATURAL OR UNION is specified, then no joinSpecification()\r
+ * is required, otherwise it is required.\r
+ */\r
+\r
+ /* RESOLVE - Since we don't support NATURAL or UNION joins yet,\r
+ * onOrUsingClause must be non-null. (Change error message if and\r
+ * when grammar changes.)\r
+ */\r
+\r
+ /* Figure out whether an ON or USING clause was used */\r
+ onClause = (ValueNode) onOrUsingClause[ON_CLAUSE];\r
+ usingClause = (ResultColumnList) onOrUsingClause[USING_CLAUSE];\r
+\r
+ if (onClause == null && usingClause == null)\r
+ {\r
+ throw StandardException.newException(SQLState.LANG_MISSING_JOIN_SPECIFICATION, \r
+ JoinNode.joinTypeToString(joinType));\r
+ }\r
+\r
+ switch(joinType)\r
+ {\r
+ case JoinNode.INNERJOIN:\r
+ ton = (TableOperatorNode) nodeFactory.getNode(\r
+ C_NodeTypes.JOIN_NODE,\r
+ leftRSN,\r
+ rightRSN,\r
+ onClause,\r
+ usingClause,\r
+ null,\r
+ null,\r
+ null,\r
+ getContextManager());\r
+ break;\r
+\r
+ case JoinNode.LEFTOUTERJOIN:\r
+ ton = (TableOperatorNode) nodeFactory.getNode(\r
+ C_NodeTypes.HALF_OUTER_JOIN_NODE,\r
+ leftRSN,\r
+ rightRSN,\r
+ onClause,\r
+ usingClause,\r
+ Boolean.FALSE,\r
+ null,\r
+ getContextManager());\r
+ break;\r
+\r
+ case JoinNode.RIGHTOUTERJOIN:\r
+ ton = (TableOperatorNode) nodeFactory.getNode(\r
+ C_NodeTypes.HALF_OUTER_JOIN_NODE,\r
+ leftRSN,\r
+ rightRSN,\r
+ onClause,\r
+ usingClause,\r
+ Boolean.TRUE,\r
+ null,\r
+ getContextManager());\r
+ break;\r
+\r
+\r
+ default:\r
+ if (SanityManager.DEBUG)\r
+ {\r
+ SanityManager.ASSERT(false, "Unexpected joinType");\r
+ }\r
+ return null;\r
+ }\r
+\r
+ /* Mark whether or not we are nested within parens */\r
+ ton.setNestedInParens(nestedInParens);\r
+ return ton;\r
+ }\r
+}\r
+\r
+int\r
+joinType() throws StandardException :\r
+{\r
+ int joinType;\r
+}\r
+{\r
+ <INNER> \r
+ {\r
+ return JoinNode.INNERJOIN;\r
+ }\r
+|\r
+ joinType = outerJoinType() [<OUTER>]\r
+ {\r
+ return joinType;\r
+ }\r
+}\r
+\r
+int\r
+outerJoinType() throws StandardException :\r
+{}\r
+{\r
+ <LEFT> \r
+ {\r
+ return JoinNode.LEFTOUTERJOIN;\r
+ }\r
+|\r
+ <RIGHT> \r
+ {\r
+ return JoinNode.RIGHTOUTERJOIN;\r
+ }\r
+}\r
+\r
+Object[]\r
+joinSpecification(ResultSetNode leftRSN, ResultSetNode rightRSN) \r
+ throws StandardException :\r
+{\r
+ Object[] onOrUsingClause = new Object[ON_OR_USING_CLAUSE_SIZE];\r
+ ResultColumnList usingClause = null;\r
+ ValueNode joinClause = null;\r
+}\r
+{\r
+ joinClause = joinCondition() \r
+ {\r
+ onOrUsingClause[ON_CLAUSE] = joinClause;\r
+ onOrUsingClause[USING_CLAUSE] = usingClause;\r
+ return onOrUsingClause;\r
+ }\r
+}\r
+\r
+ValueNode\r
+joinCondition() throws StandardException :\r
+{\r
+ ValueNode joinClause;\r
+}\r
+{\r
+ /* valueExpression() was searchCondition() */\r
+ <ON> joinClause = valueExpression(false)\r
+ {\r
+ return joinClause;\r
+ }\r
+}\r
+\r
+/*\r
+ * <A NAME="tableValueConstructor">tableValueConstructor</A>\r
+ */\r
+ResultSetNode\r
+tableValueConstructor() throws StandardException :\r
+{\r
+ ResultSetNode resultSetNode;\r
+}\r
+{\r
+ <VALUES> resultSetNode = tableValueConstructorList()\r
+ {\r
+ return resultSetNode;\r
+ }\r
+}\r
+\r
+/*\r
+ * <A NAME="tableValueConstructorList">tableValueConstructorList</A>\r
+ */\r
+ResultSetNode\r
+tableValueConstructorList() throws StandardException :\r
+{\r
+ ResultSetNode resultSetNode;\r
+}\r
+{\r
+ resultSetNode = rowValueConstructor(null) \r
+ ( <COMMA> resultSetNode = rowValueConstructor(resultSetNode) ) *\r
+ {\r
+ if (resultSetNode instanceof UnionNode)\r
+ {\r
+ ((UnionNode) resultSetNode).markTopTableConstructor();\r
+ }\r
+\r
+ return resultSetNode;\r
+ }\r
+}\r
+\r
+/*\r
+ * <A NAME="explicitTable">explicitTable</A>\r
+ */\r
+\r
+/*\r
+ * <A NAME="datetimeValueFunction">datetimeValueFunction</A>\r
+ */\r
+ValueNode\r
+datetimeValueFunction() throws StandardException :\r
+{\r
+ int prec = -1; // can't be negative, if used\r
+}\r
+{\r
+ LOOKAHEAD({(getToken(1).kind == CURRENT && getToken(2).kind == DATE)}) <CURRENT> <DATE> \r
+ {\r
+ return (ValueNode) nodeFactory.getNode(\r
+ C_NodeTypes.CURRENT_DATETIME_OPERATOR_NODE,\r
+ ReuseFactory.getInteger(\r
+ CurrentDatetimeOperatorNode.CURRENT_DATE),\r
+ getContextManager());\r
+ }\r
+ | <CURRENT_DATE>\r
+ {\r
+ return (ValueNode) nodeFactory.getNode(\r
+ C_NodeTypes.CURRENT_DATETIME_OPERATOR_NODE,\r
+ ReuseFactory.getInteger(\r
+ CurrentDatetimeOperatorNode.CURRENT_DATE),\r
+ getContextManager());\r
+ }\r
+|\r
+ LOOKAHEAD({(getToken(1).kind == CURRENT && getToken(2).kind == TIME)}) <CURRENT> <TIME> \r
+ {\r
+ return (ValueNode) nodeFactory.getNode(\r
+ C_NodeTypes.CURRENT_DATETIME_OPERATOR_NODE,\r
+ ReuseFactory.getInteger(\r
+ CurrentDatetimeOperatorNode.CURRENT_TIME),\r
+ getContextManager());\r
+ }\r
+ | <CURRENT_TIME> \r
+ {\r
+ return (ValueNode) nodeFactory.getNode(\r
+ C_NodeTypes.CURRENT_DATETIME_OPERATOR_NODE,\r
+ ReuseFactory.getInteger(\r
+ CurrentDatetimeOperatorNode.CURRENT_TIME),\r
+ getContextManager());\r
+ }\r
+|\r
+ LOOKAHEAD({(getToken(1).kind == CURRENT && getToken(2).kind == TIMESTAMP)}) <CURRENT> <TIMESTAMP> \r
+ {\r
+ return (ValueNode) nodeFactory.getNode(\r
+ C_NodeTypes.CURRENT_DATETIME_OPERATOR_NODE,\r
+ ReuseFactory.getInteger(\r
+ CurrentDatetimeOperatorNode.CURRENT_TIMESTAMP),\r
+ getContextManager());\r
+ }\r
+ | <CURRENT_TIMESTAMP> \r
+ {\r
+ return (ValueNode) nodeFactory.getNode(\r
+ C_NodeTypes.CURRENT_DATETIME_OPERATOR_NODE,\r
+ ReuseFactory.getInteger(\r
+ CurrentDatetimeOperatorNode.CURRENT_TIMESTAMP),\r
+ getContextManager());\r
+ }\r
+}\r
+\r
+/*\r
+** Note that set function and aggregate are used\r
+** interchangeably in the parser. The tree has\r
+** aggregate nodes.\r
+*/\r
+ValueNode\r
+aggregateNode() throws StandardException :\r
+{\r
+ ValueNode agg;\r
+}\r
+{\r
+ <COUNT> <LEFT_PAREN>\r
+ ( <ASTERISK>\r
+ {\r
+ agg = (ValueNode) nodeFactory.getNode(\r
+ C_NodeTypes.AGGREGATE_NODE,\r
+ null,\r
+ CountAggregateDefinition.class, \r
+ Boolean.FALSE,\r
+ "COUNT(*)",\r
+ getContextManager());\r
+ }\r
+ |\r
+ agg = aggregateExpression("COUNT", CountAggregateDefinition.class)\r
+ )\r
+ <RIGHT_PAREN>\r
+ {\r
+ return agg;\r
+ }\r
+|\r
+ agg = generalAggregate()\r
+ {\r
+ return agg;\r
+ }\r
+}\r
+\r
+\r
+\r
+ValueNode\r
+aggregateExpression(String aggName, Class aggClass) throws StandardException :\r
+{\r
+ boolean distinct = false;\r
+ ValueNode value;\r
+}\r
+{\r
+ [ distinct = setQuantifier() ] value = additiveExpression(null, 0, false)\r
+ {\r
+ return (ValueNode) nodeFactory.getNode(\r
+ C_NodeTypes.AGGREGATE_NODE,\r
+ value,\r
+ aggClass, \r
+ distinct ? Boolean.TRUE : Boolean.FALSE,\r
+ aggName,\r
+ getContextManager());\r
+ }\r
+}\r
+\r
+ValueNode\r
+generalAggregate() throws StandardException :\r
+{\r
+ Token aggToken;\r
+ String methodAliasString;\r
+ ValueNode aggExpr;\r
+ ValueNode value;\r
+}\r
+{\r
+ aggToken = builtInAggregateType()\r
+ <LEFT_PAREN>\r
+ aggExpr = aggregateExpression(aggName(aggToken), aggClass(aggToken))\r
+ <RIGHT_PAREN>\r
+ {\r
+ return aggExpr;\r
+ }\r
+}\r
+\r
+/*\r
+** All built in aggregates are pretty similar to user\r
+** defined aggregates, except we know what to map to\r
+** without looking up the class name.\r
+**\r
+** NOTE: COUNT is omitted here because the COUNT aggregate is\r
+** factored into a different rule, to distinguish between\r
+** COUNT(*) and COUNT(<expression>).\r
+*/\r
+Token\r
+builtInAggregateType() throws StandardException :\r
+{\r
+ Token retval;\r
+}\r
+{\r
+ (\r
+ retval = <MAX> |\r
+ retval = <AVG> |\r
+ retval = <MIN> |\r
+ retval = <SUM>\r
+ )\r
+ {\r
+ return retval;\r
+ }\r
+}\r
+\r
+ValueNode\r
+castSpecification() throws StandardException :\r
+{\r
+ DataTypeDescriptor dts;\r
+ ValueNode treeTop;\r
+ ValueNode value;\r
+ int charType;\r
+ int length = -1;\r
+}\r
+{\r
+ <CAST> <LEFT_PAREN> value = castOperand() <AS> dts = dataTypeCast() <RIGHT_PAREN>\r
+ {\r
+ treeTop = (ValueNode) nodeFactory.getNode(\r
+ C_NodeTypes.CAST_NODE,\r
+ value,\r
+ dts,\r
+ getContextManager());\r
+ ((CastNode) treeTop).setForExternallyGeneratedCASTnode();\r
+\r
+ /* We need to generate a SQL->Java conversion tree above us if\r
+ * the dataTypeCast is a user type.\r
+ */\r
+ if (dts.getTypeId().userType())\r
+ {\r
+ treeTop = (ValueNode) nodeFactory.getNode(\r
+ C_NodeTypes.JAVA_TO_SQL_VALUE_NODE,\r
+ nodeFactory.getNode(\r
+ C_NodeTypes.SQL_TO_JAVA_VALUE_NODE,\r
+ treeTop,\r
+ getContextManager()),\r
+ getContextManager());\r
+ }\r
+\r
+ return treeTop;\r
+ }\r
+ \r
+}\r
+\r
+/*\r
+ * <A NAME="charOrVarchar">charOrVarchar</A>\r
+ */\r
+int\r
+charOrVarchar() :\r
+{\r
+}\r
+{\r
+ <CHAR>\r
+ {\r
+ return Types.CHAR;\r
+ }\r
+|\r
+ <VARCHAR>\r
+ {\r
+ return Types.VARCHAR;\r
+ }\r
+}\r
+\r
+ValueNode\r
+castOperand() throws StandardException :\r
+{\r
+ ValueNode value;\r
+}\r
+{\r
+ value = additiveExpression(null, 0, false)\r
+ {\r
+ return value;\r
+ }\r
+|\r
+ <NULL>\r
+ {\r
+ return (ValueNode) nodeFactory.getNode(\r
+ C_NodeTypes.UNTYPED_NULL_CONSTANT_NODE,\r
+ getContextManager());\r
+ }\r
+}\r
+\r
+\r
+/*\r
+ * <A NAME="dynamicParameterSpecification">dynamicParameterSpecification</A>\r
+ */\r
+ParameterNode\r
+dynamicParameterSpecification() throws StandardException :\r
+{}\r
+{\r
+ <QUESTION_MARK>\r
+ {\r
+ return makeParameterNode( );\r
+ }\r
+}\r
+\r
+/*\r
+ * <A NAME="whereClause">whereClause</A>\r
+ */\r
+ValueNode\r
+whereClause(Token beginToken) throws StandardException :\r
+{\r
+ ValueNode value;\r
+ Token endToken;\r
+}\r
+{\r
+ /* valueExpression() was searchCondition() */\r
+ value = valueExpression(false)\r
+ {\r
+ endToken = getToken(0);\r
+\r
+ value.setBeginOffset( beginToken.endOffset + 1 );\r
+ value.setEndOffset( endToken.endOffset );\r
+\r
+ return value;\r
+ }\r
+}\r
+\r
+GroupByList\r
+groupByClause() throws StandardException :\r
+{\r
+ GroupByList groupingCols;\r
+}\r
+{\r
+ <GROUP> <BY> groupingCols = groupingColumnReferenceList()\r
+ {\r
+ return groupingCols;\r
+ }\r
+}\r
+\r
+GroupByList\r
+groupingColumnReferenceList() throws StandardException :\r
+{\r
+ GroupByList groupingCols = (GroupByList) nodeFactory.getNode(\r
+ C_NodeTypes.GROUP_BY_LIST,\r
+ getContextManager());\r
+}\r
+{\r
+ groupingColumnReference(groupingCols) ( <COMMA> groupingColumnReference(groupingCols) ) *\r
+ {\r
+ return groupingCols;\r
+ }\r
+}\r
+\r
+void\r
+groupingColumnReference(GroupByList groupingCols) throws StandardException :\r
+{\r
+ ValueNode columnExpression;\r
+}\r
+{\r
+ columnExpression = additiveExpression(null, 0, false)\r
+ {\r
+ if (columnExpression.isParameterNode()) \r
+ {\r
+ throw StandardException.newException(SQLState.LANG_SYNTAX_ERROR, "?");\r
+ }\r
+ if (columnExpression instanceof AggregateNode)\r
+ {\r
+ AggregateNode agNode = (AggregateNode)columnExpression;\r
+ throw StandardException.newException(\r
+ SQLState.LANG_AGGREGATE_IN_GROUPBY_LIST, \r
+ agNode.getAggregateName());\r
+ } \r
+ groupingCols.addGroupByColumn(\r
+ (GroupByColumn) nodeFactory.getNode(\r
+ C_NodeTypes.GROUP_BY_COLUMN,\r
+ columnExpression,\r
+ getContextManager()));\r
+ }\r
+}\r
+\r
+ValueNode\r
+havingClause() throws StandardException :\r
+{\r
+ ValueNode value;\r
+}\r
+{\r
+ /* valueExpression() was searchCondition() */\r
+ <HAVING> value = valueExpression(false)\r
+ {\r
+ return value;\r
+ }\r
+}\r
+\r
+StatementNode\r
+schemaDefinition() throws StandardException :\r
+{\r
+ String schemaName = null;\r
+ String authName = null;\r
+}\r
+{\r
+ /*\r
+ ** CREATE SCHEMA:\r
+ ** We are not currently handling character set\r
+ ** specifications for schema, or schema bodies.\r
+ */\r
+ <SCHEMA>\r
+ ( schemaName = identifier(Limits.MAX_IDENTIFIER_LENGTH, true) [ <AUTHORIZATION> authName = identifier(Limits.MAX_IDENTIFIER_LENGTH, true) ]\r
+ {\r
+ if (authName != null)\r
+ checkVersion( DataDictionary.DD_VERSION_DERBY_10_2, "AUTHORIZATION");\r
+\r
+ if (schemaName.startsWith("SYS"))\r
+ throw StandardException.newException(SQLState.INVALID_SCHEMA_SYS, schemaName);\r
+ \r
+ return (StatementNode) nodeFactory.getNode(\r
+ C_NodeTypes.CREATE_SCHEMA_NODE,\r
+ schemaName,\r
+ authName,\r
+ getContextManager()\r
+ );\r
+ }\r
+ |\r
+ <AUTHORIZATION> authName = identifier(Limits.MAX_IDENTIFIER_LENGTH, true) \r
+ {\r
+ checkVersion( DataDictionary.DD_VERSION_DERBY_10_2, "AUTHORIZATION");\r
+ if (authName.startsWith("SYS"))\r
+ throw StandardException.newException(SQLState.INVALID_SCHEMA_SYS, authName);\r
+\r
+ return (StatementNode) nodeFactory.getNode(\r
+ C_NodeTypes.CREATE_SCHEMA_NODE,\r
+ authName,\r
+ authName,\r
+ getContextManager()\r
+ );\r
+ }\r
+ )\r
+}\r
+\r
+/*\r
+ * <A NAME="tableDefinition">tableDefinition</A>\r
+ */\r
+StatementNode\r
+tableDefinition() throws StandardException :\r
+{\r
+ char lockGranularity = TableDescriptor.DEFAULT_LOCK_GRANULARITY;\r
+ Properties properties = null;\r
+ TableName tableName;\r
+ TableElementList tableElementList;\r
+ ResultColumnList resultColumns = null;\r
+ ResultSetNode queryExpression;\r
+ boolean withData = true;\r
+}\r
+{\r
+ <TABLE> tableName = qualifiedName(Limits.MAX_IDENTIFIER_LENGTH)\r
+ // Lookahead needed to choose between\r
+ // tableElementList and tableColumnList\r
+ ( LOOKAHEAD({getToken(1).kind == LEFT_PAREN && \r
+ getToken(3).kind != COMMA &&\r
+ getToken(3).kind != RIGHT_PAREN})\r
+ tableElementList = tableElementList()\r
+ [ properties = propertyList(false)<CHECK_PROPERTIES>]\r
+ {\r
+ return (StatementNode) nodeFactory.getNode(\r
+ C_NodeTypes.CREATE_TABLE_NODE,\r
+ tableName,\r
+ tableElementList,\r
+ properties,\r
+ new Character(lockGranularity),\r
+ getContextManager());\r
+ }\r
+ |\r
+ [ <LEFT_PAREN> resultColumns = tableColumnList() <RIGHT_PAREN> ]\r
+ <AS>\r
+ queryExpression = queryExpression(null, NO_SET_OP)\r
+ <WITH> [ <NO> { withData = false; } ] <DATA>\r
+ {\r
+ // Raise error if WITH DATA is specified\r
+ // (until it is implemented)\r
+ if (withData) {\r
+ throw StandardException.newException(\r
+ SQLState.NOT_IMPLEMENTED, "WITH DATA");\r
+ }\r
+ /* Parameters not allowed in create table */\r
+ HasNodeVisitor visitor =\r
+ new HasNodeVisitor(ParameterNode.class);\r
+ queryExpression.accept(visitor);\r
+ if (visitor.hasNode())\r
+ {\r
+ throw StandardException.newException(\r
+ SQLState.LANG_NO_PARAMS_IN_TABLES);\r
+ }\r
+ \r
+ return (StatementNode) nodeFactory.getNode(\r
+ C_NodeTypes.CREATE_TABLE_NODE,\r
+ tableName,\r
+ resultColumns,\r
+ queryExpression,\r
+ getContextManager());\r
+ }\r
+ )\r
+}\r
+\r
+ResultColumnList\r
+tableColumnList() throws StandardException :\r
+{\r
+ ResultColumnList resultColumns = (ResultColumnList) nodeFactory.getNode(\r
+ C_NodeTypes.RESULT_COLUMN_LIST,\r
+ getContextManager());\r
+}\r
+{\r
+ columnNameList(resultColumns)\r
+ {\r
+ return resultColumns;\r
+ }\r
+}\r
+\r
+/*\r
+ * This method is called when a comment starting with --derby-properties is found.\r
+ * Such a comment is a special directive to Derby and allows a sql to pass optimizer\r
+ * overrides. Derby looks for propertyName=value [,propertyName=value]* after\r
+ * --derby-properties and returns these properties in a Properties object as a return \r
+ * value of this method.\r
+ * The param propertiesUseAllowed true indicates that users are allowed to \r
+ * specify optimizer overrides in the given context. \r
+ * False means optimizer overrides in the given context are allowed internally \r
+ * only eg impl/load/import.java specifies property insertMode=replace/bulkInsert\r
+ * in the insert statement. This same property will not be acceptable from an \r
+ * insert statement from a user sql.\r
+ */\r
+Properties\r
+propertyList(boolean propertiesUseAllowed) throws StandardException :\r
+{\r
+ Properties properties = new FormatableProperties();\r
+ StringTokenizer commaSeparatedProperties;\r
+ StringTokenizer equalOperatorSeparatedProperty;\r
+}\r
+{\r
+ <DERBYDASHPROPERTIES> {\r
+ //first use StringTokenizer to get tokens which are delimited by ,s\r
+ commaSeparatedProperties = new StringTokenizer(getToken(1).image,",");\r
+ while (commaSeparatedProperties.hasMoreTokens()) {\r
+ //Now verify that tokens delimited by ,s follow propertyName=value pattern\r
+ String currentProperty = commaSeparatedProperties.nextToken();\r
+ equalOperatorSeparatedProperty = new StringTokenizer(currentProperty,"=", true);\r
+ if (equalOperatorSeparatedProperty.countTokens() != 3)\r
+ throw StandardException.newException(SQLState.PROPERTY_SYNTAX_INVALID);\r
+ else {\r
+ String key = equalOperatorSeparatedProperty.nextToken().trim();\r
+ if (!equalOperatorSeparatedProperty.nextToken().equals("="))\r
+ throw StandardException.newException(SQLState.PROPERTY_SYNTAX_INVALID);\r
+ String value = equalOperatorSeparatedProperty.nextToken().trim();\r
+ verifyImageLength(value);\r
+ /* Trim off the leading and trailing ', and compress all '' to ' */\r
+ if (value.startsWith("'") && value.endsWith("'"))\r
+ value = compressQuotes(value.substring(1, value.length() - 1), SINGLEQUOTES);\r
+ /* Trim off the leading and trailing ", and compress all "" to " */\r
+ else if (value.startsWith("\"") && value.endsWith("\""))\r
+ value = compressQuotes(value.substring(1, value.length() - 1), DOUBLEQUOTES);\r
+ else \r
+ value = value.toUpperCase();\r
+ // Do not allow user to specify multiple values for the same key\r
+ if (properties.put(key, value) != null)\r
+ {\r
+ throw StandardException.newException(SQLState.LANG_DUPLICATE_PROPERTY, key);\r
+ }\r
+ }\r
+ }\r
+ //if this property override is supported in internal mode only, then do that verification here.\r
+ if (!propertiesUseAllowed) \r
+ checkInternalFeature("DERBY-PROPERTIES");\r
+ return properties;\r
+ }\r
+}\r
+\r
+/*\r
+ * <A NAME="DB2lockGranularityClause">DB2lockGranularityClause</A>\r
+ */\r
+char\r
+DB2lockGranularityClause() throws StandardException :\r
+{\r
+ char lockGranularity;\r
+}\r
+{\r
+ <LOCKSIZE> lockGranularity = lockGranularity()\r
+ {\r
+ return lockGranularity;\r
+ }\r
+}\r
+\r
+/*\r
+ * <A NAME="lockGranularity">lockGranularity</A>\r
+ */\r
+char\r
+lockGranularity() throws StandardException :\r
+{\r
+}\r
+{\r
+ <TABLE>\r
+ {\r
+ return TableDescriptor.TABLE_LOCK_GRANULARITY;\r
+ }\r
+|\r
+ <ROW>\r
+ {\r
+ return TableDescriptor.ROW_LOCK_GRANULARITY;\r
+ }\r
+}\r
+\r
+/*\r
+ * <A NAME="indexDefinition">indexDefinition</A>\r
+ */\r
+StatementNode\r
+indexDefinition() throws StandardException :\r
+{\r
+ Boolean unique = Boolean.FALSE;\r
+ Properties properties = null;\r
+ TableName indexName;\r
+ TableName tableName;\r
+ Vector indexColumnList = new Vector();\r
+}\r
+{\r
+ /*\r
+ ** fyi: The INDEX keyword is pushed into the indexType()\r
+ ** production to get the grammar to work...\r
+ */\r
+ [ unique = unique() ] <INDEX>\r
+ indexName = qualifiedName(Limits.MAX_IDENTIFIER_LENGTH) <ON> tableName = qualifiedName(Limits.MAX_IDENTIFIER_LENGTH)\r
+ <LEFT_PAREN> indexColumnList(indexColumnList) <RIGHT_PAREN>\r
+ [ properties = propertyList(false) <CHECK_PROPERTIES>]\r
+ {\r
+ /* User allowed to specify schema name on table and index.\r
+ * If no schema name specified for index, then it "inherits" \r
+ * its schema name from the table.\r
+ * If index has a schema name and table does not, then\r
+ * table "inherits" its schema name from the index.\r
+ * If schema names are specified for both objects, then the\r
+ * schema names must be the same.\r
+ */\r
+ if (indexName.getSchemaName() == null)\r
+ {\r
+ indexName.setSchemaName(tableName.getSchemaName());\r
+ }\r
+ else if (tableName.getSchemaName() == null)\r
+ {\r
+ tableName.setSchemaName(indexName.getSchemaName());\r
+ }\r
+ else\r
+ {\r
+ /* schema name specified for both */\r
+ if (! (indexName.getSchemaName().equals(\r
+ tableName.getSchemaName())))\r
+ {\r
+ throw StandardException.newException(SQLState.LANG_INDEX_AND_TABLE_IN_DIFFERENT_SCHEMAS, \r
+ indexName,\r
+ tableName);\r
+ }\r
+ }\r
+ return (StatementNode) nodeFactory.getNode(\r
+ C_NodeTypes.CREATE_INDEX_NODE,\r
+ unique,\r
+ DEFAULT_INDEX_TYPE,\r
+ indexName,\r
+ tableName,\r
+ indexColumnList,\r
+ properties,\r
+ getContextManager());\r
+ }\r
+}\r
+\r
+/*\r
+ * <A NAME="unique">unique</A>\r
+ */\r
+Boolean\r
+unique() throws StandardException :\r
+{\r
+}\r
+{\r
+ <UNIQUE>\r
+ {\r
+ return Boolean.TRUE;\r
+ }\r
+}\r
+\r
+/**\r
+ CREATE PROCEDURE\r
+\r
+ procedureElements contains the description of the procedure.\r
+ (CREATE FUNCTIONS shares this lyout), see functionDefinition\r
+\r
+ 0 - Object[] 3 element array for parameters\r
+ 1 - TableName - specific name\r
+ 2 - Integer - dynamic result set count\r
+ 3 - String language (always java) - ignore\r
+ 4 - String external name (also passed directly to create alias node - ignore\r
+ 5 - Short parameter style (always java) - ignore \r
+ 6 - Short - SQL allowed.\r
+ 7 - Boolean - CALLED ON NULL INPUT (always TRUE for procedures)\r
+ 8 - TypeDescriptor - return type (always NULL for procedures)\r
+*/\r
+\r
+StatementNode\r
+procedureDefinition() throws StandardException :\r
+{\r
+ TableName procedureName;\r
+ Object[] procedureElements = new Object[9];\r
+}\r
+{\r
+ <PROCEDURE> procedureName = qualifiedName(Limits.MAX_IDENTIFIER_LENGTH)\r
+ procedureElements[0] = procedureParameterList()\r
+ ( routineElement(true, procedureElements) ) +\r
+ {\r
+ checkRequiredRoutineClause(JAVA_ROUTINE_CLAUSES, procedureElements);\r
+\r
+ return getCreateAliasNode(\r
+ procedureName,\r
+ (String) procedureElements[4],\r
+ procedureElements,\r
+ AliasInfo.ALIAS_TYPE_PROCEDURE_AS_CHAR,\r
+ Boolean.FALSE);\r
+ }\r
+}\r
+\r
+void routineElement(boolean isProcedure, Object[] routineElements) throws StandardException :\r
+{\r
+ int drs;\r
+ int clausePosition = -1;\r
+ Object clauseValue = null;\r
+}\r
+{\r
+ (\r
+ <SPECIFIC> clauseValue = qualifiedName(Limits.MAX_IDENTIFIER_LENGTH)\r
+ { clausePosition = 1; throw StandardException.newException(SQLState.NOT_IMPLEMENTED, "SPECIFIC identifier");}\r
+ |\r
+ [ <DYNAMIC> ] <RESULT> <SETS> drs = uint_value()\r
+ {\r
+ if (!isProcedure)\r
+ throw StandardException.newException(SQLState.LANG_SYNTAX_ERROR, "RESULT SETS");\r
+ clauseValue = ReuseFactory.getInteger(drs); clausePosition = 2;\r
+ }\r
+ |\r
+ <LANGUAGE> <JAVA> { clauseValue = "JAVA"; clausePosition = 3; }\r
+ |\r
+ <EXTERNAL> <NAME> clauseValue = string() { clausePosition = 4; }\r
+ |\r
+ <PARAMETER> <STYLE> clauseValue = parameterStyle() { clausePosition = 5; }\r
+\r
+ | <NO> <SQL> { clauseValue = ReuseFactory.getShort(RoutineAliasInfo.NO_SQL); clausePosition = 6; }\r
+ | <CONTAINS> <SQL> { clauseValue = ReuseFactory.getShort(RoutineAliasInfo.CONTAINS_SQL); clausePosition = 6; }\r
+ | <READS> <SQL> <DATA> { clauseValue = ReuseFactory.getShort(RoutineAliasInfo.READS_SQL_DATA); clausePosition = 6; }\r
+ | <MODIFIES> <SQL> <DATA>\r
+ {\r
+ if (!isProcedure)\r
+ throw StandardException.newException(SQLState.LANG_SYNTAX_ERROR, "MODIFIES SQL DATA");\r
+ clauseValue = ReuseFactory.getShort(RoutineAliasInfo.MODIFIES_SQL_DATA); clausePosition = 6;\r
+ }\r
+\r
+ | clauseValue = calledOnNullInput(isProcedure) { clausePosition = 7; }\r
+ )\r
+\r
+ {\r
+ if (clausePosition != -1) {\r
+ // check for repeated clause\r
+ if (routineElements[clausePosition] != null) {\r
+\r
+ String which = ROUTINE_CLAUSE_NAMES[clausePosition];\r
+ throw StandardException.newException(SQLState.LANG_DB2_MULTIPLE_ELEMENTS, which);\r
+ }\r
+ \r
+ routineElements[clausePosition] = clauseValue;\r
+ }\r
+ }\r
+}\r
+\r
+Boolean calledOnNullInput(boolean isProcedure) throws StandardException :\r
+{\r
+ Boolean calledOnNull;\r
+}\r
+{\r
+ (\r
+ <CALLED> { calledOnNull = Boolean.TRUE; }\r
+ | <RETURNS> <NULL> {\r
+ if (isProcedure)\r
+ throw StandardException.newException(SQLState.LANG_SYNTAX_ERROR,\r
+ "RETURNS NULL ON NULL INPUT");\r
+ \r
+ calledOnNull = Boolean.FALSE;\r
+ }\r
+ \r
+ ) <ON> <NULL> <INPUT>\r
+ {\r
+ return calledOnNull;\r
+ }\r
+}\r
+\r
+Short parameterStyle() :\r
+{\r
+}\r
+{\r
+ <JAVA> { return ReuseFactory.getShort(RoutineAliasInfo.PS_JAVA); }\r
+ }\r
+\r
+Object[]\r
+procedureParameterList() throws StandardException :\r
+{\r
+ Vector[] list = new Vector[3];\r
+ list[0] = new Vector(); // name\r
+ list[1] = new Vector(); // type\r
+ list[2] = new Vector(); // in/out\r
+}\r
+{\r
+ <LEFT_PAREN>\r
+ [ procedureParameterDefinition(list)\r
+ ( <COMMA> procedureParameterDefinition(list) )* ]\r
+ <RIGHT_PAREN>\r
+ {\r
+ return list;\r
+ }\r
+}\r
+\r
+/*\r
+ * <A NAME="Definition">procedureParameterDefinition</A>\r
+ */\r
+void\r
+procedureParameterDefinition(Vector[] list) throws StandardException :\r
+{\r
+ DataTypeDescriptor typeDescriptor;\r
+ String parameterName = "";\r
+ Integer inout;\r
+}\r
+{\r
+ inout = inoutParameter()\r
+ \r
+ // Lookahead needed because token could satisfy identifier and dataTypeDDL\r
+ [ LOOKAHEAD( { commonDatatypeName(2, false) })\r
+ parameterName = identifier(Limits.MAX_IDENTIFIER_LENGTH, true)\r
+ ]\r
+ typeDescriptor = dataTypeDDL() \r
+ {\r
+ list[0].addElement(parameterName);\r
+ list[1].addElement(typeDescriptor);\r
+ list[2].addElement(inout);\r
+ }\r
+}\r
+\r
+Integer\r
+inoutParameter() :\r
+{\r
+ int mode = JDBC30Translation.PARAMETER_MODE_IN;\r
+}\r
+{\r
+ [\r
+ <IN> { }\r
+ | <OUT> { mode = JDBC30Translation.PARAMETER_MODE_OUT; }\r
+ | <INOUT> { mode = JDBC30Translation.PARAMETER_MODE_IN_OUT; }\r
+ ]\r
+ { return ReuseFactory.getInteger(mode); }\r
+}\r
+\r
+/**\r
+ CREATE FUNCTION\r
+\r
+ functionElements contains the description of the function.\r
+\r
+ 0 - Object[] 3 element array for parameters\r
+ 1 - TableName - specific name\r
+ 2 - Integer - dynamic result set count - always 0\r
+ 3 - String language (always java) - required to be set\r
+ 4 - String external name (also passed directly to create alias node - ignore\r
+ 5 - Short parameter style (always java) - required to be set \r
+ 6 - Short - SQL allowed.\r
+ 7 - Boolean - CALLED ON NULL INPUT\r
+ 8 - TypeDescriptor - return type\r
+*/\r
+\r
+StatementNode\r
+functionDefinition() throws StandardException :\r
+{\r
+ TableName functionName;\r
+ Object[] functionElements = new Object[9];\r
+}\r
+{\r
+ <FUNCTION> functionName = qualifiedName(Limits.MAX_IDENTIFIER_LENGTH)\r
+ functionElements[0] = functionParameterList()\r
+ <RETURNS> functionElements[8] = dataTypeCommon() \r
+ ( routineElement(false, functionElements) ) +\r
+ {\r
+ checkRequiredRoutineClause(JAVA_ROUTINE_CLAUSES, functionElements);\r
+ \r
+ return getCreateAliasNode(\r
+ functionName,\r
+ (String) functionElements[4],\r
+ functionElements,\r
+ AliasInfo.ALIAS_TYPE_FUNCTION_AS_CHAR,\r
+ Boolean.FALSE);\r
+ }\r
+}\r
+\r
+Object[]\r
+functionParameterList() throws StandardException :\r
+{\r
+ Vector[] list = new Vector[3];\r
+ list[0] = new Vector(); // name\r
+ list[1] = new Vector(); // type\r
+ list[2] = new Vector(); // in/out - ALWAYS IN\r
+}\r
+{\r
+ <LEFT_PAREN>\r
+ [ functionParameterDefinition(list)\r
+ ( <COMMA> functionParameterDefinition(list) )* ]\r
+ <RIGHT_PAREN>\r
+ {\r
+ return list;\r
+ }\r
+}\r
+\r
+/*\r
+ * <A NAME="Definition">functionParameterDefinition</A>\r
+ */\r
+void\r
+functionParameterDefinition(Vector[] list) throws StandardException :\r
+{\r
+ DataTypeDescriptor typeDescriptor;\r
+ String parameterName = "";\r
+ Integer inout;\r
+}\r
+{\r
+ // Lookahead needed because token could satisfy identifier and dataTypeDDL\r
+ [ LOOKAHEAD( { commonDatatypeName(2, false) })\r
+ parameterName = identifier(Limits.MAX_IDENTIFIER_LENGTH, true)\r
+ ]\r
+ typeDescriptor = dataTypeDDL() \r
+ {\r
+ list[0].addElement(parameterName);\r
+ list[1].addElement(typeDescriptor);\r
+ list[2].addElement(ReuseFactory.getInteger(JDBC30Translation.PARAMETER_MODE_IN));\r
+ }\r
+}\r
+\r
+StatementNode\r
+viewDefinition(Token beginToken) throws StandardException :\r
+{\r
+ int checkOptionType;\r
+ ResultColumnList resultColumns = null;\r
+ ResultSetNode queryExpression;\r
+ TableName tableName;\r
+ Token checkTok = null;\r
+ Token endToken;\r
+}\r
+{\r
+ <VIEW> tableName = qualifiedName(Limits.MAX_IDENTIFIER_LENGTH) \r
+ [ <LEFT_PAREN> resultColumns = viewColumnList() <RIGHT_PAREN> ]\r
+ <AS> queryExpression = queryExpression(null, NO_SET_OP)\r
+ {\r
+ checkOptionType = ViewDescriptor.NO_CHECK_OPTION;\r
+ endToken = getToken(0);\r
+ /* Parameters not allowed in create view */\r
+ HasNodeVisitor visitor = new HasNodeVisitor(ParameterNode.class);\r
+ queryExpression.accept(visitor);\r
+ if (visitor.hasNode())\r
+ {\r
+ throw StandardException.newException(SQLState.LANG_NO_PARAMS_IN_VIEWS);\r
+ }\r
+\r
+ return (StatementNode) nodeFactory.getNode(\r
+ C_NodeTypes.CREATE_VIEW_NODE,\r
+ tableName, \r
+ resultColumns, \r
+ queryExpression,\r
+ ReuseFactory.getInteger(checkOptionType),\r
+ StringUtil.slice(statementSQLText,\r
+ beginToken.beginOffset,\r
+ endToken.endOffset,false),\r
+ getContextManager());\r
+ }\r
+}\r
+\r
+ResultColumnList\r
+viewColumnList() throws StandardException :\r
+{\r
+ ResultColumnList resultColumns = (ResultColumnList) nodeFactory.getNode(\r
+ C_NodeTypes.RESULT_COLUMN_LIST,\r
+ getContextManager());\r
+}\r
+{\r
+ /* RESOLVE: Passing null parameter for now just to keep Java happy */\r
+ columnNameList(resultColumns)\r
+ {\r
+ return resultColumns;\r
+ }\r
+}\r
+\r
+StatementNode\r
+triggerDefinition() throws StandardException :\r
+{\r
+ Boolean isBefore;\r
+ Boolean isRow = Boolean.FALSE; // STATEMENT implicit by default\r
+ TableName tableName;\r
+ TableName triggerName;\r
+ Token[] tokenHolder = new Token[1];\r
+ Token beginToken;\r
+ Token checkTok = null;\r
+ Token endToken;\r
+ int actionBegin;\r
+ int actionEnd;\r
+ int triggerEvent;\r
+ QueryTreeNode actionNode;\r
+ ResultColumnList triggerColumns = (ResultColumnList) nodeFactory.getNode(\r
+ C_NodeTypes.RESULT_COLUMN_LIST,\r
+ getContextManager());\r
+ Vector refClause = null;\r
+}\r
+{\r
+ <TRIGGER> triggerName = qualifiedName(Limits.MAX_IDENTIFIER_LENGTH)\r
+ isBefore = beforeOrAfter()\r
+ triggerEvent = triggerEvent(triggerColumns) // { INSERT | DELETE | UPDATE [ colList ] }\r
+ <ON> tableName = qualifiedName(Limits.MAX_IDENTIFIER_LENGTH)\r
+ [ refClause = triggerReferencingClause() ] // REFERENCING OLD/NEW AS \r
+ [ <FOR> <EACH> isRow = rowOrStatement() ]\r
+ [ <MODE> <DB2SQL> ]\r
+ //we are not top level statement\r
+ actionNode = proceduralStatement(tokenHolder)\r
+ // the trigger body\r
+ {\r
+ actionEnd = getToken(0).endOffset;\r
+ actionBegin = tokenHolder[0].beginOffset;\r
+\r
+ // No DML in action node for BEFORE triggers.\r
+ if (isBefore.booleanValue() && (actionNode instanceof DMLModStatementNode)) {\r
+ throw StandardException.newException(\r
+ SQLState.LANG_UNSUPPORTED_TRIGGER_STMT,\r
+ ((StatementNode) actionNode).statementToString(), "BEFORE");\r
+ }\r
+\r
+\r
+ // no params in trigger action\r
+ HasNodeVisitor visitor = new HasNodeVisitor(ParameterNode.class);\r
+ actionNode.accept(visitor);\r
+ if (visitor.hasNode())\r
+ {\r
+ throw StandardException.newException(SQLState.LANG_NO_PARAMS_IN_TRIGGER_ACTION);\r
+ }\r
+\r
+ return (StatementNode) nodeFactory.getNode(\r
+ C_NodeTypes.CREATE_TRIGGER_NODE,\r
+ triggerName, \r
+ tableName,\r
+ ReuseFactory.getInteger(triggerEvent),\r
+ triggerColumns,\r
+ isBefore, \r
+ isRow,\r
+ Boolean.TRUE, // enabled\r
+ refClause, // referencing clause\r
+ null,// when clause node\r
+ null, // when clause text\r
+ ReuseFactory.getInteger(0),\r
+ // when clause begin offset\r
+ actionNode,\r
+ StringUtil.slice(statementSQLText,\r
+ actionBegin,\r
+ actionEnd,false),\r
+ ReuseFactory.getInteger(actionBegin),\r
+ getContextManager());\r
+ }\r
+}\r
+\r
+StatementNode\r
+synonymDefinition() throws StandardException :\r
+{\r
+ TableName synonymName;\r
+ TableName targetName;\r
+}\r
+{\r
+ <SYNONYM> synonymName = qualifiedName(Limits.MAX_IDENTIFIER_LENGTH) <FOR>\r
+ targetName = qualifiedName(Limits.MAX_IDENTIFIER_LENGTH)\r
+ {\r
+ checkVersion(DataDictionary.DD_VERSION_DERBY_10_1,\r
+ "CREATE SYNONYM");\r
+\r
+ return (StatementNode) getNodeFactory().getCreateAliasNode\r
+ (\r
+ synonymName,\r
+ targetName,\r
+ null,\r
+ AliasInfo.ALIAS_TYPE_SYNONYM_AS_CHAR,\r
+ Boolean.FALSE,\r
+ getContextManager()\r
+ );\r
+ }\r
+}\r
+\r
+\r
+Boolean\r
+beforeOrAfter() :\r
+{}\r
+{\r
+ <NO> <CASCADE> <BEFORE> \r
+ {\r
+ return Boolean.TRUE;\r
+ }\r
+| <AFTER>\r
+ {\r
+ return Boolean.FALSE;\r
+ }\r
+}\r
+\r
+int\r
+triggerEvent(ResultColumnList rcl) throws StandardException :\r
+{}\r
+{\r
+ <INSERT> \r
+ {\r
+ return TriggerDescriptor.TRIGGER_EVENT_INSERT;\r
+ }\r
+| <DELETE>\r
+ {\r
+ return TriggerDescriptor.TRIGGER_EVENT_DELETE;\r
+ }\r
+| <UPDATE> [ <OF> columnNameList(rcl) ]\r
+ {\r
+ return TriggerDescriptor.TRIGGER_EVENT_UPDATE;\r
+ }\r
+}\r
+\r
+Boolean\r
+rowOrStatement() :\r
+{\r
+}\r
+{\r
+ token = <ROW> \r
+ {\r
+ return Boolean.TRUE;\r
+ }\r
+| token = <STATEMENT>\r
+ {\r
+ return Boolean.FALSE;\r
+ }\r
+}\r
+\r
+Vector\r
+triggerReferencingClause() throws StandardException :\r
+{\r
+ Vector vector = new Vector();\r
+}\r
+{\r
+ <REFERENCING> triggerReferencingExpression(vector) ( triggerReferencingExpression(vector) )*\r
+ {\r
+ return vector;\r
+ }\r
+}\r
+\r
+void\r
+triggerReferencingExpression(Vector vector) throws StandardException :\r
+{\r
+ String identifier;\r
+ boolean isNew = true;\r
+ boolean isRow = true;\r
+}\r
+{\r
+ (\r
+ <NEW> \r
+ |\r
+ <OLD> {isNew = false;}\r
+ |\r
+ <NEW_TABLE> { isRow = false;}\r
+ |\r
+ <OLD_TABLE> { isNew = false; isRow = false;}\r
+ )\r
+\r
+ <AS> identifier = identifier(Limits.MAX_IDENTIFIER_LENGTH, true)\r
+ {\r
+ vector.addElement(new TriggerReferencingStruct(isRow, isNew, identifier));\r
+ }\r
+}\r
+ \r
+\r
+/*\r
+ * <A NAME="defaultClause">defaultClause</A>\r
+ */\r
+ValueNode\r
+defaultClause(long[] autoIncrementInfo, String columnName) throws StandardException :\r
+{\r
+ ValueNode value;\r
+ Token beginToken;\r
+ Token endToken;\r
+}\r
+{\r
+ [ <WITH> ] beginToken = <_DEFAULT> value = defaultOption(beginToken, autoIncrementInfo, columnName)\r
+ {\r
+ return value;\r
+ }\r
+|\r
+ value = generatedColumnOption(autoIncrementInfo)\r
+ {\r
+ return value;\r
+ }\r
+}\r
+\r
+/*\r
+ * <A NAME="defaultNullOnlyClause">defaultNullOnlyClause</A>\r
+ */\r
+ValueNode\r
+defaultNullOnlyClause() throws StandardException :\r
+{\r
+}\r
+\r
+{\r
+ <_DEFAULT> <NULL>\r
+ {\r
+ return (ValueNode) nodeFactory.getNode(\r
+ C_NodeTypes.UNTYPED_NULL_CONSTANT_NODE,\r
+ getContextManager());\r
+ }\r
+}\r
+\r
+/*\r
+ * <A NAME="generatedColumnOption">generatedColumnOption</A>\r
+ */\r
+\r
+//ToCleanUp\r
+//A specific class not such long[] should exists for autoIncrementInfo ...\r
+\r
+ValueNode\r
+generatedColumnOption(long[] autoIncrementInfo) throws StandardException :\r
+{\r
+ ValueNode value = null;\r
+}\r
+{\r
+ {\r
+ autoIncrementInfo[QueryTreeNode.AUTOINCREMENT_START_INDEX] = 1;\r
+ autoIncrementInfo[QueryTreeNode.AUTOINCREMENT_INC_INDEX] = 1;\r
+ autoIncrementInfo[QueryTreeNode.AUTOINCREMENT_IS_AUTOINCREMENT_INDEX] = 1;\r
+ autoIncrementInfo[QueryTreeNode.AUTOINCREMENT_CREATE_MODIFY] = ColumnDefinitionNode.CREATE_AUTOINCREMENT;\r
+ }\r
+\r
+ <GENERATED> \r
+ (\r
+ <ALWAYS> {\r
+ value = null;\r
+ }|\r
+ <BY> <_DEFAULT> { \r
+ checkVersion(DataDictionary.DD_VERSION_DERBY_10_1,\r
+ "GENERATED BY DEFAULT");\r
+\r
+ value = (ValueNode) nodeFactory.getNode(C_NodeTypes.DEFAULT_NODE,\r
+ getContextManager()) ;}\r
+ )\r
+ <AS> <IDENTITY> [<LEFT_PAREN> autoIncrementBeginEnd(autoIncrementInfo) <RIGHT_PAREN>]\r
+ {\r
+ return value;\r
+ }\r
+}\r
+\r
+/*\r
+ * <A NAME="autoIncrementBeginEnd">autoIncrementBeginEnd</A>\r
+ */\r
+void \r
+autoIncrementBeginEnd(long[] autoIncrementInfo) throws StandardException :\r
+{\r
+ long autoIncrementInitial = 1;\r
+ long autoIncrementIncrement = 1;\r
+}\r
+{\r
+ <INCREMENT> <BY> autoIncrementIncrement = exactNumber()\r
+ {\r
+ autoIncrementInfo[QueryTreeNode.AUTOINCREMENT_INC_INDEX] = autoIncrementIncrement;\r
+ autoIncrementInfo[QueryTreeNode.AUTOINCREMENT_CREATE_MODIFY] = ColumnDefinitionNode.CREATE_AUTOINCREMENT;\r
+ return;\r
+ }\r
+|\r
+ <START> <WITH> autoIncrementInitial = exactNumber() [<COMMA> <INCREMENT> <BY> autoIncrementIncrement = exactNumber() ]\r
+ {\r
+ autoIncrementInfo[QueryTreeNode.AUTOINCREMENT_START_INDEX] = autoIncrementInitial;\r
+ autoIncrementInfo[QueryTreeNode.AUTOINCREMENT_INC_INDEX] = autoIncrementIncrement;\r
+ autoIncrementInfo[QueryTreeNode.AUTOINCREMENT_CREATE_MODIFY] = ColumnDefinitionNode.CREATE_AUTOINCREMENT;\r
+ return;\r
+ }\r
+}\r
+\r
+/*\r
+ * <A NAME="defaultOption">defaultOption</A>\r
+ */\r
+ValueNode\r
+defaultOption(Token beginToken, long[] autoIncrementInfo,\r
+ String columnName) throws StandardException :\r
+{\r
+ Token endToken;\r
+ Token errorTok = null;\r
+ Token initialTok = null;\r
+ ValueNode value;\r
+}\r
+{\r
+ //Look ahead required to tell NULL from a class name which starts with\r
+ // NULL (e.g., NULL::)\r
+ LOOKAHEAD( {getToken(1).kind == NULL && !(getToken(2).kind == PERIOD ||\r
+ getToken(2).kind == DOUBLE_COLON)})\r
+ <NULL>\r
+ {\r
+ return (ValueNode) nodeFactory.getNode(\r
+ C_NodeTypes.UNTYPED_NULL_CONSTANT_NODE,\r
+ getContextManager());\r
+ }\r
+|\r
+ value = DB2DefaultOption(columnName)\r
+ {\r
+ endToken = getToken(0);\r
+ value.setBeginOffset( beginToken.beginOffset );\r
+ value.setEndOffset( endToken.endOffset );\r
+ value = (ValueNode) nodeFactory.getNode(\r
+ C_NodeTypes.DEFAULT_NODE,\r
+ value,\r
+ StringUtil.slice(statementSQLText,\r
+ beginToken.beginOffset + 7,\r
+ endToken.endOffset,true),\r
+ getContextManager()\r
+ );\r
+ return value;\r
+ }\r
+}\r
+\r
+/*\r
+ * <A NAME="DB2DefaultOption">DB2DefaultOption</A>\r
+ */\r
+ValueNode\r
+DB2DefaultOption(String columnName) throws StandardException :\r
+{\r
+ ValueNode value;\r
+}\r
+{\r
+ // DB2 spec says default can only be one of the\r
+ // following: <constant>, <datetime-special-register> (ex.\r
+ // "current time"), CURRENT SCHEMA, USER, NULL, or\r
+ // <cast-function>. We currently support all of these\r
+ // except the 'blob' function that is part of the DB2 valid\r
+ // <cast-function> grammar. See beetle 5281 for plans\r
+ // support 'blob' function in future.\r
+\r
+ LOOKAHEAD({getToken(2).kind == SCHEMA || getToken(2).kind == SQLID}) \r
+ <CURRENT> (<SCHEMA> | <SQLID>)\r
+ {\r
+ return (ValueNode) nodeFactory.getNode(\r
+ C_NodeTypes.CURRENT_SCHEMA_NODE,\r
+ getContextManager());\r
+ }\r
+|\r
+ <USER>\r
+ {\r
+ return (ValueNode) nodeFactory.getNode(\r
+ C_NodeTypes.USER_NODE,\r
+ getContextManager());\r
+ }\r
+|\r
+ LOOKAHEAD({\r
+ getToken(1).kind == DATE ||\r
+ getToken(1).kind == TIME ||\r
+ getToken(1).kind == TIMESTAMP\r
+ })\r
+ value = miscBuiltins()\r
+ { // these functions are allowed as valid <cast-function> defaults.\r
+ // Once "BLOB" is allowed as a cast-function (5281), a case should be\r
+ // added for that, as well.\r
+ return value;\r
+ }\r
+|\r
+ LOOKAHEAD( {getToken(2).kind == LEFT_PAREN ||\r
+ (getToken(4).kind == LEFT_PAREN && \r
+ getToken(2).kind != COMMA)} ) \r
+ // Check against comma: see Derby-331 \r
+ // Before adding this, the following was erroneously\r
+ // flagged as invalid: \r
+ // create table foo(.., b int default 0, unique (a))\r
+ value = miscBuiltins()\r
+ {\r
+ // If we have a function (as indicated by an open paren,\r
+ // which can be either the 2nd token (w/ normal function name)\r
+ // or the 4th token (w/ qualified function name)), then\r
+ // it's not valid. Catch it here and throw an "invalid\r
+ // default" error (42894) instead of letting it go as\r
+ // a syntax error (this matches DB2 UDB behavior).\r
+ throw StandardException.newException(\r
+ SQLState.LANG_DB2_INVALID_DEFAULT_VALUE,\r
+ columnName);\r
+ }\r
+|\r
+ value = datetimeValueFunction()\r
+ {\r
+ return value;\r
+ }\r
+|\r
+ // Only (valid) thing left is literals (i.e. actual constants).\r
+ value = literal()\r
+ {\r
+ return value;\r
+ }\r
+\r
+}\r
+\r
+/*\r
+ * <A NAME="literal">literal</A>\r
+ */\r
+ValueNode\r
+literal() throws StandardException :\r
+{\r
+ String sign = "";\r
+ Token tok;\r
+ String datetimeString;\r
+ String bitString;\r
+ ValueNode constantNode;\r
+}\r
+{\r
+ [ sign = sign() ] constantNode = numericLiteral(sign)\r
+ {\r
+ return constantNode;\r
+ }\r
+|\r
+ constantNode = stringLiteral()\r
+ {\r
+ return constantNode;\r
+ }\r
+|\r
+ constantNode = hexLiteral()\r
+ {\r
+ return constantNode;\r
+ }\r
+|\r
+ constantNode = dateTimeLiteral()\r
+ {\r
+ return constantNode;\r
+ }\r
+|\r
+ tok = booleanLiteral()\r
+ {\r
+ checkInternalFeature(tok.image);\r
+ return (ValueNode) nodeFactory.getNode(\r
+ C_NodeTypes.BOOLEAN_CONSTANT_NODE,\r
+ StringUtil.SQLEqualsIgnoreCase(tok.image, "true") ?\r
+ Boolean.TRUE : Boolean.FALSE,\r
+ getContextManager());\r
+ }\r
+/*\r
+ JDBC and ODBC do not support the interval type, so let's not do it\r
+ ourselves for now.\r
+|\r
+ tok = <INTERVAL_LITERAL>\r
+ {\r
+ return nodeFactory.getIntervalNode(tok.image,\r
+ getTypeCompilationFactory(),\r
+ getContextManager());\r
+ }\r
+*/\r
+}\r
+\r
+/*\r
+ * <A NAME="numericLiteral">numericLiteral</A>\r
+ */\r
+ValueNode\r
+numericLiteral(String sign) throws StandardException :\r
+{\r
+ Token tok;\r
+}\r
+{\r
+ tok = <EXACT_NUMERIC>\r
+ {\r
+ /*\r
+ ** The various java parse utilities can't handle leading +,\r
+ ** so only concatenate leading -.\r
+ */\r
+\r
+ String num = tok.image;\r
+\r
+ if (sign.equals("-"))\r
+ num = sign.concat(num);\r
+\r
+ return getNumericNode(num);\r
+ }\r
+|\r
+ tok = <APPROXIMATE_NUMERIC>\r
+ {\r
+ StringBuffer doubleImage;\r
+ String doubleString;\r
+ int ePosn, dotPosn; // Position of letter e and '.' in value\r
+ Double doubleValue;\r
+ \r
+ doubleImage = new StringBuffer(sign);\r
+ doubleImage.append(tok.image);\r
+ doubleString = doubleImage.toString();\r
+\r
+ ePosn = doubleString.indexOf('E');\r
+ if (ePosn == -1)\r
+ ePosn = doubleString.indexOf('e');\r
+ if (SanityManager.DEBUG)\r
+ SanityManager.ASSERT(ePosn != -1, "no E or e in approximate numeric");\r
+\r
+ // there is a limit on the length of a floatingpoint literal in DB2\r
+ if (doubleString.length() > Limits.DB2_MAX_FLOATINGPOINT_LITERAL_LENGTH)\r
+ throw StandardException.newException(SQLState.LANG_DB2_TOO_LONG_FLOATING_POINT_LITERAL, doubleString, TypeId.DOUBLE_NAME);\r
+ // if there is no '.' before the e, put one in\r
+ dotPosn = doubleString.substring(0,ePosn).indexOf('.');\r
+ if (dotPosn == -1) {\r
+ doubleImage.insert(ePosn,'.');\r
+ doubleString = doubleImage.toString();\r
+ ePosn++;\r
+ }\r
+\r
+ try\r
+ {\r
+ doubleValue = Double.valueOf(doubleString);\r
+\r
+ }\r
+ catch (NumberFormatException nfe)\r
+ {\r
+ throw StandardException.newException(SQLState.LANG_FORMAT_EXCEPTION, TypeId.DOUBLE_NAME);\r
+ }\r
+\r
+ double dv = doubleValue.doubleValue();\r
+\r
+ // When the value is 0 it's possible rounded, try to detect it by checking if the mantissa is 0.0\r
+ // "proof of correctness": any nonzero value (mantissa) with less than 30 characters will not be\r
+ // rounded to 0.0 by a float/real. This correctly detects the case when\r
+ // the radix/exponent being "too small" (1e-900) giving a value rounded to zero.\r
+ if ( (dv == 0.0d) && (Double.parseDouble(doubleString.substring(0, ePosn-1)) != 0.0d) )\r
+ {\r
+ throw StandardException.newException(SQLState.LANG_OUTSIDE_RANGE_FOR_DATATYPE, TypeId.DOUBLE_NAME);\r
+ }\r
+\r
+ if (Double.isNaN(dv) || Double.isInfinite(dv))\r
+ throw StandardException.newException(SQLState.LANG_OUTSIDE_RANGE_FOR_DATATYPE, TypeId.DOUBLE_NAME);\r
+\r
+ return (ValueNode) nodeFactory.getNode(\r
+ C_NodeTypes.DOUBLE_CONSTANT_NODE,\r
+ doubleValue,\r
+ getContextManager());\r
+ }\r
+}\r
+\r
+/*\r
+ * <A NAME="dateTimeLiteral">dateTimeLiteral</A>\r
+ */\r
+ValueNode\r
+dateTimeLiteral() throws StandardException :\r
+{\r
+ ValueNode constantNode;\r
+}\r
+{\r
+// RESOLVE: There is an incompatibility between Derby and DB2 here. The DB2 SQL parser does not recognize\r
+// JDBC date/time escapes. They are handled in a JDBC pre-processor. However embedded Derby does not have\r
+// a separate pre-processor. JDBC date/time escapes are handled by the Derby SQL parser. This will only\r
+// be visible if Derby is accessed through a non-JDBC pathway. (ODBC?) In that case Derby will allow\r
+// the JDBC date/time escape while DB2 will not.\r
+ (\r
+ ( <LEFT_BRACE> constantNode = escapedDateTimeLiteral() <RIGHT_BRACE> )\r
+ )\r
+ {\r
+ return constantNode;\r
+ }\r
+}\r
+\r
+/*\r
+ * <A NAME="escapedDateTimeLiteral">escapedDateTimeLiteral</A>\r
+ */\r
+ValueNode\r
+escapedDateTimeLiteral() throws StandardException :\r
+{\r
+ ValueNode constantNode;\r
+}\r
+{\r
+ <D> constantNode = bareDateLiteral()\r
+ {\r
+ return constantNode;\r
+ }\r
+|\r
+ <T> constantNode = bareTimeLiteral()\r
+ {\r
+ return constantNode;\r
+ }\r
+|\r
+ <TS> constantNode = bareTimestampLiteral()\r
+ {\r
+ return constantNode;\r
+ }\r
+}\r
+\r
+/*\r
+ * <A NAME="bareDateLiteral">bareDateLiteral</A>\r
+ */\r
+ValueNode\r
+bareDateLiteral() throws StandardException :\r
+{\r
+ String dateString;\r
+}\r
+{\r
+ dateString = string()\r
+ {\r
+ return (ValueNode) nodeFactory.getNode(\r
+ C_NodeTypes.USERTYPE_CONSTANT_NODE,\r
+ getLanguageConnectionContext().getDataValueFactory().getDateValue(dateString, true),\r
+ getContextManager());\r
+ }\r
+}\r
+\r
+/*\r
+ * <A NAME="bareTimeLiteral">bareTimeLiteral</A>\r
+ */\r
+ValueNode\r
+bareTimeLiteral() throws StandardException :\r
+{\r
+ String timeString;\r
+}\r
+{\r
+ timeString = string()\r
+ {\r
+ return (ValueNode) nodeFactory.getNode(\r
+ C_NodeTypes.USERTYPE_CONSTANT_NODE,\r
+ getLanguageConnectionContext().getDataValueFactory().getTimeValue(timeString, true),\r
+ getContextManager());\r
+ }\r
+}\r
+\r
+/*\r
+ * <A NAME="bareTimestampLiteral">bareTimestampLiteral</A>\r
+ */\r
+ValueNode\r
+bareTimestampLiteral() throws StandardException :\r
+{\r
+ String timestampString;\r
+}\r
+{\r
+ timestampString = string()\r
+ {\r
+ return (ValueNode) nodeFactory.getNode(\r
+ C_NodeTypes.USERTYPE_CONSTANT_NODE,\r
+ getLanguageConnectionContext().getDataValueFactory().getTimestampValue(timestampString, true),\r
+ getContextManager());\r
+ }\r
+}\r
+\r
+/*\r
+ * <A NAME="string">string</A>\r
+ */\r
+String\r
+string() throws StandardException :\r
+{\r
+ Token tok;\r
+}\r
+{\r
+ tok = <STRING>\r
+ {\r
+ verifyImageLength(tok.image);\r
+ /* Trim off the leading and trailing ', and compress all '' to ' */\r
+ return compressQuotes(tok.image.substring(1, tok.image.length() - 1),\r
+ SINGLEQUOTES);\r
+ }\r
+}\r
+\r
+/*\r
+ * <A NAME="stringLiteral">stringLiteral</A>\r
+ */\r
+CharConstantNode\r
+stringLiteral() throws StandardException :\r
+{\r
+ Token tok;\r
+ String string;\r
+}\r
+{\r
+ tok = <STRING>\r
+ {\r
+ //there is a maximum limit on the length of the string\r
+ if (tok.image.length()-2 > Limits.DB2_MAX_CHARACTER_LITERAL_LENGTH)//-2 is for the beginning and ending quote\r
+ throw StandardException.newException(SQLState.LANG_DB2_STRING_CONSTANT_TOO_LONG, StringUtil.formatForPrint(tok.image));\r
+ string = compressQuotes(tok.image.substring(1, tok.image.length() - 1), SINGLEQUOTES);\r
+ /* Trim quotes from string. */\r
+ return (CharConstantNode) nodeFactory.getNode(\r
+ C_NodeTypes.CHAR_CONSTANT_NODE,\r
+ string,\r
+ getContextManager());\r
+ }\r
+}\r
+\r
+/*\r
+ * <A NAME="hexLiteral">hexLiteral</A>\r
+ */\r
+ValueNode\r
+hexLiteral() throws StandardException :\r
+{\r
+ Token tok;\r
+}\r
+{\r
+ tok = <HEX_STRING>\r
+ {\r
+ String hexLiteral = tok.image;\r
+\r
+ //there is a maximum limit on the length of the hex constant\r
+ if (hexLiteral.length()-3 > Limits.DB2_MAX_HEX_LITERAL_LENGTH)//-3 is for X' at the beginning and ' at the end\r
+ throw StandardException.newException(SQLState.LANG_DB2_STRING_CONSTANT_TOO_LONG, StringUtil.formatForPrint(hexLiteral));\r
+ if ((hexLiteral.length()-3)%2 == 1)\r
+ throw StandardException.newException(SQLState.LANG_DB2_INVALID_HEXADECIMAL_CONSTANT, StringUtil.formatForPrint(hexLiteral));\r
+\r
+ int bitLength = ((hexLiteral.length() - 3) / 2);\r
+ return (ValueNode)\r
+ nodeFactory.getNode(C_NodeTypes.VARBIT_CONSTANT_NODE,\r
+ hexLiteral.substring(2, hexLiteral.length() - 1), ReuseFactory.getInteger(bitLength),\r
+ getContextManager());\r
+ }\r
+}\r
+\r
+\r
+TableName\r
+constraintNameDefinition() throws StandardException :\r
+{\r
+ TableName constraintName;\r
+}\r
+{\r
+ /* changed constraintName() to qualifiedName() for compaction */\r
+ <CONSTRAINT> constraintName = qualifiedName(Limits.MAX_IDENTIFIER_LENGTH)\r
+ {\r
+ return constraintName;\r
+ }\r
+}\r
+\r
+/*\r
+ * DB2 requires column check constraints to refer to only that column. Derby\r
+ * doesn't care if check constraints are column level or table level. For DB2 compatibility\r
+ * check that column check constraints only refer to that column.\r
+ */\r
+ConstraintDefinitionNode\r
+checkConstraintDefinition(TableName constraintName, String columnName)\r
+ throws StandardException :\r
+{ \r
+ Token beginToken;\r
+ Token endToken;\r
+ ValueNode value;\r
+ ResultColumnList rclList = null;\r
+}\r
+{\r
+ /* valueExpression() was searchCondition() */\r
+ <CHECK> beginToken = \r
+ <LEFT_PAREN> value = valueExpression(false) endToken = <RIGHT_PAREN>\r
+ {\r
+ if (columnName != null)\r
+ {\r
+ /* Column check constraint */\r
+ rclList = (ResultColumnList) nodeFactory.getNode(\r
+ C_NodeTypes.RESULT_COLUMN_LIST,\r
+ getContextManager());\r
+ rclList.addElement((ResultColumn) nodeFactory.getNode(\r
+ C_NodeTypes.RESULT_COLUMN,\r
+ columnName,\r
+ null,\r
+ getContextManager()));\r
+ }\r
+\r
+ value.setBeginOffset( beginToken.beginOffset );\r
+ value.setEndOffset( endToken.endOffset );\r
+ return (ConstraintDefinitionNode) nodeFactory.getNode(\r
+ C_NodeTypes.CONSTRAINT_DEFINITION_NODE,\r
+ constraintName,\r
+ ReuseFactory.getInteger(DataDictionary.CHECK_CONSTRAINT),\r
+ rclList,\r
+ null,\r
+ value,\r
+ StringUtil.slice(statementSQLText,\r
+ beginToken.beginOffset,\r
+ endToken.endOffset,true),\r
+ getContextManager()\r
+ );\r
+ }\r
+}\r
+\r
+\r
+/*\r
+ * <A NAME="spsRenameStatement">spsRenameStatement</A>\r
+ */\r
+StatementNode\r
+spsRenameStatement() throws StandardException :\r
+{\r
+ StatementNode qtn;\r
+}\r
+{\r
+ <RENAME> (\r
+ qtn = renameTableStatement() |\r
+ qtn = renameIndexStatement() |\r
+ qtn = renameColumnStatement()\r
+ )\r
+ {\r
+ return qtn;\r
+ }\r
+}\r
+\r
+/*\r
+ * <A NAME="renameTableStatement">renameTableStatement</A>\r
+ */\r
+StatementNode\r
+renameTableStatement() throws StandardException :\r
+{\r
+ StatementNode qtn;\r
+ TableName tableName;\r
+ String newTableName;\r
+}\r
+{\r
+ <TABLE> tableName = qualifiedName(Limits.MAX_IDENTIFIER_LENGTH) <TO> newTableName = identifier(Limits.MAX_IDENTIFIER_LENGTH, true)\r
+ {\r
+ return (StatementNode) nodeFactory.getNode(\r
+ C_NodeTypes.RENAME_NODE,\r
+ tableName,\r
+ null,\r
+ newTableName,\r
+ Boolean.FALSE,\r
+ ReuseFactory.getInteger(StatementType.RENAME_TABLE),\r
+ getContextManager());\r
+ }\r
+}\r
+\r
+/*\r
+ * <A NAME="renameIndexStatement">renameIndexStatement</A>\r
+ */\r
+StatementNode\r
+renameIndexStatement() throws StandardException :\r
+{\r
+ String oldIndexName;\r
+ String newIndexName;\r
+}\r
+{\r
+ <INDEX> oldIndexName = identifier(Limits.MAX_IDENTIFIER_LENGTH, true) <TO> newIndexName = identifier(Limits.MAX_IDENTIFIER_LENGTH, true)\r
+ {\r
+ StatementNode qtn = (StatementNode) nodeFactory.getNode(\r
+ C_NodeTypes.RENAME_NODE,\r
+ null,\r
+ oldIndexName,\r
+ newIndexName,\r
+ Boolean.FALSE,\r
+ReuseFactory.getInteger(StatementType.RENAME_INDEX),\r
+ getContextManager());\r
+\r
+ return qtn;\r
+\r
+ }\r
+}\r
+StatementNode\r
+renameColumnStatement() throws StandardException :\r
+{\r
+ String newColumnName;\r
+ ColumnReference oldColumnReference;\r
+}\r
+{\r
+ <COLUMN> oldColumnReference = columnReference()\r
+ <TO> newColumnName = identifier(Limits.MAX_IDENTIFIER_LENGTH, true)\r
+ {\r
+ if (oldColumnReference.getTableNameNode() == null)\r
+ throw StandardException.newException(\r
+ SQLState.LANG_OBJECT_DOES_NOT_EXIST,\r
+ "RENAME COLUMN",\r
+ oldColumnReference.getColumnName());\r
+ return (StatementNode) nodeFactory.getNode(\r
+ C_NodeTypes.RENAME_NODE,\r
+ oldColumnReference.getTableNameNode(),\r
+ oldColumnReference.getColumnName(),\r
+ newColumnName,\r
+ Boolean.FALSE,\r
+ ReuseFactory.getInteger(StatementType.RENAME_COLUMN),\r
+ getContextManager());\r
+ }\r
+}\r
+\r
+\r
+StatementNode\r
+lockStatement() throws StandardException :\r
+{\r
+ Boolean exclusiveMode;\r
+ TableName tableName;\r
+}\r
+{\r
+ <LOCK> <TABLE> tableName = qualifiedName(Limits.MAX_IDENTIFIER_LENGTH) <IN> exclusiveMode = lockMode() <MODE>\r
+ {\r
+ return (StatementNode) nodeFactory.getNode(\r
+ C_NodeTypes.LOCK_TABLE_NODE,\r
+ tableName,\r
+ exclusiveMode,\r
+ getContextManager());\r
+ }\r
+}\r
+\r
+Boolean\r
+lockMode() :\r
+{\r
+}\r
+{\r
+ <EXCLUSIVE>\r
+ {\r
+ return Boolean.TRUE;\r
+ }\r
+|\r
+ <SHARE>\r
+ {\r
+ return Boolean.FALSE;\r
+ }\r
+}\r
+\r
+StatementNode\r
+execStatement() throws StandardException :\r
+{\r
+ TableName stmtName;\r
+}\r
+{\r
+ <EXECUTE> <STATEMENT> stmtName = qualifiedName(Limits.MAX_IDENTIFIER_LENGTH) \r
+ {\r
+ return (StatementNode) nodeFactory.getNode(\r
+ C_NodeTypes.EXEC_SPS_NODE,\r
+ stmtName,\r
+ getContextManager());\r
+ }\r
+}\r
+\r
+TransactionStatementNode\r
+setIsolationStatement() throws StandardException :\r
+{\r
+ TransactionStatementNode tranNode;\r
+}\r
+{\r
+ setIsolationHeader() [ ( <EQUALS_OPERATOR> | <TO> ) ] tranNode = transactionMode()\r
+ {\r
+ return tranNode;\r
+ }\r
+}\r
+\r
+void\r
+setIsolationHeader() throws StandardException :\r
+{}\r
+{\r
+ <ISOLATION>\r
+|\r
+ LOOKAHEAD( { getToken(1).kind == CURRENT && getToken(2).kind == ISOLATION } )\r
+ <CURRENT> <ISOLATION>\r
+}\r
+\r
+\r
+TransactionStatementNode\r
+transactionMode() throws StandardException :\r
+{\r
+ int isolationLevel;\r
+}\r
+{\r
+ isolationLevel = isolationLevelDB2OrReset() \r
+ {\r
+ return (TransactionStatementNode) nodeFactory.getNode(\r
+ C_NodeTypes.SET_TRANSACTION_ISOLATION_NODE,\r
+ ReuseFactory.getInteger(isolationLevel),\r
+ getContextManager());\r
+ }\r
+}\r
+\r
+int\r
+isolationLevelDB2OrReset() :\r
+{\r
+ int isolationLevel;\r
+}\r
+{\r
+ (\r
+ <RESET> { return ExecutionContext.UNSPECIFIED_ISOLATION_LEVEL; }\r
+ | isolationLevel = isolationLevelDB2() { return isolationLevel; }\r
+ )\r
+}\r
+\r
+int\r
+isolationLevelDB2() :\r
+{\r
+ int isolationLevel;\r
+}\r
+{\r
+ (\r
+ isolationLevel = isolationLevelDB2Abbrev() { return isolationLevel; }\r
+ | ( ( <REPEATABLE> <READ> ) | <SERIALIZABLE> )\r
+ { return ExecutionContext.SERIALIZABLE_ISOLATION_LEVEL; }\r
+ | <CURSOR> <STABILITY>\r
+ { return ExecutionContext.READ_COMMITTED_ISOLATION_LEVEL; }\r
+\r
+ | <DIRTY> <READ>\r
+ { return ExecutionContext.READ_UNCOMMITTED_ISOLATION_LEVEL; }\r
+\r
+ |\r
+ LOOKAHEAD( { getToken(1).kind == READ && getToken(2).kind == COMMITTED } )\r
+ <READ> <COMMITTED>\r
+ { return ExecutionContext.READ_COMMITTED_ISOLATION_LEVEL; }\r
+\r
+ |\r
+ LOOKAHEAD( { getToken(1).kind == READ && getToken(2).kind == UNCOMMITTED } )\r
+ <READ> <UNCOMMITTED>\r
+ { return ExecutionContext.READ_UNCOMMITTED_ISOLATION_LEVEL; }\r
+ )\r
+}\r
+\r
+int\r
+isolationLevelDB2Abbrev() :\r
+{\r
+}\r
+{\r
+ (\r
+ <RR>\r
+ { return ExecutionContext.SERIALIZABLE_ISOLATION_LEVEL; }\r
+\r
+ | <RS> { return ExecutionContext.REPEATABLE_READ_ISOLATION_LEVEL; }\r
+\r
+ | <CS>\r
+ { return ExecutionContext.READ_COMMITTED_ISOLATION_LEVEL; }\r
+\r
+ | <UR>\r
+ { return ExecutionContext.READ_UNCOMMITTED_ISOLATION_LEVEL; }\r
+ )\r
+}\r
+\r
+\r
+int\r
+isolationLevel() :\r
+{\r
+ int isolationLevel;\r
+}\r
+{\r
+ <ISOLATION> <LEVEL> isolationLevel = levelOfIsolation()\r
+ {\r
+ return isolationLevel;\r
+ }\r
+}\r
+\r
+int\r
+levelOfIsolation() :\r
+{\r
+}\r
+{\r
+ <READ>\r
+ {\r
+ return levelOfIsolationRead();\r
+ }\r
+| \r
+ <REPEATABLE> <READ>\r
+ {\r
+ return ExecutionContext.REPEATABLE_READ_ISOLATION_LEVEL;\r
+ }\r
+|\r
+ <SERIALIZABLE>\r
+ {\r
+ return ExecutionContext.SERIALIZABLE_ISOLATION_LEVEL;\r
+ }\r
+}\r
+\r
+int\r
+levelOfIsolationRead() :\r
+{\r
+}\r
+{\r
+ <UNCOMMITTED> \r
+ {\r
+ return ExecutionContext.READ_UNCOMMITTED_ISOLATION_LEVEL;\r
+ }\r
+|\r
+ <COMMITTED> \r
+ {\r
+ return ExecutionContext.READ_COMMITTED_ISOLATION_LEVEL;\r
+ }\r
+}\r
+\r
+\r
+/*\r
+ * <A NAME="simpleValueSpecification">simpleValueSpecification</A>\r
+ */\r
+ValueNode\r
+simpleValueSpecification() throws StandardException :\r
+{\r
+ ValueNode value;\r
+}\r
+{\r
+ value = literal()\r
+ {\r
+ return value;\r
+ }\r
+}\r
+\r
+\r
+StatementNode\r
+setSchemaStatement() throws StandardException :\r
+{\r
+ StatementNode setSchema;\r
+}\r
+{\r
+ setSchemaHeader() [<EQUALS_OPERATOR>] setSchema = setSchemaValues()\r
+ {\r
+ if (parameterList != null && parameterList.size() > 0)\r
+ {\r
+ setUpAndLinkParameters();\r
+ // set the type of parameter node, it should be a varchar max Limits.MAX_IDENTIFIER_LENGTH - non nullable\r
+ ParameterNode p = (ParameterNode)parameterList.elementAt(0);\r
+ p.setType(new DataTypeDescriptor(TypeId.getBuiltInTypeId(Types.VARCHAR), false, Limits.MAX_IDENTIFIER_LENGTH));\r
+ }\r
+ return setSchema;\r
+ }\r
+}\r
+\r
+void \r
+setSchemaHeader() throws StandardException :\r
+{}\r
+{\r
+ <SCHEMA>\r
+|\r
+ LOOKAHEAD( { getToken(1).kind == CURRENT && ( getToken(2).kind == SCHEMA || getToken(2).kind == SQLID ) } )\r
+ <CURRENT> ( <SCHEMA> | <SQLID> )\r
+}\r
+\r
+StatementNode\r
+setSchemaValues() throws StandardException :\r
+{\r
+ String schemaName;\r
+}\r
+{\r
+ schemaName = identifier(Limits.MAX_IDENTIFIER_LENGTH, true)\r
+ {\r
+ return (StatementNode) nodeFactory.getNode(\r
+ C_NodeTypes.SET_SCHEMA_NODE,\r
+ schemaName,\r
+ null,\r
+ getContextManager());\r
+ }\r
+|\r
+ <USER>\r
+ {\r
+ return (StatementNode) nodeFactory.getNode(\r
+ C_NodeTypes.SET_SCHEMA_NODE,\r
+ null,\r
+ ReuseFactory.getInteger(StatementType.SET_SCHEMA_USER),\r
+ getContextManager());\r
+ }\r
+| dynamicParameterSpecification()\r
+ {\r
+ return (StatementNode) nodeFactory.getNode(\r
+ C_NodeTypes.SET_SCHEMA_NODE,\r
+ null,\r
+ ReuseFactory.getInteger(StatementType.SET_SCHEMA_DYNAMIC),\r
+ getContextManager());\r
+ }\r
+| schemaName = string()\r
+ {\r
+ /* Max length for schema name is Limits.MAX_IDENTIFIER_LENGTH */\r
+ checkIdentifierLengthLimit(schemaName, Limits.MAX_IDENTIFIER_LENGTH);\r
+ return (StatementNode) nodeFactory.getNode(\r
+ C_NodeTypes.SET_SCHEMA_NODE,\r
+ schemaName,\r
+ null,\r
+ getContextManager());\r
+ }\r
+}\r
+\r
+\r
+\r
+// Set the locale for messages coming from the database system. This\r
+// is for support only, so we can get messages in our preferred language\r
+// (usually English). I didn't want to create all the execution wiring\r
+// to do this, so this command executes in the parser\r
+StatementNode\r
+setMessageLocaleStatement() throws StandardException :\r
+{\r
+ String messageLocale;\r
+}\r
+{\r
+ <MESSAGE_LOCALE> messageLocale = string()\r
+ {\r
+ getContextManager().setMessageLocale(messageLocale);\r
+\r
+ return (StatementNode) nodeFactory.getNode(\r
+ C_NodeTypes.NOP_STATEMENT_NODE,\r
+ getContextManager());\r
+ }\r
+}\r
+\r
+/*\r
+ * <A NAME="valueSpecification">valueSpecification</A>\r
+ */\r
+ValueNode\r
+valueSpecification() throws StandardException :\r
+{\r
+ ValueNode value;\r
+ ValueNode leftExpression;\r
+ ValueNode rightExpression;\r
+}\r
+{\r
+ value = literal()\r
+ {\r
+ return value;\r
+ }\r
+|\r
+ value = generalValueSpecification()\r
+ {\r
+ return value;\r
+ }\r
+|\r
+ <NULLIF> <LEFT_PAREN> leftExpression = additiveExpression(null, 0, false) <COMMA> rightExpression = additiveExpression(null, 0, false) <RIGHT_PAREN>\r
+ {\r
+ // "NULLIF(L, R)" is the same as "L=R ? untyped NULL : L"\r
+ // An impl assumption here is that Derby can promote CHAR to any comparable datatypes such as numeric\r
+ ContextManager cm = getContextManager();\r
+ ValueNodeList thenElseList = (ValueNodeList) nodeFactory.getNode(C_NodeTypes.VALUE_NODE_LIST, cm);\r
+\r
+ //Use untyped null for then clause at this point. At the bind time, we will cast it to the datatype of L \r
+ thenElseList.addElement((ValueNode) nodeFactory.getNode(\r
+ C_NodeTypes.UNTYPED_NULL_CONSTANT_NODE,\r
+ cm));\r
+ thenElseList.addElement(leftExpression);\r
+\r
+ return (ValueNode) nodeFactory.getNode(\r
+ C_NodeTypes.CONDITIONAL_NODE,\r
+ (ValueNode) nodeFactory.getNode(\r
+ C_NodeTypes.BINARY_EQUALS_OPERATOR_NODE,\r
+ leftExpression,\r
+ rightExpression,\r
+ cm),\r
+ thenElseList,\r
+ Boolean.TRUE,//this node is for nullif \r
+ cm);\r
+ }\r
+|\r
+ // CASE WHEN P1 THEN [T1 | NULL] (WHEN Pi THEN [Ti | NULL])* [ELSE E | NULL] END\r
+ <CASE> value = whenThenExpression()\r
+ {\r
+ return value;\r
+ }\r
+}\r
+\r
+/*\r
+ * <A NAME="caseExpression">caseExpression</A>\r
+ */\r
+ValueNode\r
+caseExpression() throws StandardException :\r
+{\r
+ ValueNode expr;\r
+}\r
+{\r
+ <END>\r
+ {\r
+ ValueNode value = (ValueNode) nodeFactory.getNode(\r
+ C_NodeTypes.CAST_NODE,\r
+ (ValueNode) nodeFactory.getNode(C_NodeTypes.UNTYPED_NULL_CONSTANT_NODE,\r
+ getContextManager()),\r
+ DataTypeDescriptor.getBuiltInDataTypeDescriptor(Types.CHAR, 1), \r
+ getContextManager());\r
+ ((CastNode) value).setForExternallyGeneratedCASTnode();\r
+ return value;\r
+ }\r
+|\r
+ <ELSE> expr = thenElseExpression() <END>\r
+ {\r
+ return expr;\r
+ }\r
+|\r
+ expr = whenThenExpression()\r
+ {\r
+ return expr;\r
+ }\r
+}\r
+\r
+/*\r
+ * <A NAME="whenThenExpression">whenThenExpression</A>\r
+ */\r
+ValueNode\r
+whenThenExpression() throws StandardException :\r
+{\r
+ ValueNode expr;\r
+ ValueNode thenExpr;\r
+ ValueNode elseExpr;\r
+}\r
+{\r
+ <WHEN> expr = orExpression(null, false) \r
+ (<OR> expr = orExpression(expr, false) )*\r
+ <THEN> thenExpr = thenElseExpression()\r
+ elseExpr = caseExpression()\r
+ {\r
+ ContextManager cm = getContextManager();\r
+ ValueNodeList thenElseList = (ValueNodeList) nodeFactory.getNode(C_NodeTypes.VALUE_NODE_LIST, cm);\r
+ thenElseList.addElement(thenExpr); // then\r
+ thenElseList.addElement(elseExpr); // else\r
+\r
+ return((ValueNode) nodeFactory.getNode(C_NodeTypes.CONDITIONAL_NODE,\r
+ expr,\r
+ thenElseList,\r
+ Boolean.FALSE,\r
+ cm));\r
+ }\r
+}\r
+\r
+/*\r
+ * <A NAME="thenElseExpression">thenElseExpression</A>\r
+ */\r
+ValueNode\r
+thenElseExpression() throws StandardException :\r
+{\r
+ ValueNode expr;\r
+}\r
+{ \r
+ LOOKAHEAD ( {getToken(1).kind == NULL} )\r
+ <NULL>\r
+ {\r
+ ValueNode value = (ValueNode) nodeFactory.getNode(\r
+ C_NodeTypes.CAST_NODE,\r
+ (ValueNode) nodeFactory.getNode(C_NodeTypes.UNTYPED_NULL_CONSTANT_NODE,\r
+ getContextManager()),\r
+ DataTypeDescriptor.getBuiltInDataTypeDescriptor(Types.CHAR, 1), \r
+ getContextManager());\r
+ ((CastNode) value).setForExternallyGeneratedCASTnode();\r
+ return value;\r
+ }\r
+|\r
+ expr = additiveExpression(null, 0, false)\r
+ {\r
+ return expr;\r
+ }\r
+}\r
+\r
+TableElementNode\r
+tableConstraintDefinition() throws StandardException :\r
+{\r
+ Properties properties = null;\r
+ ConstraintDefinitionNode tcdn;\r
+ TableName constraintName = null;\r
+ //initialize following two booleans before handling table level constraints\r
+ explicitNotNull = false;\r
+ explicitNull = false;\r
+}\r
+{\r
+ [ constraintName = constraintNameDefinition() ] \r
+ tcdn = tableConstraint(constraintName) \r
+ [ properties = propertyList(false) <CHECK_PROPERTIES>]\r
+ {\r
+ if (properties != null)\r
+ {\r
+ tcdn.setProperties(properties);\r
+ }\r
+ return tcdn;\r
+ }\r
+}\r
+\r
+ConstraintDefinitionNode\r
+tableConstraint(TableName constraintName) throws StandardException :\r
+{\r
+ ConstraintDefinitionNode tcdn;\r
+}\r
+{\r
+ tcdn = uniqueConstraintDefinition(constraintName) \r
+ {\r
+ return tcdn;\r
+ }\r
+|\r
+ tcdn = referentialConstraintDefinition(constraintName) \r
+ {\r
+ return tcdn;\r
+ }\r
+|\r
+ tcdn = checkConstraintDefinition(constraintName, null)\r
+ {\r
+ return tcdn;\r
+ }\r
+}\r
+\r
+ConstraintDefinitionNode\r
+uniqueConstraintDefinition(TableName constraintName) throws StandardException :\r
+{\r
+ int constraintType;\r
+ ResultColumnList uniqueColumnList;\r
+}\r
+{\r
+ //for table level constraint, second parameter will be null\r
+ constraintType = uniqueSpecification((DataTypeDescriptor) null, null) \r
+ <LEFT_PAREN> uniqueColumnList = uniqueColumnList() <RIGHT_PAREN>\r
+ {\r
+ //go through the unique columns list and if any of the columns in the\r
+ //list is explicitly defined null, throw an exception for this. Columns\r
+ //for which no nullability is defined are by default nullable. But in\r
+ //case of create table, there nullability changes automatically to \r
+ //non-nullable if primary key is defined on it. But if user explicitly\r
+ //defines the nullability, then defining a primary key on it in create\r
+ //table will result in an exception.\r
+ if (constraintType == DataDictionary.PRIMARYKEY_CONSTRAINT)\r
+ {\r
+ for (int index = 0; index < uniqueColumnList.size(); index++)\r
+ {\r
+ String primaryKeyColumnName = ((ResultColumn) uniqueColumnList.elementAt(index)).getName();\r
+ if (explicitlyNullableColumnsList.contains(primaryKeyColumnName))\r
+ {\r
+ String errorState = SQLState.LANG_DB2_ADD_UNIQUE_OR_PRIMARY_KEY_ON_NULL_COLS;\r
+ throw StandardException.newException(errorState, primaryKeyColumnName);\r
+ }\r
+ }\r
+ }\r
+ return (ConstraintDefinitionNode) nodeFactory.getNode(\r
+ C_NodeTypes.CONSTRAINT_DEFINITION_NODE,\r
+ constraintName,\r
+ ReuseFactory.getInteger(constraintType),\r
+ uniqueColumnList,\r
+ null,\r
+ null,\r
+ null,\r
+ getContextManager()\r
+ );\r
+ }\r
+}\r
+\r
+//the second parameter to the following method will always be null for a table level\r
+//constraint but not for a column level constraint\r
+int\r
+uniqueSpecification(DataTypeDescriptor dataTypeDescriptor,\r
+String columnName) throws StandardException :\r
+{\r
+}\r
+{\r
+ <UNIQUE> \r
+ {\r
+ return DataDictionary.UNIQUE_CONSTRAINT;\r
+ }\r
+|\r
+ <PRIMARY> <KEY>\r
+ {\r
+ //explicitNull can be true only if it's column level constraint and\r
+ //that column has null constraint defined on it. In that case, defining\r
+ //a column-level constraint of primary key on it will result in an error.\r
+ if (explicitNull) \r
+ {\r
+ String errorState = SQLState.LANG_DB2_ADD_UNIQUE_OR_PRIMARY_KEY_ON_NULL_COLS;\r
+ throw StandardException.newException(errorState, columnName);\r
+ }\r
+ return DataDictionary.PRIMARYKEY_CONSTRAINT;\r
+ }\r
+}\r
+\r
+ResultColumnList\r
+uniqueColumnList() throws StandardException :\r
+{\r
+ ResultColumnList resultColumns = (ResultColumnList) nodeFactory.getNode(\r
+ C_NodeTypes.RESULT_COLUMN_LIST,\r
+ getContextManager());\r
+}\r
+{\r
+ columnNameList(resultColumns)\r
+ {\r
+ return resultColumns;\r
+ }\r
+}\r
+\r
+ConstraintDefinitionNode\r
+referentialConstraintDefinition(TableName constraintName) throws StandardException :\r
+{\r
+ ResultColumnList fkRcl = (ResultColumnList) nodeFactory.getNode(\r
+ C_NodeTypes.RESULT_COLUMN_LIST,\r
+ getContextManager());\r
+ ResultColumnList refRcl = (ResultColumnList) nodeFactory.getNode(\r
+ C_NodeTypes.RESULT_COLUMN_LIST,\r
+ getContextManager());\r
+ TableName referencedTable;\r
+ int[] refActions = {StatementType.RA_NOACTION, \r
+ StatementType.RA_NOACTION}; //default values\r
+}\r
+{\r
+ <FOREIGN> <KEY> <LEFT_PAREN> columnNameList(fkRcl) <RIGHT_PAREN>\r
+ referencedTable = referencesSpecification(refRcl, refActions)\r
+ {\r
+ return (ConstraintDefinitionNode) nodeFactory.getNode(\r
+ C_NodeTypes.FK_CONSTRAINT_DEFINITION_NODE,\r
+ constraintName,\r
+ referencedTable,\r
+ fkRcl,\r
+ refRcl,\r
+ refActions,\r
+ getContextManager());\r
+ }\r
+}\r
+\r
+TableName\r
+referencesSpecification(ResultColumnList rcl, int[] refActions) throws StandardException :\r
+{\r
+ TableName tableName = null;\r
+}\r
+{\r
+ <REFERENCES> tableName = referencedTableAndColumns(rcl)\r
+ // not supporting MATCH or referential actions beyond syntax for default\r
+ [ <ON> referentialTriggeredAction(refActions) ]\r
+ {\r
+ return tableName;\r
+ }\r
+}\r
+\r
+TableName\r
+referencedTableAndColumns(ResultColumnList rcl) throws StandardException :\r
+{\r
+ TableName tableName = null;\r
+}\r
+{\r
+ tableName = qualifiedName(Limits.MAX_IDENTIFIER_LENGTH) [ <LEFT_PAREN> columnNameList(rcl) <RIGHT_PAREN> ]\r
+ {\r
+ return tableName;\r
+ }\r
+}\r
+\r
+void\r
+referentialTriggeredAction(int [] refActions) throws StandardException :\r
+{}\r
+{\r
+ ( refActions[1] = updateRule() [<ON> refActions[0] = deleteRule() ] |\r
+ refActions[0] = deleteRule() [<ON> refActions[1] = updateRule() ] )\r
+}\r
+\r
+int\r
+updateRule() :\r
+{\r
+ int action;\r
+}\r
+{\r
+ <UPDATE> action = updateReferentialAction()\r
+ {\r
+ return action;\r
+ }\r
+}\r
+\r
+int\r
+deleteRule() :\r
+{\r
+ int action;\r
+}\r
+{\r
+ <DELETE> action = deleteReferentialAction()\r
+ {\r
+ return action;\r
+ }\r
+\r
+}\r
+\r
+int\r
+updateReferentialAction() :\r
+{}\r
+{\r
+ \r
+ <RESTRICT> {return StatementType.RA_RESTRICT;}\r
+ | <NO> <ACTION> {return StatementType.RA_NOACTION;}\r
+\r
+}\r
+\r
+int\r
+deleteReferentialAction() :\r
+{}\r
+{\r
+ <CASCADE> {return StatementType.RA_CASCADE;} \r
+ | <RESTRICT> {return StatementType.RA_RESTRICT;} \r
+ | <NO> <ACTION> {return StatementType.RA_NOACTION;}\r
+ | <SET> \r
+ ( <NULL> {return StatementType.RA_SETNULL;} \r
+ |<_DEFAULT> {return StatementType.RA_SETDEFAULT;}\r
+ )\r
+}\r
+\r
+/*\r
+ * <A NAME="columnConstraintDefinition">columnConstraintDefinition</A>\r
+ */\r
+void\r
+columnConstraintDefinition(DataTypeDescriptor dataTypeDescriptor,\r
+ TableElementList tableElementList,\r
+ String columnName) throws StandardException :\r
+{\r
+ int constraintType;\r
+ TableElementNode tcdn;\r
+ TableName constraintName = null;\r
+}\r
+{\r
+ [ constraintName = constraintNameDefinition() ]\r
+ tcdn = columnConstraint(constraintName, dataTypeDescriptor, columnName)\r
+ {\r
+ /* NOT NULL constraints are handled by marking the dataTypeDescriptor\r
+ * as being non-nullable.\r
+ */\r
+ if (tcdn == null)\r
+ {\r
+ return;\r
+ }\r
+\r
+ /* All other constraints, whether column or table will be added as\r
+ * table constraints. We do this to facilitate the handling of\r
+ * multiple column constraints on the same column.\r
+ */\r
+ tableElementList.addTableElement(tcdn);\r
+ }\r
+}\r
+\r
+/*\r
+ * <A NAME="columnConstraint">columnConstraint</A>\r
+ */\r
+ConstraintDefinitionNode\r
+columnConstraint(TableName constraintName,\r
+ DataTypeDescriptor dataTypeDescriptor,\r
+ String columnName) throws StandardException :\r
+{\r
+ int constraintType;\r
+ Properties properties = null;\r
+ ConstraintDefinitionNode tcdn;\r
+ ResultColumnList refRcl = (ResultColumnList) nodeFactory.getNode(\r
+ C_NodeTypes.RESULT_COLUMN_LIST,\r
+ getContextManager());\r
+ TableName referencedTable;\r
+ int[] refActions = {StatementType.RA_NOACTION,\r
+ StatementType.RA_NOACTION} ; //default: NO ACTION\r
+}\r
+{\r
+ <NOT> <NULL>\r
+ {\r
+ //if column is explicitly defined not nullable, set following flag\r
+ explicitNotNull = true;\r
+ //if both null and not null constraints are defined for a column,\r
+ //throw an exception\r
+ if (explicitNull) \r
+ throw StandardException.newException(SQLState.LANG_ADDING_COLUMN_WITH_NULL_AND_NOT_NULL_CONSTRAINT, columnName); \r
+ dataTypeDescriptor.setNullability(false);\r
+ return null;\r
+ }\r
+|\r
+ //pass the columnname as the second parameter. It will be used to throw an\r
+ //exception if null constraint is defined for this column-level primary \r
+ //key constraint\r
+ constraintType = uniqueSpecification(dataTypeDescriptor,columnName)\r
+ [ properties = propertyList(false) <CHECK_PROPERTIES>]\r
+ {\r
+ ResultColumnList uniqueColumnList =\r
+ (ResultColumnList) nodeFactory.getNode(\r
+ C_NodeTypes.RESULT_COLUMN_LIST,\r
+ getContextManager());\r
+ uniqueColumnList.addElement(\r
+ (ResultColumn) nodeFactory.getNode(\r
+ C_NodeTypes.RESULT_COLUMN,\r
+ columnName,\r
+ null,\r
+ getContextManager()));\r
+\r
+ return (ConstraintDefinitionNode) nodeFactory.getNode(\r
+ C_NodeTypes.CONSTRAINT_DEFINITION_NODE,\r
+ constraintName,\r
+ ReuseFactory.getInteger(constraintType),\r
+ uniqueColumnList,\r
+ properties,\r
+ null,\r
+ null,\r
+ getContextManager()\r
+ );\r
+ }\r
+| \r
+ referencedTable = referencesSpecification(refRcl, refActions)\r
+ [ properties = propertyList(false)<CHECK_PROPERTIES>] \r
+ {\r
+ ResultColumnList fkRcl = (ResultColumnList) nodeFactory.getNode(\r
+ C_NodeTypes.RESULT_COLUMN_LIST,\r
+ getContextManager());\r
+ fkRcl.addElement(\r
+ (ResultColumn) nodeFactory.getNode(\r
+ C_NodeTypes.RESULT_COLUMN,\r
+ columnName,\r
+ null,\r
+ getContextManager())\r
+ );\r
+ tcdn = (ConstraintDefinitionNode) nodeFactory.getNode(\r
+ C_NodeTypes.FK_CONSTRAINT_DEFINITION_NODE,\r
+ constraintName,\r
+ referencedTable,\r
+ fkRcl,\r
+ refRcl,\r
+ refActions,\r
+ getContextManager());\r
+ if (properties != null)\r
+ {\r
+ tcdn.setProperties(properties);\r
+ }\r
+ return tcdn;\r
+ }\r
+|\r
+ tcdn = checkConstraintDefinition(constraintName, columnName)\r
+ {\r
+ return tcdn;\r
+ }\r
+}\r
+\r
+StatementNode\r
+dropSchemaStatement() throws StandardException :\r
+{\r
+ String schemaName;\r
+}\r
+{\r
+ <SCHEMA> schemaName = identifier(Limits.MAX_IDENTIFIER_LENGTH, true) <RESTRICT>\r
+ {\r
+ StatementNode stmt = (StatementNode) nodeFactory.getNode(\r
+ C_NodeTypes.DROP_SCHEMA_NODE,\r
+ schemaName,\r
+ new Integer(StatementType.DROP_RESTRICT),\r
+ getContextManager());\r
+\r
+ return stmt;\r
+ }\r
+}\r
+\r
+StatementNode\r
+alterTableStatement() throws StandardException :\r
+{\r
+ StatementNode node;\r
+ TableName tableName;\r
+}\r
+{\r
+ <TABLE> tableName = qualifiedName(Limits.MAX_IDENTIFIER_LENGTH) node = alterTableBody(tableName)\r
+ {\r
+ return node;\r
+ }\r
+}\r
+\r
+StatementNode\r
+alterTableBody(TableName tableName) throws StandardException :\r
+{\r
+ StatementNode qtn;\r
+ char lockGranularity = '\0';\r
+ String newTableName;\r
+ TableElementList tableElementList =\r
+ (TableElementList) nodeFactory.getNode(\r
+ C_NodeTypes.TABLE_ELEMENT_LIST,\r
+ getContextManager());\r
+ Token tok = null;\r
+ int[] changeType = new int[1];\r
+ int[] behavior = new int[1];\r
+ boolean[] sequential = new boolean[1];\r
+}\r
+{\r
+//insert special key before compress so that only internal SP can know\r
+ <COMPRESS> [ tok = <SEQUENTIAL> ]\r
+ { \r
+ checkInternalFeature("COMPRESS");\r
+ return (StatementNode) nodeFactory.getNode(\r
+ C_NodeTypes.ALTER_TABLE_NODE,\r
+ tableName,\r
+ new Boolean(tok != null),\r
+ getContextManager());\r
+ }\r
+|\r
+ lockGranularity = alterTableAction( tableElementList, changeType, behavior, sequential )\r
+ {\r
+ return (StatementNode) nodeFactory.getNode(\r
+ C_NodeTypes.ALTER_TABLE_NODE,\r
+ tableName,\r
+ tableElementList,\r
+ new Character(lockGranularity),\r
+ changeType,\r
+ behavior,\r
+ sequential,\r
+ getContextManager());\r
+ }\r
+}\r
+\r
+/*\r
+ * <A NAME="alterTableRenameTableStatement">alterTableRenameTableStatement</A>\r
+ */\r
+/*\r
+StatementNode\r
+alterTableRenameTableStatement(TableName tableName) throws StandardException :\r
+{\r
+ String newTableName;\r
+}\r
+{\r
+ <TO> newTableName = identifier(Limits.MAX_IDENTIFIER_LENGTH, true)\r
+ {\r
+ return (StatementNode) nodeFactory.getNode(\r
+ C_NodeTypes.RENAME_NODE,\r
+ tableName,\r
+ null,\r
+ newTableName,\r
+ Boolean.TRUE,\r
+ReuseFactory.getInteger(StatementType.RENAME_TABLE),\r
+ getContextManager());\r
+ }\r
+}\r
+*/\r
+\r
+/*\r
+ * <A NAME="alterTableRenameColumnStatement">alterTableRenameColumnStatement</A>\r
+ */\r
+/*\r
+StatementNode\r
+alterTableRenameColumnStatement(TableName tableName) throws StandardException :\r
+{\r
+ String oldColumnName;\r
+ String newColumnName;\r
+}\r
+{\r
+ oldColumnName = identifier(Limits.MAX_IDENTIFIER_LENGTH, true) <TO> newColumnName = identifier(Limits.MAX_IDENTIFIER_LENGTH, true)\r
+ {\r
+ return (StatementNode) nodeFactory.getNode(\r
+ C_NodeTypes.RENAME_NODE,\r
+ tableName,\r
+ oldColumnName,\r
+ newColumnName,\r
+ Boolean.TRUE,\r
+ReuseFactory.getInteger(StatementType.RENAME_COLUMN),\r
+ getContextManager());\r
+ }\r
+}\r
+*/\r
+char\r
+alterTableAction(TableElementList tableElementList, int[] changeType, int[] behavior, boolean[] sequential) throws StandardException :\r
+{\r
+ char lockGranularity = '\0';\r
+ TableElementNode tableElement;\r
+ DataTypeDescriptor typeDescriptor;\r
+ Token tok = null;\r
+ String columnName;\r
+ long[] autoIncrementInfo = new long[4];\r
+}\r
+{\r
+ <ADD>\r
+ (\r
+ tableElement = addColumnDefinition(tableElementList)\r
+ |\r
+ tableElement = tableConstraintDefinition()\r
+ )\r
+ {\r
+ if (tableElement instanceof ColumnDefinitionNode)\r
+ {\r
+ //bug 5724 - auto increment columns not allowed in ALTER TABLE statement\r
+ ColumnDefinitionNode cdn = (ColumnDefinitionNode) tableElement;\r
+ if ( cdn.isAutoincrementColumn())\r
+ throw StandardException.newException(SQLState.LANG_ALTER_TABLE_AUTOINCREMENT_COLUMN_NOT_ALLOWED);\r
+ }\r
+ changeType[0] = DDLStatementNode.ADD_TYPE;\r
+ tableElementList.addTableElement(tableElement);\r
+ return lockGranularity;\r
+ }\r
+|\r
+ <ALTER> [ <COLUMN> ] columnName = identifier(Limits.MAX_IDENTIFIER_LENGTH, true) \r
+ tableElement = columnAlterClause(columnName)\r
+ {\r
+ changeType[0] = DDLStatementNode.MODIFY_TYPE;\r
+ tableElementList.addTableElement(tableElement);\r
+ return lockGranularity;\r
+ }\r
+|\r
+ <DROP>\r
+ (\r
+ tableElement = dropColumnDefinition(behavior)\r
+ |\r
+ tableElement = dropTableConstraintDefinition()\r
+ )\r
+ {\r
+ changeType[0] = DDLStatementNode.DROP_TYPE;\r
+ tableElementList.addTableElement(tableElement);\r
+ return lockGranularity;\r
+ }\r
+|\r
+ lockGranularity = DB2lockGranularityClause()\r
+ {\r
+ changeType[0] = DDLStatementNode.LOCKING_TYPE;\r
+ return lockGranularity;\r
+ }\r
+}\r
+\r
+/*\r
+ * Handle\r
+ *\r
+ * ALTER TABLE tablename DROP [ COLUMN ] columnname [ CASCADE | RESTRICT ]\r
+ */\r
+TableElementNode\r
+dropColumnDefinition(int []behavior) throws StandardException :\r
+{\r
+ String columnName;\r
+ TableElementNode tableElement;\r
+}\r
+{\r
+ [ <COLUMN> ] columnName = identifier(Limits.MAX_IDENTIFIER_LENGTH, true)\r
+ dropColumnReferentialAction(behavior)\r
+ {\r
+ return (TableElementNode) nodeFactory.getNode(\r
+ C_NodeTypes.DROP_COLUMN_NODE,\r
+ columnName, null,\r
+ null, null,\r
+ getContextManager());\r
+ }\r
+}\r
+void\r
+dropColumnReferentialAction(int []behavior) :\r
+{\r
+ int refBehavior = StatementType.DROP_CASCADE;\r
+}\r
+{\r
+ [ <CASCADE> {refBehavior = StatementType.DROP_CASCADE;} \r
+ | <RESTRICT> {refBehavior = StatementType.DROP_RESTRICT;} \r
+ ]\r
+ {\r
+ behavior[0] = refBehavior;\r
+ }\r
+}\r
+\r
+TableElementNode\r
+addColumnDefinition(TableElementList tableElementList) throws StandardException :\r
+{\r
+ TableElementNode tableElement;\r
+}\r
+{\r
+ [ <COLUMN> ] tableElement = columnDefinition(tableElementList)\r
+ {\r
+ return tableElement;\r
+ }\r
+}\r
+\r
+/*\r
+ * Various variants of the ALTER TABLE ALTER COLUMN statement.\r
+ *\r
+ * By the type we get here, we've parsed\r
+ * ALTER TABLE tablename ALTER [COLUMN] columnname\r
+ * and here we parse the remainder of the ALTER COLUMN clause, one of:\r
+ * SET DATA TYPE data_type\r
+ * SET INCREMENT BY increment_value\r
+ * RESTART WITH increment_restart_value\r
+ * [WITH] DEFAULT default_value\r
+ * [NOT] NULL\r
+ */\r
+TableElementNode\r
+columnAlterClause(String columnName) throws StandardException :\r
+{\r
+ ValueNode defaultNode;\r
+ long[] autoIncrementInfo = new long[4];\r
+ long autoIncrementIncrement = 1;\r
+ long autoIncrementRestartWith = 1;\r
+ DataTypeDescriptor typeDescriptor = null;\r
+}\r
+{\r
+ LOOKAHEAD( {getToken(2).kind == DATA} )\r
+ <SET> <DATA> <TYPE> typeDescriptor = dataTypeDDL()\r
+ {\r
+ return (TableElementNode) nodeFactory.getNode(\r
+ C_NodeTypes.MODIFY_COLUMN_TYPE_NODE,\r
+ columnName, null,\r
+ typeDescriptor, null,\r
+ getContextManager());\r
+ }\r
+|\r
+ LOOKAHEAD( {getToken(2).kind == INCREMENT} )\r
+ <SET> <INCREMENT> <BY> autoIncrementIncrement = exactNumber()\r
+ {\r
+ autoIncrementInfo[QueryTreeNode.AUTOINCREMENT_INC_INDEX] = autoIncrementIncrement;\r
+ autoIncrementInfo[QueryTreeNode.AUTOINCREMENT_CREATE_MODIFY] = ColumnDefinitionNode.MODIFY_AUTOINCREMENT_INC_VALUE;\r
+ return (TableElementNode) nodeFactory.getNode(\r
+ C_NodeTypes.MODIFY_COLUMN_DEFAULT_NODE,\r
+ columnName,\r
+ null, null, autoIncrementInfo,\r
+ getContextManager());\r
+ }\r
+|\r
+ <RESTART> <WITH> autoIncrementRestartWith = exactNumber()\r
+ {\r
+ autoIncrementInfo[QueryTreeNode.AUTOINCREMENT_START_INDEX] = autoIncrementRestartWith;\r
+ autoIncrementInfo[QueryTreeNode.AUTOINCREMENT_CREATE_MODIFY] = ColumnDefinitionNode.MODIFY_AUTOINCREMENT_RESTART_VALUE;\r
+ return (TableElementNode) nodeFactory.getNode(\r
+ C_NodeTypes.MODIFY_COLUMN_DEFAULT_NODE,\r
+ columnName,\r
+ null, null, autoIncrementInfo,\r
+ getContextManager());\r
+ }\r
+|\r
+ LOOKAHEAD( {getToken(1).kind == WITH || getToken(1).kind == _DEFAULT })\r
+ defaultNode = defaultClause(autoIncrementInfo, columnName)\r
+ {\r
+ if (autoIncrementInfo[QueryTreeNode.AUTOINCREMENT_IS_AUTOINCREMENT_INDEX]\r
+ == 0)\r
+ {\r
+ autoIncrementInfo = null;\r
+ }\r
+\r
+ return (TableElementNode) nodeFactory.getNode(\r
+ C_NodeTypes.MODIFY_COLUMN_DEFAULT_NODE,\r
+ columnName,\r
+ defaultNode, null, autoIncrementInfo,\r
+ getContextManager());\r
+ }\r
+|\r
+ LOOKAHEAD ({getToken(1).kind == NULL })\r
+ <NULL>\r
+ {\r
+ // for a MODIFY column NULL clause form a modify_column node\r
+ // with all null values. In a column definition a [NOT] NULL\r
+ // column constraint is specified by setting the right value\r
+ // in the nullability field of the data type but we don't have\r
+ // a datatype here.\r
+ return (TableElementNode) nodeFactory.getNode(\r
+ C_NodeTypes.MODIFY_COLUMN_CONSTRAINT_NODE,\r
+ columnName, null, null, null,\r
+ getContextManager());\r
+ }\r
+|\r
+ LOOKAHEAD({getToken(1).kind == NOT})\r
+ <NOT> <NULL>\r
+ {\r
+ // for a MODIFY column NOT NULL clause form a modify_column node\r
+ // with all null values. In a column definition a [NOT] NULL\r
+ // column constraint is specified by setting the right value\r
+ // in the nullability field of the data type but we don't have\r
+ // a datatype here.\r
+ return (TableElementNode) nodeFactory.getNode(\r
+ C_NodeTypes.MODIFY_COLUMN_CONSTRAINT_NOT_NULL_NODE,\r
+ columnName, null, null, null,\r
+ getContextManager());\r
+ }\r
+}\r
+\r
+\r
+TableElementNode\r
+dropTableConstraintDefinition() throws StandardException :\r
+{\r
+ TableName constraintName;\r
+}\r
+{\r
+ LOOKAHEAD( {getToken(1).kind == CONSTRAINT} )\r
+ /* changed constraintName() to qualifiedName() for compaction */\r
+ <CONSTRAINT> constraintName = qualifiedName(Limits.MAX_IDENTIFIER_LENGTH)\r
+ {\r
+ return (TableElementNode) nodeFactory.getNode(\r
+ C_NodeTypes.CONSTRAINT_DEFINITION_NODE,\r
+ constraintName,\r
+ ReuseFactory.getInteger(DataDictionary.DROP_CONSTRAINT),\r
+ null,\r
+ null,\r
+ null,\r
+ null,\r
+ ReuseFactory.getInteger(StatementType.DROP_DEFAULT),\r
+ getContextManager()\r
+ );\r
+ }\r
+|\r
+ LOOKAHEAD( {getToken(1).kind == PRIMARY} )\r
+ <PRIMARY> <KEY>\r
+ {\r
+ return (TableElementNode) nodeFactory.getNode(\r
+ C_NodeTypes.CONSTRAINT_DEFINITION_NODE,\r
+ null,\r
+ ReuseFactory.getInteger(DataDictionary.DROP_CONSTRAINT),\r
+ null,\r
+ null,\r
+ null,\r
+ null,\r
+ ReuseFactory.getInteger(StatementType.DROP_DEFAULT),\r
+ getContextManager()\r
+ );\r
+ }\r
+|\r
+ LOOKAHEAD( {getToken(1).kind == FOREIGN} )\r
+ <FOREIGN> <KEY> constraintName = qualifiedName(Limits.MAX_IDENTIFIER_LENGTH)\r
+ {\r
+ return (TableElementNode) nodeFactory.getNode(\r
+ C_NodeTypes.CONSTRAINT_DEFINITION_NODE,\r
+ constraintName,\r
+ ReuseFactory.getInteger(DataDictionary.DROP_CONSTRAINT),\r
+ null,\r
+ null,\r
+ null,\r
+ null,\r
+ ReuseFactory.getInteger(StatementType.DROP_DEFAULT),\r
+ ReuseFactory.getInteger(DataDictionary.FOREIGNKEY_CONSTRAINT),\r
+ getContextManager()\r
+ );\r
+ }\r
+|\r
+ LOOKAHEAD( {getToken(1).kind == UNIQUE} )\r
+ <UNIQUE> constraintName = qualifiedName(Limits.MAX_IDENTIFIER_LENGTH)\r
+ {\r
+ return (TableElementNode) nodeFactory.getNode(\r
+ C_NodeTypes.CONSTRAINT_DEFINITION_NODE,\r
+ constraintName,\r
+ ReuseFactory.getInteger(DataDictionary.DROP_CONSTRAINT),\r
+ null,\r
+ null,\r
+ null,\r
+ null,\r
+ ReuseFactory.getInteger(StatementType.DROP_DEFAULT),\r
+ ReuseFactory.getInteger(DataDictionary.UNIQUE_CONSTRAINT),\r
+ getContextManager()\r
+ );\r
+ }\r
+|\r
+ <CHECK> constraintName = qualifiedName(Limits.MAX_IDENTIFIER_LENGTH)\r
+ {\r
+ return (TableElementNode) nodeFactory.getNode(\r
+ C_NodeTypes.CONSTRAINT_DEFINITION_NODE,\r
+ constraintName,\r
+ ReuseFactory.getInteger(DataDictionary.DROP_CONSTRAINT),\r
+ null,\r
+ null,\r
+ null,\r
+ null,\r
+ ReuseFactory.getInteger(StatementType.DROP_DEFAULT),\r
+ ReuseFactory.getInteger(DataDictionary.CHECK_CONSTRAINT),\r
+ getContextManager()\r
+ );\r
+ }\r
+}\r
+\r
+/*\r
+ * <A NAME="dropTableStatement">dropTableStatement</A>\r
+ */\r
+StatementNode\r
+dropTableStatement() throws StandardException :\r
+{\r
+ TableName tableName;\r
+}\r
+{\r
+ <TABLE> tableName = qualifiedName(Limits.MAX_IDENTIFIER_LENGTH) \r
+ {\r
+ // DB2 does not support a drop behaviour\r
+ return (StatementNode) nodeFactory.getNode(\r
+ C_NodeTypes.DROP_TABLE_NODE,\r
+ tableName,\r
+ new Integer(StatementType.DROP_DEFAULT),\r
+ getContextManager());\r
+ }\r
+}\r
+\r
+/*\r
+ * <A NAME="dropIndexStatement">dropIndexStatement</A>\r
+ */\r
+StatementNode\r
+dropIndexStatement() throws StandardException :\r
+{\r
+ TableName indexName;\r
+}\r
+{\r
+ <INDEX> indexName = qualifiedName(Limits.MAX_IDENTIFIER_LENGTH)\r
+ {\r
+ return (StatementNode) nodeFactory.getNode(\r
+ C_NodeTypes.DROP_INDEX_NODE,\r
+ indexName,\r
+ getContextManager());\r
+ }\r
+}\r
+\r
+/*\r
+ * <A NAME="dropAliasStatement">dropAliasStatement</A>\r
+ */\r
+StatementNode\r
+dropAliasStatement() throws StandardException :\r
+{\r
+ Object aliasName;\r
+}\r
+{\r
+ <PROCEDURE> aliasName = qualifiedName(Limits.MAX_IDENTIFIER_LENGTH) \r
+ {\r
+ return dropAliasNode(aliasName, AliasInfo.ALIAS_TYPE_PROCEDURE_AS_CHAR);\r
+ } \r
+| <FUNCTION> aliasName = qualifiedName(Limits.MAX_IDENTIFIER_LENGTH) \r
+ {\r
+ return dropAliasNode(aliasName, AliasInfo.ALIAS_TYPE_FUNCTION_AS_CHAR);\r
+ } \r
+| <SYNONYM> aliasName = qualifiedName(Limits.MAX_IDENTIFIER_LENGTH)\r
+ {\r
+ checkVersion(DataDictionary.DD_VERSION_DERBY_10_1, "DROP SYNONYM");\r
+\r
+ return dropAliasNode(aliasName, AliasInfo.ALIAS_TYPE_SYNONYM_AS_CHAR);\r
+ }\r
+}\r
+\r
+StatementNode\r
+dropViewStatement() throws StandardException :\r
+{\r
+ TableName viewName;\r
+}\r
+{\r
+ <VIEW> viewName = qualifiedName(Limits.MAX_IDENTIFIER_LENGTH) \r
+ {\r
+ return (StatementNode) nodeFactory.getNode(\r
+ C_NodeTypes.DROP_VIEW_NODE,\r
+ viewName,\r
+ getContextManager());\r
+ }\r
+}\r
+\r
+StatementNode\r
+dropTriggerStatement() throws StandardException :\r
+{\r
+ TableName triggerName;\r
+}\r
+{\r
+ <TRIGGER> triggerName = qualifiedName(Limits.MAX_IDENTIFIER_LENGTH) \r
+ {\r
+ return (StatementNode) nodeFactory.getNode(\r
+ C_NodeTypes.DROP_TRIGGER_NODE,\r
+ triggerName,\r
+ getContextManager());\r
+ }\r
+}\r
+\r
+\r
+StatementNode\r
+truncateTableStatement() throws StandardException :\r
+{\r
+ TableName tableName;\r
+}\r
+{\r
+ <TRUNCATE> <TABLE> tableName = qualifiedName(Limits.MAX_IDENTIFIER_LENGTH) \r
+ {\r
+ return (StatementNode) nodeFactory.getNode(\r
+ C_NodeTypes.ALTER_TABLE_NODE,\r
+ tableName,\r
+ getContextManager());\r
+ }\r
+}\r
+\r
+/*\r
+ * <A NAME="grantStatement">grantStatement</A>\r
+ */\r
+StatementNode\r
+grantStatement() throws StandardException :\r
+{\r
+ StatementNode node;\r
+}\r
+{\r
+ <GRANT>\r
+ {\r
+ checkVersion( DataDictionary.DD_VERSION_DERBY_10_2, "GRANT");\r
+ checkSqlStandardAccess( "GRANT");\r
+ }\r
+ ( node = tableGrantStatement() | node = routineGrantStatement() )\r
+ {\r
+ return node;\r
+ }\r
+}\r
+\r
+/*\r
+ * <A NAME="tableGrantStatement">tableGrantStatement</A>\r
+ */\r
+StatementNode\r
+tableGrantStatement() throws StandardException :\r
+{\r
+ PrivilegeNode privileges;\r
+ List grantees;\r
+}\r
+{\r
+ privileges = tablePrivileges()\r
+ <TO> grantees = granteeList()\r
+ {\r
+ return (StatementNode) nodeFactory.getNode( C_NodeTypes.GRANT_NODE,\r
+ privileges, grantees,\r
+ getContextManager());\r
+ }\r
+}// end of tableGrantStatement\r
+\r
+/*\r
+ * <A NAME="tablePrivileges">tablePrivileges</A>\r
+ */\r
+PrivilegeNode tablePrivileges() throws StandardException :\r
+{\r
+ TablePrivilegesNode tablePrivilegesNode = null;\r
+ TableName objectName = null;\r
+}\r
+{\r
+ tablePrivilegesNode = tableActions()\r
+ <ON> [ <TABLE> ] objectName = qualifiedName(Limits.MAX_IDENTIFIER_LENGTH)\r
+ {\r
+ return (PrivilegeNode) nodeFactory.getNode( C_NodeTypes.PRIVILEGE_NODE,\r
+ ReuseFactory.getInteger( PrivilegeNode.TABLE_PRIVILEGES),\r
+ objectName, tablePrivilegesNode,\r
+ getContextManager());\r
+ }\r
+} // end of tablePrivilege \r
+\r
+/*\r
+ * <A NAME="tableActions">tableActions</A>\r
+ */\r
+TablePrivilegesNode tableActions() throws StandardException :\r
+{\r
+ TablePrivilegesNode tableActionsNode = (TablePrivilegesNode)\r
+ nodeFactory.getNode( C_NodeTypes.TABLE_PRIVILEGES_NODE, getContextManager());\r
+}\r
+{\r
+ <ALL> <PRIVILEGES>\r
+ {\r
+ tableActionsNode.addAll();\r
+ return tableActionsNode;\r
+ }\r
+|\r
+ tableAction( tableActionsNode) ( <COMMA> tableAction( tableActionsNode) )*\r
+ {\r
+ return tableActionsNode;\r
+ }\r
+} // end of tableActions\r
+\r
+/*\r
+ * <A NAME="routineGrantStatement">routineGrantStatement</A>\r
+ */\r
+StatementNode\r
+routineGrantStatement() throws StandardException :\r
+{\r
+ List grantees;\r
+ RoutineDesignator routine;\r
+}\r
+{\r
+ <EXECUTE> <ON> routine = routineDesignator()\r
+ <TO> grantees = granteeList()\r
+ {\r
+ PrivilegeNode routinePrivilege = (PrivilegeNode)\r
+ nodeFactory.getNode( C_NodeTypes.PRIVILEGE_NODE,\r
+ ReuseFactory.getInteger( PrivilegeNode.ROUTINE_PRIVILEGES),\r
+ routine, null,\r
+ getContextManager());\r
+ return (StatementNode) nodeFactory.getNode( C_NodeTypes.GRANT_NODE,\r
+ routinePrivilege, grantees,\r
+ getContextManager());\r
+ }\r
+}// end of routineGrantStatement\r
+\r
+/*\r
+ * <A NAME="routineAlias">routineAlias</A>\r
+ */\r
+RoutineDesignator routineDesignator() throws StandardException :\r
+{\r
+ Token procOrFunction;\r
+ RoutineDesignator routine = null;\r
+ TableName name = null;\r
+ List paramTypeList = null;\r
+}\r
+{\r
+ ( procOrFunction = <FUNCTION> | procOrFunction = <PROCEDURE> )\r
+ name = qualifiedName(Limits.MAX_IDENTIFIER_LENGTH)\r
+ [ <LEFT_PAREN> paramTypeList = parameterTypeList() <RIGHT_PAREN> ]\r
+ {\r
+ return new RoutineDesignator( false,\r
+ name,\r
+ (procOrFunction.kind == FUNCTION),\r
+ paramTypeList);\r
+ }\r
+} // end of routineDesignator\r
+\r
+\r
+/*\r
+ * <A NAME="parameterTypeList">parameterTypeList</A>\r
+ */\r
+List parameterTypeList( ) throws StandardException :\r
+{\r
+ ArrayList list = new ArrayList();\r
+ DataTypeDescriptor dtd;\r
+}\r
+{\r
+ [ dtd = dataTypeCommon()\r
+ {\r
+ list.add( dtd);\r
+ }\r
+ ( <COMMA> dtd = dataTypeCommon()\r
+ {\r
+ list.add( dtd);\r
+ }\r
+ ) * ]\r
+ {\r
+ return list;\r
+ }\r
+} // end of parameterTypeList\r
+\r
+\r
+/*\r
+ * <A NAME="tableAction">tableAction</A>\r
+ */\r
+void tableAction( TablePrivilegesNode tablePrivilegesNode) throws StandardException :\r
+{\r
+ ResultColumnList columnList = null;\r
+}\r
+{\r
+ <SELECT> [ columnList = privilegeColumnList() ]\r
+ {\r
+ tablePrivilegesNode.addAction( TablePrivilegeInfo.SELECT_ACTION, columnList);\r
+ }\r
+|\r
+ <DELETE>\r
+ {\r
+ tablePrivilegesNode.addAction( TablePrivilegeInfo.DELETE_ACTION, (ResultColumnList) null);\r
+ }\r
+|\r
+ <INSERT>\r
+ {\r
+ tablePrivilegesNode.addAction( TablePrivilegeInfo.INSERT_ACTION, (ResultColumnList) null);\r
+ }\r
+|\r
+ <UPDATE> [ columnList = privilegeColumnList() ]\r
+ {\r
+ tablePrivilegesNode.addAction( TablePrivilegeInfo.UPDATE_ACTION, columnList);\r
+ }\r
+|\r
+ <REFERENCES> [ columnList = privilegeColumnList() ]\r
+ {\r
+ tablePrivilegesNode.addAction( TablePrivilegeInfo.REFERENCES_ACTION, columnList);\r
+ }\r
+|\r
+ <TRIGGER>\r
+ {\r
+ tablePrivilegesNode.addAction( TablePrivilegeInfo.TRIGGER_ACTION, (ResultColumnList) null);\r
+ }\r
+} // end of tableAction\r
+\r
+/*\r
+ * <A NAME="privilegeColumnList">privilegeColumnList</A>\r
+ */\r
+ResultColumnList privilegeColumnList() throws StandardException :\r
+{\r
+ ResultColumnList cl = (ResultColumnList) nodeFactory.getNode( C_NodeTypes.RESULT_COLUMN_LIST,\r
+ getContextManager());\r
+}\r
+{\r
+ <LEFT_PAREN> columnNameList( cl) <RIGHT_PAREN>\r
+ {\r
+ return cl;\r
+ }\r
+} // end of privilegeColumnList\r
+\r
+/*\r
+ * <A NAME="granteeList">granteeList</A>\r
+ */\r
+List granteeList() throws StandardException :\r
+{\r
+ ArrayList list = new ArrayList();\r
+}\r
+{\r
+ grantee( list) ( <COMMA> grantee( list) ) *\r
+ {\r
+ return list;\r
+ }\r
+}\r
+\r
+void\r
+grantee( List list) throws StandardException :\r
+{\r
+ String str;\r
+}\r
+{\r
+ str = identifier(Limits.MAX_IDENTIFIER_LENGTH, true)\r
+ {\r
+ checkAuthorizationLength(str);\r
+ list.add(str);\r
+ }\r
+|\r
+ <PUBLIC>\r
+ {\r
+ list.add( Authorizer.PUBLIC_AUTHORIZATION_ID);\r
+ }\r
+}\r
+\r
+/*\r
+ * <A NAME="revokeStatement">revokeStatement</A>\r
+ */\r
+StatementNode\r
+revokeStatement() throws StandardException :\r
+{\r
+ StatementNode node;\r
+}\r
+{\r
+ <REVOKE>\r
+ {\r
+ checkVersion( DataDictionary.DD_VERSION_DERBY_10_2, "REVOKE");\r
+ checkSqlStandardAccess( "REVOKE");\r
+ }\r
+ ( node = tableRevokeStatement() | node = routineRevokeStatement() )\r
+ {\r
+ return node;\r
+ }\r
+}\r
+\r
+/*\r
+ * <A NAME="tableRevokeStatement">tableRevokeStatement</A>\r
+ */\r
+StatementNode\r
+tableRevokeStatement() throws StandardException :\r
+{\r
+ PrivilegeNode privileges = null;\r
+ List grantees;\r
+}\r
+{\r
+ privileges = tablePrivileges()\r
+ <FROM> grantees = granteeList()\r
+ {\r
+ return (StatementNode) nodeFactory.getNode( C_NodeTypes.REVOKE_NODE,\r
+ privileges, grantees,\r
+ getContextManager());\r
+ }\r
+}// end of tableRevokeStatement\r
+\r
+/*\r
+ * <A NAME="routineRevokeStatement">routineRevokeStatement</A>\r
+ */\r
+StatementNode\r
+routineRevokeStatement() throws StandardException :\r
+{\r
+ List grantees;\r
+ RoutineDesignator routine = null;\r
+}\r
+{\r
+ <EXECUTE> <ON> routine = routineDesignator()\r
+ <FROM> grantees = granteeList() <RESTRICT>\r
+ {\r
+ PrivilegeNode routinePrivilege = (PrivilegeNode)\r
+ nodeFactory.getNode( C_NodeTypes.PRIVILEGE_NODE,\r
+ ReuseFactory.getInteger( PrivilegeNode.ROUTINE_PRIVILEGES),\r
+ routine, null,\r
+ getContextManager());\r
+ return (StatementNode) nodeFactory.getNode( C_NodeTypes.REVOKE_NODE,\r
+ routinePrivilege, grantees,\r
+ getContextManager());\r
+ }\r
+}// end of routineRevokeStatement\r
+\r
+/*\r
+ * <A NAME="identifier">identifier</A>\r
+ */\r
+String\r
+internalIdentifier( int id_length_limit, boolean checkLength) throws StandardException :\r
+{\r
+ String str;\r
+ Token tok;\r
+}\r
+{\r
+ tok = <IDENTIFIER>\r
+ {\r
+ str = StringUtil.SQLToUpperCase(tok.image);\r
+ \r
+ if (checkLength) {//if checkLength false, then calling method would do the length limit checks\r
+ //limit the identifier to the id length limit passed to this method\r
+ checkIdentifierLengthLimit(str, id_length_limit);\r
+ }\r
+ // Remember whether last token was a delimited identifier\r
+ nextToLastTokenDelimitedIdentifier = lastTokenDelimitedIdentifier;\r
+ lastTokenDelimitedIdentifier = Boolean.FALSE;\r
+ nextToLastIdentifierToken = lastIdentifierToken;\r
+ lastIdentifierToken = tok;\r
+ return str;\r
+ }\r
+|\r
+ str = delimitedIdentifier()\r
+ {\r
+ if (checkLength) {//if checkLength false, then calling method would do the length limit checks\r
+ //limit the identifier to the id length limit passed to this method\r
+ checkIdentifierLengthLimit(str, id_length_limit);\r
+ } \r
+ return str;\r
+ }\r
+|\r
+ str = nonReservedKeyword()\r
+ {\r
+ return StringUtil.SQLToUpperCase(str);\r
+ }\r
+}\r
+\r
+String\r
+identifier(int id_length_limit, boolean checkLength) throws StandardException :\r
+{\r
+ String id;\r
+}\r
+{\r
+ id = internalIdentifier( id_length_limit, checkLength)\r
+ {\r
+ return id;\r
+ }\r
+}\r
+\r
+/*\r
+ * <A NAME="delimitedIdentifier">delimitedIdentifier</A>\r
+ */\r
+String\r
+delimitedIdentifier() :\r
+{\r
+ String str;\r
+ Token tok;\r
+}\r
+{\r
+ tok = <DELIMITED_IDENTIFIER>\r
+ {\r
+ str = tok.image.substring(1, tok.image.length() -1);\r
+ str = normalizeDelimitedID( str );\r
+ // Remember whether last token was a delimited identifier\r
+ nextToLastTokenDelimitedIdentifier = lastTokenDelimitedIdentifier;\r
+ lastTokenDelimitedIdentifier = Boolean.TRUE;\r
+ nextToLastIdentifierToken = lastIdentifierToken;\r
+ lastIdentifierToken = tok;\r
+\r
+ return str;\r
+ }\r
+}\r
+\r
+/*\r
+ * <A NAME="reservedKeyword">reservedKeyword</A>\r
+ */\r
+String\r
+reservedKeyword() :\r
+{\r
+ Token tok;\r
+}\r
+{\r
+ /*\r
+ All reserved keywords have to be repeated here,\r
+ so that they may be used as normal identifiers.\r
+\r
+ NOTE: The same ones are commented out here as above in the token\r
+ rule, for the same reason.\r
+ \r
+ Derby-139 - LOCAL removed as reserved word as most other\r
+ databases do not enforce it. LOCAL not used at all in grammar so token removed.\r
+ */\r
+ (\r
+ /* SQL92 reserved Keywords */\r
+ tok = <ADD>\r
+| tok = <ALL>\r
+| tok = <ALLOCATE>\r
+| tok = <ALTER>\r
+| tok = <AND>\r
+| tok = <ANY>\r
+| tok = <ARE>\r
+| tok = <AS>\r
+| tok = <ASC>\r
+| tok = <ASSERTION>\r
+| tok = <AT>\r
+| tok = <AUTHORIZATION>\r
+| tok = <AVG>\r
+| tok = <BEGIN>\r
+| tok = <BETWEEN>\r
+| tok = <BIT>\r
+| tok = <BOTH>\r
+| tok = <BY>\r
+| tok = <CASCADE>\r
+| tok = <CASCADED>\r
+| tok = <CASE>\r
+| tok = <CAST>\r
+| tok = <CHAR>\r
+| tok = <CHARACTER>\r
+| tok = <CHECK>\r
+| tok = <CLOSE>\r
+| tok = <COLLATE>\r
+| tok = <COLLATION>\r
+| tok = <COLUMN>\r
+| tok = <COMMIT>\r
+| tok = <CONNECT>\r
+| tok = <CONNECTION>\r
+| tok = <CONSTRAINT>\r
+| tok = <CONSTRAINTS>\r
+| tok = <CONTINUE>\r
+| tok = <CONVERT>\r
+| tok = <CORRESPONDING>\r
+| tok = <CREATE>\r
+| tok = <CURRENT>\r
+| tok = <CURRENT_DATE>\r
+| tok = <CURRENT_TIME>\r
+| tok = <CURRENT_TIMESTAMP>\r
+| tok = <CURRENT_USER>\r
+| tok = <CURSOR>\r
+| tok = <DEALLOCATE>\r
+| tok = <DEC>\r
+| tok = <DECIMAL>\r
+| tok = <DECLARE>\r
+| tok = <_DEFAULT>\r
+| tok = <DEFERRABLE>\r
+| tok = <DEFERRED>\r
+| tok = <DELETE>\r
+| tok = <DESC>\r
+| tok = <DESCRIBE>\r
+| tok = <DIAGNOSTICS>\r
+| tok = <DISCONNECT>\r
+| tok = <DISTINCT>\r
+| tok = <DOUBLE>\r
+| tok = <DROP>\r
+| tok = <ELSE>\r
+| tok = <END>\r
+| tok = <ENDEXEC>\r
+| tok = <ESCAPE>\r
+| tok = <EXCEPT>\r
+| tok = <EXCEPTION>\r
+| tok = <EXEC>\r
+| tok = <EXECUTE>\r
+| tok = <EXISTS>\r
+| tok = <EXTERNAL>\r
+| tok = <FALSE>\r
+| tok = <FETCH>\r
+| tok = <FIRST>\r
+| tok = <FLOAT>\r
+| tok = <FOR>\r
+| tok = <FOREIGN>\r
+| tok = <FOUND>\r
+| tok = <FROM>\r
+| tok = <FULL>\r
+| tok = <FUNCTION>\r
+| tok = <GET>\r
+| tok = <GET_CURRENT_CONNECTION>\r
+| tok = <GLOBAL>\r
+| tok = <GO>\r
+| tok = <GOTO>\r
+| tok = <GRANT>\r
+| tok = <GROUP>\r
+| tok = <HAVING>\r
+| tok = <HOUR>\r
+| tok = <IDENTITY>\r
+| tok = <IMMEDIATE>\r
+| tok = <IN>\r
+| tok = <INDICATOR>\r
+| tok = <INITIALLY>\r
+| tok = <INNER>\r
+| tok = <INOUT>\r
+| tok = <INPUT>\r
+| tok = <INSENSITIVE>\r
+| tok = <INSERT>\r
+| tok = <INT>\r
+| tok = <INTEGER>\r
+| tok = <INTERSECT>\r
+// SQL92 says it is reserved, but we want it to be non-reserved.\r
+| tok = <INTO>\r
+| tok = <IS>\r
+| tok = <ISOLATION>\r
+| tok = <JOIN>\r
+| tok = <KEY>\r
+| tok = <LAST>\r
+| tok = <LEADING>\r
+| tok = <LEFT>\r
+| tok = <LIKE>\r
+| tok = <LOWER>\r
+| tok = <MATCH>\r
+| tok = <MAX>\r
+| tok = <MIN>\r
+| tok = <MINUTE>\r
+// SQL92 says it is reserved, but we want it to be non-reserved.\r
+| tok = <NATIONAL>\r
+| tok = <NATURAL>\r
+| tok = <NCHAR>\r
+| tok = <NVARCHAR> \r
+| tok = <NEXT>\r
+| tok = <NO>\r
+| tok = <NOT>\r
+| tok = <NULL>\r
+| tok = <NULLIF>\r
+| tok = <NUMERIC>\r
+| tok = <OF>\r
+| tok = <ON>\r
+| tok = <ONLY>\r
+| tok = <OPEN>\r
+| tok = <OPTION>\r
+| tok = <OR>\r
+| tok = <ORDER>\r
+| tok = <OUT>\r
+| tok = <OUTER>\r
+| tok = <OUTPUT>\r
+| tok = <OVERLAPS>\r
+| tok = <PAD>\r
+| tok = <PARTIAL>\r
+| tok = <PREPARE>\r
+| tok = <PRESERVE>\r
+| tok = <PRIMARY>\r
+| tok = <PRIOR>\r
+| tok = <PRIVILEGES>\r
+| tok = <PROCEDURE>\r
+| tok = <PUBLIC>\r
+| tok = <READ>\r
+| tok = <REAL>\r
+| tok = <REFERENCES>\r
+| tok = <RELATIVE>\r
+| tok = <RESTRICT>\r
+| tok = <REVOKE>\r
+| tok = <RIGHT>\r
+| tok = <ROLLBACK>\r
+| tok = <ROWS>\r
+| tok = <SCHEMA>\r
+| tok = <SCROLL>\r
+| tok = <SECOND>\r
+| tok = <SELECT>\r
+| tok = <SESSION_USER>\r
+| tok = <SET>\r
+| tok = <SMALLINT>\r
+| tok = <SOME>\r
+| tok = <SPACE>\r
+| tok = <SQL>\r
+| tok = <SQLCODE>\r
+| tok = <SQLERROR>\r
+| tok = <SQLSTATE>\r
+| tok = <SUBSTRING>\r
+| tok = <SUM>\r
+| tok = <SYSTEM_USER>\r
+| tok = <TABLE>\r
+| tok = <TEMPORARY>\r
+| tok = <TIMEZONE_HOUR>\r
+| tok = <TIMEZONE_MINUTE>\r
+| tok = <TO>\r
+| tok = <TRAILING>\r
+| tok = <TRANSACTION>\r
+| tok = <TRANSLATE>\r
+| tok = <TRANSLATION>\r
+| tok = <TRUE>\r
+| tok = <UNION>\r
+| tok = <UNIQUE>\r
+| tok = <UNKNOWN>\r
+| tok = <UPDATE>\r
+| tok = <UPPER>\r
+| tok = <USER>\r
+| tok = <USING>\r
+| tok = <VALUES>\r
+| tok = <VARCHAR>\r
+| tok = <VARYING>\r
+| tok = <VIEW>\r
+| tok = <WHENEVER>\r
+| tok = <WHERE>\r
+| tok = <WITH>\r
+| tok = <WORK>\r
+| tok = <WRITE>\r
+| tok = <YEAR>\r
+ /* Additional JSQL reserved keywords -- non-SQL92 reserved Keywords */\r
+| tok = <BOOLEAN>\r
+| tok = <CALL>\r
+| tok = <EXPLAIN>\r
+| tok = <LONGINT>\r
+| tok = <LTRIM>\r
+| tok = <RTRIM>\r
+| tok = <TRIM>\r
+| tok = <SUBSTR>\r
+| tok = <XML>\r
+| tok = <XMLPARSE>\r
+| tok = <XMLSERIALIZE>\r
+| tok = <XMLEXISTS>\r
+| tok = <XMLQUERY>\r
+)\r
+ {\r
+ // Remember whether last token was a delimited identifier\r
+ nextToLastTokenDelimitedIdentifier = lastTokenDelimitedIdentifier;\r
+ lastTokenDelimitedIdentifier = Boolean.FALSE;\r
+ return tok.image;\r
+ }\r
+}\r
+\r
+/*\r
+ * <A NAME="nonReservedKeyword">nonReservedKeyword</A>\r
+ */\r
+String\r
+nonReservedKeyword() :\r
+{\r
+ Token tok;\r
+}\r
+{\r
+ /*\r
+ All non-reserved keywords have to be repeated here,\r
+ so that they may be used as normal identifiers.\r
+\r
+ NOTE: The same ones are commented out here as above in the token\r
+ rule, for the same reason.\r
+ */\r
+ (\r
+ tok = <ABS> \r
+ | tok = <ABSVAL> \r
+ | tok = <ACTION>\r
+ | tok = <AFTER>\r
+ | tok = <ALWAYS>\r
+ | tok = <BEFORE>\r
+ | tok = <BINARY>\r
+ | tok = <BLOB>\r
+ | tok = <C>\r
+ | tok = <CALLED>\r
+ | tok = <CLASS>\r
+ | tok = <CLOB>\r
+| tok = <COALESCE>\r
+ | tok = <COBOL>\r
+ | tok = <COMMITTED>\r
+ | tok = <COMPRESS>\r
+ | tok = <CONCAT>\r
+ | tok = <CONTAINS>\r
+ | tok = <CONTENT>\r
+ | tok = <COUNT>\r
+ | tok = <CS>\r
+ | tok = <CURDATE>\r
+ | tok = <CURTIME>\r
+ | tok = <D>\r
+ | tok = <DATA>\r
+ | tok = <DATE>\r
+ | tok = <DAY>\r
+ | tok = <DIRTY>\r
+ | tok = <DYNAMIC>\r
+ | tok = <DATABASE>\r
+ | tok = <DB2SQL>\r
+ | tok = <DOCUMENT>\r
+ | tok = <EACH>\r
+ | tok = <EMPTY>\r
+ | tok = <EXCLUSIVE>\r
+ | tok = <FN>\r
+ | tok = <FORTRAN>\r
+ | tok = <GENERATED>\r
+ | tok = <IDENTITY_VAL_LOCAL>\r
+ | tok = <INCREMENT>\r
+ | tok = <INDEX>\r
+ | tok = <INITIAL>\r
+// SQL92 says it is reserved, but we want it to be non-reserved.\r
+ | tok = <INTERVAL>\r
+ | tok = <JAVA>\r
+ | tok = <LANGUAGE>\r
+ | tok = <LARGE>\r
+ | tok = <LCASE>\r
+ | tok = <LENGTH>\r
+ | tok = <LEVEL>\r
+ | tok = <LOCATE>\r
+ | tok = <LOCK>\r
+ | tok = <LOCKS>\r
+ | tok = <LOCKSIZE>\r
+ | tok = <LOGGED>\r
+ | tok = <LONG>\r
+ | tok = <MESSAGE_LOCALE>\r
+ | tok = <METHOD>\r
+ | tok = <MOD>\r
+ | tok = <MODE>\r
+ | tok = <MODIFIES>\r
+ | tok = <MODIFY>\r
+// SQL92 says it is reserved, but we want it to be non-reserved.\r
+ | tok = <MODULE>\r
+ | tok = <MONTH>\r
+ | tok = <_MORE>\r
+ | tok = <MUMPS>\r
+ | tok = <NAME>\r
+ | tok = <NCLOB>\r
+ | tok = <NEW>\r
+ | tok = <NEW_TABLE>\r
+ | tok = <NULLABLE>\r
+ | tok = <NUMBER>\r
+ | tok = <OBJECT>\r
+ | tok = <OFF>\r
+ | tok = <OLD>\r
+ | tok = <OLD_TABLE>\r
+ | tok = <OJ>\r
+ | tok = <PASCAL>\r
+ | tok = <PASSING>\r
+ | tok = <PLI>\r
+ | tok = <PRECISION>\r
+ | tok = <PROPERTIES>\r
+ | tok = <READS>\r
+ | tok = <REF>\r
+// SQL92 says it is reserved, but we want it to be non-reserved.\r
+ | tok = <RELEASE>\r
+ | tok = <RENAME>\r
+ | tok = <REPEATABLE>\r
+ | tok = <REFERENCING>\r
+ | tok = <RESET>\r
+ | tok = <RESTART>\r
+ | tok = <RESULT>\r
+ | tok = <RETAIN>\r
+ | tok = <RETURNING>\r
+ | tok = <RETURNS>\r
+ | tok = <ROW>\r
+// | tok = <ROW_COUNT>\r
+ | tok = <RR>\r
+ | tok = <RS>\r
+ | tok = <SCALE>\r
+ | tok = <SAVEPOINT>\r
+ | tok = <SEQUENCE>\r
+ | tok = <SEQUENTIAL>\r
+ | tok = <SERIALIZABLE>\r
+ | tok = <SETS>\r
+ | tok = <SHARE>\r
+ | tok = <SPECIFIC>\r
+ | tok = <SQLID>\r
+ | tok = <SQL_TSI_FRAC_SECOND>\r
+ | tok = <SQL_TSI_SECOND>\r
+ | tok = <SQL_TSI_MINUTE>\r
+ | tok = <SQL_TSI_HOUR>\r
+ | tok = <SQL_TSI_DAY>\r
+ | tok = <SQL_TSI_WEEK>\r
+ | tok = <SQL_TSI_MONTH>\r
+ | tok = <SQL_TSI_QUARTER>\r
+ | tok = <SQL_TSI_YEAR>\r
+ | tok = <SQRT>\r
+ | tok = <STABILITY>\r
+ | tok = <START>\r
+ | tok = <STATEMENT>\r
+ | tok = <STRIP>\r
+ | tok = <SYNONYM>\r
+ | tok = <STYLE>\r
+ | tok = <T>\r
+ | tok = <THEN>\r
+ | tok = <TIME>\r
+ | tok = <TIMESTAMP>\r
+ | tok = <TIMESTAMPADD>\r
+ | tok = <TIMESTAMPDIFF>\r
+ | tok = <TRIGGER>\r
+ | tok = <TRUNCATE>\r
+ | tok = <TS>\r
+ | tok = <TYPE>\r
+ | tok = <UCASE>\r
+ | tok = <UNCOMMITTED>\r
+ | tok = <UR>\r
+ | tok = <USAGE>\r
+// SQL92 says VALUE is reserved, but we want it to be nonreserved.\r
+ | tok = <VALUE>\r
+ | tok = <VARBINARY>\r
+ | tok = <PARAMETER>\r
+ | tok = <WHEN>\r
+ | tok = <WHITESPACE>\r
+ )\r
+ {\r
+ // Remember whether last token was a delimited identifier\r
+ nextToLastTokenDelimitedIdentifier = lastTokenDelimitedIdentifier;\r
+ lastTokenDelimitedIdentifier = Boolean.FALSE;\r
+ nextToLastIdentifierToken = lastIdentifierToken;\r
+ lastIdentifierToken = tok;\r
+ return tok.image;\r
+ }\r
+}\r
+\r
+/*\r
+ * <A NAME="caseSensitiveIdentifierPlusReservedWords">caseSensitiveIdentifierPlusReservedWords</A>\r
+ */\r
+String\r
+caseSensitiveIdentifierPlusReservedWords() :\r
+{\r
+ String str;\r
+}\r
+{\r
+ str = caseSensitiveIdentifier()\r
+ {\r
+ return str;\r
+ }\r
+|\r
+ str = reservedKeyword()\r
+ {\r
+ return str;\r
+ }\r
+}\r
+\r
+/*\r
+ * <A NAME="caseInsensitiveIdentifierPlusReservedWords">caseInsensitiveIdentifierPlusReservedWords</A>\r
+ */\r
+String\r
+caseInsensitiveIdentifierPlusReservedWords() throws StandardException :\r
+{\r
+ String str;\r
+}\r
+{\r
+ str = identifier(Limits.MAX_IDENTIFIER_LENGTH, true)\r
+ {\r
+ return str;\r
+ }\r
+|\r
+ str = reservedKeyword()\r
+ {\r
+ return StringUtil.SQLToUpperCase(str);\r
+ }\r
+}\r
+\r
+/*\r
+ * <A NAME="caseSensitiveIdentifier">caseSensitiveIdentifier</A>\r
+ */\r
+String\r
+caseSensitiveIdentifier() :\r
+{\r
+ String str;\r
+ Token tok;\r
+}\r
+{\r
+ tok = <IDENTIFIER>\r
+ {\r
+ // Remember whether last token was a delimited identifier\r
+ nextToLastTokenDelimitedIdentifier = lastTokenDelimitedIdentifier;\r
+ lastTokenDelimitedIdentifier = Boolean.FALSE;\r
+ return tok.image;\r
+ }\r
+|\r
+ str = delimitedIdentifier()\r
+ {\r
+ return str;\r
+ }\r
+|\r
+ str = nonReservedKeyword()\r
+ {\r
+ return str;\r
+ }\r
+}\r