--- /dev/null
+/*\r
+\r
+ Derby - Class org.apache.derby.impl.sql.compile.CreateViewNode\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.compile.Visitable;\r
+import org.apache.derby.iapi.sql.compile.Visitor;\r
+\r
+import org.apache.derby.iapi.services.context.ContextManager;\r
+\r
+import org.apache.derby.iapi.services.sanity.SanityManager;\r
+\r
+import org.apache.derby.iapi.error.StandardException;\r
+\r
+import org.apache.derby.iapi.sql.compile.CompilerContext;\r
+import org.apache.derby.iapi.sql.compile.C_NodeTypes;\r
+import org.apache.derby.iapi.sql.compile.NodeFactory;\r
+\r
+import org.apache.derby.iapi.sql.conn.Authorizer;\r
+import org.apache.derby.iapi.sql.conn.LanguageConnectionContext;\r
+\r
+import org.apache.derby.iapi.sql.dictionary.DataDictionary;\r
+import org.apache.derby.iapi.sql.dictionary.SchemaDescriptor;\r
+import org.apache.derby.iapi.sql.dictionary.TableDescriptor;\r
+\r
+import org.apache.derby.iapi.sql.depend.DependencyManager;\r
+import org.apache.derby.iapi.sql.depend.Dependent;\r
+import org.apache.derby.iapi.sql.depend.ProviderInfo;\r
+import org.apache.derby.iapi.sql.depend.ProviderList;\r
+\r
+import org.apache.derby.iapi.reference.SQLState;\r
+import org.apache.derby.iapi.reference.Limits;\r
+\r
+import org.apache.derby.iapi.sql.execute.ConstantAction;\r
+\r
+import org.apache.derby.impl.sql.execute.ColumnInfo;\r
+import org.apache.derby.catalog.UUID;\r
+\r
+/**\r
+ * A CreateViewNode is the root of a QueryTree that represents a CREATE VIEW\r
+ * statement.\r
+ *\r
+ */\r
+\r
+public class CreateViewNode extends DDLStatementNode\r
+{\r
+ ResultColumnList resultColumns;\r
+ ResultSetNode queryExpression;\r
+ String qeText;\r
+ int checkOption;\r
+ ProviderInfo[] providerInfos;\r
+ ColumnInfo[] colInfos;\r
+\r
+\r
+ /**\r
+ * Initializer for a CreateViewNode\r
+ *\r
+ * @param newObjectName The name of the table to be created\r
+ * @param resultColumns The column list from the view definition, \r
+ * if specified\r
+ * @param queryExpression The query expression for the view\r
+ * @param checkOption The type of WITH CHECK OPTION that was specified\r
+ * (NONE for now)\r
+ * @param qeText The text for the queryExpression\r
+ *\r
+ * @exception StandardException Thrown on error\r
+ */\r
+\r
+ public void init(Object newObjectName,\r
+ Object resultColumns,\r
+ Object queryExpression,\r
+ Object checkOption,\r
+ Object qeText)\r
+ throws StandardException\r
+ {\r
+ initAndCheck(newObjectName);\r
+ this.resultColumns = (ResultColumnList) resultColumns;\r
+ this.queryExpression = (ResultSetNode) queryExpression;\r
+ this.checkOption = ((Integer) checkOption).intValue();\r
+ this.qeText = ((String) qeText).trim();\r
+\r
+ implicitCreateSchema = true;\r
+ }\r
+\r
+ /**\r
+ * Convert this object to a String. See comments in QueryTreeNode.java\r
+ * for how this should be done for tree printing.\r
+ *\r
+ * @return This object as a String\r
+ */\r
+\r
+ public String toString()\r
+ {\r
+ if (SanityManager.DEBUG)\r
+ {\r
+ return super.toString() +\r
+ "checkOption: " + checkOption + "\n" +\r
+ "qeText: " + qeText + "\n";\r
+ }\r
+ else\r
+ {\r
+ return "";\r
+ }\r
+ }\r
+\r
+ public String statementToString()\r
+ {\r
+ return "CREATE VIEW";\r
+ }\r
+\r
+ /**\r
+ * Prints the sub-nodes of this object. See QueryTreeNode.java for\r
+ * how tree printing is supposed to work.\r
+ *\r
+ * @param depth The depth of this node in the tree\r
+ */\r
+\r
+ public void printSubNodes(int depth)\r
+ {\r
+ if (SanityManager.DEBUG)\r
+ {\r
+ super.printSubNodes(depth);\r
+\r
+ if (resultColumns != null)\r
+ {\r
+ printLabel(depth, "resultColumns: ");\r
+ resultColumns.treePrint(depth + 1);\r
+ }\r
+\r
+ printLabel(depth, "queryExpression: ");\r
+ queryExpression.treePrint(depth + 1);\r
+ }\r
+ }\r
+\r
+ // accessors\r
+\r
+ public int getCheckOption() { return checkOption; }\r
+\r
+ public ProviderInfo[] getProviderInfo() { return providerInfos; }\r
+\r
+ public ColumnInfo[] getColumnInfo() { return colInfos; }\r
+\r
+ // We inherit the generate() method from DDLStatementNode.\r
+\r
+ /**\r
+ * Bind this CreateViewNode. This means doing any static error\r
+ * checking that can be done before actually creating the table.\r
+ * For example, verifying that the ResultColumnList does not\r
+ * contain any duplicate column names.\r
+ *\r
+ *\r
+ * @exception StandardException Thrown on error\r
+ */\r
+ public void bindStatement() throws StandardException\r
+ {\r
+ CompilerContext cc = getCompilerContext();\r
+ DataDictionary dataDictionary = getDataDictionary();\r
+ ResultColumnList qeRCL;\r
+ String duplicateColName;\r
+\r
+ // bind the query expression\r
+\r
+ providerInfos = bindViewDefinition\r
+ ( dataDictionary, cc, getLanguageConnectionContext(),\r
+ getNodeFactory(), \r
+ queryExpression,\r
+ getContextManager()\r
+ );\r
+\r
+ qeRCL = queryExpression.getResultColumns();\r
+\r
+ /* If there is an RCL for the view definition then\r
+ * copy the names to the queryExpression's RCL after verifying\r
+ * that they both have the same size.\r
+ */\r
+ if (resultColumns != null)\r
+ {\r
+ if (resultColumns.size() != qeRCL.visibleSize())\r
+ {\r
+ throw StandardException.newException(SQLState.LANG_VIEW_DEFINITION_R_C_L_MISMATCH,\r
+ getFullName());\r
+ }\r
+ qeRCL.copyResultColumnNames(resultColumns);\r
+ }\r
+\r
+ /* Check to make sure the queryExpression's RCL has unique names. If target column\r
+ * names not specified, raise error if there are any un-named columns to match DB2\r
+ */\r
+ duplicateColName = qeRCL.verifyUniqueNames((resultColumns == null) ? true : false);\r
+ if (duplicateColName != null)\r
+ {\r
+ throw StandardException.newException(SQLState.LANG_DUPLICATE_COLUMN_NAME_CREATE_VIEW, duplicateColName);\r
+ }\r
+\r
+ /* Only 5000 columns allowed per view */\r
+ if (queryExpression.getResultColumns().size() > Limits.DB2_MAX_COLUMNS_IN_VIEW)\r
+ {\r
+ throw StandardException.newException(SQLState.LANG_TOO_MANY_COLUMNS_IN_TABLE_OR_VIEW,\r
+ String.valueOf(queryExpression.getResultColumns().size()),\r
+ getRelativeName(),\r
+ String.valueOf(Limits.DB2_MAX_COLUMNS_IN_VIEW));\r
+ }\r
+\r
+ // for each column, stuff system.column\r
+ colInfos = new ColumnInfo[queryExpression.getResultColumns().size()];\r
+ genColumnInfos(colInfos);\r
+ }\r
+\r
+ /**\r
+ * Bind the query expression for a view definition. \r
+ *\r
+ * @param dataDictionary The DataDictionary to use to look up\r
+ * columns, tables, etc.\r
+ *\r
+ * @return Array of providers that this view depends on.\r
+ *\r
+ * @exception StandardException Thrown on error\r
+ */\r
+\r
+ private ProviderInfo[] bindViewDefinition( DataDictionary dataDictionary,\r
+ CompilerContext compilerContext,\r
+ LanguageConnectionContext lcc,\r
+ NodeFactory nodeFactory,\r
+ ResultSetNode queryExpr,\r
+ ContextManager cm)\r
+ throws StandardException\r
+ {\r
+ FromList fromList = (FromList) nodeFactory.getNode(\r
+ C_NodeTypes.FROM_LIST,\r
+ nodeFactory.doJoinOrderOptimization(),\r
+ cm);\r
+\r
+ ProviderList prevAPL = compilerContext.getCurrentAuxiliaryProviderList();\r
+ ProviderList apl = new ProviderList();\r
+\r
+ try {\r
+ compilerContext.setCurrentAuxiliaryProviderList(apl);\r
+ compilerContext.pushCurrentPrivType(Authorizer.SELECT_PRIV);\r
+\r
+ /* Bind the tables in the queryExpression */\r
+ queryExpr = queryExpr.bindNonVTITables(dataDictionary, fromList);\r
+ queryExpr = queryExpr.bindVTITables(fromList);\r
+\r
+ /* Bind the expressions under the resultSet */\r
+ queryExpr.bindExpressions(fromList);\r
+\r
+ //cannot define views on temporary tables\r
+ if (queryExpr instanceof SelectNode)\r
+ {\r
+ //If attempting to reference a SESSION schema table (temporary or permanent) in the view, throw an exception\r
+ if (queryExpr.referencesSessionSchema())\r
+ throw StandardException.newException(SQLState.LANG_OPERATION_NOT_ALLOWED_ON_SESSION_SCHEMA_TABLES);\r
+ }\r
+\r
+ // bind the query expression\r
+ queryExpr.bindResultColumns(fromList);\r
+ \r
+ // rejects any untyped nulls in the RCL\r
+ // e.g.: CREATE VIEW v1 AS VALUES NULL\r
+ queryExpr.bindUntypedNullsToResultColumns(null);\r
+ }\r
+ finally\r
+ {\r
+ compilerContext.popCurrentPrivType();\r
+ compilerContext.setCurrentAuxiliaryProviderList(prevAPL);\r
+ }\r
+\r
+ DependencyManager dm = dataDictionary.getDependencyManager();\r
+ ProviderInfo[] providerInfos = dm.getPersistentProviderInfos(apl);\r
+ // need to clear the column info in case the same table descriptor\r
+ // is reused, eg., in multiple target only view definition\r
+ dm.clearColumnInfoInProviders(apl);\r
+\r
+ /* Verify that all underlying ResultSets reclaimed their FromList */\r
+ if (SanityManager.DEBUG)\r
+ {\r
+ SanityManager.ASSERT(fromList.size() == 0,\r
+ "fromList.size() is expected to be 0, not " + fromList.size() +\r
+ " on return from RS.bindExpressions()");\r
+ }\r
+\r
+ return providerInfos;\r
+ }\r
+\r
+ /**\r
+ * Return true if the node references SESSION schema tables (temporary or permanent)\r
+ *\r
+ * @return true if references SESSION schema tables, else false\r
+ *\r
+ * @exception StandardException Thrown on error\r
+ */\r
+ public boolean referencesSessionSchema()\r
+ throws StandardException\r
+ {\r
+ //If create view is part of create statement and the view references SESSION schema tables, then it will\r
+ //get caught in the bind phase of the view and exception will be thrown by the view bind. \r
+ return (queryExpression.referencesSessionSchema());\r
+ }\r
+\r
+ /**\r
+ * Create the Constant information that will drive the guts of Execution.\r
+ *\r
+ * @exception StandardException Thrown on failure\r
+ */\r
+ public ConstantAction makeConstantAction() throws StandardException\r
+ {\r
+ /* RESOLVE - need to build up dependendencies and store them away through\r
+ * the constant action.\r
+ */\r
+ return getGenericConstantActionFactory().getCreateViewConstantAction(getSchemaDescriptor().getSchemaName(),\r
+ getRelativeName(),\r
+ TableDescriptor.VIEW_TYPE,\r
+ qeText,\r
+ checkOption,\r
+ colInfos,\r
+ providerInfos,\r
+ (UUID)null); // compilation schema, filled\r
+ // in when we create the view\r
+ }\r
+\r
+ /**\r
+ * Fill in the ColumnInfo[] for this create view.\r
+ * \r
+ * @param colInfos The ColumnInfo[] to be filled in.\r
+ */\r
+ private void genColumnInfos(ColumnInfo[] colInfos)\r
+ {\r
+ ResultColumnList rcl = queryExpression.getResultColumns();\r
+ int rclSize = rcl.size();\r
+\r
+ for (int index = 0; index < rclSize; index++)\r
+ {\r
+ ResultColumn rc = (ResultColumn) rcl.elementAt(index);\r
+\r
+ //RESOLVEAUTOINCREMENT\r
+ colInfos[index] = new ColumnInfo(rc.getName(),\r
+ rc.getType(),\r
+ null,\r
+ null,\r
+ null,\r
+ null,\r
+ ColumnInfo.CREATE,\r
+ 0, 0, 0);\r
+ }\r
+ }\r
+\r
+ /*\r
+ * class interface\r
+ */\r
+\r
+ /**\r
+ * Get the parsed query expression (the SELECT statement).\r
+ *\r
+ * @return the parsed query expression.\r
+ */\r
+ ResultSetNode getParsedQueryExpression() { return queryExpression; }\r
+\r
+\r
+ /*\r
+ * These methods are used by execution\r
+ * to get information for storing into\r
+ * the system catalogs.\r
+ */\r
+\r
+\r
+ /**\r
+ * Accept a visitor, and call v.visit()\r
+ * on child nodes as necessary. \r
+ * \r
+ * @param v the visitor\r
+ *\r
+ * @exception StandardException on error\r
+ */\r
+ public Visitable accept(Visitor v) \r
+ throws StandardException\r
+ {\r
+ Visitable returnNode = v.visit(this);\r
+\r
+ if (v.skipChildren(this))\r
+ {\r
+ return returnNode;\r
+ }\r
+\r
+ if (!v.stopTraversal())\r
+ {\r
+ super.accept(v);\r
+ }\r
+\r
+ if (queryExpression != null && !v.stopTraversal())\r
+ {\r
+ queryExpression = (ResultSetNode)queryExpression.accept(v);\r
+ }\r
+\r
+ return returnNode;\r
+ }\r
+\r
+}\r