001: /*
002:
003: Derby - Class org.apache.derby.impl.sql.execute.DDLConstantAction
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.execute;
023:
024: import java.util.Iterator;
025: import java.util.List;
026:
027: import org.apache.derby.iapi.services.monitor.Monitor;
028:
029: import org.apache.derby.iapi.services.sanity.SanityManager;
030:
031: import org.apache.derby.iapi.services.io.FormatIdUtil;
032: import org.apache.derby.iapi.services.io.Formatable;
033: import org.apache.derby.iapi.services.io.StoredFormatIds;
034:
035: import org.apache.derby.iapi.error.StandardException;
036:
037: import org.apache.derby.iapi.sql.conn.Authorizer;
038: import org.apache.derby.iapi.sql.conn.LanguageConnectionContext;
039:
040: import org.apache.derby.iapi.sql.dictionary.ColPermsDescriptor;
041: import org.apache.derby.iapi.sql.dictionary.DataDictionary;
042: import org.apache.derby.iapi.sql.dictionary.DataDictionaryContext;
043: import org.apache.derby.iapi.sql.dictionary.PermissionsDescriptor;
044: import org.apache.derby.iapi.sql.dictionary.ReferencedKeyConstraintDescriptor;
045: import org.apache.derby.iapi.sql.dictionary.SchemaDescriptor;
046: import org.apache.derby.iapi.sql.dictionary.StatementColumnPermission;
047: import org.apache.derby.iapi.sql.dictionary.StatementPermission;
048: import org.apache.derby.iapi.sql.dictionary.StatementRoutinePermission;
049: import org.apache.derby.iapi.sql.dictionary.StatementSchemaPermission;
050: import org.apache.derby.iapi.sql.dictionary.StatementTablePermission;
051:
052: import org.apache.derby.iapi.sql.depend.Dependency;
053: import org.apache.derby.iapi.sql.depend.Dependent;
054: import org.apache.derby.iapi.sql.depend.DependencyManager;
055:
056: import org.apache.derby.iapi.sql.Activation;
057:
058: import org.apache.derby.iapi.reference.SQLState;
059:
060: import org.apache.derby.iapi.sql.execute.ConstantAction;
061:
062: import org.apache.derby.iapi.store.access.ConglomerateController;
063: import org.apache.derby.iapi.store.access.TransactionController;
064:
065: import org.apache.derby.catalog.UUID;
066:
067: /**
068: * Abstract class that has actions that are across
069: * all DDL actions.
070: *
071: * @author jamie
072: */
073: public abstract class DDLConstantAction extends GenericConstantAction {
074: //TransactionController tc;
075: //protected LanguageConnectionContext lcc;
076: //DataDescriptorGenerator ddg;
077: //DataDictionary dd;
078: //DependencyManager dm;
079:
080: /**
081: * Set up the "environment variables" for this
082: * constant action.
083: */
084: //protected void setEnvironmentVariables(Activation activation)
085: //{
086: /* find the language context.
087: * NOTE: The activation could be null if
088: * we are creating the SPSs for the metadata
089: * queries in the background, so we get
090: * the lcc from the ContextService.
091: */
092: //lcc = (activation == null) ?
093: // (LanguageConnectionContext)
094: // ContextService.getContext(LanguageConnectionContext.CONTEXT_ID):
095: // activation.getLanguageConnectionContext();
096:
097: // Get the current transaction controller
098: //tc = lcc.getTransactionExecute();
099: //dd = lcc.getDataDictionary();
100: //dm = dd.getDependencyManager();
101: //ddg = dd.getDataDescriptorGenerator();
102: // }
103: /**
104: * Get the schema descriptor for the schemaid.
105: *
106: * @param dd the data dictionary
107: * @param schemaId the schema id
108: * @param statementType string describing type of statement for error
109: * reporting. e.g. "ALTER STATEMENT"
110: *
111: * @return the schema descriptor
112: *
113: * @exception StandardException if schema is system schema
114: */
115: static SchemaDescriptor getAndCheckSchemaDescriptor(
116: DataDictionary dd, UUID schemaId, String statementType)
117: throws StandardException {
118: SchemaDescriptor sd = dd.getSchemaDescriptor(schemaId, null);
119: return sd;
120: }
121:
122: /**
123: * Get the schema descriptor in the creation of an object in
124: the passed in schema.
125: *
126: * @param dd the data dictionary
127: @param activation activation
128: @param schemaName name of the schema
129: *
130: * @return the schema descriptor
131: *
132: * @exception StandardException if the schema does not exist
133: */
134: static SchemaDescriptor getSchemaDescriptorForCreate(
135: DataDictionary dd, Activation activation, String schemaName)
136: throws StandardException {
137: TransactionController tc = activation
138: .getLanguageConnectionContext().getTransactionExecute();
139: SchemaDescriptor sd = dd.getSchemaDescriptor(schemaName, tc,
140: false);
141:
142: if (sd == null || sd.getUUID() == null) {
143: ConstantAction csca = new CreateSchemaConstantAction(
144: schemaName, (String) null);
145:
146: try {
147: csca.executeConstantAction(activation);
148: } catch (StandardException se) {
149: if (se.getMessageId().equals(
150: SQLState.LANG_OBJECT_ALREADY_EXISTS)) {
151: // Ignore "Schema already exists". Another thread has
152: // probably created it after we checked for it
153: } else {
154: throw se;
155: }
156: }
157:
158: sd = dd.getSchemaDescriptor(schemaName, tc, true);
159: }
160:
161: return sd;
162: }
163:
164: /**
165: * Lock the table in exclusive or share mode to prevent deadlocks.
166: *
167: * @param tc The TransactionController
168: * @param heapConglomerateNumber The conglomerate number for the heap.
169: * @param exclusiveMode Whether or not to lock the table in exclusive mode.
170: *
171: * @exception StandardException if schema is system schema
172: */
173: final void lockTableForDDL(TransactionController tc,
174: long heapConglomerateNumber, boolean exclusiveMode)
175: throws StandardException {
176: ConglomerateController cc;
177:
178: cc = tc
179: .openConglomerate(
180: heapConglomerateNumber,
181: false,
182: (exclusiveMode) ? (TransactionController.OPENMODE_FORUPDATE | TransactionController.OPENMODE_FOR_LOCK_ONLY)
183: : TransactionController.OPENMODE_FOR_LOCK_ONLY,
184: TransactionController.MODE_TABLE,
185: TransactionController.ISOLATION_SERIALIZABLE);
186: cc.close();
187: }
188:
189: protected String constructToString(String statementType,
190: String objectName) {
191: // Do not put this under SanityManager.DEBUG - it is needed for
192: // error reporting.
193:
194: return statementType + objectName;
195: }
196:
197: /**
198: * This method saves dependencies of constraints on privileges in the
199: * dependency system. It gets called by CreateConstraintConstantAction.
200: * Views and triggers and constraints run with definer's privileges. If
201: * one of the required privileges is revoked from the definer, the
202: * dependent view/trigger/constraint on that privilege will be dropped
203: * automatically. In order to implement this behavior, we need to save
204: * view/trigger/constraint dependencies on required privileges in the
205: * dependency system. Following method accomplishes that part of the
206: * equation for constraints only. The dependency collection for
207: * constraints is not same as for views and triggers and hence
208: * constraints are handled by this special method.
209: * Views and triggers can depend on many different kind of privileges
210: * where as constraints only depend on REFERENCES privilege on a table.
211: * Another difference is only one view or trigger can be defined by a
212: * sql statement and hence all the dependencies collected for the sql
213: * statement apply to the view or trigger in question. As for constraints,
214: * one sql statement can defined multiple constraints and hence the
215: * all the privileges required by the statement are not necessarily
216: * required by all the constraints defined by that sql statement. We need
217: * to identify right privileges for right constraints for a given sql
218: * statement. Because of these differences between constraints and views
219: * (and triggers), there are 2 different methods in this class to save
220: * their privileges in the dependency system.
221: *
222: * @param activation The execution environment for this constant action.
223: * @param dependent Make this object depend on required privileges
224: * @param refTableUUID Make sure we are looking for REFERENCES privilege
225: * for right table
226: *
227: * @exception StandardException Thrown on failure
228: */
229: protected void storeConstraintDependenciesOnPrivileges(
230: Activation activation, Dependent dependent,
231: UUID refTableUUID) throws StandardException {
232: LanguageConnectionContext lcc = activation
233: .getLanguageConnectionContext();
234: DataDictionary dd = lcc.getDataDictionary();
235: DependencyManager dm = dd.getDependencyManager();
236:
237: //If the Database Owner is creating this constraint, then no need to
238: //collect any privilege dependencies because the Database Owner can
239: //access any objects without any restrictions
240: if (!(lcc.getAuthorizationId().equals(dd
241: .getAuthorizationDatabaseOwner()))) {
242: PermissionsDescriptor permDesc;
243: //Now, it is time to add into dependency system, constraint's
244: //dependency on REFERENCES privilege. If the REFERENCES privilege is
245: //revoked from the constraint owner, the constraint will get
246: //dropped automatically.
247: List requiredPermissionsList = activation
248: .getPreparedStatement()
249: .getRequiredPermissionsList();
250: if (requiredPermissionsList != null
251: && !requiredPermissionsList.isEmpty()) {
252: for (Iterator iter = requiredPermissionsList.iterator(); iter
253: .hasNext();) {
254: StatementPermission statPerm = (StatementPermission) iter
255: .next();
256: //First check if we are dealing with a Table or
257: //Column level privilege. All the other privileges
258: //are not required for a foreign key constraint.
259: if (statPerm instanceof StatementTablePermission) {//It is a table/column level privilege
260: StatementTablePermission statementTablePermission = (StatementTablePermission) statPerm;
261: //Check if we are dealing with REFERENCES privilege.
262: //If not, move on to the next privilege in the
263: //required privileges list
264: if (statementTablePermission.getPrivType() != Authorizer.REFERENCES_PRIV)
265: continue;
266: //Next check is this REFERENCES privilege is
267: //on the same table as referenced by the foreign
268: //key constraint? If not, move on to the next
269: //privilege in the required privileges list
270: if (!statementTablePermission.getTableUUID()
271: .equals(refTableUUID))
272: continue;
273: } else if (statPerm instanceof StatementSchemaPermission
274: || statPerm instanceof StatementRoutinePermission)
275: continue;
276:
277: //We know that we are working with a REFERENCES
278: //privilege. Find all the PermissionDescriptors for
279: //this privilege and make constraint depend on it
280: //through dependency manager.
281: //The REFERENCES privilege could be defined at the
282: //table level or it could be defined at individual
283: //column levels. In addition, individual column
284: //REFERENCES privilege could be available at the
285: //user level or PUBLIC level.
286: permDesc = statPerm.getPermissionDescriptor(lcc
287: .getAuthorizationId(), dd);
288: if (permDesc == null) {
289: //No REFERENCES privilege exists for given
290: //authorizer at table or column level.
291: //REFERENCES privilege has to exist at at PUBLIC level
292: permDesc = statPerm.getPermissionDescriptor(
293: Authorizer.PUBLIC_AUTHORIZATION_ID, dd);
294: if (!(permDesc.checkOwner(lcc
295: .getAuthorizationId())))
296: dm.addDependency(dependent, permDesc, lcc
297: .getContextManager());
298: } else
299: //if the object on which permission is required is owned by the
300: //same user as the current user, then no need to keep that
301: //object's privilege dependency in the dependency system
302: if (!(permDesc.checkOwner(lcc.getAuthorizationId()))) {
303: dm.addDependency(dependent, permDesc, lcc
304: .getContextManager());
305: if (permDesc instanceof ColPermsDescriptor) {
306: //The if statement above means we found a
307: //REFERENCES privilege at column level for
308: //the given authorizer. If this privilege
309: //doesn't cover all the column , then there
310: //has to exisit REFERENCES for the remaining
311: //columns at PUBLIC level. Get that permission
312: //descriptor and save it in dependency system
313: StatementColumnPermission statementColumnPermission = (StatementColumnPermission) statPerm;
314: permDesc = statementColumnPermission
315: .getPUBLIClevelColPermsDescriptor(
316: lcc.getAuthorizationId(),
317: dd);
318: //Following if checks if some column level privileges
319: //exist only at public level. If so, then the public
320: //level column privilege dependency is added
321: //into the dependency system
322: if (permDesc != null)
323: dm.addDependency(dependent, permDesc,
324: lcc.getContextManager());
325: }
326: }
327: //We have found the REFERENCES privilege for all the
328: //columns in foreign key constraint and we don't
329: //need to go through the rest of the privileges
330: //for this sql statement.
331: break;
332: }
333: }
334: }
335:
336: }
337:
338: /**
339: * This method saves dependencies of views and triggers on privileges in
340: * the dependency system. It gets called by CreateViewConstantAction
341: * and CreateTriggerConstantAction. Views and triggers and constraints
342: * run with definer's privileges. If one of the required privileges is
343: * revoked from the definer, the dependent view/trigger/constraint on
344: * that privilege will be dropped automatically. In order to implement
345: * this behavior, we need to save view/trigger/constraint dependencies
346: * on required privileges in the dependency system. Following method
347: * accomplishes that part of the equation for views and triggers. The
348: * dependency collection for constraints is not same as for views and
349: * triggers and hence constraints are not covered by this method.
350: * Views and triggers can depend on many different kind of privileges
351: * where as constraints only depend on REFERENCES privilege on a table.
352: * Another difference is only one view or trigger can be defined by a
353: * sql statement and hence all the dependencies collected for the sql
354: * statement apply to the view or trigger in question. As for constraints,
355: * one sql statement can defined multiple constraints and hence the
356: * all the privileges required by the statement are not necessarily
357: * required by all the constraints defined by that sql statement. We need
358: * to identify right privileges for right constraints for a given sql
359: * statement. Because of these differences between constraints and views
360: * (and triggers), there are 2 different methods in this class to save
361: * their privileges in the dependency system.
362: *
363: * @param activation The execution environment for this constant action.
364: * @param dependent Make this object depend on required privileges
365: *
366: * @exception StandardException Thrown on failure
367: */
368: protected void storeViewTriggerDependenciesOnPrivileges(
369: Activation activation, Dependent dependent)
370: throws StandardException {
371: LanguageConnectionContext lcc = activation
372: .getLanguageConnectionContext();
373: DataDictionary dd = lcc.getDataDictionary();
374: DependencyManager dm = dd.getDependencyManager();
375:
376: //If the Database Owner is creating this view/triiger, then no need to
377: //collect any privilege dependencies because the Database Owner can
378: //access any objects without any restrictions
379: if (!(lcc.getAuthorizationId().equals(dd
380: .getAuthorizationDatabaseOwner()))) {
381: PermissionsDescriptor permDesc;
382: List requiredPermissionsList = activation
383: .getPreparedStatement()
384: .getRequiredPermissionsList();
385: if (requiredPermissionsList != null
386: && !requiredPermissionsList.isEmpty()) {
387: for (Iterator iter = requiredPermissionsList.iterator(); iter
388: .hasNext();) {
389: StatementPermission statPerm = (StatementPermission) iter
390: .next();
391: //The schema ownership permission just needs to be checked
392: //at object creation time, to see if the object creator has
393: //permissions to create the object in the specified schema.
394: //But we don't need to add schema permission to list of
395: //permissions that the object is dependent on once it is
396: //created.
397: if (statPerm instanceof StatementSchemaPermission)
398: continue;
399: //See if we can find the required privilege for given authorizer?
400: permDesc = statPerm.getPermissionDescriptor(lcc
401: .getAuthorizationId(), dd);
402: if (permDesc == null)//privilege not found for given authorizer
403: {
404: //The if condition above means that required privilege does
405: //not exist at the user level. The privilege has to exist at
406: //PUBLIC level.
407: permDesc = statPerm.getPermissionDescriptor(
408: Authorizer.PUBLIC_AUTHORIZATION_ID, dd);
409: //If the user accessing the object is the owner of that
410: //object, then no privilege tracking is needed for the
411: //owner.
412: if (!(permDesc.checkOwner(lcc
413: .getAuthorizationId())))
414: dm.addDependency(dependent, permDesc, lcc
415: .getContextManager());
416: continue;
417: }
418: //if the object on which permission is required is owned by the
419: //same user as the current user, then no need to keep that
420: //object's privilege dependency in the dependency system
421: if (!(permDesc.checkOwner(lcc.getAuthorizationId()))) {
422: dm.addDependency(dependent, permDesc, lcc
423: .getContextManager());
424: if (permDesc instanceof ColPermsDescriptor) {
425: //For a given table, the table owner can give privileges
426: //on some columns at individual user level and privileges
427: //on some columns at PUBLIC level. Hence, when looking for
428: //column level privileges, we need to look both at user
429: //level as well as PUBLIC level(only if user level column
430: //privileges do not cover all the columns accessed by this
431: //object). We have finished adding dependency for user level
432: //columns, now we are checking if some required column
433: //level privileges are at PUBLIC level.
434: //A specific eg of a view
435: //user1
436: //create table t11(c11 int, c12 int);
437: //grant select(c11) on t1 to user2;
438: //grant select(c12) on t1 to PUBLIC;
439: //user2
440: //create view v1 as select c11 from user1.t11 where c12=2;
441: //For the view above, there are 2 column level privilege
442: //depencies, one for column c11 which exists directly
443: //for user2 and one for column c12 which exists at PUBLIC level.
444: StatementColumnPermission statementColumnPermission = (StatementColumnPermission) statPerm;
445: permDesc = statementColumnPermission
446: .getPUBLIClevelColPermsDescriptor(
447: lcc.getAuthorizationId(),
448: dd);
449: //Following if checks if some column level privileges
450: //exist only at public level. If so, then the public
451: //level column privilege dependency of view is added
452: //into dependency system.
453: if (permDesc != null)
454: dm.addDependency(dependent, permDesc,
455: lcc.getContextManager());
456: }
457: }
458: }
459: }
460:
461: }
462: }
463: }
|