--- /dev/null
+/*\r
+\r
+ Derby - Class org.apache.derby.impl.sql.execute.CreateAliasConstantAction\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.execute;\r
+\r
+import org.apache.derby.catalog.AliasInfo;\r
+import org.apache.derby.catalog.UUID;\r
+import org.apache.derby.catalog.types.RoutineAliasInfo;\r
+import org.apache.derby.catalog.types.SynonymAliasInfo;\r
+import org.apache.derby.iapi.error.StandardException;\r
+import org.apache.derby.iapi.reference.SQLState;\r
+import org.apache.derby.iapi.services.sanity.SanityManager;\r
+import org.apache.derby.iapi.sql.Activation;\r
+import org.apache.derby.iapi.sql.conn.LanguageConnectionContext;\r
+import org.apache.derby.iapi.sql.dictionary.AliasDescriptor;\r
+import org.apache.derby.iapi.sql.dictionary.DataDescriptorGenerator;\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
+import org.apache.derby.iapi.sql.execute.ConstantAction;\r
+import org.apache.derby.iapi.store.access.TransactionController;\r
+\r
+/**\r
+ * This class performs actions that are ALWAYS performed for a\r
+ * CREATE FUNCTION, PROCEDURE or SYNONYM Statement at execution time.\r
+ * These SQL objects are stored in the SYS.SYSALIASES table and\r
+ * represented as AliasDescriptors.\r
+ *\r
+ */\r
+class CreateAliasConstantAction extends DDLConstantAction\r
+{\r
+\r
+ private final String aliasName;\r
+ private final String schemaName;\r
+ private final String javaClassName;\r
+ private final char aliasType;\r
+ private final char nameSpace;\r
+ private final AliasInfo aliasInfo;\r
+\r
+ // CONSTRUCTORS\r
+\r
+ /**\r
+ * Make the ConstantAction for a CREATE alias statement.\r
+ *\r
+ * @param aliasName Name of alias.\r
+ * @param schemaName Name of alias's schema.\r
+ * @param javaClassName Name of java class.\r
+ * @param aliasInfo AliasInfo\r
+ * @param aliasType The type of the alias\r
+ */\r
+ CreateAliasConstantAction(\r
+ String aliasName,\r
+ String schemaName,\r
+ String javaClassName,\r
+ AliasInfo aliasInfo,\r
+ char aliasType)\r
+ {\r
+ this.aliasName = aliasName;\r
+ this.schemaName = schemaName;\r
+ this.javaClassName = javaClassName;\r
+ this.aliasInfo = aliasInfo;\r
+ this.aliasType = aliasType;\r
+ switch (aliasType)\r
+ {\r
+ case AliasInfo.ALIAS_TYPE_PROCEDURE_AS_CHAR:\r
+ nameSpace = AliasInfo.ALIAS_NAME_SPACE_PROCEDURE_AS_CHAR;\r
+ break;\r
+\r
+ case AliasInfo.ALIAS_TYPE_FUNCTION_AS_CHAR:\r
+ nameSpace = AliasInfo.ALIAS_NAME_SPACE_FUNCTION_AS_CHAR;\r
+ break;\r
+\r
+ case AliasInfo.ALIAS_TYPE_SYNONYM_AS_CHAR:\r
+ nameSpace = AliasInfo.ALIAS_NAME_SPACE_SYNONYM_AS_CHAR;\r
+ break;\r
+\r
+ default:\r
+ if (SanityManager.DEBUG)\r
+ {\r
+ SanityManager.THROWASSERT(\r
+ "Unexpected value for aliasType (" + aliasType + ")");\r
+ }\r
+ nameSpace = '\0';\r
+ break;\r
+ }\r
+ }\r
+\r
+ // OBJECT SHADOWS\r
+\r
+ public String toString()\r
+ {\r
+ // Do not put this under SanityManager.DEBUG - it is needed for\r
+ // error reporting.\r
+ String type = null;\r
+\r
+ switch (aliasType)\r
+ {\r
+ case AliasInfo.ALIAS_TYPE_PROCEDURE_AS_CHAR:\r
+ type = "CREATE PROCEDURE ";\r
+ break;\r
+\r
+ case AliasInfo.ALIAS_TYPE_FUNCTION_AS_CHAR:\r
+ type = "CREATE FUNCTION ";\r
+ break;\r
+\r
+ case AliasInfo.ALIAS_TYPE_SYNONYM_AS_CHAR:\r
+ type = "CREATE SYNONYM ";\r
+ break;\r
+\r
+ default:\r
+ if (SanityManager.DEBUG)\r
+ {\r
+ SanityManager.THROWASSERT(\r
+ "Unexpected value for aliasType (" + aliasType + ")");\r
+ }\r
+ }\r
+\r
+ return type + aliasName;\r
+ }\r
+\r
+ // INTERFACE METHODS\r
+\r
+\r
+ /**\r
+ * This is the guts of the Execution-time logic for\r
+ * CREATE FUNCTION, PROCEDURE or SYNONYM.\r
+ * <P>\r
+ * A routine (function or procedure) is represented as:\r
+ * <UL>\r
+ * <LI> AliasDescriptor\r
+ * </UL>\r
+ * Routine dependencies are created as:\r
+ * <UL>\r
+ * <LI> None\r
+ * </UL>\r
+ * \r
+ * <P>\r
+ * A synonym is represented as:\r
+ * <UL>\r
+ * <LI> AliasDescriptor\r
+ * <LI> TableDescriptor\r
+ * </UL>\r
+ * Synonym dependencies are created as:\r
+ * <UL>\r
+ * <LI> None\r
+ * </UL>\r
+ * \r
+ * In both cases a SchemaDescriptor will be created if\r
+ * needed. No dependency is created on the SchemaDescriptor.\r
+ * \r
+ * @see ConstantAction#executeConstantAction\r
+ * @see AliasDescriptor\r
+ * @see TableDescriptor\r
+ * @see SchemaDescriptor\r
+ *\r
+ * @exception StandardException Thrown on failure\r
+ */\r
+ public void executeConstantAction( Activation activation )\r
+ throws StandardException\r
+ {\r
+ LanguageConnectionContext lcc =\r
+ activation.getLanguageConnectionContext();\r
+\r
+ DataDictionary dd = lcc.getDataDictionary();\r
+ TransactionController tc = lcc.getTransactionExecute();\r
+\r
+ // For routines no validity checking is made\r
+ // on the Java method, that is checked when the\r
+ // routine is executed.\r
+ \r
+ /*\r
+ ** Inform the data dictionary that we are about to write to it.\r
+ ** There are several calls to data dictionary "get" methods here\r
+ ** that might be done in "read" mode in the data dictionary, but\r
+ ** it seemed safer to do this whole operation in "write" mode.\r
+ **\r
+ ** We tell the data dictionary we're done writing at the end of\r
+ ** the transaction.\r
+ */\r
+ dd.startWriting(lcc);\r
+\r
+ \r
+ SchemaDescriptor sd =\r
+ DDLConstantAction.getSchemaDescriptorForCreate(dd, activation, schemaName);\r
+\r
+ //\r
+ // Create a new method alias descriptor with aliasID filled in.\r
+ // \r
+ UUID aliasID = dd.getUUIDFactory().createUUID();\r
+\r
+ AliasDescriptor ads = new AliasDescriptor(dd, aliasID,\r
+ aliasName,\r
+ sd.getUUID(),\r
+ javaClassName,\r
+ aliasType,\r
+ nameSpace,\r
+ false,\r
+ aliasInfo, null);\r
+\r
+ // perform duplicate rule checking\r
+ switch (aliasType) {\r
+ case AliasInfo.ALIAS_TYPE_PROCEDURE_AS_CHAR:\r
+ case AliasInfo.ALIAS_TYPE_FUNCTION_AS_CHAR:\r
+ {\r
+\r
+ java.util.List list = dd.getRoutineList(\r
+ sd.getUUID().toString(), aliasName, aliasType);\r
+ for (int i = list.size() - 1; i >= 0; i--) {\r
+\r
+ AliasDescriptor proc = (AliasDescriptor) list.get(i);\r
+\r
+ RoutineAliasInfo procedureInfo = (RoutineAliasInfo) proc.getAliasInfo();\r
+ int parameterCount = procedureInfo.getParameterCount();\r
+ if (parameterCount != ((RoutineAliasInfo) aliasInfo).getParameterCount())\r
+ continue;\r
+\r
+ // procedure duplicate checking is simple, only\r
+ // one procedure with a given number of parameters.\r
+ throw StandardException.newException(SQLState.LANG_OBJECT_ALREADY_EXISTS,\r
+ ads.getDescriptorType(),\r
+ aliasName);\r
+ }\r
+ }\r
+ break;\r
+ case AliasInfo.ALIAS_TYPE_SYNONYM_AS_CHAR:\r
+ // If target table/view exists already, error.\r
+ TableDescriptor targetTD = dd.getTableDescriptor(aliasName, sd);\r
+ if (targetTD != null)\r
+ {\r
+ throw StandardException.newException(\r
+ SQLState.LANG_OBJECT_ALREADY_EXISTS,\r
+ targetTD.getDescriptorType(),\r
+ targetTD.getDescriptorName());\r
+ }\r
+\r
+ // Detect synonym cycles, if present.\r
+ String nextSynTable = ((SynonymAliasInfo)aliasInfo).getSynonymTable();\r
+ String nextSynSchema = ((SynonymAliasInfo)aliasInfo).getSynonymSchema();\r
+ SchemaDescriptor nextSD;\r
+ for (;;)\r
+ {\r
+ nextSD = dd.getSchemaDescriptor(nextSynSchema, tc, false);\r
+ if (nextSD == null)\r
+ break;\r
+ \r
+ AliasDescriptor nextAD = dd.getAliasDescriptor(nextSD.getUUID().toString(),\r
+ nextSynTable, nameSpace);\r
+ if (nextAD == null)\r
+ break;\r
+\r
+ SynonymAliasInfo info = (SynonymAliasInfo) nextAD.getAliasInfo();\r
+ nextSynTable = info.getSynonymTable();\r
+ nextSynSchema = info.getSynonymSchema();\r
+\r
+ if (aliasName.equals(nextSynTable) && schemaName.equals(nextSynSchema))\r
+ throw StandardException.newException(SQLState.LANG_SYNONYM_CIRCULAR,\r
+ aliasName, ((SynonymAliasInfo)aliasInfo).getSynonymTable());\r
+ }\r
+\r
+ // If synonym final target is not present, raise a warning\r
+ if (nextSD != null)\r
+ targetTD = dd.getTableDescriptor(nextSynTable, nextSD);\r
+ if (nextSD == null || targetTD == null)\r
+ activation.addWarning(\r
+ StandardException.newWarning(SQLState.LANG_SYNONYM_UNDEFINED,\r
+ aliasName, nextSynSchema+"."+nextSynTable));\r
+\r
+ // To prevent any possible deadlocks with SYSTABLES, we insert a row into\r
+ // SYSTABLES also for synonyms. This also ensures tables/views/synonyms share\r
+ // same namespace\r
+ TableDescriptor td;\r
+ DataDescriptorGenerator ddg = dd.getDataDescriptorGenerator();\r
+ td = ddg.newTableDescriptor(aliasName, sd, TableDescriptor.SYNONYM_TYPE,\r
+ TableDescriptor.DEFAULT_LOCK_GRANULARITY);\r
+ dd.addDescriptor(td, sd, DataDictionary.SYSTABLES_CATALOG_NUM, false, tc);\r
+ break;\r
+ \r
+ default:\r
+ break;\r
+ }\r
+\r
+ dd.addDescriptor(ads, null, DataDictionary.SYSALIASES_CATALOG_NUM,\r
+ false, tc);\r
+ }\r
+}\r