001: /*
002:
003: Derby - Class org.apache.derby.impl.sql.compile.CreateAliasNode
004:
005: Licensed to the Apache Software Foundation (ASF) under one or more
006: contributor license agreements. See the NOTICE file distributed with
007: this work for additional information regarding copyright ownership.
008: The ASF licenses this file to you under the Apache License, Version 2.0
009: (the "License"); you may not use this file except in compliance with
010: the License. You may obtain a copy of the License at
011:
012: http://www.apache.org/licenses/LICENSE-2.0
013:
014: Unless required by applicable law or agreed to in writing, software
015: distributed under the License is distributed on an "AS IS" BASIS,
016: WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
017: See the License for the specific language governing permissions and
018: limitations under the License.
019:
020: */
021:
022: package org.apache.derby.impl.sql.compile;
023:
024: import org.apache.derby.iapi.services.loader.ClassInspector;
025:
026: import org.apache.derby.iapi.services.context.ContextManager;
027:
028: import org.apache.derby.iapi.sql.compile.CompilerContext;
029: import org.apache.derby.iapi.sql.compile.C_NodeTypes;
030:
031: import org.apache.derby.iapi.reference.SQLState;
032: import org.apache.derby.iapi.reference.Limits;
033:
034: import org.apache.derby.iapi.sql.ResultSet;
035: import org.apache.derby.iapi.sql.execute.ConstantAction;
036:
037: import org.apache.derby.iapi.types.TypeId;
038:
039: import org.apache.derby.iapi.sql.dictionary.DataDictionary;
040: import org.apache.derby.iapi.sql.dictionary.TableDescriptor;
041: import org.apache.derby.iapi.sql.dictionary.SchemaDescriptor;
042:
043: import org.apache.derby.iapi.error.StandardException;
044:
045: import org.apache.derby.iapi.services.monitor.Monitor;
046: import org.apache.derby.iapi.services.sanity.SanityManager;
047:
048: import org.apache.derby.impl.sql.compile.ActivationClassBuilder;
049: import org.apache.derby.impl.sql.execute.BaseActivation;
050:
051: import org.apache.derby.catalog.AliasInfo;
052: import org.apache.derby.catalog.TypeDescriptor;
053: import org.apache.derby.catalog.types.RoutineAliasInfo;
054: import org.apache.derby.catalog.types.SynonymAliasInfo;
055:
056: import java.lang.reflect.Member;
057: import java.util.Vector;
058:
059: /**
060: * A CreateAliasNode represents a CREATE ALIAS statement.
061: *
062: * @author Jerry Brenner
063: */
064:
065: public class CreateAliasNode extends DDLStatementNode {
066: private String javaClassName;
067: private String methodName;
068: private char aliasType;
069: private boolean delimitedIdentifier;
070:
071: private AliasInfo aliasInfo;
072:
073: /**
074: * Initializer for a CreateAliasNode
075: *
076: * @param aliasName The name of the alias
077: * @param targetObject Target name
078: * @param methodName The method name
079: * @param aliasType The alias type
080: * @param delimitedIdentifier Whether or not to treat the class name
081: * as a delimited identifier if trying to
082: * resolve it as a class alias
083: *
084: * @exception StandardException Thrown on error
085: */
086: public void init(Object aliasName, Object targetObject,
087: Object methodName, Object aliasSpecificInfo,
088: Object aliasType, Object delimitedIdentifier)
089: throws StandardException {
090: TableName qn = (TableName) aliasName;
091: this .aliasType = ((Character) aliasType).charValue();
092:
093: initAndCheck(qn);
094:
095: switch (this .aliasType) {
096: case AliasInfo.ALIAS_TYPE_PROCEDURE_AS_CHAR:
097: case AliasInfo.ALIAS_TYPE_FUNCTION_AS_CHAR: {
098: this .javaClassName = (String) targetObject;
099: this .methodName = (String) methodName;
100: this .delimitedIdentifier = ((Boolean) delimitedIdentifier)
101: .booleanValue();
102:
103: //routineElements contains the description of the procedure.
104: //
105: // 0 - Object[] 3 element array for parameters
106: // 1 - TableName - specific name
107: // 2 - Integer - dynamic result set count
108: // 3 - String language (always java) - ignore
109: // 4 - String external name (also passed directly to create alias node - ignore
110: // 5 - Integer parameter style
111: // 6 - Short - SQL control
112: // 7 - Boolean - CALLED ON NULL INPUT (always TRUE for procedures)
113: // 8 - TypeDescriptor - return type (always NULL for procedures)
114:
115: Object[] routineElements = (Object[]) aliasSpecificInfo;
116: Object[] parameters = (Object[]) routineElements[0];
117: int paramCount = ((Vector) parameters[0]).size();
118:
119: // Support for Java signatures in Derby was added in 10.1
120: // Check to see the catalogs have been upgraded to 10.1 before
121: // accepting such a method name for a routine. Otherwise
122: // a routine that works in 10.1 soft upgrade mode would
123: // exist when running 10.0 but not resolve to anything.
124: if (this .methodName.indexOf('(') != -1) {
125: getDataDictionary().checkVersion(
126: DataDictionary.DD_VERSION_DERBY_10_1,
127: "EXTERNAL NAME 'class.method(<signature>)'");
128:
129: }
130:
131: String[] names = null;
132: TypeDescriptor[] types = null;
133: int[] modes = null;
134:
135: if (paramCount > Limits.DB2_MAX_PARAMS_IN_STORED_PROCEDURE)
136: throw StandardException
137: .newException(
138: SQLState.LANG_TOO_MANY_PARAMETERS_FOR_STORED_PROC,
139: String
140: .valueOf(Limits.DB2_MAX_PARAMS_IN_STORED_PROCEDURE),
141: aliasName, String.valueOf(paramCount));
142:
143: if (paramCount != 0) {
144:
145: names = new String[paramCount];
146: ((Vector) parameters[0]).copyInto(names);
147:
148: types = new TypeDescriptor[paramCount];
149: ((Vector) parameters[1]).copyInto(types);
150:
151: modes = new int[paramCount];
152: for (int i = 0; i < paramCount; i++) {
153: modes[i] = ((Integer) (((Vector) parameters[2])
154: .elementAt(i))).intValue();
155:
156: if (TypeId.getBuiltInTypeId(
157: types[i].getJDBCTypeId())
158: .isLongConcatableTypeId())
159: throw StandardException
160: .newException(
161: SQLState.LANG_LONG_DATA_TYPE_NOT_ALLOWED,
162: names[i]);
163:
164: }
165:
166: if (paramCount > 1) {
167: String[] dupNameCheck = new String[paramCount];
168: System.arraycopy(names, 0, dupNameCheck, 0,
169: paramCount);
170: java.util.Arrays.sort(dupNameCheck);
171: for (int dnc = 1; dnc < dupNameCheck.length; dnc++) {
172: if (dupNameCheck[dnc]
173: .equals(dupNameCheck[dnc - 1]))
174: throw StandardException.newException(
175: SQLState.LANG_DB2_DUPLICATE_NAMES,
176: dupNameCheck[dnc], getFullName());
177: }
178: }
179: }
180:
181: Integer drso = (Integer) routineElements[2];
182: int drs = drso == null ? 0 : drso.intValue();
183:
184: short sqlAllowed;
185: Short sqlAllowedObject = (Short) routineElements[6];
186: if (sqlAllowedObject != null)
187: sqlAllowed = sqlAllowedObject.shortValue();
188: else
189: sqlAllowed = (this .aliasType == AliasInfo.ALIAS_TYPE_PROCEDURE_AS_CHAR ? RoutineAliasInfo.MODIFIES_SQL_DATA
190: : RoutineAliasInfo.READS_SQL_DATA);
191:
192: Boolean calledOnNullInputO = (Boolean) routineElements[7];
193: boolean calledOnNullInput;
194: if (calledOnNullInputO == null)
195: calledOnNullInput = true;
196: else
197: calledOnNullInput = calledOnNullInputO.booleanValue();
198:
199: aliasInfo = new RoutineAliasInfo(this .methodName,
200: paramCount, names, types, modes,
201: drs,
202: ((Short) routineElements[5]).shortValue(), // parameter style
203: sqlAllowed, calledOnNullInput,
204: (TypeDescriptor) routineElements[8]);
205:
206: implicitCreateSchema = true;
207: }
208: break;
209:
210: case AliasInfo.ALIAS_TYPE_SYNONYM_AS_CHAR:
211: String targetSchema;
212: implicitCreateSchema = true;
213: TableName t = (TableName) targetObject;
214: if (t.getSchemaName() != null)
215: targetSchema = t.getSchemaName();
216: else
217: targetSchema = getSchemaDescriptor().getSchemaName();
218: aliasInfo = new SynonymAliasInfo(targetSchema, t
219: .getTableName());
220: break;
221:
222: default:
223: if (SanityManager.DEBUG) {
224: SanityManager
225: .THROWASSERT("Unexpected value for aliasType ("
226: + aliasType + ")");
227: }
228: }
229: }
230:
231: public String statementToString() {
232: switch (this .aliasType) {
233: case AliasInfo.ALIAS_TYPE_PROCEDURE_AS_CHAR:
234: return "CREATE PROCEDURE";
235: case AliasInfo.ALIAS_TYPE_SYNONYM_AS_CHAR:
236: return "CREATE SYNONYM";
237: default:
238: return "CREATE FUNCTION";
239: }
240: }
241:
242: // We inherit the generate() method from DDLStatementNode.
243:
244: /**
245: * Bind this CreateAliasNode. This means doing any static error
246: * checking that can be done before actually creating the table.
247: * For example, verifying that the column name list does not
248: * contain any duplicate column names.
249: *
250: * @return The bound query tree
251: *
252: * @exception StandardException Thrown on error
253: */
254:
255: public QueryTreeNode bind() throws StandardException {
256: // Procedures and functions do not check class or method validity until
257: // runtime execution. Synonyms do need some validity checks.
258: if (aliasType != AliasInfo.ALIAS_TYPE_SYNONYM_AS_CHAR)
259: return this ;
260:
261: // Don't allow creating synonyms in SESSION schema. Causes confusion if
262: // a temporary table is created later with same name.
263: if (isSessionSchema(getSchemaDescriptor().getSchemaName()))
264: throw StandardException
265: .newException(SQLState.LANG_OPERATION_NOT_ALLOWED_ON_SESSION_SCHEMA_TABLES);
266:
267: String targetSchema = ((SynonymAliasInfo) aliasInfo)
268: .getSynonymSchema();
269: String targetTable = ((SynonymAliasInfo) aliasInfo)
270: .getSynonymTable();
271: if (this .getObjectName().equals(targetSchema, targetTable))
272: throw StandardException.newException(
273: SQLState.LANG_SYNONYM_CIRCULAR, this .getFullName(),
274: targetSchema + "." + targetTable);
275:
276: SchemaDescriptor targetSD = getSchemaDescriptor(targetSchema,
277: false);
278: if ((targetSD != null) && isSessionSchema(targetSD))
279: throw StandardException
280: .newException(SQLState.LANG_OPERATION_NOT_ALLOWED_ON_SESSION_SCHEMA_TABLES);
281:
282: return this ;
283: }
284:
285: /**
286: * Create the Constant information that will drive the guts of Execution.
287: *
288: * @exception StandardException Thrown on failure
289: */
290: public ConstantAction makeConstantAction() throws StandardException {
291: String schemaName;
292: switch (aliasType) {
293: case AliasInfo.ALIAS_TYPE_PROCEDURE_AS_CHAR:
294: case AliasInfo.ALIAS_TYPE_FUNCTION_AS_CHAR:
295: schemaName = getSchemaDescriptor().getSchemaName();
296: break;
297: case AliasInfo.ALIAS_TYPE_SYNONYM_AS_CHAR:
298: schemaName = getSchemaDescriptor().getSchemaName();
299: break;
300: default:
301: schemaName = null;
302: }
303:
304: return getGenericConstantActionFactory()
305: .getCreateAliasConstantAction(getRelativeName(),
306: schemaName, javaClassName, aliasInfo, aliasType);
307: }
308: }
|