| /* |
| |
| Derby - Class org.apache.derby.impl.sql.catalog.DataDictionaryImpl |
| |
| Licensed to the Apache Software Foundation (ASF) under one or more |
| contributor license agreements. See the NOTICE file distributed with |
| this work for additional information regarding copyright ownership. |
| The ASF licenses this file to you under the Apache License, Version 2.0 |
| (the "License"); you may not use this file except in compliance with |
| the License. You may obtain a copy of the License at |
| |
| http://www.apache.org/licenses/LICENSE-2.0 |
| |
| Unless required by applicable law or agreed to in writing, software |
| distributed under the License is distributed on an "AS IS" BASIS, |
| WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| See the License for the specific language governing permissions and |
| limitations under the License. |
| |
| */ |
| |
| package org.apache.derby.impl.sql.catalog; |
| |
| import java.io.File; |
| import java.io.IOException; |
| import java.io.InputStream; |
| import java.security.PrivilegedActionException; |
| import java.security.PrivilegedAction; |
| import java.security.PrivilegedExceptionAction; |
| import java.security.AccessController; |
| import java.security.MessageDigest; |
| import java.security.NoSuchAlgorithmException; |
| import java.security.SecureRandom; |
| import java.sql.ParameterMetaData; |
| import java.sql.Types; |
| import java.util.Arrays; |
| import java.util.ArrayList; |
| import java.util.Calendar; |
| import java.util.Collections; |
| import java.util.Dictionary; |
| import java.util.Enumeration; |
| import java.util.GregorianCalendar; |
| import java.util.HashMap; |
| import java.util.HashSet; |
| import java.util.Hashtable; |
| import java.util.Iterator; |
| import java.util.LinkedList; |
| import java.util.List; |
| import java.util.Map; |
| import java.util.Properties; |
| import java.util.SortedSet; |
| import org.apache.derby.catalog.AliasInfo; |
| import org.apache.derby.catalog.DefaultInfo; |
| import org.apache.derby.catalog.DependableFinder; |
| import org.apache.derby.catalog.TypeDescriptor; |
| import org.apache.derby.catalog.UUID; |
| import org.apache.derby.catalog.types.BaseTypeIdImpl; |
| import org.apache.derby.catalog.types.RoutineAliasInfo; |
| import org.apache.derby.iapi.db.Database; |
| import org.apache.derby.iapi.error.StandardException; |
| import org.apache.derby.iapi.reference.Attribute; |
| import org.apache.derby.iapi.reference.EngineType; |
| import org.apache.derby.iapi.reference.Limits; |
| import org.apache.derby.iapi.reference.Property; |
| import org.apache.derby.iapi.reference.SQLState; |
| import org.apache.derby.iapi.services.cache.CacheFactory; |
| import org.apache.derby.iapi.services.cache.CacheManager; |
| import org.apache.derby.iapi.services.cache.Cacheable; |
| import org.apache.derby.iapi.services.cache.CacheableFactory; |
| import org.apache.derby.iapi.services.context.ContextManager; |
| import org.apache.derby.iapi.services.context.Context; |
| import org.apache.derby.iapi.services.context.ContextService; |
| import org.apache.derby.iapi.services.daemon.IndexStatisticsDaemon; |
| import org.apache.derby.iapi.services.io.FormatableBitSet; |
| import org.apache.derby.iapi.services.locks.C_LockFactory; |
| import org.apache.derby.iapi.services.locks.CompatibilitySpace; |
| import org.apache.derby.iapi.services.locks.LockFactory; |
| import org.apache.derby.iapi.services.locks.ShExLockable; |
| import org.apache.derby.iapi.services.locks.ShExQual; |
| import org.apache.derby.iapi.services.monitor.ModuleControl; |
| import org.apache.derby.iapi.services.monitor.ModuleFactory; |
| import org.apache.derby.iapi.services.monitor.ModuleSupportable; |
| import org.apache.derby.iapi.services.monitor.Monitor; |
| import org.apache.derby.iapi.services.property.PropertyUtil; |
| import org.apache.derby.shared.common.sanity.AssertFailure; |
| import org.apache.derby.shared.common.sanity.SanityManager; |
| import org.apache.derby.iapi.services.uuid.UUIDFactory; |
| import org.apache.derby.iapi.sql.compile.Visitable; |
| import org.apache.derby.iapi.sql.conn.Authorizer; |
| import org.apache.derby.iapi.sql.conn.LanguageConnectionContext; |
| import org.apache.derby.iapi.sql.conn.LanguageConnectionFactory; |
| import org.apache.derby.iapi.sql.depend.DependencyManager; |
| import org.apache.derby.iapi.sql.dictionary.AliasDescriptor; |
| import org.apache.derby.iapi.sql.dictionary.BulkInsertCounter; |
| import org.apache.derby.iapi.sql.dictionary.CatalogRowFactory; |
| import org.apache.derby.iapi.sql.dictionary.CheckConstraintDescriptor; |
| import org.apache.derby.iapi.sql.dictionary.ColPermsDescriptor; |
| import org.apache.derby.iapi.sql.dictionary.ColumnDescriptor; |
| import org.apache.derby.iapi.sql.dictionary.ColumnDescriptorList; |
| import org.apache.derby.iapi.sql.dictionary.ConglomerateDescriptor; |
| import org.apache.derby.iapi.sql.dictionary.ConglomerateDescriptorList; |
| import org.apache.derby.iapi.sql.dictionary.ConstraintDescriptor; |
| import org.apache.derby.iapi.sql.dictionary.ConstraintDescriptorList; |
| import org.apache.derby.iapi.sql.dictionary.DataDescriptorGenerator; |
| import org.apache.derby.iapi.sql.dictionary.DataDictionary; |
| import org.apache.derby.iapi.sql.dictionary.DefaultDescriptor; |
| import org.apache.derby.iapi.sql.dictionary.DependencyDescriptor; |
| import org.apache.derby.iapi.sql.dictionary.FileInfoDescriptor; |
| import org.apache.derby.iapi.sql.dictionary.ForeignKeyConstraintDescriptor; |
| import org.apache.derby.iapi.sql.dictionary.TriggerDescriptorList; |
| import org.apache.derby.iapi.sql.dictionary.IndexRowGenerator; |
| import org.apache.derby.iapi.sql.dictionary.KeyConstraintDescriptor; |
| import org.apache.derby.iapi.sql.dictionary.PasswordHasher; |
| import org.apache.derby.iapi.sql.dictionary.PermDescriptor; |
| import org.apache.derby.iapi.sql.dictionary.PermissionsDescriptor; |
| import org.apache.derby.iapi.sql.dictionary.ReferencedKeyConstraintDescriptor; |
| import org.apache.derby.iapi.sql.dictionary.RoleClosureIterator; |
| import org.apache.derby.iapi.sql.dictionary.RoleGrantDescriptor; |
| import org.apache.derby.iapi.sql.dictionary.RoutinePermsDescriptor; |
| import org.apache.derby.iapi.sql.dictionary.SPSDescriptor; |
| import org.apache.derby.iapi.sql.dictionary.SchemaDescriptor; |
| import org.apache.derby.iapi.sql.dictionary.SequenceDescriptor; |
| import org.apache.derby.iapi.sql.dictionary.StatisticsDescriptor; |
| import org.apache.derby.iapi.sql.dictionary.SubCheckConstraintDescriptor; |
| import org.apache.derby.iapi.sql.dictionary.SubConstraintDescriptor; |
| import org.apache.derby.iapi.sql.dictionary.SubKeyConstraintDescriptor; |
| import org.apache.derby.iapi.sql.dictionary.SystemColumn; |
| import org.apache.derby.iapi.sql.dictionary.TableDescriptor; |
| import org.apache.derby.iapi.sql.dictionary.TablePermsDescriptor; |
| import org.apache.derby.iapi.sql.dictionary.TriggerDescriptor; |
| import org.apache.derby.iapi.sql.dictionary.TupleDescriptor; |
| import org.apache.derby.iapi.sql.dictionary.UserDescriptor; |
| import org.apache.derby.iapi.sql.dictionary.ViewDescriptor; |
| import org.apache.derby.iapi.sql.execute.ExecIndexRow; |
| import org.apache.derby.iapi.sql.execute.ExecRow; |
| import org.apache.derby.iapi.sql.execute.ExecutionContext; |
| import org.apache.derby.iapi.sql.execute.ExecutionFactory; |
| import org.apache.derby.iapi.sql.execute.ScanQualifier; |
| import org.apache.derby.iapi.sql.execute.TupleFilter; |
| import org.apache.derby.iapi.store.access.AccessFactory; |
| import org.apache.derby.iapi.store.access.ConglomerateController; |
| import org.apache.derby.iapi.store.access.FileResource; |
| import org.apache.derby.iapi.store.access.Qualifier; |
| import org.apache.derby.iapi.store.access.RowUtil; |
| import org.apache.derby.iapi.store.access.ScanController; |
| import org.apache.derby.iapi.store.access.TransactionController; |
| import org.apache.derby.iapi.types.DataTypeDescriptor; |
| import org.apache.derby.iapi.types.DataValueDescriptor; |
| import org.apache.derby.iapi.types.DataValueFactory; |
| import org.apache.derby.iapi.types.NumberDataValue; |
| import org.apache.derby.iapi.types.Orderable; |
| import org.apache.derby.iapi.types.RowLocation; |
| import org.apache.derby.iapi.types.SQLBoolean; |
| import org.apache.derby.iapi.types.SQLChar; |
| import org.apache.derby.iapi.types.SQLLongint; |
| import org.apache.derby.iapi.types.SQLVarchar; |
| import org.apache.derby.iapi.types.StringDataValue; |
| import org.apache.derby.iapi.types.TypeId; |
| import org.apache.derby.iapi.types.UserType; |
| import org.apache.derby.iapi.util.IdUtil; |
| import org.apache.derby.impl.services.daemon.IndexStatisticsDaemonImpl; |
| import org.apache.derby.impl.services.locks.Timeout; |
| import org.apache.derby.impl.sql.compile.ColumnReference; |
| import org.apache.derby.impl.sql.compile.QueryTreeNode; |
| import org.apache.derby.impl.sql.compile.TableName; |
| import org.apache.derby.impl.sql.depend.BasicDependencyManager; |
| import org.apache.derby.impl.sql.execute.JarUtil; |
| import org.apache.derby.shared.common.error.MessageUtils; |
| |
| /** |
| * Standard database implementation of the data dictionary |
| * that stores the information in the system catalogs. |
| */ |
| @SuppressWarnings("UseOfObsoleteCollectionType") |
| public final class DataDictionaryImpl |
| implements DataDictionary, CacheableFactory, ModuleControl, ModuleSupportable,java.security.PrivilegedAction<Properties> |
| { |
| |
| private static final String CFG_SYSTABLES_ID = "SystablesIdentifier"; |
| private static final String CFG_SYSTABLES_INDEX1_ID = "SystablesIndex1Identifier"; |
| private static final String CFG_SYSTABLES_INDEX2_ID = "SystablesIndex2Identifier"; |
| private static final String CFG_SYSCOLUMNS_ID = "SyscolumnsIdentifier"; |
| private static final String CFG_SYSCOLUMNS_INDEX1_ID = "SyscolumnsIndex1Identifier"; |
| private static final String CFG_SYSCOLUMNS_INDEX2_ID = "SyscolumnsIndex2Identifier"; |
| private static final String CFG_SYSCONGLOMERATES_ID = "SysconglomeratesIdentifier"; |
| private static final String CFG_SYSCONGLOMERATES_INDEX1_ID = "SysconglomeratesIndex1Identifier"; |
| private static final String CFG_SYSCONGLOMERATES_INDEX2_ID = "SysconglomeratesIndex2Identifier"; |
| private static final String CFG_SYSCONGLOMERATES_INDEX3_ID = "SysconglomeratesIndex3Identifier"; |
| private static final String CFG_SYSSCHEMAS_ID = "SysschemasIdentifier"; |
| private static final String CFG_SYSSCHEMAS_INDEX1_ID = "SysschemasIndex1Identifier"; |
| private static final String CFG_SYSSCHEMAS_INDEX2_ID = "SysschemasIndex2Identifier"; |
| |
| private static final int SYSCONGLOMERATES_CORE_NUM = 0; |
| private static final int SYSTABLES_CORE_NUM = 1; |
| private static final int SYSCOLUMNS_CORE_NUM = 2; |
| private static final int SYSSCHEMAS_CORE_NUM = 3; |
| private static final int NUM_CORE = 4; |
| |
| /** |
| * SYSFUN functions. Table of functions that automatically appear |
| * in the SYSFUN schema. These functions are resolved to directly |
| * if no schema name is given, e.g. |
| * |
| * <code> |
| * SELECT COS(angle) FROM ROOM_WALLS |
| * </code> |
| * |
| * Adding a function here is suitable when the function defintion |
| * can have a single return type and fixed parameter types. |
| * |
| * Functions that need to have a return type based upon the |
| * input type(s) are not supported here. Typically those are |
| * added into the parser and methods added into the DataValueDescriptor interface. |
| * Examples are character based functions whose return type |
| * length is based upon the passed in type, e.g. passed a CHAR(10) |
| * returns a CHAR(10). |
| * |
| * |
| * This simple table can handle an arbitrary number of arguments |
| * and RETURNS NULL ON NULL INPUT. The scheme could be expanded |
| * to handle other function options such as other parameters if needed. |
| *[0] = FUNCTION name |
| *[1] = RETURNS type |
| *[2] = Java class |
| *[3] = method name and signature |
| *[4] = "true" or "false" depending on whether the function is DETERMINSTIC |
| *[5] = "true" or "false" depending on whether the function has VARARGS |
| *[6..N] = arguments (optional, if not present zero arguments is assumed) |
| * |
| */ |
| private static final String[][] SYSFUN_FUNCTIONS = { |
| {"ACOS", "DOUBLE", "java.lang.StrictMath", "acos(double)", "true", "false", "DOUBLE" }, |
| {"ASIN", "DOUBLE", "java.lang.StrictMath", "asin(double)", "true", "false", "DOUBLE" }, |
| {"ATAN", "DOUBLE", "java.lang.StrictMath", "atan(double)", "true", "false", "DOUBLE" }, |
| {"ATAN2", "DOUBLE", "java.lang.StrictMath", "atan2(double,double)", "true", "false", "DOUBLE", "DOUBLE" }, |
| {"COS", "DOUBLE", "java.lang.StrictMath", "cos(double)", "true", "false", "DOUBLE" }, |
| {"SIN", "DOUBLE", "java.lang.StrictMath", "sin(double)", "true", "false", "DOUBLE" }, |
| {"TAN", "DOUBLE", "java.lang.StrictMath", "tan(double)", "true", "false", "DOUBLE" }, |
| {"PI", "DOUBLE", "org.apache.derby.catalog.SystemProcedures", "PI()", "true", "false" }, |
| {"DEGREES", "DOUBLE", "java.lang.StrictMath", "toDegrees(double)", "true", "false", "DOUBLE" }, |
| {"RADIANS", "DOUBLE", "java.lang.StrictMath", "toRadians(double)", "true", "false", "DOUBLE" }, |
| {"LN", "DOUBLE", "java.lang.StrictMath", "log(double)", "true", "false", "DOUBLE" }, |
| {"LOG", "DOUBLE", "java.lang.StrictMath", "log(double)", "true", "false", "DOUBLE" }, // Same as LN |
| {"LOG10", "DOUBLE", "java.lang.StrictMath", "log10(double)", "true", "false", "DOUBLE" }, |
| {"EXP", "DOUBLE", "java.lang.StrictMath", "exp(double)", "true", "false", "DOUBLE" }, |
| {"CEIL", "DOUBLE", "java.lang.StrictMath", "ceil(double)", "true", "false", "DOUBLE" }, |
| {"CEILING", "DOUBLE", "java.lang.StrictMath", "ceil(double)", "true", "false", "DOUBLE" }, // Same as CEIL |
| {"FLOOR", "DOUBLE", "java.lang.StrictMath", "floor(double)", "true", "false", "DOUBLE" }, |
| {"SIGN", "INTEGER", "org.apache.derby.catalog.SystemProcedures", "SIGN(double)", "true", "false", "DOUBLE" }, |
| {"RANDOM", "DOUBLE", "java.lang.StrictMath", "random()", "false", "false" }, |
| {"RAND", "DOUBLE", "org.apache.derby.catalog.SystemProcedures", "RAND(int)", "false", "false", "INTEGER" }, // Escape function spec. |
| {"COT", "DOUBLE", "org.apache.derby.catalog.SystemProcedures", "COT(double)", "true", "false", "DOUBLE" }, |
| {"COSH", "DOUBLE", "java.lang.StrictMath", "cosh(double)", "true", "false", "DOUBLE" }, |
| {"SINH", "DOUBLE", "java.lang.StrictMath", "sinh(double)", "true", "false", "DOUBLE" }, |
| {"TANH", "DOUBLE", "java.lang.StrictMath", "tanh(double)", "true", "false", "DOUBLE" } |
| }; |
| |
| |
| /** |
| * Index into SYSFUN_FUNCTIONS of the DETERMINISTIC indicator. |
| * Used to determine whether the system function is DETERMINISTIC |
| */ |
| private static final int SYSFUN_DETERMINISTIC_INDEX = 4; |
| |
| /** |
| * Index into SYSFUN_FUNCTIONS of the VARARGS indicator. |
| * Used to determine whether the system function has VARARGS |
| */ |
| private static final int SYSFUN_VARARGS_INDEX = 5; |
| |
| /** |
| * The index of the first parameter in entries in the SYSFUN_FUNCTIONS |
| * table. Used to determine the parameter count (zero to many). |
| */ |
| private static final int SYSFUN_FIRST_PARAMETER_INDEX = 6; |
| |
| /** |
| * Runtime definition of the functions from SYSFUN_FUNCTIONS. |
| * Populated dynamically as functions are called. |
| */ |
| private final AliasDescriptor[] sysfunDescriptors = |
| new AliasDescriptor[SYSFUN_FUNCTIONS.length]; |
| |
| // the structure that holds all the core table info |
| private TabInfoImpl[] coreInfo; |
| |
| /* |
| ** SchemaDescriptors for system and app schemas. Both |
| ** are canonical. We cache them for fast lookup. |
| */ |
| private SchemaDescriptor systemSchemaDesc; |
| private SchemaDescriptor sysIBMSchemaDesc; |
| private SchemaDescriptor declaredGlobalTemporaryTablesSchemaDesc; |
| private SchemaDescriptor systemUtilSchemaDesc; |
| |
| // This array of non-core table names *MUST* be in the same order |
| // as the non-core table numbers in DataDictionary. |
| private static final String[] nonCoreNames = { |
| "SYSCONSTRAINTS", |
| "SYSKEYS", |
| "SYSDEPENDS", |
| "SYSALIASES", |
| "SYSVIEWS", |
| "SYSCHECKS", |
| "SYSFOREIGNKEYS", |
| "SYSSTATEMENTS", |
| "SYSFILES", |
| "SYSTRIGGERS", |
| "SYSSTATISTICS", |
| "SYSDUMMY1", |
| "SYSTABLEPERMS", |
| "SYSCOLPERMS", |
| "SYSROUTINEPERMS", |
| "SYSROLES", |
| "SYSSEQUENCES", |
| "SYSPERMS", |
| "SYSUSERS" |
| }; |
| |
| private static final int NUM_NONCORE = nonCoreNames.length; |
| |
| /** |
| * List of all "system" schemas |
| * <p> |
| * This list should contain all schema's used by the system and are |
| * created when the database is created. Users should not be able to |
| * create or drop these schema's and should not be able to create or |
| * drop objects in these schema's. This list is used by code that |
| * needs to check if a particular schema is a "system" schema. |
| **/ |
| private static final String[] systemSchemaNames = { |
| SchemaDescriptor.IBM_SYSTEM_CAT_SCHEMA_NAME, |
| SchemaDescriptor.IBM_SYSTEM_FUN_SCHEMA_NAME, |
| SchemaDescriptor.IBM_SYSTEM_PROC_SCHEMA_NAME, |
| SchemaDescriptor.IBM_SYSTEM_STAT_SCHEMA_NAME, |
| SchemaDescriptor.IBM_SYSTEM_NULLID_SCHEMA_NAME, |
| SchemaDescriptor.STD_SYSTEM_DIAG_SCHEMA_NAME, |
| SchemaDescriptor.STD_SYSTEM_UTIL_SCHEMA_NAME, |
| SchemaDescriptor.IBM_SYSTEM_SCHEMA_NAME, |
| SchemaDescriptor.STD_SQLJ_SCHEMA_NAME, |
| SchemaDescriptor.STD_SYSTEM_SCHEMA_NAME |
| }; |
| |
| |
| /** Dictionary version of the on-disk database */ |
| private DD_Version dictionaryVersion; |
| /** Dictionary version of the currently running engine */ |
| private DD_Version softwareVersion; |
| |
| private String authorizationDatabaseOwner; |
| private boolean usesSqlAuthorization; |
| |
| /* |
| ** This property and value are written into the database properties |
| ** when the database is created, and are used to determine whether |
| ** the system catalogs need to be upgraded. |
| */ |
| |
| // the structure that holds all the noncore info |
| private TabInfoImpl[] noncoreInfo; |
| |
| // no other system tables have id's in the configuration. |
| |
| public DataDescriptorGenerator dataDescriptorGenerator; |
| private DataValueFactory dvf; |
| AccessFactory af; |
| //DataDictionaryContext ddc; |
| |
| private ExecutionFactory exFactory; |
| protected UUIDFactory uuidFactory; |
| /** Daemon creating and refreshing index cardinality statistics. */ |
| private IndexStatisticsDaemon indexRefresher; |
| |
| Properties startupParameters; |
| int engineType; |
| |
| /* Information about whether or not we are at boot time */ |
| protected boolean booting; |
| private TransactionController bootingTC; |
| protected DependencyManager dmgr; |
| |
| /* Cache of table descriptors */ |
| CacheManager OIDTdCache; |
| CacheManager nameTdCache; |
| private CacheManager spsNameCache; |
| private CacheManager sequenceGeneratorCache; |
| private Hashtable<UUID,SPSDescriptor> spsIdHash; |
| // private Hashtable spsTextHash; |
| int tdCacheSize; |
| int stmtCacheSize; |
| private int seqgenCacheSize; |
| |
| /* Cache of permissions data */ |
| CacheManager permissionsCache; |
| int permissionsCacheSize; |
| |
| /* |
| ** Lockable object for synchronizing transition from caching to non-caching |
| */ |
| ShExLockable cacheCoordinator; |
| public LockFactory lockFactory; |
| |
| volatile int cacheMode = DataDictionary.COMPILE_ONLY_MODE; |
| |
| /* Number of DDL users */ |
| volatile int ddlUsers; |
| /* Number of readers that start in DDL_MODE */ |
| volatile int readersInDDLMode; |
| |
| private HashMap<String,HashMap<String,String>> sequenceIDs; |
| |
| /** |
| True if the database is read only and requires |
| some form of upgrade, that makes the stored prepared |
| statements invalid. |
| With this case the engine is running at a different |
| version to the underlying stored database. This |
| can happen in 5.1 if the database is read only |
| and a different point release (later than 5.1.25?) |
| to the one that created it, has been booted. (Beetle 5170). |
| |
| <P> |
| In 5.2 and newer this will be the case if the engine |
| booting the database is newer than the engine |
| that created it. |
| |
| */ |
| private boolean readOnlyUpgrade; |
| |
| /** |
| * Tells if the automatic index statistics refresher has been disabled. |
| * <p> |
| * The refresher can be disabled explicitly by the user by setting a |
| * property (system wide or database property), or if the daemon encounters |
| * an exception it doesn't know how to recover from. |
| */ |
| private boolean indexStatsUpdateDisabled; |
| private boolean indexStatsUpdateLogging; |
| private String indexStatsUpdateTracing; |
| |
| //systemSQLNameNumber is the number used as the last digit during the previous call to getSystemSQLName. |
| //If it is 9 for a given calendarForLastSystemSQLName, we will restart the counter to 0 |
| //and increment the calendarForLastSystemSQLName by 10ms. |
| private int systemSQLNameNumber; |
| private GregorianCalendar calendarForLastSystemSQLName = new GregorianCalendar(); |
| private long timeForLastSystemSQLName; |
| |
| /** |
| * List of procedures in SYSCS_UTIL schema with PUBLIC access |
| */ |
| private static final String[] sysUtilProceduresWithPublicAccess = { |
| "SYSCS_SET_RUNTIMESTATISTICS", |
| "SYSCS_SET_STATISTICS_TIMING", |
| "SYSCS_INPLACE_COMPRESS_TABLE", |
| "SYSCS_COMPRESS_TABLE", |
| "SYSCS_UPDATE_STATISTICS", |
| "SYSCS_MODIFY_PASSWORD", |
| "SYSCS_DROP_STATISTICS", |
| }; |
| |
| /** |
| * List of functions in SYSCS_UTIL schema with PUBLIC access |
| */ |
| private static final String[] sysUtilFunctionsWithPublicAccess = { |
| "SYSCS_GET_RUNTIMESTATISTICS", |
| "SYSCS_PEEK_AT_SEQUENCE", |
| "SYSCS_PEEK_AT_IDENTITY", |
| "SYSCS_GET_DATABASE_NAME", |
| }; |
| |
| /** |
| * Collation Type for SYSTEM schemas. In Derby 10.3, this will always |
| * be UCS_BASIC |
| */ |
| private int collationTypeOfSystemSchemas; |
| |
| /** |
| * Collation Type for user schemas. In Derby 10.3, this is either |
| * UCS_BASIC or TERRITORY_BASED. The exact value is decided by what has |
| * user asked for through JDBC url optional attribute COLLATION. If that |
| * atrribute is set to UCS_BASIC, the collation type for user schemas |
| * will be UCS_BASIC. If that attribute is set to TERRITORY_BASED, the |
| * collation type for user schemas will be TERRITORY_BASED. If the user |
| * has not provide COLLATION attribute value in the JDBC url at database |
| * create time, then collation type of user schemas will default to |
| * UCS_BASIC. Pre-10.3 databases after upgrade to Derby 10.3 will also |
| * use UCS_BASIC for collation type of user schemas. |
| */ |
| private int collationTypeOfUserSchemas; |
| |
| /* |
| ** Constructor |
| */ |
| |
| public DataDictionaryImpl() { |
| |
| } |
| |
| |
| /** |
| * This is the data dictionary implementation for |
| * the standard database engine. |
| |
| @return true if this service requested is for a database engine. |
| */ |
| |
| public boolean canSupport(Properties startParams) |
| { |
| return Monitor.isDesiredType(startParams, EngineType.STANDALONE_DB); |
| } |
| |
| /** |
| * Start-up method for this instance of the data dictionary. |
| * |
| * @param startParams The start-up parameters |
| * |
| * @exception StandardException Thrown if the module fails to start |
| */ |
| public void boot(boolean create, Properties startParams) |
| throws StandardException |
| { |
| softwareVersion = new DD_Version(this, DataDictionary.DD_VERSION_DERBY_10_13); |
| |
| startupParameters = startParams; |
| |
| uuidFactory = getMonitor().getUUIDFactory(); |
| |
| engineType = Monitor.getEngineType( startParams ); |
| |
| //Set the collation type of system schemas before we start loading |
| //built-in schemas's SchemaDescriptor(s). This is because |
| //SchemaDescriptor will look to DataDictionary to get the correct |
| //collation type for themselves. We can't load SD for SESSION schema |
| //just yet because we do not know the collation type for user schemas |
| //yet. We will know the right collation for user schema little later |
| //in this boot method. |
| collationTypeOfSystemSchemas = StringDataValue.COLLATION_TYPE_UCS_BASIC; |
| getBuiltinSystemSchemas(); |
| |
| // REMIND: actually, we're supposed to get the DataValueFactory |
| // out of the connection context...this is a bit of a shortcut. |
| // We get the DataValueFactory early in order to help bootstrap the system catalogs. |
| LanguageConnectionFactory langConnFactory = (LanguageConnectionFactory) bootServiceModule( |
| create, this, LanguageConnectionFactory.MODULE, startParams); |
| |
| dvf = langConnFactory.getDataValueFactory(); |
| exFactory = (ExecutionFactory) bootServiceModule( |
| create, this, |
| ExecutionFactory.MODULE, |
| startParams); |
| |
| // initailze the arrays of core and noncore tables |
| initializeCatalogInfo(); |
| |
| // indicate that we are in the process of booting |
| booting = true; |
| |
| // set only if child class hasn't overriden this already |
| if ( dataDescriptorGenerator == null ) |
| { dataDescriptorGenerator = new DataDescriptorGenerator( this ); } |
| |
| if (!create) { |
| |
| |
| // SYSTABLES |
| |
| coreInfo[SYSTABLES_CORE_NUM].setHeapConglomerate( |
| getBootParameter(startParams, CFG_SYSTABLES_ID, true)); |
| |
| coreInfo[SYSTABLES_CORE_NUM].setIndexConglomerate(SYSTABLESRowFactory.SYSTABLES_INDEX1_ID, |
| getBootParameter(startParams, CFG_SYSTABLES_INDEX1_ID, true)); |
| |
| |
| coreInfo[SYSTABLES_CORE_NUM].setIndexConglomerate( |
| SYSTABLESRowFactory.SYSTABLES_INDEX2_ID, |
| getBootParameter(startParams, CFG_SYSTABLES_INDEX2_ID, true)); |
| |
| // SYSCOLUMNS |
| |
| coreInfo[SYSCOLUMNS_CORE_NUM].setHeapConglomerate( |
| getBootParameter(startParams, CFG_SYSCOLUMNS_ID, true)); |
| |
| |
| coreInfo[SYSCOLUMNS_CORE_NUM].setIndexConglomerate( |
| SYSCOLUMNSRowFactory.SYSCOLUMNS_INDEX1_ID, |
| getBootParameter(startParams, CFG_SYSCOLUMNS_INDEX1_ID, true)); |
| // 2nd syscolumns index added in Xena, hence may not be there |
| coreInfo[SYSCOLUMNS_CORE_NUM].setIndexConglomerate( |
| SYSCOLUMNSRowFactory.SYSCOLUMNS_INDEX2_ID, |
| getBootParameter(startParams, CFG_SYSCOLUMNS_INDEX2_ID, false)); |
| |
| // SYSCONGLOMERATES |
| |
| coreInfo[SYSCONGLOMERATES_CORE_NUM].setHeapConglomerate( |
| getBootParameter(startParams, CFG_SYSCONGLOMERATES_ID, true)); |
| |
| |
| coreInfo[SYSCONGLOMERATES_CORE_NUM].setIndexConglomerate( |
| SYSCONGLOMERATESRowFactory.SYSCONGLOMERATES_INDEX1_ID, |
| getBootParameter(startParams, CFG_SYSCONGLOMERATES_INDEX1_ID, true)); |
| |
| |
| coreInfo[SYSCONGLOMERATES_CORE_NUM].setIndexConglomerate( |
| SYSCONGLOMERATESRowFactory.SYSCONGLOMERATES_INDEX2_ID, |
| getBootParameter(startParams, CFG_SYSCONGLOMERATES_INDEX2_ID, true)); |
| |
| coreInfo[SYSCONGLOMERATES_CORE_NUM].setIndexConglomerate( |
| SYSCONGLOMERATESRowFactory.SYSCONGLOMERATES_INDEX3_ID, |
| getBootParameter(startParams, CFG_SYSCONGLOMERATES_INDEX3_ID, true)); |
| |
| |
| // SYSSCHEMAS |
| coreInfo[SYSSCHEMAS_CORE_NUM].setHeapConglomerate( |
| getBootParameter(startParams, CFG_SYSSCHEMAS_ID, true)); |
| |
| |
| coreInfo[SYSSCHEMAS_CORE_NUM].setIndexConglomerate( |
| SYSSCHEMASRowFactory.SYSSCHEMAS_INDEX1_ID, |
| getBootParameter(startParams, CFG_SYSSCHEMAS_INDEX1_ID, true)); |
| |
| coreInfo[SYSSCHEMAS_CORE_NUM].setIndexConglomerate( |
| SYSSCHEMASRowFactory.SYSSCHEMAS_INDEX2_ID, |
| getBootParameter(startParams, CFG_SYSSCHEMAS_INDEX2_ID, true)); |
| |
| } |
| |
| |
| |
| String value = startParams.getProperty(Property.LANG_TD_CACHE_SIZE); |
| tdCacheSize = PropertyUtil.intPropertyValue(Property.LANG_TD_CACHE_SIZE, value, |
| 0, Integer.MAX_VALUE, Property.LANG_TD_CACHE_SIZE_DEFAULT); |
| |
| |
| value = startParams.getProperty(Property.LANG_SPS_CACHE_SIZE); |
| stmtCacheSize = PropertyUtil.intPropertyValue(Property.LANG_SPS_CACHE_SIZE, value, |
| 0, Integer.MAX_VALUE, Property.LANG_SPS_CACHE_SIZE_DEFAULT); |
| |
| value = startParams.getProperty(Property.LANG_SEQGEN_CACHE_SIZE); |
| seqgenCacheSize = PropertyUtil.intPropertyValue(Property.LANG_SEQGEN_CACHE_SIZE, value, |
| 0, Integer.MAX_VALUE, Property.LANG_SEQGEN_CACHE_SIZE_DEFAULT); |
| |
| value = startParams.getProperty(Property.LANG_PERMISSIONS_CACHE_SIZE); |
| permissionsCacheSize = PropertyUtil.intPropertyValue(Property.LANG_PERMISSIONS_CACHE_SIZE, value, |
| 0, Integer.MAX_VALUE, Property.LANG_PERMISSIONS_CACHE_SIZE_DEFAULT); |
| |
| // See if automatic index statistics update is disabled through a |
| // system wide property. May be overridden by a database specific |
| // property later on. |
| // The default is that automatic index statistics update is enabled. |
| indexStatsUpdateDisabled = !PropertyUtil.getSystemBoolean( |
| Property.STORAGE_AUTO_INDEX_STATS, true); |
| |
| // See if we should enable logging of index stats activities. |
| indexStatsUpdateLogging = PropertyUtil.getSystemBoolean( |
| Property.STORAGE_AUTO_INDEX_STATS_LOGGING); |
| |
| // See if we should enable tracing of index stats activities. |
| indexStatsUpdateTracing = PropertyUtil.getSystemProperty( |
| Property.STORAGE_AUTO_INDEX_STATS_TRACING, "off"); |
| |
| /* |
| * data dictionary contexts are only associated with connections. |
| * we have to look for the basic data dictionary, as there is |
| * no connection, and thus no context stack yet. |
| */ |
| |
| /* |
| * Get the table descriptor cache. |
| */ |
| CacheFactory cf = |
| (CacheFactory) startSystemModule(org.apache.derby.iapi.reference.Module.CacheFactory); |
| OIDTdCache = |
| cf.newCacheManager(this, |
| "TableDescriptorOIDCache", |
| tdCacheSize, |
| tdCacheSize); |
| nameTdCache = |
| cf.newCacheManager(this, |
| "TableDescriptorNameCache", |
| tdCacheSize, |
| tdCacheSize); |
| |
| if (stmtCacheSize > 0) |
| { |
| spsNameCache = |
| cf.newCacheManager(this, |
| "SPSNameDescriptorCache", |
| stmtCacheSize, |
| stmtCacheSize); |
| spsIdHash = new Hashtable<UUID,SPSDescriptor>(stmtCacheSize); |
| // spsTextHash = new Hashtable(stmtCacheSize); |
| } |
| |
| sequenceGeneratorCache = cf.newCacheManager |
| ( this, "SequenceGeneratorCache", seqgenCacheSize, seqgenCacheSize ); |
| |
| sequenceIDs = new HashMap<String,HashMap<String,String>>(); |
| |
| /* Get the object to coordinate cache transitions */ |
| cacheCoordinator = new ShExLockable(); |
| |
| /* Get AccessFactory in order to transaction stuff */ |
| af = (AccessFactory) findServiceModule(this, AccessFactory.MODULE); |
| |
| /* Get the lock factory */ |
| lockFactory = af.getLockFactory(); |
| |
| /* |
| * now we need to setup a context stack for the database creation work. |
| * We assume the System boot process has created a context |
| * manager already, but not that contexts we need are there. |
| */ |
| ContextService csf = getContextService(); |
| |
| ContextManager cm = csf.getCurrentContextManager(); |
| if (SanityManager.DEBUG) |
| SanityManager.ASSERT((cm != null), "Failed to get current ContextManager"); |
| |
| // RESOLVE other non-StandardException errors. |
| bootingTC = null; |
| try |
| { |
| // Get a transaction controller. This has the side effect of |
| // creating a transaction context if there isn't one already. |
| bootingTC = af.getTransaction(cm); |
| |
| /* |
| We need an execution context so that we can generate rows |
| REMIND: maybe only for create case? |
| */ |
| exFactory.newExecutionContext(cm); |
| |
| DataDescriptorGenerator ddg = getDataDescriptorGenerator(); |
| |
| //We should set the user schema collation type here now because |
| //later on, we are going to create user schema APP. By the time any |
| //user schema gets created, we should have the correct collation |
| //type set for such schemas to use. For this reason, don't remove |
| //the following if else statement and don't move it later in this |
| //method. |
| String userDefinedCollation; |
| if (create) { |
| //Get the collation attribute from the JDBC url. It can only |
| //have one of 2 possible values - UCS_BASIC or TERRITORY_BASED |
| //This attribute can only be specified at database create time. |
| //The attribute value has already been verified in DVF.boot and |
| //hence we can be assured that the attribute value if provided |
| //is either UCS_BASIC or TERRITORY_BASED. If none provided, |
| //then we will take it to be the default which is UCS_BASIC. |
| userDefinedCollation = startParams.getProperty( |
| Attribute.COLLATION, Property.UCS_BASIC_COLLATION); |
| bootingTC.setProperty(Property.COLLATION,userDefinedCollation,true); |
| } else { |
| userDefinedCollation = startParams.getProperty( |
| Property.COLLATION, Property.UCS_BASIC_COLLATION); |
| } |
| |
| //Initialize the collation type of user schemas by looking at |
| //collation property/attribute. |
| collationTypeOfUserSchemas = DataTypeDescriptor.getCollationType(userDefinedCollation); |
| if (SanityManager.DEBUG) |
| SanityManager.ASSERT((collationTypeOfUserSchemas != -1), "Invalid collation type: "+userDefinedCollation); |
| |
| //Now is also a good time to create schema descriptor for global |
| //temporary tables. Since this is a user schema, it should use the |
| //collation type associated with user schemas. Since we just |
| //finished setting up the collation type of user schema, it is |
| //safe to create user SchemaDescriptor(s) now. |
| declaredGlobalTemporaryTablesSchemaDesc = |
| newDeclaredGlobalTemporaryTablesSchemaDesc( |
| SchemaDescriptor.STD_DECLARED_GLOBAL_TEMPORARY_TABLES_SCHEMA_NAME); |
| |
| boolean nativeAuthenticationEnabled = PropertyUtil.nativeAuthenticationEnabled( startParams ); |
| |
| if (create) { |
| String userName = IdUtil.getUserNameFromURLProps(startParams); |
| authorizationDatabaseOwner = IdUtil.getUserAuthorizationId(userName); |
| |
| HashSet<String> newlyCreatedRoutines = new HashSet<String>(); |
| |
| // create any required tables. |
| createDictionaryTables(startParams, bootingTC, ddg); |
| //create procedures for network server metadata |
| create_SYSIBM_procedures(bootingTC, newlyCreatedRoutines ); |
| //create metadata sps statement required for network server |
| createSystemSps(bootingTC); |
| // create the SYSCS_UTIL system procedures) |
| create_SYSCS_procedures(bootingTC, newlyCreatedRoutines ); |
| // now grant execute permission on some of these routines |
| grantPublicAccessToSystemRoutines( newlyCreatedRoutines, bootingTC, authorizationDatabaseOwner ); |
| // log the current dictionary version |
| dictionaryVersion = softwareVersion; |
| |
| /* Set properties for current and create time |
| * DataDictionary versions. |
| */ |
| bootingTC.setProperty( |
| DataDictionary.CORE_DATA_DICTIONARY_VERSION, |
| dictionaryVersion, true); |
| |
| bootingTC.setProperty( |
| DataDictionary.CREATE_DATA_DICTIONARY_VERSION, |
| dictionaryVersion, true); |
| |
| // |
| // If SqlAuthorization is set as a system property during database |
| // creation, set it as a database property also, so that it gets persisted. |
| // |
| // We also turn on SqlAuthorization if NATIVE authentication has been specified. |
| // |
| if ( PropertyUtil.getSystemBoolean(Property.SQL_AUTHORIZATION_PROPERTY) ) |
| { |
| bootingTC.setProperty(Property.SQL_AUTHORIZATION_PROPERTY,"true",true); |
| } |
| if ( PropertyUtil.getSystemBoolean(Property.SQL_AUTHORIZATION_PROPERTY) || nativeAuthenticationEnabled ) |
| { |
| usesSqlAuthorization=true; |
| } |
| |
| // Set default hash algorithm used to protect passwords stored |
| // in the database for BUILTIN and NATIVE authentication. |
| bootingTC.setProperty( |
| Property.AUTHENTICATION_BUILTIN_ALGORITHM, |
| findDefaultBuiltinAlgorithm(), |
| false); |
| } else { |
| // Get the ids for non-core tables |
| loadDictionaryTables(bootingTC, startParams); |
| |
| // See if index stats update is disabled by a database prop. |
| String dbIndexStatsUpdateAuto = |
| PropertyUtil.getDatabaseProperty(bootingTC, |
| Property.STORAGE_AUTO_INDEX_STATS); |
| if (dbIndexStatsUpdateAuto != null) { |
| indexStatsUpdateDisabled = !Boolean.valueOf( |
| dbIndexStatsUpdateAuto).booleanValue(); |
| } |
| String dbEnableIndexStatsLogging = |
| PropertyUtil.getDatabaseProperty(bootingTC, |
| Property.STORAGE_AUTO_INDEX_STATS_LOGGING); |
| if (dbEnableIndexStatsLogging != null) { |
| indexStatsUpdateLogging = Boolean.valueOf( |
| dbEnableIndexStatsLogging).booleanValue(); |
| } |
| String dbEnableIndexStatsTracing = |
| PropertyUtil.getDatabaseProperty(bootingTC, |
| Property.STORAGE_AUTO_INDEX_STATS_TRACING); |
| if (dbEnableIndexStatsTracing != null) { |
| if (!(dbEnableIndexStatsTracing.equalsIgnoreCase("off") || |
| dbEnableIndexStatsTracing.equalsIgnoreCase("log") || |
| dbEnableIndexStatsTracing.equalsIgnoreCase("stdout") || |
| dbEnableIndexStatsTracing.equalsIgnoreCase("both"))) { |
| indexStatsUpdateTracing = "off"; |
| } else { |
| indexStatsUpdateTracing = dbEnableIndexStatsTracing; |
| } |
| } |
| |
| String sqlAuth = PropertyUtil.getDatabaseProperty(bootingTC, |
| Property.SQL_AUTHORIZATION_PROPERTY); |
| |
| // Feature compatibility check. |
| if (Boolean.valueOf |
| (startParams.getProperty( |
| Attribute.SOFT_UPGRADE_NO_FEATURE_CHECK)) |
| .booleanValue()) { |
| // Do not perform check if this boot is the first |
| // phase (soft upgrade boot) of a hard upgrade, |
| // which happens in two phases beginning with |
| // DERBY-2264. In this case, we need to always be |
| // able to boot to authenticate, notwithstanding |
| // any feature properties set |
| // (e.g. derby.database.sqlAuthorization) which |
| // may not yet be supported until that hard |
| // upgrade has happened, normally causing an error |
| // below. |
| // |
| // Feature sqlAuthorization is a special case: |
| // Since database ownership checking only happens |
| // when sqlAuthorization is true, we can't afford |
| // to *not* use it for upgrades from 10.2 or |
| // later, lest we lose the database owner check. |
| // For upgrades from 10.1 and earlier there is no |
| // database owner check at a hard upgrade. |
| if (dictionaryVersion.majorVersionNumber >= |
| DataDictionary.DD_VERSION_DERBY_10_2) { |
| usesSqlAuthorization = Boolean.valueOf(sqlAuth).booleanValue() || nativeAuthenticationEnabled; |
| } |
| } else { |
| if (Boolean.valueOf(sqlAuth).booleanValue() || nativeAuthenticationEnabled) { |
| // SQL authorization requires 10.2 or higher database |
| checkVersion(DataDictionary.DD_VERSION_DERBY_10_2, |
| "sqlAuthorization"); |
| usesSqlAuthorization=true; |
| } |
| } |
| } |
| |
| if (SanityManager.DEBUG) |
| SanityManager.ASSERT((authorizationDatabaseOwner != null), "Failed to get Database Owner authorization"); |
| |
| /* Commit & destroy the create database */ |
| bootingTC.commit(); |
| cm.getContext(ExecutionContext.CONTEXT_ID).popMe(); // done with ctx |
| } finally { |
| |
| if (bootingTC != null) { |
| bootingTC.destroy(); // gets rid of the transaction context |
| bootingTC = null; |
| } |
| } |
| |
| setDependencyManager(); |
| booting = false; |
| } |
| |
| /** |
| * Find the default message digest algorithm to use for BUILTIN |
| * authentication on this database. |
| * |
| * @return the name of the algorithm to use as the default |
| */ |
| private String findDefaultBuiltinAlgorithm() { |
| try { |
| // First check for the preferred default, and return it if present |
| MessageDigest.getInstance( |
| Property.AUTHENTICATION_BUILTIN_ALGORITHM_DEFAULT); |
| return Property.AUTHENTICATION_BUILTIN_ALGORITHM_DEFAULT; |
| } catch (NoSuchAlgorithmException nsae) { |
| // Couldn't find the preferred algorithm, so use the fallback |
| return Property.AUTHENTICATION_BUILTIN_ALGORITHM_FALLBACK; |
| } |
| } |
| |
| private CacheManager getPermissionsCache() throws StandardException |
| { |
| if( permissionsCache == null) |
| { |
| CacheFactory cf = |
| (CacheFactory) startSystemModule(org.apache.derby.iapi.reference.Module.CacheFactory); |
| LanguageConnectionContext lcc = getLCC(); |
| TransactionController tc = lcc.getTransactionExecute(); |
| permissionsCacheSize = PropertyUtil.getServiceInt( tc, |
| Property.LANG_PERMISSIONS_CACHE_SIZE, |
| 40, /* min value */ |
| Integer.MAX_VALUE, |
| permissionsCacheSize /* value from boot time. */); |
| permissionsCache = cf.newCacheManager( this, |
| "PermissionsCache", |
| permissionsCacheSize, |
| permissionsCacheSize); |
| } |
| return permissionsCache; |
| } // end of getPermissionsCache |
| |
| /** |
| * sets the dependencymanager associated with this dd. subclasses can |
| * override this to install their own funky dependency manager. |
| */ |
| protected void setDependencyManager() |
| { |
| dmgr = new BasicDependencyManager(this); |
| } |
| |
| /** |
| * returns the dependencymanager associated with this datadictionary. |
| * @see DataDictionary#getDependencyManager |
| */ |
| public DependencyManager getDependencyManager() |
| { |
| return dmgr; |
| } |
| |
| /** |
| * Stop this module. In this case, nothing needs to be done. |
| */ |
| |
| public void stop() { |
| // Shut down the index statistics refresher, mostly to make it print |
| // processing stats |
| // Not sure if the reference can be null here, but it may be possible |
| // if multiple threads are competing to boot and shut down the db. |
| if (indexRefresher != null) { |
| indexRefresher.stop(); |
| } |
| } |
| |
| /* |
| ** CacheableFactory interface |
| */ |
| public Cacheable newCacheable(CacheManager cm) { |
| |
| if ( cm == OIDTdCache ) { return new OIDTDCacheable( this ); } |
| else if ( cm == nameTdCache ) { return new NameTDCacheable( this ); } |
| else if ( cm == permissionsCache ) { return new PermissionsCacheable( this ); } |
| else if ( cm == sequenceGeneratorCache ) { return new SequenceUpdater.SyssequenceUpdater( this ); } |
| else { return new SPSNameCacheable( this ); } |
| } |
| |
| /* |
| ** Methods related to ModuleControl |
| */ |
| |
| /** |
| * @see org.apache.derby.iapi.sql.dictionary.DataDictionary#startReading |
| * |
| * @exception StandardException Thrown on error |
| */ |
| public int startReading(LanguageConnectionContext lcc) |
| throws StandardException |
| { |
| int bindCount = lcc.incrementBindCount(); |
| int localCacheMode; |
| |
| boolean needRetry = false; |
| |
| do |
| { |
| if (needRetry) |
| { |
| // could not get lock while holding the synchronized(this), |
| // so now wait until we can get the lock. Once we get the |
| // lock it is automatically released, hopefully when we |
| // go the the synchronized(this) block we will be able to |
| // get the lock, while holding the synchronized(this) |
| // monitor now. |
| |
| try |
| { |
| lockFactory.zeroDurationlockObject( |
| lcc.getTransactionExecute().getLockSpace(), |
| cacheCoordinator, |
| ShExQual.SH, |
| C_LockFactory.WAIT_FOREVER); |
| } |
| catch (StandardException e) |
| { |
| // DEADLOCK, timeout will not happen with WAIT_FOREVER |
| |
| lcc.decrementBindCount(); |
| throw e; |
| } |
| needRetry = false; |
| } |
| |
| // "this" is used to synchronize between startReading,doneReading, |
| // and startWriting. |
| |
| synchronized(this) |
| { |
| localCacheMode = getCacheMode(); |
| |
| /* |
| ** Keep track of how deeply nested this bind() operation is. |
| ** It's possible for nested binding to happen if the user |
| ** prepares SQL statements from within a static initializer |
| ** of a class, and calls a method on that class (or uses a |
| ** field in the class). |
| ** |
| ** If nested binding is happening, we only want to lock the |
| ** DataDictionary on the outermost nesting level. |
| */ |
| if (bindCount == 1) |
| { |
| if (localCacheMode == DataDictionary.COMPILE_ONLY_MODE) |
| { |
| if (SanityManager.DEBUG) |
| { |
| SanityManager.ASSERT(ddlUsers == 0, |
| "Cache mode is COMPILE_ONLY and there are DDL users."); |
| } |
| |
| /* |
| ** If we deadlock while waiting for a lock, |
| ** then be sure to restore things as they |
| ** were. |
| */ |
| boolean lockGranted = false; |
| |
| try |
| { |
| // When the C_LockFactory.NO_WAIT is used this |
| // routine will not throw timeout or deadlock |
| // exceptions. The boolean returned will indicate |
| // if the lock was granted or not. If it would |
| // have had to wait, it just returns immediately |
| // and returns false. |
| // |
| // See if we can get this lock granted without |
| // waiting (while holding the dataDictionary |
| // synchronization). |
| |
| CompatibilitySpace space = |
| lcc.getTransactionExecute().getLockSpace(); |
| |
| lockGranted = |
| lockFactory.lockObject( |
| space, space.getOwner(), |
| cacheCoordinator, |
| ShExQual.SH, |
| C_LockFactory.NO_WAIT); |
| } |
| catch (StandardException e) |
| { |
| // neither TIMEOUT or DEADLOCK can happen with |
| // NO_WAIT flag. This must be some other exception. |
| |
| lcc.decrementBindCount(); |
| throw e; |
| } |
| |
| if (!lockGranted) |
| needRetry = true; |
| } |
| else |
| { |
| readersInDDLMode++; |
| } |
| } |
| } // end of sync block |
| |
| } while (needRetry); |
| |
| return localCacheMode; |
| } |
| |
| /* @see org.apache.derby.iapi.sql.dictionary.DataDictionary#doneReading */ |
| public void doneReading(int mode, LanguageConnectionContext lcc) |
| throws StandardException |
| { |
| int bindCount = lcc.decrementBindCount(); |
| |
| /* This is an arbitrary choice of object to synchronize these methods */ |
| synchronized(this) |
| { |
| /* |
| ** Keep track of how deeply nested this bind() operation is. |
| ** It's possible for nested binding to happen if the user |
| ** prepares SQL statements from within a static initializer |
| ** of a class, and calls a method on that class (or uses a |
| ** field in the class). |
| ** |
| ** If nested binding is happening, we only want to unlock the |
| ** DataDictionary on the outermost nesting level. |
| */ |
| if (bindCount == 0) |
| { |
| if (mode == DataDictionary.COMPILE_ONLY_MODE) |
| { |
| /* |
| ** Release the share lock that was acquired by the reader when |
| ** it called startReading(). |
| ** Beetle 4418, during bind, we may even execute something (eg., in a vti |
| ** constructor) and if a severe error occured, the transaction is rolled |
| ** back and lock released already, so don't try to unlock if statement context |
| ** is cleared. |
| */ |
| if ((lcc.getStatementContext() != null) && lcc.getStatementContext().inUse()) |
| { |
| CompatibilitySpace space = |
| lcc.getTransactionExecute().getLockSpace(); |
| int unlockCount = |
| lockFactory.unlock( |
| space, space.getOwner(), |
| cacheCoordinator, ShExQual.SH); |
| if (SanityManager.DEBUG) |
| { |
| if (unlockCount != 1) |
| { |
| SanityManager.THROWASSERT("unlockCount not "+ |
| "1 as expected, it is "+unlockCount); |
| } |
| } |
| } |
| } |
| else |
| { |
| readersInDDLMode--; |
| |
| /* |
| ** We can only switch back to cached (COMPILE_ONLY) |
| ** mode if there aren't any readers that started in |
| ** DDL_MODE. Otherwise we could get a reader |
| ** in DDL_MODE that reads a cached object that |
| ** was brought in by a reader in COMPILE_ONLY_MODE. |
| ** If 2nd reader finished and releases it lock |
| ** on the cache there is nothing to pevent another |
| ** writer from coming along an deleting the cached |
| ** object. |
| */ |
| if (ddlUsers == 0 && readersInDDLMode == 0) |
| { |
| // Until we implement ALTER SEQUENCE, there should be no need |
| // to clear the sequence cache. Always clearing the sequence cache |
| // here gives rise to heisenbug DERBY-6595. |
| clearCaches( false ); |
| setCacheMode(DataDictionary.COMPILE_ONLY_MODE); |
| } |
| |
| if (SanityManager.DEBUG) |
| { |
| SanityManager.ASSERT(readersInDDLMode >= 0, |
| "readersInDDLMode is invalid -- should never be < 0"); |
| } |
| } |
| } |
| } |
| } |
| |
| /* |
| * @see org.apache.derby.iapi.sql.dictionary.DataDictionary#startWriting |
| * |
| * @exception StandardException Thrown on error |
| */ |
| public void startWriting(LanguageConnectionContext lcc) |
| throws StandardException |
| { |
| |
| boolean blocked = true; |
| |
| /* |
| ** Don't allow DDL if we're binding a SQL statement. |
| */ |
| if (lcc.getBindCount() != 0) |
| { |
| throw StandardException.newException(SQLState.LANG_DDL_IN_BIND); |
| } |
| |
| /* |
| ** Check whether we've already done a DDL statement in this |
| ** transaction. If so, we don't want to re-enter DDL mode, or |
| ** bump the DDL user count. |
| */ |
| if ( ! lcc.dataDictionaryInWriteMode()) |
| { |
| for (int i = 0; blocked; i++) |
| { |
| /* |
| ** If we already tried 5 times and failed, do |
| ** an unbounded wait for the lock w/o |
| ** synchronization. Immediately unlock and |
| ** sleep a random amount of time and start |
| ** the whole process over again. |
| */ |
| if (i > 4 && |
| getCacheMode() == DataDictionary.COMPILE_ONLY_MODE) |
| { |
| // Wait until the settable timeout value for the lock, |
| // and once granted, immediately release the lock. If |
| // this wait time's out then a TIMEOUT error is sent |
| // up the stack. |
| |
| lockFactory.zeroDurationlockObject( |
| lcc.getTransactionExecute().getLockSpace(), |
| cacheCoordinator, |
| ShExQual.EX, |
| C_LockFactory.TIMED_WAIT); |
| |
| |
| i = 1; |
| } |
| |
| if (i > 0) |
| { |
| try |
| { |
| Thread.sleep( |
| (long)((java.lang.Math.random() * 1131) % 20)); |
| } |
| catch (InterruptedException ie) |
| { |
| throw StandardException.interrupt(ie); |
| } |
| } |
| |
| synchronized(this) |
| { |
| if (getCacheMode() == DataDictionary.COMPILE_ONLY_MODE) |
| { |
| // When the C_LockFactory.NO_WAIT is used this routine |
| // will not throw timeout or deadlock exceptions. The |
| // boolean returned will indicate if the lock was |
| // granted or not. If it would have had to wait, it |
| // just returns immediately and returns false. |
| // |
| |
| // See if we can get this lock granted without waiting |
| // (while holding the dataDictionary synchronization). |
| |
| boolean lockGranted = |
| lockFactory.zeroDurationlockObject( |
| lcc.getTransactionExecute().getLockSpace(), |
| cacheCoordinator, |
| ShExQual.EX, |
| C_LockFactory.NO_WAIT); |
| |
| if (!lockGranted) |
| continue; |
| |
| /* Switch the caching mode to DDL */ |
| setCacheMode(DataDictionary.DDL_MODE); |
| |
| // Until we implement ALTER SEQUENCE, there should be no need |
| // to clear the sequence cache. Always clearing the sequence cache |
| // here gives rise to DERBY-6137. |
| clearCaches( false ); |
| } |
| |
| /* Keep track of the number of DDL users */ |
| ddlUsers++; |
| } // end synchronized |
| |
| /* |
| ** Tell the connection the DD is in DDL mode, so it can take |
| ** it out of DDL mode when the transaction finishes. |
| */ |
| lcc.setDataDictionaryWriteMode(); |
| blocked = false; |
| } |
| |
| } |
| else if (SanityManager.DEBUG) |
| { |
| SanityManager.ASSERT(getCacheMode() == DataDictionary.DDL_MODE, |
| "lcc.getDictionaryInWriteMode() but DataDictionary is COMPILE_MODE"); |
| } |
| } |
| |
| |
| /* @see org.apache.derby.iapi.sql.dictionary.DataDictionary#transactionFinished */ |
| public void transactionFinished() throws StandardException |
| { |
| /* This is an arbitrary choice of object to synchronize these methods */ |
| synchronized(this) |
| { |
| if (SanityManager.DEBUG) |
| { |
| SanityManager.ASSERT(ddlUsers > 0, |
| "Number of DDL Users is <= 0 when finishing a transaction"); |
| |
| SanityManager.ASSERT(getCacheMode() == DataDictionary.DDL_MODE, |
| "transactionFinished called when not in DDL_MODE"); |
| } |
| |
| ddlUsers--; |
| |
| /* |
| ** We can only switch back to cached (COMPILE_ONLY) |
| ** mode if there aren't any readers that started in |
| ** DDL_MODE. Otherwise we could get a reader |
| ** in DDL_MODE that reads a cached object that |
| ** was brought in by a reader in COMPILE_ONLY_MODE. |
| ** If 2nd reader finished and releases it lock |
| ** on the cache there is nothing to pevent another |
| ** writer from coming along an deleting the cached |
| ** object. |
| */ |
| if (ddlUsers == 0 && readersInDDLMode == 0) |
| { |
| clearCaches(); |
| setCacheMode(DataDictionary.COMPILE_ONLY_MODE); |
| } |
| |
| } |
| } |
| |
| public int getCacheMode() |
| { |
| return cacheMode; |
| } |
| |
| private void setCacheMode(int newMode) |
| { |
| cacheMode = newMode; |
| } |
| |
| /** |
| * Get a DataDescriptorGenerator, through which we can create |
| * objects to be stored in the DataDictionary. |
| * |
| * @return A DataDescriptorGenerator |
| */ |
| |
| public DataDescriptorGenerator getDataDescriptorGenerator() |
| { |
| return dataDescriptorGenerator; |
| } |
| |
| /** |
| * Get authorizationID of Database Owner |
| * |
| * @return authorizationID |
| */ |
| public String getAuthorizationDatabaseOwner() |
| { |
| return authorizationDatabaseOwner; |
| } |
| |
| /** |
| * @see DataDictionary#usesSqlAuthorization |
| */ |
| public boolean usesSqlAuthorization() |
| { |
| return usesSqlAuthorization; |
| } |
| |
| /** @see DataDictionary#getCollationTypeOfSystemSchemas() */ |
| public int getCollationTypeOfSystemSchemas() |
| { |
| return collationTypeOfSystemSchemas; |
| } |
| |
| /** @see DataDictionary#getCollationTypeOfUserSchemas() */ |
| public int getCollationTypeOfUserSchemas() |
| { |
| return collationTypeOfUserSchemas; |
| } |
| |
| /** |
| * Get a DataValueFactory, through which we can create |
| * data value objects. |
| * |
| * @return A DataValueFactory |
| */ |
| public DataValueFactory getDataValueFactory() |
| { |
| return dvf; |
| } |
| |
| /** |
| * Get ExecutionFactory associated with this database. |
| * |
| * @return The ExecutionFactory |
| */ |
| public ExecutionFactory getExecutionFactory() |
| { |
| return exFactory; |
| } |
| |
| |
| /** |
| * Set up the builtin schema descriptors for system schemas. |
| */ |
| private void getBuiltinSystemSchemas() |
| { |
| if (systemSchemaDesc != null) |
| return; |
| |
| systemSchemaDesc = |
| newSystemSchemaDesc(SchemaDescriptor.STD_SYSTEM_SCHEMA_NAME, |
| SchemaDescriptor.SYSTEM_SCHEMA_UUID); |
| sysIBMSchemaDesc = |
| newSystemSchemaDesc(SchemaDescriptor.IBM_SYSTEM_SCHEMA_NAME, |
| SchemaDescriptor.SYSIBM_SCHEMA_UUID); |
| systemUtilSchemaDesc = |
| newSystemSchemaDesc(SchemaDescriptor.STD_SYSTEM_UTIL_SCHEMA_NAME, |
| SchemaDescriptor.SYSCS_UTIL_SCHEMA_UUID); |
| } |
| |
| // returns null if database is at rev level 10.5 or earlier |
| public PasswordHasher makePasswordHasher( Dictionary<?,?> props ) |
| throws StandardException |
| { |
| // Support for configurable hash algorithm was added in Derby 10.6, so |
| // we don't want to store a hash using the new scheme if the database |
| // is running in soft upgrade and may be used with an older version |
| // later. |
| boolean supportConfigurableHash = checkVersion(DataDictionary.DD_VERSION_DERBY_10_6, null); |
| |
| // Support for key stretching was added in Derby 10.9, so don't use it |
| // if the database may still be used with an older version. |
| boolean supportKeyStretching = checkVersion(DataDictionary.DD_VERSION_DERBY_10_9, null); |
| |
| if ( !supportConfigurableHash ) { return null; } |
| else |
| { |
| String algorithm = (String) |
| PropertyUtil.getPropertyFromSet( |
| props, |
| Property.AUTHENTICATION_BUILTIN_ALGORITHM); |
| |
| if ( algorithm == null ) { return null; } |
| |
| byte[] salt = null; |
| int iterations = 1; |
| |
| if (algorithm.length() > 0) { |
| |
| if (supportKeyStretching) { |
| salt = generateRandomSalt(props); |
| iterations = getIntProperty( |
| props, |
| Property.AUTHENTICATION_BUILTIN_ITERATIONS, |
| Property.AUTHENTICATION_BUILTIN_ITERATIONS_DEFAULT, |
| 1, Integer.MAX_VALUE); |
| } |
| } |
| |
| return new PasswordHasher( algorithm, salt, iterations ); |
| } |
| } |
| |
| /** |
| * Generate an array of random bytes to use as salt when hashing |
| * credentials. |
| * |
| * @param props database properties that possibly specify the desired |
| * length of the salt |
| * @return random bytes |
| */ |
| private byte[] generateRandomSalt(Dictionary props) { |
| int saltLength = getIntProperty( |
| props, |
| Property.AUTHENTICATION_BUILTIN_SALT_LENGTH, |
| Property.AUTHENTICATION_BUILTIN_SALT_LENGTH_DEFAULT, |
| 0, Integer.MAX_VALUE); |
| |
| SecureRandom random = new SecureRandom(); |
| byte[] salt = new byte[saltLength]; |
| random.nextBytes(salt); |
| |
| return salt; |
| } |
| /** |
| * Get the value of an integer property. |
| * |
| * @param props database properties |
| * @param key the key of the property |
| * @param defaultValue which value to return if the property is not set, |
| * or if the property value is not in the valid range |
| * @param minValue lowest property value to accept |
| * @param maxValue highest property value to accept |
| * @return the value of the property |
| */ |
| private int getIntProperty( |
| Dictionary props, String key, |
| int defaultValue, int minValue, int maxValue) { |
| |
| String sVal = (String) PropertyUtil.getPropertyFromSet(props, key); |
| |
| if (sVal != null) { |
| try { |
| int i = Integer.parseInt(sVal); |
| if (i >= minValue && i <= maxValue) { |
| return i; |
| } |
| } catch (NumberFormatException nfe) { |
| // By convention, Derby ignores property values that cannot be |
| // parsed. Use the default value instead. |
| } |
| } |
| |
| return defaultValue; |
| } |
| |
| |
| |
| /** |
| * Get the descriptor for the system schema. Schema descriptors include |
| * authorization ids and schema ids. |
| * |
| * SQL92 allows a schema to specify a default character set - we will |
| * not support this. |
| * |
| * @return The descriptor for the schema. |
| * |
| * @exception StandardException Thrown on failure |
| */ |
| public SchemaDescriptor getSystemSchemaDescriptor() |
| throws StandardException |
| { |
| return systemSchemaDesc; |
| } |
| |
| |
| /** |
| * Get the descriptor for the SYSCS_UTIL system schema. |
| * Schema descriptors include authorization ids and schema ids. |
| * |
| * SQL92 allows a schema to specify a default character set - we will |
| * not support this. |
| * |
| * @return The descriptor for the schema. |
| * |
| * @exception StandardException Thrown on failure |
| */ |
| public SchemaDescriptor getSystemUtilSchemaDescriptor() |
| throws StandardException |
| { |
| return(systemUtilSchemaDesc); |
| } |
| |
| /** |
| * Get the descriptor for the SYSIBM schema. Schema descriptors include |
| * authorization ids and schema ids. |
| * |
| * SQL92 allows a schema to specify a default character set - we will |
| * not support this. |
| * |
| * @return The descriptor for the schema. |
| * |
| * @exception StandardException Thrown on failure |
| */ |
| public SchemaDescriptor getSysIBMSchemaDescriptor() |
| throws StandardException |
| { |
| return sysIBMSchemaDesc; |
| } |
| |
| /** |
| * Get the descriptor for the declared global temporary table schema which |
| * is always named "SESSION". |
| * |
| * @return The descriptor for the schema. |
| * |
| * @exception StandardException Thrown on failure |
| */ |
| public SchemaDescriptor getDeclaredGlobalTemporaryTablesSchemaDescriptor() |
| throws StandardException |
| { |
| return declaredGlobalTemporaryTablesSchemaDesc; |
| } |
| |
| /** |
| * Determine whether a string is the name of the system schema. |
| * |
| * @param name |
| * @return true or false |
| * |
| * @exception StandardException Thrown on failure |
| */ |
| public boolean isSystemSchemaName( String name) |
| throws StandardException |
| { |
| boolean ret_val = false; |
| |
| for (int i = systemSchemaNames.length - 1; i >= 0;) |
| { |
| if ((ret_val = systemSchemaNames[i--].equals(name))) |
| break; |
| } |
| |
| return(ret_val); |
| } |
| |
| /** |
| * Get the descriptor for the named schema. |
| * Schema descriptors include authorization ids and schema ids. |
| * SQL92 allows a schema to specify a default character set - we will |
| * not support this. Will check default schema for a match |
| * before scanning a system table. |
| * |
| * @param schemaName The name of the schema we're interested in. Must not be null. |
| * @param tc TransactionController |
| * |
| * @param raiseError whether an exception should be thrown if the schema does not exist. |
| * |
| * @return The descriptor for the schema. Can be null (not found) if raiseError is false. |
| * |
| * @exception StandardException Thrown on error |
| */ |
| public SchemaDescriptor getSchemaDescriptor(String schemaName, |
| TransactionController tc, |
| boolean raiseError) |
| throws StandardException |
| { |
| /* |
| ** Check for APP and SYS schemas before going any |
| ** further. |
| */ |
| |
| if ( tc == null ) |
| { |
| tc = getTransactionCompile(); |
| } |
| |
| if (getSystemSchemaDescriptor().getSchemaName().equals(schemaName)) |
| { |
| return getSystemSchemaDescriptor(); |
| } |
| else if (getSysIBMSchemaDescriptor().getSchemaName().equals(schemaName)) |
| { |
| // oh you are really asking SYSIBM, if this db is soft upgraded |
| // from pre 52, I may have 2 versions for you, one on disk |
| // (user SYSIBM), one imaginary (builtin). The |
| // one on disk (real one, if it exists), should always be used. |
| if (dictionaryVersion.checkVersion( |
| DataDictionary.DD_VERSION_CS_5_2, null)) |
| { |
| return getSysIBMSchemaDescriptor(); |
| } |
| } |
| |
| /* |
| ** Manual lookup |
| */ |
| SchemaDescriptor sd = locateSchemaRow(schemaName, tc); |
| |
| //if no schema found and schema name is SESSION, then create an |
| //in-memory schema descriptor |
| if (sd == null && |
| getDeclaredGlobalTemporaryTablesSchemaDescriptor().getSchemaName().equals(schemaName)) |
| { |
| return getDeclaredGlobalTemporaryTablesSchemaDescriptor(); |
| } |
| |
| if (sd == null && raiseError) |
| { |
| throw StandardException.newException( |
| SQLState.LANG_SCHEMA_DOES_NOT_EXIST, schemaName); |
| } |
| else |
| { |
| return sd; |
| } |
| } |
| |
| /** |
| * Get the target schema by searching for a matching row |
| * in SYSSCHEMAS by schemaId. Read only scan. |
| * |
| * @param schemaId The id of the schema we're interested in. |
| * If non-null, overrides schemaName |
| * |
| * @param tc TransactionController. If null, one |
| * is gotten off of the language connection context. |
| * |
| * @return The row for the schema |
| * |
| * @exception StandardException Thrown on error |
| */ |
| private SchemaDescriptor locateSchemaRow(UUID schemaId, |
| TransactionController tc) |
| throws StandardException |
| { |
| return locateSchemaRowBody( |
| schemaId, |
| TransactionController.ISOLATION_REPEATABLE_READ, |
| tc); |
| } |
| |
| |
| /** |
| * Get the target schema by searching for a matching row |
| * in SYSSCHEMAS by schemaId. Read only scan. |
| * |
| * @param schemaId The id of the schema we're interested in. |
| * If non-null, overrides schemaName |
| * @param isolationLevel Use this explicit isolation level. Only |
| * ISOLATION_REPEATABLE_READ (normal usage) or |
| * ISOLATION_READ_UNCOMMITTED (corner cases) |
| * supported for now. |
| * @param tc TransactionController. If null, one |
| * is gotten off of the language connection context. |
| * |
| * @return The row for the schema |
| * |
| * @exception StandardException Thrown on error |
| */ |
| private SchemaDescriptor locateSchemaRow(UUID schemaId, |
| int isolationLevel, |
| TransactionController tc) |
| throws StandardException |
| { |
| return locateSchemaRowBody( |
| schemaId, |
| isolationLevel, |
| tc); |
| } |
| |
| |
| private SchemaDescriptor locateSchemaRowBody(UUID schemaId, |
| int isolationLevel, |
| TransactionController tc) |
| throws StandardException |
| { |
| DataValueDescriptor UUIDStringOrderable; |
| TabInfoImpl ti = coreInfo[SYSSCHEMAS_CORE_NUM]; |
| |
| /* Use UUIDStringOrderable in both start and stop positions for scan */ |
| UUIDStringOrderable = getIDValueAsCHAR(schemaId); |
| |
| /* Set up the start/stop position for the scan */ |
| ExecIndexRow keyRow = exFactory.getIndexableRow(1); |
| keyRow.setColumn(1, UUIDStringOrderable); |
| |
| return getDescriptorViaIndex( |
| SYSSCHEMASRowFactory.SYSSCHEMAS_INDEX2_ID, |
| keyRow, |
| (ScanQualifier [][]) null, |
| ti, |
| (TupleDescriptor) null, |
| (List<TupleDescriptor>) null, |
| SchemaDescriptor.class, |
| false, |
| isolationLevel, |
| tc); |
| } |
| |
| /** |
| * Get the target schema by searching for a matching row |
| * in SYSSCHEMAS by schema name. Read only scan. |
| * |
| * @param schemaName The name of the schema we're interested in. |
| * If schemaId is null, used to qual. |
| * |
| * @param tc TransactionController. If null, one |
| * is gotten off of the language connection context. |
| * |
| * @return The row for the schema |
| * |
| * @exception StandardException Thrown on error |
| */ |
| private SchemaDescriptor locateSchemaRow(String schemaName, |
| TransactionController tc) |
| throws StandardException |
| { |
| DataValueDescriptor schemaNameOrderable; |
| TabInfoImpl ti = coreInfo[SYSSCHEMAS_CORE_NUM]; |
| |
| /* Use aliasNameOrderable in both start |
| * and stop position for scan. |
| */ |
| schemaNameOrderable = new SQLVarchar(schemaName); |
| |
| /* Set up the start/stop position for the scan */ |
| ExecIndexRow keyRow = exFactory.getIndexableRow(1); |
| keyRow.setColumn(1, schemaNameOrderable); |
| |
| return getDescriptorViaIndex( |
| SYSSCHEMASRowFactory.SYSSCHEMAS_INDEX1_ID, |
| keyRow, |
| (ScanQualifier [][]) null, |
| ti, |
| (TupleDescriptor) null, |
| (List<TupleDescriptor>) null, |
| SchemaDescriptor.class, |
| false, |
| TransactionController.ISOLATION_REPEATABLE_READ, |
| tc); |
| } |
| |
| |
| /** |
| * Get the SchemaDescriptor for the given schema identifier. |
| * |
| * @param schemaId The id of the schema we're interested in. |
| * |
| * @param tc The transaction controller to us when scanning |
| * SYSSCHEMAS |
| * |
| * @return The descriptor for the schema, null if no such schema exists. |
| * |
| * @exception StandardException Thrown on failure |
| */ |
| public SchemaDescriptor getSchemaDescriptor(UUID schemaId, |
| TransactionController tc) |
| throws StandardException |
| { |
| return getSchemaDescriptorBody( |
| schemaId, |
| TransactionController.ISOLATION_REPEATABLE_READ, |
| tc); |
| } |
| |
| /** |
| * Get the SchemaDescriptor for the given schema identifier. |
| * |
| * @param schemaId the uuid of the schema we want a descriptor for |
| * @param isolationLevel use this explicit isolation level. Only |
| * ISOLATION_REPEATABLE_READ (normal usage) or |
| * ISOLATION_READ_UNCOMMITTED (corner cases) |
| * supported for now. |
| * @param tc transaction controller |
| * @throws StandardException thrown on error |
| */ |
| public SchemaDescriptor getSchemaDescriptor(UUID schemaId, |
| int isolationLevel, |
| TransactionController tc) |
| throws StandardException |
| { |
| return getSchemaDescriptorBody( |
| schemaId, |
| isolationLevel, |
| tc); |
| } |
| |
| |
| private SchemaDescriptor getSchemaDescriptorBody( |
| UUID schemaId, |
| int isolationLevel, |
| TransactionController tc) throws StandardException |
| { |
| if ( tc == null ) |
| { |
| tc = getTransactionCompile(); |
| } |
| |
| /* |
| ** Check for APP and SYS schemas before going any |
| ** further. |
| */ |
| if (schemaId != null) |
| { |
| if (getSystemSchemaDescriptor().getUUID().equals(schemaId)) |
| { |
| return getSystemSchemaDescriptor(); |
| } |
| else if (getSysIBMSchemaDescriptor().getUUID().equals(schemaId)) |
| { |
| return getSysIBMSchemaDescriptor(); |
| } |
| } |
| |
| /* |
| ** If we aren't booting, lets see if we already |
| ** have the descriptor. If we are in the middle |
| ** of booting we cannot get the LanguageConnectionContext. |
| */ |
| if (!booting) |
| { |
| |
| LanguageConnectionContext lcc = getLCC(); |
| |
| if (lcc != null) |
| { |
| SchemaDescriptor sd = lcc.getDefaultSchema(); |
| |
| if ((sd != null) && |
| ((schemaId == null) || |
| schemaId.equals(sd.getUUID()))) |
| { |
| return sd; |
| } |
| } |
| } |
| |
| return locateSchemaRow(schemaId, isolationLevel, tc); |
| } |
| |
| |
| /** |
| * Return true of there exists a schema whose authorizationId equals |
| * authid, i.e. SYS.SYSSCHEMAS contains a row whose column |
| * (AUTHORIZATIONID) equals authid. |
| * |
| * @param authid authorizationId |
| * @param tc TransactionController |
| * @return true iff there is a matching schema |
| * @exception StandardException |
| */ |
| public boolean existsSchemaOwnedBy(String authid, |
| TransactionController tc) |
| throws StandardException { |
| |
| TabInfoImpl ti = coreInfo[SYSSCHEMAS_CORE_NUM]; |
| SYSSCHEMASRowFactory |
| rf = (SYSSCHEMASRowFactory)ti.getCatalogRowFactory(); |
| ConglomerateController |
| heapCC = tc.openConglomerate( |
| ti.getHeapConglomerate(), false, 0, |
| TransactionController.MODE_RECORD, |
| TransactionController.ISOLATION_REPEATABLE_READ); |
| |
| DataValueDescriptor authIdOrderable = new SQLVarchar(authid); |
| ScanQualifier[][] scanQualifier = exFactory.getScanQualifier(1); |
| |
| scanQualifier[0][0].setQualifier( |
| SYSSCHEMASRowFactory.SYSSCHEMAS_SCHEMAAID - 1, /* to zero-based */ |
| authIdOrderable, |
| Orderable.ORDER_OP_EQUALS, |
| false, |
| false, |
| false); |
| |
| ScanController sc = tc.openScan( |
| ti.getHeapConglomerate(), |
| false, // don't hold open across commit |
| 0, // for update |
| TransactionController.MODE_RECORD, |
| TransactionController.ISOLATION_REPEATABLE_READ, |
| (FormatableBitSet) null, // all fields as objects |
| (DataValueDescriptor[]) null, // start position - |
| 0, // startSearchOperation - none |
| scanQualifier, // |
| (DataValueDescriptor[]) null, // stop position -through last row |
| 0); // stopSearchOperation - none |
| |
| boolean result = false; |
| |
| try { |
| ExecRow outRow = rf.makeEmptyRow(); |
| |
| if (sc.fetchNext(outRow.getRowArray())) { |
| result = true; |
| } |
| } finally { |
| if (sc != null) { |
| sc.close(); |
| } |
| |
| if (heapCC != null) { |
| heapCC.close(); |
| } |
| } |
| |
| return result; |
| } |
| |
| |
| /** |
| * @see DataDictionary#addDescriptor |
| */ |
| public void addDescriptor(TupleDescriptor td, TupleDescriptor parent, |
| int catalogNumber, boolean duplicatesAllowed, |
| TransactionController tc) |
| throws StandardException |
| { |
| TabInfoImpl ti = (catalogNumber < NUM_CORE) ? coreInfo[catalogNumber] : |
| getNonCoreTI(catalogNumber); |
| |
| ExecRow row = ti.getCatalogRowFactory().makeRow(td, parent); |
| |
| int insertRetCode = ti.insertRow(row, tc); |
| |
| if (!duplicatesAllowed) |
| { |
| if (insertRetCode != TabInfoImpl.ROWNOTDUPLICATE) |
| throw duplicateDescriptorException(td, parent); |
| } |
| } |
| |
| private StandardException |
| duplicateDescriptorException(TupleDescriptor tuple, |
| TupleDescriptor parent) |
| { |
| if (parent != null) |
| return |
| StandardException.newException(SQLState.LANG_OBJECT_ALREADY_EXISTS_IN_OBJECT, |
| tuple.getDescriptorType(), |
| tuple.getDescriptorName(), |
| parent.getDescriptorType(), |
| parent.getDescriptorName()); |
| |
| else return |
| StandardException.newException(SQLState.LANG_OBJECT_ALREADY_EXISTS, |
| tuple.getDescriptorType(), |
| tuple.getDescriptorName()); |
| } |
| |
| /** array version of addDescriptor. |
| * @see DataDictionary#addDescriptor |
| */ |
| public void addDescriptorArray(TupleDescriptor[] td, |
| TupleDescriptor parent, |
| int catalogNumber, |
| boolean allowDuplicates, |
| TransactionController tc) |
| throws StandardException |
| { |
| TabInfoImpl ti = (catalogNumber < NUM_CORE) ? coreInfo[catalogNumber] : |
| getNonCoreTI(catalogNumber); |
| CatalogRowFactory crf = ti.getCatalogRowFactory(); |
| |
| ExecRow[] rl = new ExecRow[td.length]; |
| |
| for (int index = 0; index < td.length; index++) |
| { |
| ExecRow row = crf.makeRow(td[index], parent); |
| rl[index] = row; |
| } |
| |
| int insertRetCode = ti.insertRowList( rl, tc ); |
| if (!allowDuplicates && insertRetCode != TabInfoImpl.ROWNOTDUPLICATE) |
| { |
| throw duplicateDescriptorException(td[insertRetCode], parent); |
| } |
| } |
| |
| |
| /** |
| * @see DataDictionary#dropRoleGrant |
| */ |
| public void dropRoleGrant(String roleName, |
| String grantee, |
| String grantor, |
| TransactionController tc) |
| throws StandardException |
| { |
| DataValueDescriptor roleNameOrderable; |
| DataValueDescriptor granteeOrderable; |
| DataValueDescriptor grantorOrderable; |
| |
| TabInfoImpl ti = getNonCoreTI(SYSROLES_CATALOG_NUM); |
| |
| roleNameOrderable = new SQLVarchar(roleName); |
| granteeOrderable = new SQLVarchar(grantee); |
| grantorOrderable = new SQLVarchar(grantor); |
| |
| /* Set up the start/stop position for the scan */ |
| ExecIndexRow keyRow = exFactory.getIndexableRow(3); |
| keyRow.setColumn(1, roleNameOrderable); |
| keyRow.setColumn(2, granteeOrderable); |
| keyRow.setColumn(3, grantorOrderable); |
| |
| ti.deleteRow(tc, keyRow, |
| SYSROLESRowFactory.SYSROLES_INDEX_ID_EE_OR_IDX); |
| } |
| |
| |
| /** |
| * Drop the descriptor for a schema, given the schema's name |
| * |
| * @param schemaName The name of the schema to drop |
| * @param tc TransactionController for the transaction |
| * |
| * @exception StandardException Thrown on error |
| */ |
| public void dropSchemaDescriptor(String schemaName, |
| TransactionController tc) |
| throws StandardException |
| { |
| ExecIndexRow keyRow1 = null; |
| DataValueDescriptor schemaNameOrderable; |
| TabInfoImpl ti = coreInfo[SYSSCHEMAS_CORE_NUM]; |
| |
| if (SanityManager.DEBUG) |
| { |
| SchemaDescriptor sd = getSchemaDescriptor(schemaName, getTransactionCompile(), true); |
| if (!isSchemaEmpty(sd)) |
| { |
| SanityManager.THROWASSERT("Attempt to drop schema "+schemaName+" that is not empty"); |
| } |
| } |
| |
| /* Use schemaNameOrderable in both start |
| * and stop position for index 1 scan. |
| */ |
| schemaNameOrderable = new SQLVarchar(schemaName); |
| |
| /* Set up the start/stop position for the scan */ |
| keyRow1 = exFactory.getIndexableRow(1); |
| keyRow1.setColumn(1, schemaNameOrderable); |
| |
| ti.deleteRow( tc, keyRow1, SYSSCHEMASRowFactory.SYSSCHEMAS_INDEX1_ID ); |
| } |
| |
| /** |
| * Get the descriptor for the named table within the given schema. |
| * If the schema parameter is NULL, it looks for the table in the |
| * current (default) schema. Table descriptors include object ids, |
| * object types (table, view, etc.) |
| * |
| * @param tableName The name of the table to get the descriptor for |
| * @param schema The descriptor for the schema the table lives in. |
| * If null, use the system schema. |
| * @return The descriptor for the table, null if table does not |
| * exist. |
| * |
| * @exception StandardException Thrown on failure |
| */ |
| public TableDescriptor getTableDescriptor(String tableName, |
| SchemaDescriptor schema, TransactionController tc) |
| throws StandardException |
| { |
| TableDescriptor retval = null; |
| |
| /* |
| ** If we didn't get a schema descriptor, we had better |
| ** have a system table. |
| */ |
| if (SanityManager.DEBUG) |
| { |
| if ((schema == null) && !tableName.startsWith("SYS")) |
| { |
| SanityManager.THROWASSERT("null schema for non system table "+tableName); |
| } |
| } |
| |
| SchemaDescriptor sd = (schema == null) ? |
| getSystemSchemaDescriptor() |
| : schema; |
| |
| UUID schemaUUID = sd.getUUID(); |
| |
| if (SchemaDescriptor.STD_SYSTEM_DIAG_SCHEMA_NAME.equals( |
| sd.getSchemaName())) |
| { |
| TableDescriptor td = |
| new TableDescriptor(this, tableName, sd, |
| TableDescriptor.VTI_TYPE, |
| TableDescriptor.DEFAULT_LOCK_GRANULARITY); |
| |
| // ensure a vti class exists |
| if (getVTIClass(td, false) != null) |
| return td; |
| |
| // otherwise just standard search |
| } |
| |
| TableKey tableKey = new TableKey(schemaUUID, tableName); |
| |
| /* Only use the cache if we're in compile-only mode */ |
| if (getCacheMode() == DataDictionary.COMPILE_ONLY_MODE) |
| { |
| NameTDCacheable cacheEntry = (NameTDCacheable) nameTdCache.find(tableKey); |
| if (cacheEntry != null) |
| { |
| retval = cacheEntry.getTableDescriptor(); |
| // bind in previous command might have set refernced cols |
| retval.setReferencedColumnMap(null); |
| nameTdCache.release(cacheEntry); |
| } |
| return retval; |
| } |
| |
| return getTableDescriptorIndex1Scan(tableName, schemaUUID.toString()); |
| |
| } |
| |
| /** |
| * Scan systables_index1 (tablename, schemaid) for a match. |
| * |
| * @return TableDescriptor The matching descriptor, if any. |
| * |
| * @exception StandardException Thrown on failure |
| */ |
| private TableDescriptor getTableDescriptorIndex1Scan( |
| String tableName, |
| String schemaUUID) |
| throws StandardException |
| { |
| DataValueDescriptor schemaIDOrderable; |
| DataValueDescriptor tableNameOrderable; |
| TableDescriptor td; |
| TabInfoImpl ti = coreInfo[SYSTABLES_CORE_NUM]; |
| |
| /* Use tableNameOrderable and schemaIdOrderable in both start |
| * and stop position for scan. |
| */ |
| tableNameOrderable = new SQLVarchar(tableName); |
| schemaIDOrderable = new SQLChar(schemaUUID); |
| |
| /* Set up the start/stop position for the scan */ |
| ExecIndexRow keyRow = exFactory.getIndexableRow(2); |
| keyRow.setColumn(1, tableNameOrderable); |
| keyRow.setColumn(2, schemaIDOrderable); |
| |
| td = getDescriptorViaIndex( |
| SYSTABLESRowFactory.SYSTABLES_INDEX1_ID, |
| keyRow, |
| (ScanQualifier [][]) null, |
| ti, |
| (TupleDescriptor) null, |
| (List<TupleDescriptor>) null, |
| TableDescriptor.class, |
| false); |
| |
| return finishTableDescriptor(td); |
| } |
| |
| /** |
| * This method can get called from the DataDictionary cache. |
| * |
| * @param tableKey The TableKey of the table |
| * |
| * @return The descriptor for the table, null if the table does |
| * not exist. |
| * |
| * @exception StandardException Thrown on failure |
| */ |
| TableDescriptor getUncachedTableDescriptor(TableKey tableKey) |
| throws StandardException |
| { |
| return getTableDescriptorIndex1Scan(tableKey.getTableName(), |
| tableKey.getSchemaId().toString()); |
| } |
| |
| /** |
| * Get the descriptor for the table with the given UUID. |
| * |
| * NOTE: I'm assuming that the object store will define an UUID for |
| * persistent objects. I'm also assuming that UUIDs are unique across |
| * schemas, and that the object store will be able to do efficient |
| * lookups across schemas (i.e. that no schema descriptor parameter |
| * is needed). |
| * |
| * @param tableID The UUID of the table to get the descriptor for |
| * |
| * @return The descriptor for the table, null if the table does |
| * not exist. |
| * |
| * @exception StandardException Thrown on failure |
| */ |
| public TableDescriptor getTableDescriptor(UUID tableID) |
| throws StandardException |
| { |
| OIDTDCacheable cacheEntry; |
| TableDescriptor retval = null; |
| |
| /* Only use the cache if we're in compile-only mode */ |
| if (getCacheMode() == DataDictionary.COMPILE_ONLY_MODE) |
| { |
| cacheEntry = (OIDTDCacheable) OIDTdCache.find(tableID); |
| if (cacheEntry != null) |
| { |
| retval = cacheEntry.getTableDescriptor(); |
| // bind in previous command might have set refernced cols |
| retval.setReferencedColumnMap(null); |
| OIDTdCache.release(cacheEntry); |
| } |
| |
| return retval; |
| |
| } |
| |
| return getTableDescriptorIndex2Scan(tableID.toString()); |
| } |
| |
| /** |
| * This method can get called from the DataDictionary cache. |
| * |
| * @param tableID The UUID of the table to get the descriptor for |
| * |
| * @return The descriptor for the table, null if the table does |
| * not exist. |
| * |
| * @exception StandardException Thrown on failure |
| */ |
| protected TableDescriptor getUncachedTableDescriptor(UUID tableID) |
| throws StandardException |
| { |
| return getTableDescriptorIndex2Scan(tableID.toString()); |
| } |
| |
| /** |
| * Scan systables_index2 (tableid) for a match. |
| * |
| * @return TableDescriptor The matching descriptor, if any. |
| * |
| * @exception StandardException Thrown on failure |
| */ |
| private TableDescriptor getTableDescriptorIndex2Scan( |
| String tableUUID) |
| throws StandardException |
| { |
| DataValueDescriptor tableIDOrderable; |
| TableDescriptor td; |
| TabInfoImpl ti = coreInfo[SYSTABLES_CORE_NUM]; |
| |
| /* Use tableIDOrderable in both start and stop position for scan. |
| */ |
| tableIDOrderable = new SQLChar(tableUUID); |
| |
| /* Set up the start/stop position for the scan */ |
| ExecIndexRow keyRow = exFactory.getIndexableRow(1); |
| keyRow.setColumn(1, tableIDOrderable); |
| |
| td = getDescriptorViaIndex( |
| SYSTABLESRowFactory.SYSTABLES_INDEX2_ID, |
| keyRow, |
| (ScanQualifier [][]) null, |
| ti, |
| (TupleDescriptor) null, |
| (List<TupleDescriptor>) null, |
| TableDescriptor.class, |
| false); |
| |
| return finishTableDescriptor(td); |
| } |
| |
| /** |
| * Finish filling in the TableDescriptor. |
| * (Build the various lists that hang off the TD.) |
| * |
| * @param td The TableDescriptor. |
| * |
| * @return The completed TableDescriptor. |
| * |
| * @exception StandardException Thrown on failure |
| */ |
| private TableDescriptor finishTableDescriptor(TableDescriptor td) |
| throws StandardException |
| { |
| |
| if (td != null) |
| { |
| synchronized(td) |
| { |
| getColumnDescriptorsScan(td); |
| getConglomerateDescriptorsScan(td); |
| } |
| } |
| |
| return td; |
| } |
| |
| /** |
| * Indicate whether there is anything in the |
| * particular schema. Checks for tables in the |
| * the schema, on the assumption that there cannot |
| * be any other objects in a schema w/o a table. |
| * |
| * @param sd descriptor |
| * |
| * @return true/false |
| * |
| * @exception StandardException on error |
| */ |
| public boolean isSchemaEmpty(SchemaDescriptor sd) |
| throws StandardException |
| { |
| DataValueDescriptor schemaIdOrderable; |
| TransactionController tc = getTransactionCompile(); |
| |
| schemaIdOrderable = getIDValueAsCHAR(sd.getUUID()); |
| |
| if (isSchemaReferenced(tc, coreInfo[SYSTABLES_CORE_NUM], |
| SYSTABLESRowFactory.SYSTABLES_INDEX1_ID, |
| SYSTABLESRowFactory.SYSTABLES_INDEX1_SCHEMAID, |
| schemaIdOrderable)) |
| { |
| return false; |
| } |
| |
| if (isSchemaReferenced(tc, getNonCoreTI(SYSCONSTRAINTS_CATALOG_NUM), |
| SYSCONSTRAINTSRowFactory.SYSCONSTRAINTS_INDEX2_ID, |
| 2, |
| schemaIdOrderable)) |
| { |
| return false; |
| } |
| |
| if (isSchemaReferenced(tc, getNonCoreTI(SYSSTATEMENTS_CATALOG_NUM), |
| SYSSTATEMENTSRowFactory.SYSSTATEMENTS_INDEX2_ID, |
| 2, |
| schemaIdOrderable)) |
| { |
| return false; |
| } |
| |
| if (isSchemaReferenced(tc, getNonCoreTI(SYSTRIGGERS_CATALOG_NUM), |
| SYSTRIGGERSRowFactory.SYSTRIGGERS_INDEX2_ID, |
| 2, |
| schemaIdOrderable)) |
| { |
| return false; |
| } |
| |
| // don't orphan routines or UDTs |
| if (isSchemaReferenced(tc, getNonCoreTI(SYSALIASES_CATALOG_NUM), |
| SYSALIASESRowFactory.SYSALIASES_INDEX1_ID, |
| 1, |
| schemaIdOrderable)) |
| { |
| return false; |
| } |
| |
| // These catalogs were added in 10.6. Don't look for these catalogs if we |
| // have soft-upgraded from an older release. |
| if( dictionaryVersion.majorVersionNumber >= DataDictionary.DD_VERSION_DERBY_10_6) |
| { |
| if (isSchemaReferenced(tc, getNonCoreTI(SYSSEQUENCES_CATALOG_NUM), |
| SYSSEQUENCESRowFactory.SYSSEQUENCES_INDEX2_ID, |
| 1, |
| schemaIdOrderable)) |
| { |
| return false; |
| } |
| } |
| |
| return true; |
| } |
| |
| /** |
| * Is the schema id referenced by the system table in question? |
| * Currently assumes that the schema id is in an index. |
| * NOTE: could be generalized a bit, and possibly used |
| * elsewhere... |
| * |
| * @param tc transaction controller |
| * @param ti table info for the system table |
| * @param indexId index id |
| * @param indexCol 1 based index column |
| * @param schemaIdOrderable the schemaid in a char orderable |
| * |
| * @return true if there is a reference to this schema |
| * |
| * @exception StandardException on error |
| */ |
| protected boolean isSchemaReferenced(TransactionController tc, |
| TabInfoImpl ti, |
| int indexId, |
| int indexCol, |
| DataValueDescriptor schemaIdOrderable ) |
| throws StandardException |
| { |
| ConglomerateController heapCC = null; |
| ScanController scanController = null; |
| boolean foundRow; |
| FormatableBitSet colToCheck = new FormatableBitSet(indexCol); |
| |
| if (SanityManager.DEBUG) |
| { |
| SanityManager.ASSERT(indexId >= 0, "code needs to be enhanced"+ |
| " to support a table scan to find the index id"); |
| } |
| |
| colToCheck.set(indexCol - 1); |
| |
| ScanQualifier[][] qualifier = exFactory.getScanQualifier(1); |
| qualifier[0][0].setQualifier |
| (indexCol - 1, |
| schemaIdOrderable, |
| Orderable.ORDER_OP_EQUALS, |
| false, |
| false, |
| false); |
| |
| try |
| { |
| heapCC = |
| tc.openConglomerate( |
| ti.getHeapConglomerate(), false, 0, |
| TransactionController.MODE_RECORD, |
| TransactionController.ISOLATION_REPEATABLE_READ); |
| |
| scanController = tc.openScan( |
| ti.getIndexConglomerate(indexId), // conglomerate to open |
| false, // don't hold open across commit |
| 0, // for read |
| TransactionController.MODE_RECORD, // row locking |
| TransactionController.ISOLATION_REPEATABLE_READ, |
| colToCheck, // don't get any rows |
| null, // start position - first row |
| ScanController.GE, // startSearchOperation |
| qualifier, // scanQualifier, |
| null, // stop position - through last row |
| ScanController.GT); // stopSearchOperation |
| |
| foundRow = (scanController.next()); |
| } |
| finally |
| { |
| if (scanController != null) |
| { |
| scanController.close(); |
| } |
| if (heapCC != null) |
| { |
| heapCC.close(); |
| } |
| } |
| |
| return foundRow; |
| } |
| |
| /** |
| * Drop the table descriptor. |
| * |
| * @param td The table descriptor to drop |
| * @param schema A descriptor for the schema the table |
| * is a part of. If this parameter is |
| * NULL, then the table is part of the |
| * current (default) schema |
| * @param tc TransactionController for the transaction |
| * |
| * @exception StandardException Thrown on error |
| */ |
| public void dropTableDescriptor(TableDescriptor td, SchemaDescriptor schema, |
| TransactionController tc) |
| throws StandardException |
| { |
| ExecIndexRow keyRow1 = null; |
| DataValueDescriptor schemaIDOrderable; |
| DataValueDescriptor tableNameOrderable; |
| TabInfoImpl ti = coreInfo[SYSTABLES_CORE_NUM]; |
| |
| /* Use tableIdOrderable and schemaIdOrderable in both start |
| * and stop position for index 1 scan. |
| */ |
| tableNameOrderable = new SQLVarchar(td.getName()); |
| schemaIDOrderable = getIDValueAsCHAR(schema.getUUID()); |
| |
| /* Set up the start/stop position for the scan */ |
| keyRow1 = (ExecIndexRow) exFactory.getIndexableRow(2); |
| keyRow1.setColumn(1, tableNameOrderable); |
| keyRow1.setColumn(2, schemaIDOrderable); |
| |
| ti.deleteRow( tc, keyRow1, SYSTABLESRowFactory.SYSTABLES_INDEX1_ID ); |
| } |
| |
| /** |
| * Update the lockGranularity for the specified table. |
| * |
| * @param td The TableDescriptor for the table |
| * @param schema The SchemaDescriptor for the table |
| * @param lockGranularity The new lockGranularity |
| * @param tc The TransactionController to use. |
| * |
| * @exception StandardException Thrown on error |
| */ |
| public void updateLockGranularity(TableDescriptor td, SchemaDescriptor schema, |
| char lockGranularity, TransactionController tc) |
| throws StandardException |
| { |
| ExecRow row; |
| DataValueDescriptor schemaIDOrderable; |
| DataValueDescriptor tableNameOrderable; |
| TabInfoImpl ti = coreInfo[SYSTABLES_CORE_NUM]; |
| SYSTABLESRowFactory rf = (SYSTABLESRowFactory) ti.getCatalogRowFactory(); |
| |
| /* Use tableIdOrderable and schemaIdOrderable in both start |
| * and stop position for index 1 scan. |
| */ |
| tableNameOrderable = new SQLVarchar(td.getName()); |
| schemaIDOrderable = getIDValueAsCHAR(schema.getUUID()); |
| |
| /* Set up the start/stop position for the scan */ |
| ExecIndexRow keyRow1 = exFactory.getIndexableRow(2); |
| keyRow1.setColumn(1, tableNameOrderable); |
| keyRow1.setColumn(2, schemaIDOrderable); |
| |
| // build the row to be stuffed into SYSTABLES. |
| row = rf.makeRow(td, schema); |
| // update row in catalog (no indexes) |
| boolean[] bArray = new boolean[2]; |
| for (int index = 0; index < 2; index++) |
| { |
| bArray[index] = false; |
| } |
| ti.updateRow(keyRow1, row, |
| SYSTABLESRowFactory.SYSTABLES_INDEX1_ID, |
| bArray, |
| (int[])null, |
| tc); |
| } |
| |
| /** |
| * 10.6 upgrade logic to update the return type of SYSIBM.CLOBGETSUBSTRING. The length of the |
| * return type was changed in 10.5 but old versions of the metadata were not |
| * upgraded at that time. See DERBY-4214. |
| */ |
| void upgradeCLOBGETSUBSTRING_10_6( TransactionController tc ) |
| throws StandardException |
| { |
| TabInfoImpl ti = getNonCoreTI(SYSALIASES_CATALOG_NUM); |
| ExecIndexRow keyRow = exFactory.getIndexableRow(3); |
| DataValueDescriptor |
| aliasNameOrderable = new SQLVarchar( "CLOBGETSUBSTRING" ); |
| DataValueDescriptor nameSpaceOrderable = new SQLChar |
| ( new String( new char[] { AliasInfo.ALIAS_TYPE_FUNCTION_AS_CHAR } ) ); |
| |
| keyRow.setColumn(1, new SQLChar( SchemaDescriptor.SYSIBM_SCHEMA_UUID )); |
| keyRow.setColumn(2, aliasNameOrderable); |
| keyRow.setColumn(3, nameSpaceOrderable); |
| |
| AliasDescriptor oldAD = getDescriptorViaIndex |
| ( |
| SYSALIASESRowFactory.SYSALIASES_INDEX1_ID, |
| keyRow, |
| (ScanQualifier [][]) null, |
| ti, |
| (TupleDescriptor) null, |
| (List<TupleDescriptor>) null, |
| AliasDescriptor.class, |
| true, |
| TransactionController.ISOLATION_REPEATABLE_READ, |
| tc); |
| RoutineAliasInfo oldRai = (RoutineAliasInfo) oldAD.getAliasInfo(); |
| TypeDescriptor newReturnType = DataTypeDescriptor.getCatalogType( Types.VARCHAR, Limits.MAX_CLOB_RETURN_LEN ); |
| RoutineAliasInfo newRai = new RoutineAliasInfo |
| ( |
| oldRai.getMethodName(), |
| oldRai.getParameterCount(), |
| oldRai.getParameterNames(), |
| oldRai.getParameterTypes(), |
| oldRai.getParameterModes(), |
| oldRai.getMaxDynamicResultSets(), |
| oldRai.getParameterStyle(), |
| oldRai.getSQLAllowed(), |
| oldRai.isDeterministic(), |
| oldRai.hasVarargs(), |
| oldRai.hasDefinersRights(), |
| oldRai.calledOnNullInput(), |
| newReturnType |
| ); |
| AliasDescriptor newAD = new AliasDescriptor |
| ( |
| this, |
| oldAD.getUUID(), |
| oldAD.getObjectName(), |
| oldAD.getSchemaUUID(), |
| oldAD.getJavaClassName(), |
| oldAD.getAliasType(), |
| oldAD.getNameSpace(), |
| oldAD.getSystemAlias(), |
| newRai, |
| oldAD.getSpecificName() |
| ); |
| ExecRow newRow = ti.getCatalogRowFactory().makeRow( newAD, null ); |
| |
| ti.updateRow |
| ( |
| keyRow, |
| newRow, |
| SYSALIASESRowFactory.SYSALIASES_INDEX1_ID, |
| new boolean[] { false, false, false }, |
| (int[])null, |
| tc |
| ); |
| } |
| |
| /** |
| * 10.6 upgrade logic to update the permissions granted to SYSCS_UTIL.SYSCS_INPLACE_COMPRESS_TABLE. |
| * If a 10.0 database was upgraded to 10.2, 10.3, or 10.4, then there will |
| * be an extra permissions tuple in SYSROUTINEPERMS--that tuple will have a |
| * null grantor field. We must delete this tuple. See DERBY-4215. |
| */ |
| void upgradeSYSROUTINEPERMS_10_6( TransactionController tc ) |
| throws StandardException |
| { |
| // |
| // Get the aliasID of SYSCS_INPLACE_COMPRESS_TABLE |
| // |
| TabInfoImpl aliasTI = getNonCoreTI(SYSALIASES_CATALOG_NUM); |
| ExecIndexRow aliasKeyRow = exFactory.getIndexableRow(3); |
| DataValueDescriptor aliasNameOrderable = new SQLVarchar( "SYSCS_INPLACE_COMPRESS_TABLE" );; |
| DataValueDescriptor nameSpaceOrderable = new SQLChar |
| ( new String( new char[] { AliasInfo.ALIAS_TYPE_PROCEDURE_AS_CHAR } ) ); |
| |
| aliasKeyRow.setColumn(1, new SQLChar( SchemaDescriptor.SYSCS_UTIL_SCHEMA_UUID )); |
| aliasKeyRow.setColumn(2, aliasNameOrderable); |
| aliasKeyRow.setColumn(3, nameSpaceOrderable); |
| |
| AliasDescriptor oldAD = getDescriptorViaIndex |
| ( |
| SYSALIASESRowFactory.SYSALIASES_INDEX1_ID, |
| aliasKeyRow, |
| (ScanQualifier [][]) null, |
| aliasTI, |
| (TupleDescriptor) null, |
| (List<TupleDescriptor>) null, |
| AliasDescriptor.class, |
| true, |
| TransactionController.ISOLATION_REPEATABLE_READ, |
| tc); |
| UUID aliasID = oldAD.getUUID(); |
| |
| // |
| // Now delete the permissions tuple which has a null grantor |
| // |
| TabInfoImpl rpTI = getNonCoreTI(SYSROUTINEPERMS_CATALOG_NUM); |
| ExecIndexRow rpKeyRow = exFactory.getIndexableRow(3); |
| |
| rpKeyRow.setColumn(1, new SQLVarchar( "PUBLIC" )); |
| rpKeyRow.setColumn(2, new SQLChar( aliasID.toString() )); |
| rpKeyRow.setColumn(3, new SQLVarchar( (String) null ) ); |
| |
| int deleteCount = rpTI.deleteRow(tc, rpKeyRow, SYSROUTINEPERMSRowFactory.GRANTEE_ALIAS_GRANTOR_INDEX_NUM); |
| } |
| |
| /** |
| * Drop all table descriptors for a schema. |
| * |
| * @param schema A descriptor for the schema to drop the tables |
| * from. |
| * |
| * @return Nothing. |
| * |
| * @exception StandardException Thrown on failure |
| */ |
| /* |
| public void dropAllTableDescriptors(SchemaDescriptor schema) |
| throws StandardException |
| { |
| if (SanityManager.DEBUG) SanityManager.NOTREACHED(); |
| } |
| */ |
| |
| /** |
| * Get a ColumnDescriptor given its Default ID. |
| * |
| * @param uuid The UUID of the default |
| * |
| * @return The ColumnDescriptor for the column. |
| * |
| * @exception StandardException Thrown on failure |
| */ |
| public ColumnDescriptor getColumnDescriptorByDefaultId(UUID uuid) |
| throws StandardException |
| { |
| DataValueDescriptor UUIDStringOrderable; |
| TabInfoImpl ti = coreInfo[SYSCOLUMNS_CORE_NUM]; |
| |
| /* Use UUIDStringOrderable in both start and stop positions for scan */ |
| UUIDStringOrderable = getIDValueAsCHAR(uuid); |
| |
| /* Set up the start/stop position for the scan */ |
| ExecIndexRow keyRow = exFactory.getIndexableRow(1); |
| keyRow.setColumn(1, UUIDStringOrderable); |
| |
| return getDescriptorViaIndex( |
| SYSCOLUMNSRowFactory.SYSCOLUMNS_INDEX2_ID, |
| keyRow, |
| (ScanQualifier [][]) null, |
| ti, |
| (DefaultDescriptor) null, |
| (List<TupleDescriptor>) null, |
| ColumnDescriptor.class, |
| false); |
| } |
| |
| |
| /** |
| * Populate the ColumnDescriptorList for the specified TableDescriptor. |
| * |
| * MT synchronization: it is assumed that the caller has synchronized |
| * on the CDL in the given TD. |
| * |
| * @param td The TableDescriptor. |
| * |
| * @exception StandardException Thrown on failure |
| */ |
| private void getColumnDescriptorsScan(TableDescriptor td) |
| throws StandardException |
| { |
| getColumnDescriptorsScan( |
| td.getUUID(), |
| td.getColumnDescriptorList(), |
| td); |
| } |
| |
| /** |
| * Populate the ColumnDescriptorList for the specified TableDescriptor. |
| * |
| * MT synchronization: it is assumed that the caller has synchronized |
| * on the CDL in the given TD. |
| * |
| * @param uuid The referencing UUID |
| * @param cdl The column descriptor list |
| * @param td The parent tuple descriptor |
| * |
| * @exception StandardException Thrown on failure |
| */ |
| private void getColumnDescriptorsScan( |
| UUID uuid, |
| ColumnDescriptorList cdl, |
| TupleDescriptor td) |
| throws StandardException |
| { |
| ColumnDescriptor cd; |
| ColumnDescriptorList cdlCopy = new ColumnDescriptorList(); |
| DataValueDescriptor refIDOrderable = null; |
| TabInfoImpl ti = coreInfo[SYSCOLUMNS_CORE_NUM]; |
| |
| /* Use refIDOrderable in both start and stop position for scan. */ |
| refIDOrderable = getIDValueAsCHAR(uuid); |
| |
| /* Set up the start/stop position for the scan */ |
| ExecIndexRow keyRow = exFactory.getIndexableRow(1); |
| keyRow.setColumn(1, refIDOrderable); |
| |
| getDescriptorViaIndex( |
| SYSCOLUMNSRowFactory.SYSCOLUMNS_INDEX1_ID, |
| keyRow, |
| (ScanQualifier [][]) null, |
| ti, |
| td, |
| cdl, |
| ColumnDescriptor.class, |
| false); |
| |
| /* The TableDescriptor's column descriptor list must be ordered by |
| * columnNumber. (It is probably not ordered correctly at this point due |
| * to the index on syscolumns being on (tableId, columnName).) The |
| * cheapest way to reorder the list appears to be to copy it (above), and then |
| * walk the copy and put the elements back into the original in the |
| * expected locations. |
| */ |
| int cdlSize = cdl.size(); |
| for (int index = 0; index < cdlSize; index++) |
| { |
| cdlCopy.add( cdl.get(index)); |
| } |
| for (int index = 0; index < cdlSize; index++) |
| { |
| cd = (ColumnDescriptor) cdlCopy.elementAt(index); |
| cdl.set(cd.getPosition() - 1, cd); |
| } |
| } |
| |
| /** |
| * Given a column name and a table ID, drops the column descriptor |
| * from the table. |
| * |
| * @param tableID The UUID of the table to drop the column from |
| * @param columnName The name of the column to drop |
| * @param tc TransactionController for the transaction |
| * |
| * @exception StandardException Thrown on error |
| */ |
| public void dropColumnDescriptor(UUID tableID, |
| String columnName, TransactionController tc) |
| throws StandardException |
| { |
| DataValueDescriptor columnNameOrderable; |
| DataValueDescriptor tableIdOrderable; |
| |
| /* Use tableIDOrderable and columnNameOrderable in both start |
| * and stop position for scan. |
| */ |
| tableIdOrderable = getIDValueAsCHAR(tableID); |
| columnNameOrderable = new SQLVarchar(columnName); |
| |
| /* Set up the start/stop position for the scan */ |
| ExecIndexRow keyRow = exFactory.getIndexableRow(2); |
| keyRow.setColumn(1, tableIdOrderable); |
| keyRow.setColumn(2, columnNameOrderable); |
| |
| dropColumnDescriptorCore( tc, keyRow); |
| } |
| |
| /** |
| * Drops all column descriptors from the given table. Useful for |
| * DROP TABLE. |
| * |
| * @param tableID The UUID of the table from which to drop |
| * all the column descriptors |
| * @param tc TransactionController for the transaction |
| * |
| * @exception StandardException Thrown on error |
| */ |
| public void dropAllColumnDescriptors(UUID tableID, TransactionController tc) |
| throws StandardException |
| { |
| DataValueDescriptor tableIdOrderable; |
| |
| /* Use tableIDOrderable in both start and stop position for scan. */ |
| tableIdOrderable = getIDValueAsCHAR(tableID); |
| |
| /* Set up the start/stop position for the scan */ |
| ExecIndexRow keyRow = exFactory.getIndexableRow(1); |
| keyRow.setColumn(1, tableIdOrderable); |
| |
| dropColumnDescriptorCore(tc, keyRow); |
| } |
| |
| /** |
| * Drops all table and column permission descriptors for the given table. |
| * |
| * @param tableID The UUID of the table from which to drop |
| * all the permission descriptors |
| * @param tc TransactionController for the transaction |
| * |
| * @exception StandardException Thrown on error |
| */ |
| public void dropAllTableAndColPermDescriptors(UUID tableID, TransactionController tc) |
| throws StandardException |
| { |
| DataValueDescriptor tableIdOrderable; |
| |
| // In Derby authorization mode, permission catalogs may not be present |
| if (!usesSqlAuthorization) |
| return; |
| |
| /* Use tableIDOrderable in both start and stop position for scan. */ |
| tableIdOrderable = getIDValueAsCHAR(tableID); |
| |
| /* Set up the start/stop position for the scan */ |
| ExecIndexRow keyRow = exFactory.getIndexableRow(1); |
| keyRow.setColumn(1, tableIdOrderable); |
| |
| dropTablePermDescriptor(tc, keyRow); |
| dropColumnPermDescriptor(tc, keyRow); |
| } |
| |
| /** |
| * Need to update SYSCOLPERMS for a given table because a new column has |
| * been added to that table. SYSCOLPERMS has a column called "COLUMNS" |
| * which is a bit map for all the columns in a given user table. Since |
| * ALTER TABLE .. ADD COLUMN .. has added one more column, we need to |
| * expand "COLUMNS" for that new column |
| * |
| * Currently, this code gets called during execution phase of |
| * ALTER TABLE .. ADD COLUMN .. |
| * |
| * @param tableID The UUID of the table to which a column has been added |
| * @param tc TransactionController for the transaction |
| * |
| * @exception StandardException Thrown on error |
| */ |
| public void updateSYSCOLPERMSforAddColumnToUserTable(UUID tableID, TransactionController tc) |
| throws StandardException |
| { |
| rewriteSYSCOLPERMSforAlterTable(tableID, tc, null); |
| } |
| /** |
| * Update SYSCOLPERMS due to dropping a column from a table. |
| * |
| * Since ALTER TABLE .. DROP COLUMN .. has removed a column from the |
| * table, we need to shrink COLUMNS by removing the corresponding bit |
| * position, and shifting all the subsequent bits "left" one position. |
| * |
| * @param tableID The UUID of the table from which a col has been dropped |
| * @param tc TransactionController for the transaction |
| * @param columnDescriptor Information about the dropped column |
| * |
| * @exception StandardException Thrown on error |
| */ |
| public void updateSYSCOLPERMSforDropColumn(UUID tableID, |
| TransactionController tc, ColumnDescriptor columnDescriptor) |
| throws StandardException |
| { |
| rewriteSYSCOLPERMSforAlterTable(tableID, tc, columnDescriptor); |
| } |
| /** |
| * Workhorse for ALTER TABLE-driven mods to SYSCOLPERMS |
| * |
| * This method finds all the SYSCOLPERMS rows for this table. Then it |
| * iterates through each row, either adding a new column to the end of |
| * the table, or dropping a column from the table, as appropriate. It |
| * updates each SYSCOLPERMS row to store the new COLUMNS value. |
| * |
| * @param tableID The UUID of the table being altered |
| * @param tc TransactionController for the transaction |
| * @param columnDescriptor Dropped column info, or null if adding |
| * |
| * @exception StandardException Thrown on error |
| */ |
| private void rewriteSYSCOLPERMSforAlterTable(UUID tableID, |
| TransactionController tc, ColumnDescriptor columnDescriptor) |
| throws StandardException |
| { |
| // In Derby authorization mode, permission catalogs may not be present |
| if (!usesSqlAuthorization) |
| return; |
| |
| /* This method has 2 steps to it. First get all the ColPermsDescriptor |
| for given tableid. And next step is to go back to SYSCOLPERMS to find |
| unique row corresponding to each of ColPermsDescriptor and update the |
| "COLUMNS" column in SYSCOLPERMS. The reason for this 2 step process is |
| that SYSCOLPERMS has a non-unique row on "TABLEID" column and hence |
| we can't get a unique handle on each of the affected row in SYSCOLPERMS |
| using just the "TABLEID" column */ |
| |
| // First get all the ColPermsDescriptor for the given tableid from |
| //SYSCOLPERMS using getDescriptorViaIndex(). |
| List<ColPermsDescriptor> permissionDescriptorsList;//all ColPermsDescriptor for given tableid |
| DataValueDescriptor tableIDOrderable = getIDValueAsCHAR(tableID); |
| TabInfoImpl ti = getNonCoreTI(SYSCOLPERMS_CATALOG_NUM); |
| SYSCOLPERMSRowFactory rf = (SYSCOLPERMSRowFactory) ti.getCatalogRowFactory(); |
| ExecIndexRow keyRow = exFactory.getIndexableRow(1); |
| keyRow.setColumn(1, tableIDOrderable); |
| permissionDescriptorsList = newSList(); |
| getDescriptorViaIndex( |
| SYSCOLPERMSRowFactory.TABLEID_INDEX_NUM, |
| keyRow, |
| (ScanQualifier [][]) null, |
| ti, |
| (TupleDescriptor) null, |
| permissionDescriptorsList, |
| ColPermsDescriptor.class, |
| false); |
| |
| /* Next, using each of the ColPermDescriptor's uuid, get the unique row |
| in SYSCOLPERMS and adjust the "COLUMNS" column in SYSCOLPERMS to |
| accomodate the added or dropped column in the tableid*/ |
| ExecRow curRow; |
| ExecIndexRow uuidKey; |
| // Not updating any indexes on SYSCOLPERMS |
| boolean[] bArray = new boolean[SYSCOLPERMSRowFactory.TOTAL_NUM_OF_INDEXES]; |
| int[] colsToUpdate = {SYSCOLPERMSRowFactory.COLUMNS_COL_NUM}; |
| for (ColPermsDescriptor colPermsDescriptor : permissionDescriptorsList) |
| { |
| removePermEntryInCache(colPermsDescriptor); |
| uuidKey = rf.buildIndexKeyRow(rf.COLPERMSID_INDEX_NUM, colPermsDescriptor); |
| curRow=ti.getRow(tc, uuidKey, rf.COLPERMSID_INDEX_NUM); |
| FormatableBitSet columns = (FormatableBitSet) curRow.getColumn( |
| SYSCOLPERMSRowFactory.COLUMNS_COL_NUM).getObject(); |
| // See whether this is ADD COLUMN or DROP COLUMN. If ADD, then |
| // add a new bit to the bit set. If DROP, then remove the bit |
| // for the dropped column. |
| if (columnDescriptor == null) |
| { |
| int currentLength = columns.getLength(); |
| columns.grow(currentLength+1); |
| } |
| else |
| { |
| FormatableBitSet modifiedColumns=new FormatableBitSet(columns); |
| modifiedColumns.shrink(columns.getLength()-1); |
| // All the bits from 0 ... colPosition-2 are OK. The bits from |
| // colPosition to the end need to be shifted 1 to the left. |
| // The bit for colPosition-1 simply disappears from COLUMNS. |
| // ColumnPosition values count from 1, while bits in the |
| // FormatableBitSet count from 0. |
| for (int i = columnDescriptor.getPosition()-1; |
| i < modifiedColumns.getLength(); |
| i++) |
| { |
| if (columns.isSet(i+1)) |
| modifiedColumns.set(i); |
| else |
| modifiedColumns.clear(i); |
| } |
| columns = modifiedColumns; |
| } |
| curRow.setColumn(SYSCOLPERMSRowFactory.COLUMNS_COL_NUM, |
| new UserType((Object) columns)); |
| ti.updateRow(uuidKey, curRow, |
| SYSCOLPERMSRowFactory.COLPERMSID_INDEX_NUM, |
| bArray, |
| colsToUpdate, |
| tc); |
| } |
| } |
| |
| |
| /** |
| * Remove PermissionsDescriptor from permissions cache if present |
| */ |
| private void removePermEntryInCache(PermissionsDescriptor perm) |
| throws StandardException |
| { |
| // Remove cached permissions entry if present |
| Cacheable cacheEntry = getPermissionsCache().findCached( perm); |
| if (cacheEntry != null) |
| getPermissionsCache().remove(cacheEntry); |
| } |
| |
| /** |
| * Drops all routine permission descriptors for the given routine. |
| * |
| * @param routineID The UUID of the routine from which to drop |
| * all the permission descriptors |
| * @param tc TransactionController for the transaction |
| * |
| * @exception StandardException Thrown on error |
| */ |
| public void dropAllRoutinePermDescriptors(UUID routineID, TransactionController tc) |
| throws StandardException |
| { |
| TabInfoImpl ti = getNonCoreTI(SYSROUTINEPERMS_CATALOG_NUM); |
| SYSROUTINEPERMSRowFactory rf = (SYSROUTINEPERMSRowFactory) ti.getCatalogRowFactory(); |
| DataValueDescriptor routineIdOrderable; |
| ExecRow curRow; |
| PermissionsDescriptor perm; |
| |
| // In Derby authorization mode, permission catalogs may not be present |
| if (!usesSqlAuthorization) |
| return; |
| |
| /* Use tableIDOrderable in both start and stop position for scan. */ |
| routineIdOrderable = getIDValueAsCHAR(routineID); |
| |
| /* Set up the start/stop position for the scan */ |
| ExecIndexRow keyRow = exFactory.getIndexableRow(1); |
| keyRow.setColumn(1, routineIdOrderable); |
| |
| while ((curRow=ti.getRow(tc, keyRow, rf.ALIASID_INDEX_NUM)) != null) |
| { |
| perm = (PermissionsDescriptor)rf.buildDescriptor(curRow, (TupleDescriptor) null, this); |
| removePermEntryInCache(perm); |
| |
| // Build new key based on UUID and drop the entry as we want to drop |
| // only this row |
| ExecIndexRow uuidKey; |
| uuidKey = rf.buildIndexKeyRow(rf.ROUTINEPERMSID_INDEX_NUM, perm); |
| ti.deleteRow(tc, uuidKey, rf.ROUTINEPERMSID_INDEX_NUM); |
| } |
| } |
| |
| |
| /** |
| * @see DataDictionary#dropRoleGrantsByGrantee |
| */ |
| public void dropRoleGrantsByGrantee(String grantee, |
| TransactionController tc) |
| throws StandardException |
| { |
| TabInfoImpl ti = getNonCoreTI(SYSROLES_CATALOG_NUM); |
| SYSROLESRowFactory rf = (SYSROLESRowFactory)ti.getCatalogRowFactory(); |
| |
| visitRoleGrants(ti, |
| rf, |
| rf.SYSROLES_GRANTEE_COLPOS_IN_INDEX_ID_EE_OR, |
| grantee, |
| tc, |
| DataDictionaryImpl.DROP); |
| } |
| |
| |
| /** |
| * Return true if there exists a role grant to authorization |
| * identifier. |
| * |
| * @param grantee authorization identifier |
| * @param tc Transaction Controller |
| * |
| * @return true if there exists such a grant |
| * @exception StandardException Thrown on failure |
| */ |
| private boolean existsRoleGrantByGrantee(String grantee, |
| TransactionController tc) |
| throws StandardException |
| { |
| TabInfoImpl ti = getNonCoreTI(SYSROLES_CATALOG_NUM); |
| SYSROLESRowFactory rf = (SYSROLESRowFactory)ti.getCatalogRowFactory(); |
| |
| return visitRoleGrants(ti, |
| rf, |
| rf.SYSROLES_GRANTEE_COLPOS_IN_INDEX_ID_EE_OR, |
| grantee, |
| tc, |
| DataDictionaryImpl.EXISTS); |
| } |
| |
| |
| /** |
| * @see DataDictionary#dropRoleGrantsByName |
| */ |
| public void dropRoleGrantsByName(String roleName, |
| TransactionController tc) |
| throws StandardException |
| { |
| TabInfoImpl ti = getNonCoreTI(SYSROLES_CATALOG_NUM); |
| SYSROLESRowFactory rf = (SYSROLESRowFactory)ti.getCatalogRowFactory(); |
| |
| visitRoleGrants(ti, |
| rf, |
| rf.SYSROLES_ROLEID_COLPOS_IN_INDEX_ID_EE_OR, |
| roleName, |
| tc, |
| DataDictionaryImpl.DROP); |
| } |
| |
| /** |
| * Scan the {roleid, grantee, grantor} index on SYSROLES, |
| * locate rows containing authId in column columnNo. |
| * |
| * The action argument can be either <code>EXISTS</code> or |
| * <code>DROP</code> (to check for existence, or to drop that row). |
| * |
| * If the scan proves too slow, we should add more indexes. only. |
| * |
| * @param ti <code>TabInfoImpl</code> for SYSROLES. |
| * @param rf row factory for SYSROLES |
| * @param columnNo the column number to match <code>authId</code> against |
| * @param tc transaction controller |
| * @param action drop matching rows (<code>DROP</code>), or return |
| * <code>true</code> if there is a matching row |
| * (<code>EXISTS</code>) |
| * |
| * @return action=EXISTS: return {@code true} if there is a matching row |
| * else return {@code false}. |
| * @exception StandardException |
| */ |
| private boolean visitRoleGrants(TabInfoImpl ti, |
| SYSROLESRowFactory rf, |
| int columnNo, |
| String authId, |
| TransactionController tc, |
| int action) |
| throws StandardException |
| { |
| ConglomerateController heapCC = tc.openConglomerate( |
| ti.getHeapConglomerate(), false, 0, |
| TransactionController.MODE_RECORD, |
| TransactionController.ISOLATION_REPEATABLE_READ); |
| |
| DataValueDescriptor authIdOrderable = new SQLVarchar(authId); |
| ScanQualifier[][] scanQualifier = exFactory.getScanQualifier(1); |
| |
| scanQualifier[0][0].setQualifier( |
| columnNo - 1, /* to zero-based */ |
| authIdOrderable, |
| Orderable.ORDER_OP_EQUALS, |
| false, |
| false, |
| false); |
| |
| ScanController sc = tc.openScan( |
| ti.getIndexConglomerate(rf.SYSROLES_INDEX_ID_EE_OR_IDX), |
| false, // don't hold open across commit |
| 0, // for update |
| TransactionController.MODE_RECORD, |
| TransactionController.ISOLATION_REPEATABLE_READ, |
| (FormatableBitSet) null, // all fields as objects |
| (DataValueDescriptor[]) null, // start position - |
| 0, // startSearchOperation - none |
| scanQualifier, // |
| (DataValueDescriptor[]) null, // stop position -through last row |
| 0); // stopSearchOperation - none |
| |
| try { |
| ExecRow outRow = rf.makeEmptyRow(); |
| ExecIndexRow indexRow = getIndexRowFromHeapRow( |
| ti.getIndexRowGenerator(rf.SYSROLES_INDEX_ID_EE_OR_IDX), |
| heapCC.newRowLocationTemplate(), |
| outRow); |
| |
| while (sc.fetchNext(indexRow.getRowArray())) { |
| if (action == DataDictionaryImpl.EXISTS) { |
| return true; |
| } else if (action == DataDictionaryImpl.DROP) { |
| ti.deleteRow(tc, indexRow, |
| rf.SYSROLES_INDEX_ID_EE_OR_IDX); |
| } |
| } |
| } finally { |
| if (sc != null) { |
| sc.close(); |
| } |
| |
| if (heapCC != null) { |
| heapCC.close(); |
| } |
| } |
| return false; |
| } |
| |
| |
| /** |
| * Return an in-memory representation of the role grant graph (sans |
| * grant of roles to users, only role-role relation. |
| * |
| * @param tc Transaction Controller |
| * @param inverse make graph on inverse grant relation |
| * @return hash map representing role grant graph. |
| * <ul><li>Key: rolename,</li> |
| * <li>Value: List<RoleGrantDescriptor> representing a |
| * grant of that rolename to another role (not user). |
| * </li> |
| * </ul> |
| * |
| * FIXME: Need to cache graph and invalidate when role graph is modified. |
| * Currently, we always read from SYSROLES. |
| */ |
| HashMap<String,List<RoleGrantDescriptor>> getRoleGrantGraph(TransactionController tc, boolean inverse) |
| throws StandardException { |
| |
| HashMap<String,List<RoleGrantDescriptor>> hm = new HashMap<String,List<RoleGrantDescriptor>>(); |
| |
| TabInfoImpl ti = getNonCoreTI(SYSROLES_CATALOG_NUM); |
| SYSROLESRowFactory rf = (SYSROLESRowFactory) ti.getCatalogRowFactory(); |
| |
| DataValueDescriptor isDefOrderable = new SQLVarchar("N"); |
| ScanQualifier[][] scanQualifier = exFactory.getScanQualifier(1); |
| |
| scanQualifier[0][0].setQualifier( |
| SYSROLESRowFactory.SYSROLES_ISDEF - 1, /* to zero-based */ |
| isDefOrderable, |
| Orderable.ORDER_OP_EQUALS, |
| false, |
| false, |
| false); |
| |
| ScanController sc = tc.openScan( |
| ti.getHeapConglomerate(), |
| false, // don't hold open across commit |
| 0, // for update |
| TransactionController.MODE_RECORD, |
| TransactionController.ISOLATION_REPEATABLE_READ, |
| (FormatableBitSet) null, // all fields as objects |
| (DataValueDescriptor[]) null, // start position - |
| 0, // startSearchOperation - none |
| scanQualifier, // |
| (DataValueDescriptor[]) null, // stop position -through last row |
| 0); // stopSearchOperation - none |
| |
| ExecRow outRow = rf.makeEmptyRow(); |
| RoleGrantDescriptor grantDescr; |
| |
| while (sc.fetchNext(outRow.getRowArray())) { |
| grantDescr = (RoleGrantDescriptor)rf.buildDescriptor( |
| outRow, |
| (TupleDescriptor) null, |
| this); |
| |
| // Next call is potentially inefficient. We could read in |
| // definitions first in a separate hash table limiting |
| // this to a 2-pass scan. |
| RoleGrantDescriptor granteeDef = getRoleDefinitionDescriptor |
| (grantDescr.getGrantee()); |
| |
| if (granteeDef == null) { |
| // not a role, must be user authid, skip |
| continue; |
| } |
| |
| String hashKey; |
| if (inverse) { |
| hashKey = granteeDef.getRoleName(); |
| } else { |
| hashKey = grantDescr.getRoleName(); |
| } |
| |
| List<RoleGrantDescriptor> arcs = hm.get(hashKey); |
| if (arcs == null) { |
| arcs = new LinkedList<RoleGrantDescriptor>(); |
| } |
| |
| arcs.add(grantDescr); |
| hm.put(hashKey, arcs); |
| } |
| |
| sc.close(); |
| |
| return hm; |
| |
| } |
| |
| /** |
| * @see DataDictionary#createRoleClosureIterator |
| */ |
| public RoleClosureIterator createRoleClosureIterator |
| (TransactionController tc, |
| String role, |
| boolean inverse |
| ) throws StandardException { |
| |
| return new RoleClosureIteratorImpl(role, inverse, this, tc); |
| } |
| |
| |
| /** |
| * Drop all permission descriptors corresponding to a grant to |
| * the named authentication identifier |
| * |
| * @param authId The authentication identifier |
| * @param tc Transaction Controller |
| * |
| * @exception StandardException Thrown on failure |
| */ |
| public void dropAllPermsByGrantee(String authId, |
| TransactionController tc) |
| throws StandardException |
| { |
| dropPermsByGrantee( |
| authId, |
| tc, |
| SYSTABLEPERMS_CATALOG_NUM, |
| SYSTABLEPERMSRowFactory.GRANTEE_TABLE_GRANTOR_INDEX_NUM, |
| SYSTABLEPERMSRowFactory. |
| GRANTEE_COL_NUM_IN_GRANTEE_TABLE_GRANTOR_INDEX); |
| |
| dropPermsByGrantee( |
| authId, |
| tc, |
| SYSCOLPERMS_CATALOG_NUM, |
| SYSCOLPERMSRowFactory.GRANTEE_TABLE_TYPE_GRANTOR_INDEX_NUM, |
| SYSCOLPERMSRowFactory. |
| GRANTEE_COL_NUM_IN_GRANTEE_TABLE_TYPE_GRANTOR_INDEX); |
| |
| dropPermsByGrantee( |
| authId, |
| tc, |
| SYSROUTINEPERMS_CATALOG_NUM, |
| SYSROUTINEPERMSRowFactory.GRANTEE_ALIAS_GRANTOR_INDEX_NUM, |
| SYSROUTINEPERMSRowFactory. |
| GRANTEE_COL_NUM_IN_GRANTEE_ALIAS_GRANTOR_INDEX); |
| } |
| |
| |
| /** |
| * Presently only used when dropping roles - user dropping is not under |
| * Derby control (well, built-in users are if properties are stored in |
| * database), any permissions granted to users remain in place even if the |
| * user is no more. |
| */ |
| private void dropPermsByGrantee(String authId, |
| TransactionController tc, |
| int catalog, |
| int indexNo, |
| int granteeColnoInIndex) |
| throws StandardException |
| { |
| visitPermsByGrantee(authId, |
| tc, |
| catalog, |
| indexNo, |
| granteeColnoInIndex, |
| DataDictionaryImpl.DROP); |
| } |
| |
| /** |
| * Return true if there exists a permission grant descriptor to this |
| * authorization id. |
| */ |
| private boolean existsPermByGrantee(String authId, |
| TransactionController tc, |
| int catalog, |
| int indexNo, |
| int granteeColnoInIndex) |
| throws StandardException |
| { |
| return visitPermsByGrantee(authId, |
| tc, |
| catalog, |
| indexNo, |
| granteeColnoInIndex, |
| DataDictionaryImpl.EXISTS); |
| } |
| |
| |
| /** |
| * Possible action for visitPermsByGrantee and visitRoleGrants. |
| */ |
| static final int DROP = 0; |
| /** |
| * Possible action for visitPermsByGrantee and visitRoleGrants. |
| */ |
| static final int EXISTS = 1; |
| |
| /** |
| * Scan <code>indexNo</code> index on a permission table |
| * <code>catalog</code>, looking for match(es) for the grantee column |
| * (given by granteeColnoInIndex for the catalog in question). |
| * |
| * The action argument can be either <code>EXISTS</code> or |
| * <code>DROP</code> (to check for existence, or to drop that row). |
| * |
| * There is no index on grantee column only on on any of the |
| * permissions tables, so we use the index which contain grantee |
| * and scan that, setting up a scan qualifier to match the |
| * grantee, then fetch the base row. |
| * |
| * If this proves too slow, we should add an index on grantee |
| * only. |
| * |
| * @param authId grantee to match against |
| * @param tc transaction controller |
| * @param catalog the underlying permission table to visit |
| * @param indexNo the number of the index by which to access the catalog |
| * @param granteeColnoInIndex the column number to match |
| * <code>authId</code> against |
| * @param action drop matching rows (<code>DROP</code>), or return |
| * <code>true</code> if there is a matching row |
| * (<code>EXISTS</code>) |
| * |
| * @return action=EXISTS: return {@code true} if there is a matching row |
| * else return {@code false}. |
| * @exception StandardException |
| */ |
| private boolean visitPermsByGrantee(String authId, |
| TransactionController tc, |
| int catalog, |
| int indexNo, |
| int granteeColnoInIndex, |
| int action) |
| throws StandardException |
| { |
| TabInfoImpl ti = getNonCoreTI(catalog); |
| PermissionsCatalogRowFactory rf = |
| (PermissionsCatalogRowFactory)ti.getCatalogRowFactory(); |
| |
| ConglomerateController heapCC = tc.openConglomerate( |
| ti.getHeapConglomerate(), false, 0, |
| TransactionController.MODE_RECORD, |
| TransactionController.ISOLATION_REPEATABLE_READ); |
| |
| DataValueDescriptor authIdOrderable = new SQLVarchar(authId); |
| ScanQualifier[][] scanQualifier = exFactory.getScanQualifier(1); |
| |
| scanQualifier[0][0].setQualifier( |
| granteeColnoInIndex - 1, /* to zero-based */ |
| authIdOrderable, |
| Orderable.ORDER_OP_EQUALS, |
| false, |
| false, |
| false); |
| |
| ScanController sc = tc.openScan( |
| ti.getIndexConglomerate(indexNo), |
| false, // don't hold open across commit |
| 0, // for update |
| TransactionController.MODE_RECORD, |
| TransactionController.ISOLATION_REPEATABLE_READ, |
| (FormatableBitSet) null, // all fields as objects |
| (DataValueDescriptor[]) null, // start position - |
| 0, // startSearchOperation - none |
| scanQualifier, // |
| (DataValueDescriptor[]) null, // stop position -through last row |
| 0); // stopSearchOperation - none |
| |
| try { |
| ExecRow outRow = rf.makeEmptyRow(); |
| ExecIndexRow indexRow = getIndexRowFromHeapRow( |
| ti.getIndexRowGenerator(indexNo), |
| heapCC.newRowLocationTemplate(), |
| outRow); |
| |
| while (sc.fetchNext(indexRow.getRowArray())) { |
| RowLocation baseRowLocation = (RowLocation)indexRow.getColumn( |
| indexRow.nColumns()); |
| |
| boolean base_row_exists = |
| heapCC.fetch( |
| baseRowLocation, outRow.getRowArray(), |
| (FormatableBitSet)null); |
| |
| if (SanityManager.DEBUG) { |
| // it can not be possible for heap row to |
| // disappear while holding scan cursor on index at |
| // ISOLATION_REPEATABLE_READ. |
| SanityManager.ASSERT(base_row_exists, |
| "base row doesn't exist"); |
| } |
| |
| if (action == DataDictionaryImpl.EXISTS) { |
| return true; |
| } else if (action == DataDictionaryImpl.DROP) { |
| PermissionsDescriptor perm = (PermissionsDescriptor)rf. |
| buildDescriptor(outRow, |
| (TupleDescriptor) null, |
| this); |
| removePermEntryInCache(perm); |
| ti.deleteRow(tc, indexRow, indexNo); |
| } |
| } |
| } finally { |
| if (sc != null) { |
| sc.close(); |
| } |
| |
| if (heapCC != null) { |
| heapCC.close(); |
| } |
| } |
| return false; |
| } |
| |
| |
| /** |
| * Delete the appropriate rows from syscolumns when |
| * dropping 1 or more columns. |
| * |
| * @param tc The TransactionController |
| * @param keyRow Start/stop position. |
| * |
| * @exception StandardException Thrown on failure |
| */ |
| private void dropColumnDescriptorCore( |
| TransactionController tc, |
| ExecIndexRow keyRow) |
| throws StandardException |
| { |
| TabInfoImpl ti = coreInfo[SYSCOLUMNS_CORE_NUM]; |
| |
| ti.deleteRow( tc, keyRow, SYSCOLUMNSRowFactory.SYSCOLUMNS_INDEX1_ID ); |
| } |
| |
| /** |
| * Delete the appropriate rows from systableperms when |
| * dropping a table |
| * |
| * @param tc The TransactionController |
| * @param keyRow Start/stop position. |
| * |
| * @exception StandardException Thrown on failure |
| */ |
| private void dropTablePermDescriptor( |
| TransactionController tc, |
| ExecIndexRow keyRow) |
| throws StandardException |
| { |
| ExecRow curRow; |
| PermissionsDescriptor perm; |
| TabInfoImpl ti = getNonCoreTI(SYSTABLEPERMS_CATALOG_NUM); |
| SYSTABLEPERMSRowFactory rf = (SYSTABLEPERMSRowFactory) ti.getCatalogRowFactory(); |
| |
| while ((curRow=ti.getRow(tc, keyRow, rf.TABLEID_INDEX_NUM)) != null) |
| { |
| perm = (PermissionsDescriptor)rf.buildDescriptor(curRow, (TupleDescriptor) null, this); |
| removePermEntryInCache(perm); |
| |
| // Build key on UUID and drop the entry as we want to drop only this row |
| ExecIndexRow uuidKey; |
| uuidKey = rf.buildIndexKeyRow(rf.TABLEPERMSID_INDEX_NUM, perm); |
| ti.deleteRow(tc, uuidKey, rf.TABLEPERMSID_INDEX_NUM); |
| } |
| } |
| |
| /** |
| * Delete the appropriate rows from syscolperms when |
| * dropping a table |
| * |
| * @param tc The TransactionController |
| * @param keyRow Start/stop position. |
| * |
| * @exception StandardException Thrown on failure |
| */ |
| private void dropColumnPermDescriptor( |
| TransactionController tc, |
| ExecIndexRow keyRow) |
| throws StandardException |
| { |
| ExecRow curRow; |
| PermissionsDescriptor perm; |
| TabInfoImpl ti = getNonCoreTI(SYSCOLPERMS_CATALOG_NUM); |
| SYSCOLPERMSRowFactory rf = (SYSCOLPERMSRowFactory) ti.getCatalogRowFactory(); |
| |
| while ((curRow=ti.getRow(tc, keyRow, rf.TABLEID_INDEX_NUM)) != null) |
| { |
| perm = (PermissionsDescriptor)rf.buildDescriptor(curRow, (TupleDescriptor) null, this); |
| removePermEntryInCache(perm); |
| |
| // Build key on UUID and drop the entry as we want to drop only this row |
| ExecIndexRow uuidKey; |
| uuidKey = rf.buildIndexKeyRow(rf.COLPERMSID_INDEX_NUM, perm); |
| ti.deleteRow(tc, uuidKey, rf.COLPERMSID_INDEX_NUM); |
| } |
| } |
| |
| /** |
| * Update the column descriptor in question. Updates |
| * every row in the base conglomerate. |
| * |
| * @param cd The ColumnDescriptor |
| * @param formerUUID The UUID for this column in SYSCOLUMNS, |
| * may differ from what is in cd if this |
| * is the column that is being set. |
| * @param formerName The name for this column in SYSCOLUMNS |
| * may differ from what is in cd if this |
| * is the column that is being set. |
| * @param colsToSet Array of ints of columns to be modified, |
| * 1 based. May be null (all cols). |
| * @param tc The TransactionController to use |
| * |
| * @exception StandardException Thrown on failure |
| */ |
| private void updateColumnDescriptor(ColumnDescriptor cd, |
| UUID formerUUID, |
| String formerName, |
| int[] colsToSet, |
| TransactionController tc) |
| throws StandardException |
| { |
| ExecIndexRow keyRow1 = null; |
| ExecRow row; |
| DataValueDescriptor refIDOrderable; |
| DataValueDescriptor columnNameOrderable; |
| TabInfoImpl ti = coreInfo[SYSCOLUMNS_CORE_NUM]; |
| SYSCOLUMNSRowFactory rf = (SYSCOLUMNSRowFactory) ti.getCatalogRowFactory(); |
| |
| /* Use objectID/columnName in both start |
| * and stop position for index 1 scan. |
| */ |
| refIDOrderable = getIDValueAsCHAR(formerUUID); |
| columnNameOrderable = new SQLVarchar(formerName); |
| |
| /* Set up the start/stop position for the scan */ |
| keyRow1 = (ExecIndexRow) exFactory.getIndexableRow(2); |
| keyRow1.setColumn(1, refIDOrderable); |
| keyRow1.setColumn(2, columnNameOrderable); |
| |
| // build the row to be stuffed into SYSCOLUMNS. |
| row = rf.makeRow(cd, null); |
| |
| /* |
| ** Figure out if the index in syscolumns needs |
| ** to be updated. |
| */ |
| if (SanityManager.DEBUG) |
| { |
| SanityManager.ASSERT(rf.getNumIndexes() == 2, |
| "There are more indexes on syscolumns than expected, the code herein needs to change"); |
| } |
| |
| boolean[] bArray = new boolean[rf.getNumIndexes()]; |
| |
| /* |
| ** Do we need to update indexes? |
| */ |
| if (colsToSet == null) |
| { |
| bArray[0] = true; |
| bArray[1] = true; |
| } |
| else |
| { |
| /* |
| ** Check the specific columns for indexed |
| ** columns. |
| */ |
| for (int i = 0; i < colsToSet.length; i++) |
| { |
| if ((colsToSet[i] == rf.SYSCOLUMNS_COLUMNNAME) || |
| (colsToSet[i] == rf.SYSCOLUMNS_REFERENCEID)) |
| { |
| bArray[0] = true; |
| break; |
| } |
| else if (colsToSet[i] == rf.SYSCOLUMNS_COLUMNDEFAULTID) |
| { |
| bArray[1] = true; |
| break; |
| } |
| } |
| } |
| |
| ti.updateRow(keyRow1, row, |
| SYSCOLUMNSRowFactory.SYSCOLUMNS_INDEX1_ID, |
| bArray, |
| colsToSet, |
| tc); |
| } |
| |
| /** |
| * Gets the viewDescriptor for the view with the given UUID. |
| * |
| * @param uuid The UUID for the view |
| * |
| * @return A descriptor for the view |
| * |
| * @exception StandardException Thrown on error |
| */ |
| public ViewDescriptor getViewDescriptor(UUID uuid) |
| throws StandardException |
| { |
| return getViewDescriptor(getTableDescriptor(uuid)); |
| } |
| |
| /** |
| * Gets the viewDescriptor for the view given the TableDescriptor. |
| * |
| * @param td The TableDescriptor for the view. |
| * |
| * @return A descriptor for the view |
| * |
| * @exception StandardException Thrown on error |
| */ |
| public ViewDescriptor getViewDescriptor(TableDescriptor td) |
| throws StandardException |
| { |
| TableDescriptor tdi = (TableDescriptor) td; |
| |
| /* See if the view info is cached */ |
| if (tdi.getViewDescriptor() != null) |
| { |
| return tdi.getViewDescriptor(); |
| } |
| |
| synchronized(tdi) |
| { |
| /* See if we were waiting on someone who just filled it in */ |
| if (tdi.getViewDescriptor() != null) |
| { |
| return tdi.getViewDescriptor(); |
| } |
| |
| tdi.setViewDescriptor((ViewDescriptor) getViewDescriptorScan(tdi)); |
| } |
| return tdi.getViewDescriptor(); |
| } |
| |
| /** |
| * Get the information for the view from sys.sysviews. |
| * |
| * @param tdi The TableDescriptor for the view. |
| * |
| * @return ViewDescriptor The ViewDescriptor for the view. |
| * |
| * @exception StandardException Thrown on error |
| */ |
| private ViewDescriptor getViewDescriptorScan(TableDescriptor tdi) |
| throws StandardException |
| { |
| ViewDescriptor vd; |
| DataValueDescriptor viewIdOrderable; |
| TabInfoImpl ti = getNonCoreTI(SYSVIEWS_CATALOG_NUM); |
| UUID viewID = tdi.getUUID(); |
| |
| /* Use viewIdOrderable in both start |
| * and stop position for scan. |
| */ |
| viewIdOrderable = getIDValueAsCHAR(viewID); |
| |
| /* Set up the start/stop position for the scan */ |
| ExecIndexRow keyRow = exFactory.getIndexableRow(1); |
| keyRow.setColumn(1, viewIdOrderable); |
| |
| vd = getDescriptorViaIndex( |
| SYSVIEWSRowFactory.SYSVIEWS_INDEX1_ID, |
| keyRow, |
| (ScanQualifier [][]) null, |
| ti, |
| (TupleDescriptor) null, |
| (List<TupleDescriptor>) null, |
| ViewDescriptor.class, |
| false); |
| |
| if (vd != null) |
| { |
| vd.setViewName(tdi.getName()); |
| } |
| return vd; |
| } |
| |
| /** |
| * Drops the view descriptor from the data dictionary. |
| * |
| * @param vd A descriptor for the view to be dropped |
| * @param tc TransactionController to use |
| * |
| * @exception StandardException Thrown on error |
| */ |
| public void dropViewDescriptor(ViewDescriptor vd, |
| TransactionController tc) |
| throws StandardException |
| { |
| DataValueDescriptor viewIdOrderable; |
| TabInfoImpl ti = getNonCoreTI(SYSVIEWS_CATALOG_NUM); |
| |
| /* Use aliasNameOrderable in both start |
| * and stop position for scan. |
| */ |
| viewIdOrderable = getIDValueAsCHAR(vd.getUUID()); |
| |
| /* Set up the start/stop position for the scan */ |
| ExecIndexRow keyRow = (ExecIndexRow) exFactory.getIndexableRow(1); |
| keyRow.setColumn(1, viewIdOrderable); |
| |
| ti.deleteRow( tc, keyRow, SYSVIEWSRowFactory.SYSVIEWS_INDEX1_ID ); |
| |
| } |
| |
| /** |
| * Scan sysfiles_index2 (id) for a match. |
| * @return TableDescriptor The matching descriptor, or null. |
| * @exception StandardException Thrown on failure |
| */ |
| private FileInfoDescriptor |
| getFileInfoDescriptorIndex2Scan(UUID id) |
| throws StandardException |
| { |
| DataValueDescriptor idOrderable; |
| TabInfoImpl ti = getNonCoreTI(SYSFILES_CATALOG_NUM); |
| idOrderable = getIDValueAsCHAR(id); |
| |
| /* Set up the start/stop position for the scan */ |
| ExecIndexRow keyRow = exFactory.getIndexableRow(1); |
| keyRow.setColumn(1, idOrderable); |
| |
| return getDescriptorViaIndex( |
| SYSFILESRowFactory.SYSFILES_INDEX2_ID, |
| keyRow, |
| (ScanQualifier [][]) null, |
| ti, |
| (TupleDescriptor) null, |
| (List<TupleDescriptor>) null, |
| FileInfoDescriptor.class, |
| false); |
| } |
| |
| /** |
| * @see DataDictionary#getFileInfoDescriptor |
| * @exception StandardException Thrown on failure |
| */ |
| public FileInfoDescriptor getFileInfoDescriptor(UUID id) |
| throws StandardException |
| { |
| return getFileInfoDescriptorIndex2Scan(id); |
| } |
| |
| |
| /** |
| * Scan sysfiles_index1 (schemaid,name) for a match. |
| * @return The matching descriptor or null. |
| * @exception StandardException Thrown on failure |
| */ |
| private FileInfoDescriptor getFileInfoDescriptorIndex1Scan( |
| UUID schemaId, |
| String name) |
| throws StandardException |
| { |
| DataValueDescriptor schemaIDOrderable; |
| DataValueDescriptor nameOrderable; |
| TabInfoImpl ti = getNonCoreTI(SYSFILES_CATALOG_NUM); |
| |
| nameOrderable = new SQLVarchar(name); |
| schemaIDOrderable = getIDValueAsCHAR(schemaId); |
| |
| /* Set up the start/stop position for the scan */ |
| ExecIndexRow keyRow = exFactory.getIndexableRow(2); |
| keyRow.setColumn(1, nameOrderable); |
| keyRow.setColumn(2, schemaIDOrderable); |
| FileInfoDescriptor r = getDescriptorViaIndex( |
| SYSFILESRowFactory.SYSFILES_INDEX1_ID, |
| keyRow, |
| (ScanQualifier [][]) null, |
| ti, |
| (TupleDescriptor) null, |
| (List<TupleDescriptor>) null, |
| FileInfoDescriptor.class, |
| false); |
| return r; |
| } |
| |
| /** |
| * @see DataDictionary#getFileInfoDescriptor |
| * @exception StandardException Thrown on failure |
| */ |
| public FileInfoDescriptor getFileInfoDescriptor(SchemaDescriptor sd, String name) |
| throws StandardException |
| { |
| return getFileInfoDescriptorIndex1Scan(sd.getUUID(),name); |
| } |
| |
| /** |
| * @see DataDictionary#dropFileInfoDescriptor |
| * @exception StandardException Thrown on error |
| */ |
| public void dropFileInfoDescriptor(FileInfoDescriptor fid) |
| throws StandardException |
| { |
| ExecIndexRow keyRow1 = null; |
| DataValueDescriptor idOrderable; |
| TabInfoImpl ti = getNonCoreTI(SYSFILES_CATALOG_NUM); |
| TransactionController tc = getTransactionExecute(); |
| |
| /* Use tableIdOrderable and schemaIdOrderable in both start |
| * and stop position for index 1 scan. |
| */ |
| idOrderable = getIDValueAsCHAR(fid.getUUID()); |
| |
| /* Set up the start/stop position for the scan */ |
| keyRow1 = (ExecIndexRow) exFactory.getIndexableRow(1); |
| keyRow1.setColumn(1, idOrderable); |
| ti.deleteRow( tc, keyRow1, SYSFILESRowFactory.SYSFILES_INDEX2_ID ); |
| } |
| |
| /** |
| * Get a SPSDescriptor given its UUID. |
| * |
| * @param uuid The UUID |
| * |
| * @return The SPSDescriptor for the constraint. |
| * |
| * @exception StandardException Thrown on failure |
| */ |
| public SPSDescriptor getSPSDescriptor(UUID uuid) |
| throws StandardException |
| { |
| SPSDescriptor sps; |
| |
| /* Make sure that non-core info is initialized */ |
| getNonCoreTI(SYSSTATEMENTS_CATALOG_NUM); |
| |
| /* Only use the cache if we're in compile-only mode */ |
| if ((spsNameCache != null) && |
| (getCacheMode() == DataDictionary.COMPILE_ONLY_MODE)) |
| { |
| sps = spsIdHash.get(uuid); |
| if (sps != null) |
| { |
| //System.out.println("found in hash table "); |
| // System.out.println("stmt text " + sps.getText()); |
| |
| return sps; |
| } |
| |
| sps = getSPSDescriptorIndex2Scan(uuid.toString()); |
| TableKey stmtKey = new TableKey(sps.getSchemaDescriptor().getUUID(), sps.getName()); |
| try |
| { |
| SPSNameCacheable cacheEntry = (SPSNameCacheable)spsNameCache.create(stmtKey, sps); |
| spsNameCache.release(cacheEntry); |
| } catch (StandardException se) |
| { |
| /* |
| ** If the error is that the item is already |
| ** in the cache, then that is ok. |
| */ |
| if (SQLState.OBJECT_EXISTS_IN_CACHE.equals(se.getMessageId())) |
| { |
| return sps; |
| } |
| else |
| { |
| throw se; |
| } |
| } |
| |
| } |
| else |
| { |
| sps = getSPSDescriptorIndex2Scan(uuid.toString()); |
| } |
| |
| return sps; |
| } |
| |
| /** |
| Add an entry to the hashtables for lookup from the cache. |
| */ |
| void spsCacheEntryAdded(SPSDescriptor spsd) |
| { |
| spsIdHash.put(spsd.getUUID(), spsd); |
| // spsTextHash.put(spsd.getText(), spsd); |
| } |
| |
| void spsCacheEntryRemoved(SPSDescriptor spsd) { |
| spsIdHash.remove(spsd.getUUID()); |
| // spsTextHash.remove(spsd.getText()); |
| } |
| |
| //public SPSDescriptor getSPSBySQLText(String text) { |
| |
| // return (SPSDescriptor) spsTextHash.get(text); |
| //} |
| |
| /** |
| * This method can get called from the DataDictionary cache. |
| * |
| * @param stmtKey The TableKey of the sps |
| * |
| * @return The descriptor for the sps, null if the sps does |
| * not exist. |
| * |
| * @exception StandardException Thrown on failure |
| */ |
| SPSDescriptor getUncachedSPSDescriptor(TableKey stmtKey) |
| throws StandardException |
| { |
| return getSPSDescriptorIndex1Scan(stmtKey.getTableName(), |
| stmtKey.getSchemaId().toString()); |
| } |
| |
| /** |
| * This method can get called from the DataDictionary cache. |
| * |
| * @param stmtId The UUID of the stmt to get the descriptor for |
| * |
| * @return The descriptor for the stmt, null if the table does |
| * not exist. |
| * |
| * @exception StandardException Thrown on failure |
| */ |
| protected SPSDescriptor getUncachedSPSDescriptor(UUID stmtId) |
| throws StandardException |
| { |
| return getSPSDescriptorIndex2Scan(stmtId.toString()); |
| } |
| |
| /** |
| * Scan sysstatements_index2 (stmtid) for a match. |
| * Note that we do not do a lookup of parameter info. |
| * |
| * @return SPSDescriptor The matching descriptor, if any. |
| * |
| * @exception StandardException Thrown on failure |
| */ |
| private SPSDescriptor getSPSDescriptorIndex2Scan( |
| String stmtUUID) |
| throws StandardException |
| { |
| DataValueDescriptor stmtIDOrderable; |
| TabInfoImpl ti = getNonCoreTI(SYSSTATEMENTS_CATALOG_NUM); |
| |
| /* Use stmtIdOrderable in both start |
| * and stop position for scan. |
| */ |
| stmtIDOrderable = new SQLChar(stmtUUID); |
| |
| /* Set up the start/stop position for the scan */ |
| ExecIndexRow keyRow = exFactory.getIndexableRow(1); |
| keyRow.setColumn(1, stmtIDOrderable); |
| |
| SPSDescriptor spsd = getDescriptorViaIndex( |
| SYSSTATEMENTSRowFactory.SYSSTATEMENTS_INDEX1_ID, |
| keyRow, |
| (ScanQualifier [][]) null, |
| ti, |
| (TupleDescriptor) null, |
| (List<TupleDescriptor>) null, |
| SPSDescriptor.class, |
| false); |
| |
| return spsd; |
| } |
| |
| /** |
| * Get a SPSDescriptor given its name. |
| * Currently no cacheing. With caching |
| * we need to be very careful about invalidation. |
| * No caching means invalidations block on |
| * existing SPSD instances (since they were read in |
| * |
| * @param stmtName the statement name |
| * @param sd The SchemaDescriptor |
| * |
| * @return The SPSDescriptor for the constraint. |
| * |
| * @exception StandardException Thrown on failure |
| */ |
| public SPSDescriptor getSPSDescriptor(String stmtName, SchemaDescriptor sd) |
| throws StandardException |
| { |
| SPSDescriptor sps = null; |
| TableKey stmtKey; |
| UUID schemaUUID; |
| |
| /* |
| ** If we didn't get a schema descriptor, we had better |
| ** have a system table. |
| */ |
| if (SanityManager.DEBUG) |
| { |
| if (sd == null) |
| { |
| SanityManager.THROWASSERT("null schema for statement "+stmtName); |
| } |
| } |
| |
| schemaUUID = sd.getUUID(); |
| |
| /* Only use the cache if we're in compile-only mode */ |
| if ((spsNameCache != null) && |
| (getCacheMode() == DataDictionary.COMPILE_ONLY_MODE)) |
| { |
| stmtKey = new TableKey(schemaUUID, stmtName); |
| SPSNameCacheable cacheEntry = (SPSNameCacheable) spsNameCache.find(stmtKey); |
| if (cacheEntry != null) |
| { |
| sps = cacheEntry.getSPSDescriptor(); |
| spsNameCache.release(cacheEntry); |
| } |
| //System.out.println("found in cache " + stmtName); |
| //System.out.println("stmt text " + sps.getText()); |
| return sps; |
| } |
| |
| return getSPSDescriptorIndex1Scan(stmtName, schemaUUID.toString()); |
| } |
| |
| /** |
| * Scan sysschemas_index1 (stmtname, schemaid) for a match. |
| * |
| * @return SPSDescriptor The matching descriptor, if any. |
| * |
| * @exception StandardException Thrown on failure |
| */ |
| private SPSDescriptor getSPSDescriptorIndex1Scan( |
| String stmtName, |
| String schemaUUID) |
| throws StandardException |
| { |
| DataValueDescriptor schemaIDOrderable; |
| DataValueDescriptor stmtNameOrderable; |
| TabInfoImpl ti = getNonCoreTI(SYSSTATEMENTS_CATALOG_NUM); |
| |
| /* Use stmtNameOrderable and schemaIdOrderable in both start |
| * and stop position for scan. |
| */ |
| stmtNameOrderable = new SQLVarchar(stmtName); |
| schemaIDOrderable = new SQLChar(schemaUUID); |
| |
| /* Set up the start/stop position for the scan */ |
| ExecIndexRow keyRow = exFactory.getIndexableRow(2); |
| keyRow.setColumn(1, stmtNameOrderable); |
| keyRow.setColumn(2, schemaIDOrderable); |
| |
| SPSDescriptor spsd = getDescriptorViaIndex( |
| SYSSTATEMENTSRowFactory.SYSSTATEMENTS_INDEX2_ID, |
| keyRow, |
| (ScanQualifier [][]) null, |
| ti, |
| (TupleDescriptor) null, |
| (List<TupleDescriptor>) null, |
| SPSDescriptor.class, |
| false); |
| |
| /* |
| ** Set up the parameter defaults. We are only |
| ** doing this when we look up by name because |
| ** this is the only time we cache, and it can |
| ** be foolish to look up the parameter defaults |
| ** for someone that doesn't need them. |
| */ |
| if (spsd != null) |
| { |
| List<DataValueDescriptor> tmpDefaults = new ArrayList<DataValueDescriptor>(); |
| spsd.setParams(getSPSParams(spsd, tmpDefaults)); |
| Object[] defaults = tmpDefaults.toArray(); |
| spsd.setParameterDefaults(defaults); |
| } |
| |
| return spsd; |
| } |
| |
| /** |
| * Adds the given SPSDescriptor to the data dictionary, |
| * associated with the given table and constraint type. |
| * |
| * @param descriptor The descriptor to add |
| * @param tc The transaction controller |
| * |
| * @exception StandardException Thrown on error |
| */ |
| public void addSPSDescriptor |
| ( |
| SPSDescriptor descriptor, |
| TransactionController tc |
| ) throws StandardException |
| { |
| ExecRow row; |
| TabInfoImpl ti = getNonCoreTI(SYSSTATEMENTS_CATALOG_NUM); |
| SYSSTATEMENTSRowFactory rf = (SYSSTATEMENTSRowFactory) ti.getCatalogRowFactory(); |
| int insertRetCode; |
| |
| /* |
| ** We must make sure the descriptor is locked |
| ** while we are writing it out. Otherwise, |
| ** the descriptor could be invalidated while |
| ** we are writing. |
| */ |
| synchronized(descriptor) |
| { |
| // build the row to be stuffed into SYSSTATEMENTS. this will stuff an |
| // UUID into the descriptor |
| boolean compileMe = descriptor.initiallyCompilable(); |
| row = rf.makeSYSSTATEMENTSrow(compileMe, descriptor); |
| |
| // insert row into catalog and all its indices |
| insertRetCode = ti.insertRow(row, tc); |
| } |
| |
| // Throw an exception duplicate table descriptor |
| if (insertRetCode != TabInfoImpl.ROWNOTDUPLICATE) |
| { |
| throw StandardException.newException(SQLState.LANG_OBJECT_ALREADY_EXISTS_IN_OBJECT, |
| descriptor.getDescriptorType(), |
| descriptor.getDescriptorName(), |
| descriptor.getSchemaDescriptor().getDescriptorType(), |
| descriptor.getSchemaDescriptor().getSchemaName()); |
| } |
| |
| addSPSParams(descriptor, tc); |
| } |
| |
| /** |
| * Add a column in SYS.SYSCOLUMNS for each parameter in the |
| * parameter list. |
| */ |
| private void addSPSParams(SPSDescriptor spsd, TransactionController tc) |
| throws StandardException |
| { |
| UUID uuid = spsd.getUUID(); |
| DataTypeDescriptor[] params = spsd.getParams(); |
| Object[] parameterDefaults = spsd.getParameterDefaults(); |
| |
| if (params == null) |
| return; |
| |
| /* Create the columns */ |
| int pdlSize = params.length; |
| for (int index = 0; index < pdlSize; index++) |
| { |
| int parameterId = index + 1; |
| |
| //RESOLVEAUTOINCREMENT |
| ColumnDescriptor cd = |
| new ColumnDescriptor( |
| "PARAM" + parameterId, |
| parameterId, // position |
| params[index], |
| ((parameterDefaults == null) || // default |
| (index >= parameterDefaults.length)) ? |
| (DataValueDescriptor)null : |
| (DataValueDescriptor)parameterDefaults[index], |
| (DefaultInfo) null, |
| uuid, |
| (UUID) null, 0, 0, 0); |
| |
| addDescriptor(cd, null, SYSCOLUMNS_CATALOG_NUM, |
| false, // no chance of duplicates here |
| tc); |
| } |
| } |
| |
| /** |
| * Get all the parameter descriptors for an SPS. |
| * Look up the params in SYSCOLUMNS and turn them |
| * into parameter descriptors. |
| * |
| * @param spsd sps descriptor |
| * @param defaults list for storing column defaults |
| * |
| * @return array of data type descriptors |
| * |
| * @exception StandardException Thrown on error |
| */ |
| public DataTypeDescriptor[] getSPSParams(SPSDescriptor spsd, List<DataValueDescriptor> defaults) |
| throws StandardException |
| { |
| ColumnDescriptorList cdl = new ColumnDescriptorList(); |
| getColumnDescriptorsScan(spsd.getUUID(), cdl, spsd); |
| |
| int cdlSize = cdl.size(); |
| DataTypeDescriptor[] params = new DataTypeDescriptor[cdlSize]; |
| for (int index = 0; index < cdlSize; index++) |
| { |
| ColumnDescriptor cd = (ColumnDescriptor) cdl.elementAt(index); |
| params[index] = cd.getType(); |
| if (defaults != null) { |
| defaults.add(cd.getDefaultValue()); |
| } |
| } |
| |
| return params; |
| } |
| |
| /** |
| * Updates SYS.SYSSTATEMENTS with the info from the |
| * SPSD. |
| * |
| * @param spsd The descriptor to add |
| * @param tc The transaction controller |
| * @param recompile Whether to recompile or invalidate |
| * |
| * @exception StandardException Thrown on error |
| */ |
| @Override |
| public void updateSPS( |
| SPSDescriptor spsd, |
| TransactionController tc, |
| boolean recompile) |
| throws StandardException |
| { |
| ExecIndexRow keyRow1 = null; |
| ExecRow row; |
| DataValueDescriptor idOrderable; |
| TabInfoImpl ti = getNonCoreTI(SYSSTATEMENTS_CATALOG_NUM); |
| SYSSTATEMENTSRowFactory rf = (SYSSTATEMENTSRowFactory) ti.getCatalogRowFactory(); |
| int[] updCols; |
| if (recompile) |
| { |
| updCols = new int[] { |
| SYSSTATEMENTSRowFactory.SYSSTATEMENTS_VALID, |
| SYSSTATEMENTSRowFactory.SYSSTATEMENTS_TEXT, |
| SYSSTATEMENTSRowFactory.SYSSTATEMENTS_LASTCOMPILED, |
| SYSSTATEMENTSRowFactory.SYSSTATEMENTS_USINGTEXT, |
| SYSSTATEMENTSRowFactory.SYSSTATEMENTS_CONSTANTSTATE, |
| }; |
| } |
| else |
| { |
| // This is an invalidation request. Update the VALID column (to |
| // false) and clear the plan stored in the CONSTANTSTATE column. |
| updCols = new int[] { |
| SYSSTATEMENTSRowFactory.SYSSTATEMENTS_VALID, |
| SYSSTATEMENTSRowFactory.SYSSTATEMENTS_CONSTANTSTATE, |
| }; |
| } |
| |
| idOrderable = getIDValueAsCHAR(spsd.getUUID()); |
| |
| /* Set up the start/stop position for the scan */ |
| keyRow1 = (ExecIndexRow) exFactory.getIndexableRow(1); |
| keyRow1.setColumn(1, idOrderable); |
| |
| row = rf.makeSYSSTATEMENTSrow(false, // don't compile |
| spsd); |
| |
| /* |
| ** Not updating any indexes |
| */ |
| boolean[] bArray = new boolean[2]; |
| |
| /* |
| ** Partial update |
| */ |
| ti.updateRow(keyRow1, row, |
| SYSSTATEMENTSRowFactory.SYSSTATEMENTS_INDEX1_ID, |
| bArray, |
| updCols, |
| tc); |
| |
| |
| // If this is an invalidation request, we don't need to update the |
| // parameter descriptors, so we are done. |
| if (!recompile) |
| { |
| return; |
| } |
| |
| /* |
| ** Set the defaults and datatypes for the parameters, if |
| ** there are parameters. |
| */ |
| DataTypeDescriptor[] params = spsd.getParams(); |
| if (params == null) |
| { |
| return; |
| } |
| |
| // Update the parameter descriptors by dropping the existing ones |
| // and recreating them. If this is the first time the SPS is being |
| // compiled, the drop operation will be a no-op. |
| dropAllColumnDescriptors(spsd.getUUID(), tc); |
| addSPSParams(spsd, tc); |
| } |
| |
| /** |
| * @see DataDictionary#invalidateAllSPSPlans |
| * @exception StandardException Thrown on error |
| */ |
| public void invalidateAllSPSPlans() throws StandardException |
| { |
| LanguageConnectionContext lcc = (LanguageConnectionContext) |
| getContext(LanguageConnectionContext.CONTEXT_ID); |
| invalidateAllSPSPlans(lcc); |
| } |
| |
| /** |
| * @see DataDictionary#invalidateAllSPSPlans |
| * @exception StandardException Thrown on error |
| */ |
| public void invalidateAllSPSPlans(LanguageConnectionContext lcc) throws StandardException |
| { |
| startWriting(lcc); |
| |
| for (SPSDescriptor spsd : getAllSPSDescriptors()) |
| { |
| spsd.makeInvalid(DependencyManager.USER_RECOMPILE_REQUEST, lcc); |
| } |
| } |
| |
| |
| /** |
| * Mark all SPS plans in the data dictionary invalid. This does |
| * not invalidate cached plans. This function is for use by |
| * the boot-up code. |
| * @exception StandardException Thrown on error |
| */ |
| void clearSPSPlans() throws StandardException |
| { |
| TabInfoImpl ti = getNonCoreTI(SYSSTATEMENTS_CATALOG_NUM); |
| faultInTabInfo(ti); |
| |
| TransactionController tc = getTransactionExecute(); |
| |
| FormatableBitSet columnToReadSet = new FormatableBitSet(SYSSTATEMENTSRowFactory.SYSSTATEMENTS_COLUMN_COUNT); |
| FormatableBitSet columnToUpdateSet = new FormatableBitSet(SYSSTATEMENTSRowFactory.SYSSTATEMENTS_COLUMN_COUNT); |
| columnToUpdateSet.set(SYSSTATEMENTSRowFactory.SYSSTATEMENTS_VALID -1); |
| columnToUpdateSet.set(SYSSTATEMENTSRowFactory.SYSSTATEMENTS_CONSTANTSTATE -1); |
| |
| DataValueDescriptor[] replaceRow = |
| new DataValueDescriptor[SYSSTATEMENTSRowFactory.SYSSTATEMENTS_COLUMN_COUNT]; |
| |
| /* Set up a couple of row templates for fetching CHARS */ |
| |
| replaceRow[SYSSTATEMENTSRowFactory.SYSSTATEMENTS_VALID - 1] = |
| new SQLBoolean(false); |
| replaceRow[SYSSTATEMENTSRowFactory.SYSSTATEMENTS_CONSTANTSTATE - 1] = |
| new UserType((Object) null); |
| |
| /* Scan the entire heap */ |
| ScanController sc = |
| tc.openScan( |
| ti.getHeapConglomerate(), |
| false, |
| TransactionController.OPENMODE_FORUPDATE, |
| TransactionController.MODE_TABLE, |
| TransactionController.ISOLATION_REPEATABLE_READ, |
| columnToReadSet, |
| (DataValueDescriptor[]) null, |
| ScanController.NA, |
| (Qualifier[][]) null, |
| (DataValueDescriptor[]) null, |
| ScanController.NA); |
| |
| while (sc.fetchNext((DataValueDescriptor[]) null)) |
| { |
| /* Replace the column in the table */ |
| sc.replace(replaceRow, columnToUpdateSet); |
| } |
| |
| sc.close(); |
| } |
| |
| /** |
| * Drops the given SPSDescriptor. |
| * |
| * @param descriptor The descriptor to drop |
| * @param tc The TransactionController. |
| * |
| * @exception StandardException Thrown on failure |
| */ |
| public void dropSPSDescriptor(SPSDescriptor descriptor, |
| TransactionController tc) |
| throws StandardException |
| { |
| dropSPSDescriptor(descriptor.getUUID(), tc); |
| } |
| |
| /** |
| * Drops the given SPSDescriptor. |
| * |
| * @param uuid the statement uuid |
| * @param tc The TransactionController. |
| * |
| * @exception StandardException Thrown on failure |
| */ |
| public void dropSPSDescriptor |
| ( |
| UUID uuid, |
| TransactionController tc |
| ) throws StandardException |
| { |
| DataValueDescriptor stmtIdOrderable; |
| TabInfoImpl ti = getNonCoreTI(SYSSTATEMENTS_CATALOG_NUM); |
| |
| stmtIdOrderable = getIDValueAsCHAR(uuid); |
| |
| /* Set up the start/stop position for the scan */ |
| ExecIndexRow keyRow = (ExecIndexRow) exFactory.getIndexableRow(1); |
| keyRow.setColumn(1, stmtIdOrderable); |
| |
| ti.deleteRow( tc, keyRow, SYSSTATEMENTSRowFactory.SYSSTATEMENTS_INDEX1_ID ); |
| |
| /* drop all columns in SYSCOLUMNS */ |
| dropAllColumnDescriptors(uuid, tc); |
| } |
| |
| /** |
| * Get every statement in this database. |
| * Return the SPSDescriptors in an list. |
| * The returned descriptors don't contain the compiled statement, so it |
| * it safe to call this method during upgrade when it isn't known if the |
| * saved statement can still be deserialized with the new version. |
| * |
| * @return the list of descriptors |
| * |
| * @exception StandardException Thrown on failure |
| */ |
| public List<SPSDescriptor> getAllSPSDescriptors() |
| throws StandardException |
| { |
| TabInfoImpl ti = getNonCoreTI(SYSSTATEMENTS_CATALOG_NUM); |
| |
| List<SPSDescriptor> list = newSList(); |
| |
| // DERBY-3870: The compiled plan may not be possible to deserialize |
| // during upgrade. Skip the column that contains the compiled plan to |
| // prevent deserialization errors when reading the rows. We don't care |
| // about the value in that column, since this method is only called |
| // when we want to drop or invalidate rows in SYSSTATEMENTS. |
| FormatableBitSet cols = new FormatableBitSet( |
| ti.getCatalogRowFactory().getHeapColumnCount()); |
| for (int i = 0; i < cols.size(); i++) { |
| if (i + 1 == SYSSTATEMENTSRowFactory.SYSSTATEMENTS_CONSTANTSTATE) { |
| cols.clear(i); |
| } else { |
| cols.set(i); |
| } |
| } |
| |
| getDescriptorViaHeap( |
| cols, |
| (ScanQualifier[][]) null, |
| ti, |
| (TupleDescriptor) null, |
| list, |
| SPSDescriptor.class); |
| |
| return list; |
| |
| } |
| |
| /** |
| * Get every constraint in this database. |
| * Note that this list of ConstraintDescriptors is |
| * not going to be the same objects that are typically |
| * cached off of the table descriptors, so this will |
| * most likely instantiate some duplicate objects. |
| * |
| * @return the list of descriptors |
| * |
| * @exception StandardException Thrown on failure |
| */ |
| private ConstraintDescriptorList getAllConstraintDescriptors() |
| throws StandardException |
| { |
| TabInfoImpl ti = getNonCoreTI(SYSCONSTRAINTS_CATALOG_NUM); |
| |
| ConstraintDescriptorList list = new ConstraintDescriptorList(); |
| |
| getConstraintDescriptorViaHeap( |
| (ScanQualifier[][]) null, |
| ti, |
| (TupleDescriptor) null, |
| list); |
| return list; |
| } |
| |
| /** |
| * Get the trigger action string associated with the trigger after the |
| * references to old/new transition tables/variables in trigger action |
| * sql provided by CREATE TRIGGER have been transformed eg |
| * DELETE FROM t WHERE c = old.c |
| * turns into |
| * DELETE FROM t WHERE c = org.apache.derby.iapi.db.Factory:: |
| * getTriggerExecutionContext().getOldRow(). |
| * getInt(columnNumberFor'C'inRuntimeResultset) |
| * or |
| * DELETE FROM t WHERE c in (SELECT c FROM OLD) |
| * turns into |
| * DELETE FROM t WHERE c in |
| * (SELECT c FROM new TriggerOldTransitionTable OLD) |
| * |
| * @param actionStmt This is needed to get access to the various nodes |
| * generated by the Parser for the trigger action sql. These nodes will be |
| * used to find REFERENCEs column nodes. |
| * |
| * @param oldReferencingName The name specified by the user for REFERENCEs |
| * to old row columns |
| * |
| * @param newReferencingName The name specified by the user for REFERENCEs |
| * to new row columns |
| * |
| * @param triggerDefinition The original trigger action text provided by |
| * the user during CREATE TRIGGER time. |
| * |
| * @param referencedCols Trigger is defined on these columns (will be null |
| * in case of INSERT AND DELETE Triggers. Can also be null for DELETE |
| * Triggers if UPDATE trigger is not defined on specific column(s)) |
| * |
| * @param referencedColsInTriggerAction what columns does the trigger |
| * action reference through old/new transition variables (may be null) |
| * |
| * @param actionOffset offset of start of action clause |
| * |
| * @param triggerTableDescriptor Table descriptor for trigger table |
| * |
| * @param triggerEventMask TriggerDescriptor.TRIGGER_EVENT_XXX |
| * |
| * @param createTriggerTime True if here for CREATE TRIGGER, |
| * false if here because an invalidated row level trigger with |
| * REFERENCEd columns has been fired and hence trigger action |
| * sql associated with SPSDescriptor may be invalid too. |
| * |
| * @return Transformed trigger action sql |
| * @throws StandardException |
| */ |
| public int[] examineTriggerNodeAndCols( |
| Visitable actionStmt, |
| String oldReferencingName, |
| String newReferencingName, |
| String triggerDefinition, |
| int[] referencedCols, |
| int[] referencedColsInTriggerAction, |
| int actionOffset, |
| TableDescriptor triggerTableDescriptor, |
| int triggerEventMask, |
| boolean createTriggerTime, |
| List<int[]> replacements |
| ) throws StandardException |
| { |
| // If we are dealing with database created in 10.8 and prior, |
| // then we must be in soft upgrade mode. For such databases, |
| // we want to generate trigger action sql which assumes that |
| // all columns are getting read from the trigger table. We |
| // need to do this to maintain backward compatibility. |
| boolean in10_9_orHigherVersion = checkVersion(DataDictionary.DD_VERSION_DERBY_10_9,null); |
| |
| StringBuilder newText = new StringBuilder(); |
| int start = 0; |
| |
| //Total Number of columns in the trigger table |
| int numberOfColsInTriggerTable = triggerTableDescriptor.getNumberOfColumns(); |
| |
| //The purpose of following array(triggerColsAndTriggerActionCols) |
| //is to identify all the trigger columns and all the columns from |
| //the trigger action which are referenced though old/new |
| //transition variables(in other words, accessed through the |
| //REFERENCING clause section of CREATE TRIGGER sql). This array |
| //will be initialized to -1 at the beginning. By the end of this |
| //method, all the columns referenced by the trigger action |
| //through the REFERENCING clause and all the trigger columns will |
| //have their column positions in the trigger table noted in this |
| //array. |
| //eg |
| //CREATE TRIGGER tr1 AFTER UPDATE OF c12 ON table1 |
| // REFERENCING OLD AS oldt NEW AS newt |
| // FOR EACH ROW UPDATE table2 SET c24=oldt.c14; |
| //For the trigger above, triggerColsAndTriggerActionCols will |
| //finally have [-1,2,-1,4,-1] This list will include all the |
| //columns that need to be fetched into memory during trigger |
| //execution. All the columns with their entries marked -1 will |
| //not be read into memory because they are not referenced in the |
| //trigger action through old/new transition variables and they are |
| //not recognized as trigger columns. |
| int[] triggerColsAndTriggerActionCols = new int[numberOfColsInTriggerTable]; |
| |
| /** |
| * It identifies all the trigger action columns and is initialized to -1. |
| */ |
| |
| int[] triggerActionColsOnly = new int[numberOfColsInTriggerTable]; |
| java.util.Arrays.fill(triggerActionColsOnly, -1); |
| |
| if (referencedCols == null) { |
| //This means that even though the trigger is defined at row |
| //level, it is either an INSERT/DELETE trigger. Or it is an |
| //UPDATE trigger with no specific column(s) identified as the |
| //trigger column(s). In these cases, Derby is going to read all |
| //the columns from the trigger table during trigger execution. |
| //eg of an UPDATE trigger with no specific trigger column(s) |
| // CREATE TRIGGER tr1 AFTER UPDATE ON table1 |
| // REFERENCING OLD AS oldt NEW AS newt |
| // FOR EACH ROW UPDATE table2 SET c24=oldt.c14; |
| for (int i=0; i < numberOfColsInTriggerTable; i++) { |
| triggerColsAndTriggerActionCols[i]=i+1; |
| } |
| } else { |
| //This means that this row level trigger is an UPDATE trigger |
| //defined on specific column(s). |
| java.util.Arrays.fill(triggerColsAndTriggerActionCols, -1); |
| for (int i=0; i < referencedCols.length; i++){ |
| //Make a note of this trigger column's column position in |
| //triggerColsAndTriggerActionCols. This will tell us that |
| //this column needs to be read in when the trigger fires. |
| //eg for the CREATE TRIGGER below, we will make a note of |
| //column c12's position in triggerColsAndTriggerActionCols |
| //eg |
| //CREATE TRIGGER tr1 AFTER UPDATE OF c12 ON table1 |
| // REFERENCING OLD AS oldt NEW AS newt |
| // FOR EACH ROW UPDATE table2 SET c24=oldt.c14; |
| triggerColsAndTriggerActionCols[referencedCols[i]-1] = referencedCols[i]; |
| } |
| } |
| if (referencedColsInTriggerAction != null) { |
| for (int i=0; i < referencedColsInTriggerAction.length; i++){ |
| if( referencedColsInTriggerAction[i] > 0 ) |
| triggerColsAndTriggerActionCols[referencedColsInTriggerAction[i]-1] = referencedColsInTriggerAction[i]; |
| } |
| } |
| |
| /* we need to sort on position in string, beetle 4324 |
| */ |
| SortedSet<ColumnReference> refs = getTransitionVariables( |
| actionStmt, oldReferencingName, newReferencingName); |
| |
| if (createTriggerTime) { |
| //The purpose of following array(triggerActionColsOnly) is to |
| //identify all the columns from the trigger action which are |
| //referenced though old/new transition variables(in other words, |
| //accessed through the REFERENCING clause section of |
| //CREATE TRIGGER sql). This array will be initialized to -1 at the |
| //beginning. By the end of this method, all the columns referenced |
| //by the trigger action through the REFERENCING clause will have |
| //their column positions in the trigger table noted in this array. |
| //eg |
| //CREATE TABLE table1 (c11 int, c12 int, c13 int, c14 int, c15 int); |
| //CREATE TABLE table2 (c21 int, c22 int, c23 int, c24 int, c25 int); |
| //CREATE TRIGGER tr1 AFTER UPDATE OF c12 ON table1 |
| // REFERENCING OLD AS oldt NEW AS newt |
| // FOR EACH ROW UPDATE table2 SET c24=oldt.c14; |
| //For the trigger above, triggerActionColsOnly will finally have |
| //[-1,-1,-1,4,-1]. We will note all the entries for this array |
| //which are not -1 into SYSTRIGGERS(-1 indiciates columns with |
| //those column positions from the trigger table are not being |
| //referenced in the trigger action through the old/new transition |
| //variables. |
| |
| //By this time, we have collected the positions of the trigger |
| //columns in array triggerColsAndTriggerActionCols. Now we need |
| //to start looking at the columns in trigger action to collect |
| //all the columns referenced through REFERENCES clause. These |
| //columns will be noted in triggerColsAndTriggerActionCols and |
| //triggerActionColsOnly arrays. |
| |
| //At the end of the for loop below, we will have both arrays |
| //triggerColsAndTriggerActionCols & triggerActionColsOnly |
| //filled up with the column positions of the columns which are |
| //either trigger columns or triger action columns which are |
| //referenced through old/new transition variables. |
| //eg |
| //CREATE TRIGGER tr1 AFTER UPDATE OF c12 ON table1 |
| // REFERENCING OLD AS oldt NEW AS newt |
| // FOR EACH ROW UPDATE table2 SET c24=oldt.c14; |
| //For the above trigger, before the for loop below, the contents |
| //of the 2 arrays will be as follows |
| //triggerActionColsOnly [-1,-1,-1,-1,-1] |
| //triggerColsAndTriggerActionCols [-1,2,-1,-1,-1] |
| //After the for loop below, the 2 arrays will look as follows |
| //triggerActionColsOnly [-1,-1,-1,4,-1] |
| //triggerColsAndTriggerActionCols [-1,2,-1,4,-1] |
| //If the database is at 10.8 or earlier version(meaning we are in |
| //soft-upgrade mode), then we do not want to collect any |
| //information about trigger action columns. The collection and |
| //usage of trigger action columns was introduced in first 10.7 |
| //release (DERBY-1482) but a regression was found (DERBY-5121) and |
| //hence we stopped doing the collection of trigger action columns |
| //in next version of 10.7 and 10.8. In 10.9, DERBY-1482 was |
| //reimplemented correctly and we started doing the collection and |
| //usage of trigger action columns again in 10.9 |
| for (ColumnReference ref : refs) |
| { |
| TableName tableName = ref.getQualifiedTableName(); |
| |
| checkInvalidTriggerReference(tableName.getTableName(), |
| oldReferencingName, |
| newReferencingName, |
| triggerEventMask); |
| String colName = ref.getColumnName(); |
| |
| ColumnDescriptor triggerColDesc; |
| //Following will catch the case where an invalid column is |
| //used in trigger action through the REFERENCING clause. The |
| //following tigger is trying to use oldt.c13 but there is no |
| //column c13 in trigger table table1 |
| //CREATE TRIGGER tr1 AFTER UPDATE OF c12 ON table1 |
| // REFERENCING OLD AS oldt NEW AS newt |
| // FOR EACH ROW UPDATE table2 SET c24=oldt.c14567; |
| if ((triggerColDesc = triggerTableDescriptor.getColumnDescriptor(colName)) == |
| null) { |
| throw StandardException.newException( |
| SQLState.LANG_COLUMN_NOT_FOUND, tableName+"."+colName); |
| } |
| |
| if (in10_9_orHigherVersion) { |
| int triggerColDescPosition = triggerColDesc.getPosition(); |
| triggerColsAndTriggerActionCols[triggerColDescPosition-1]=triggerColDescPosition; |
| triggerActionColsOnly[triggerColDescPosition-1]=triggerColDescPosition; |
| referencedColsInTriggerAction[triggerColDescPosition-1] = triggerColDescPosition; |
| } |
| } |
| } else { |
| //We are here because we have come across an invalidated trigger |
| //which is being fired. This code gets called for such a trigger |
| //only if it is a row level trigger with REFERENCEs clause |
| // |
| // referencedColsInTriggerAction can be null if trigger action |
| // does not use any columns through REFERENCING clause. This can |
| // happen when we are coming here through ALTER TABLE DROP COLUMN |
| // and the trigger being rebuilt does not use any columns through |
| // REFERENCING clause. DERBY-4887 |
| if (referencedCols != null && referencedColsInTriggerAction != null){ |
| for (int i = 0; i < referencedColsInTriggerAction.length; i++) |
| { |
| triggerColsAndTriggerActionCols[referencedColsInTriggerAction[i]-1] = referencedColsInTriggerAction[i]; |
| } |
| } |
| } |
| |
| Arrays.sort( triggerColsAndTriggerActionCols ); |
| |
| //Now that we know what columns we need for trigger columns and |
| //trigger action columns, we can get rid of remaining -1 entries |
| //for the remaining columns from trigger table. |
| //eg |
| //CREATE TRIGGER tr1 AFTER UPDATE OF c12 ON table1 |
| // REFERENCING OLD AS oldt NEW AS newt |
| // FOR EACH ROW UPDATE table2 SET c24=oldt.c14; |
| //For the above trigger, before the justTheRequiredColumns() call, |
| //the content of triggerColsAndTriggerActionCols array were as |
| //follows [-1, 2, -1, 4, -1] |
| //After the justTheRequiredColumns() call below, |
| //triggerColsAndTriggerActionCols will have [2,4]. What this means |
| //that, at run time, during trigger execution, these are the only |
| //2 column positions that will be read into memory from the |
| //trigger table. The columns in other column positions are not |
| //needed for trigger execution. |
| triggerColsAndTriggerActionCols = justTheRequiredColumns( |
| triggerColsAndTriggerActionCols, triggerTableDescriptor); |
| |
| return triggerColsAndTriggerActionCols; |
| } |
| |
| |
| public String getTriggerActionString( |
| Visitable actionStmt, |
| String oldReferencingName, |
| String newReferencingName, |
| String triggerDefinition, |
| int[] referencedCols, |
| int[] referencedColsInTriggerAction, |
| int actionOffset, |
| TableDescriptor triggerTableDescriptor, |
| int triggerEventMask, |
| boolean createTriggerTime, |
| List<int[]> replacements, |
| int[] cols |
| ) throws StandardException |
| { |
| boolean in10_9_orHigherVersion = checkVersion(DataDictionary.DD_VERSION_DERBY_10_9,null); |
| |
| StringBuilder newText = new StringBuilder(); |
| int start = 0; |
| |
| //Total Number of columns in the trigger table |
| int numberOfColsInTriggerTable = triggerTableDescriptor.getNumberOfColumns(); |
| int[] triggerColsAndTriggerActionCols = new int[numberOfColsInTriggerTable]; |
| |
| SortedSet<ColumnReference> refs = getTransitionVariables( |
| actionStmt, oldReferencingName, newReferencingName); |
| |
| triggerColsAndTriggerActionCols = cols; |
| |
| //This is where we do the actual transformation of trigger action |
| //sql. An eg of that is |
| // DELETE FROM t WHERE c = old.c |
| // turns into |
| // DELETE FROM t WHERE c = org.apache.derby.iapi.db.Factory:: |
| // getTriggerExecutionContext().getOldRow(). |
| // getInt(columnNumberFor'C'inRuntimeResultset) |
| // or |
| // DELETE FROM t WHERE c in (SELECT c FROM OLD) |
| // turns into |
| // DELETE FROM t WHERE c in |
| // (SELECT c FROM new TriggerOldTransitionTable OLD) |
| for (ColumnReference ref : refs) |
| { |
| TableName tableName = ref.getQualifiedTableName(); |
| int tableBeginOffset = tableName.getBeginOffset() - actionOffset; |
| |
| String colName = ref.getColumnName(); |
| |
| // Add whatever we've seen after the previous replacement. |
| newText.append(triggerDefinition, start, tableBeginOffset); |
| |
| int colPositionInRuntimeResultSet = -1; |
| ColumnDescriptor triggerColDesc = triggerTableDescriptor.getColumnDescriptor(colName); |
| //DERBY-5121 We can come here if the column being used in trigger |
| // action is getting dropped and we have come here through that |
| // ALTER TABLE DROP COLUMN. In that case, we will not find the |
| // column in the trigger table. |
| if (triggerColDesc == null) { |
| throw StandardException.newException( |
| SQLState.LANG_COLUMN_NOT_FOUND, tableName+"."+colName); |
| } |
| int colPositionInTriggerTable = triggerColDesc.getPosition(); |
| |
| //This part of code is little tricky and following will help |
| //understand what mapping is happening here. |
| //eg |
| //CREATE TRIGGER tr1 AFTER UPDATE OF c12 ON table1 |
| // REFERENCING OLD AS oldt NEW AS newt |
| // FOR EACH ROW UPDATE table2 SET c24=oldt.c14; |
| //For the above trigger, triggerColsAndTriggerActionCols will |
| //have [2,4]. What this means that, at run time, during trigger |
| //execution, these are the only 2 column positions that will be |
| //read into memory from the trigger table. The columns in other |
| //column positions are not needed for trigger execution. But |
| //even though column positions in original trigger table are 2 |
| //and 4, their relative column positions in the columns read at |
| //execution time is really [1,2]. At run time, when the trigger |
| //gets fired, column position 2 from the trigger table will be |
| //read as the first column and column position 4 from the |
| //trigger table will be read as the second column. And those |
| //relative column positions at runtime is what should be used |
| //during trigger action conversion from |
| //UPDATE table2 SET c24=oldt.c14 |
| //to |
| //UPDATE table2 SET c24= |
| // org.apache.derby.iapi.db.Factory::getTriggerExecutionContext(). |
| // getOldRow().getInt(2) |
| //Note that the generated code above refers to column c14 from |
| //table1 by position 2 rather than position 4. Column c14's |
| //column position in table1 is 4 but in the relative columns |
| //that will be fetched during trigger execution, it's position |
| //is 2. That is what the following code is doing. |
| if (in10_9_orHigherVersion && triggerColsAndTriggerActionCols != null){ |
| for (int j=0; j<triggerColsAndTriggerActionCols.length; j++){ |
| if (triggerColsAndTriggerActionCols[j] == colPositionInTriggerTable) |
| colPositionInRuntimeResultSet=j+1; |
| } |
| } else |
| colPositionInRuntimeResultSet=colPositionInTriggerTable; |
| |
| // Add the replacement code that accesses a value in the |
| // transition variable. |
| final int replacementOffset = newText.length(); |
| newText.append(genColumnReferenceSQL(triggerTableDescriptor, colName, |
| tableName.getTableName(), |
| tableName.getTableName().equals(oldReferencingName), |
| colPositionInRuntimeResultSet)); |
| |
| start = ref.getEndOffset() + 1 - actionOffset; |
| |
| if (replacements != null) { |
| // Record that we have made a change. |
| replacements.add(new int[] { |
| tableBeginOffset, // offset to replaced text |
| start, // offset to token after replaced text |
| replacementOffset, // offset to replacement |
| newText.length() // offset to token after replacement |
| }); |
| } |
| } |
| |
| //By this point, we are finished transforming the trigger action if |
| //it has any references to old/new transition variables. |
| newText.append(triggerDefinition, start, triggerDefinition.length()); |
| |
| return newText.toString(); |
| } |
| |
| /** |
| * Get all columns that reference transition variables in triggers. |
| * The columns should be returned in the same order as in the SQL text. |
| * |
| * @param node the node in which to look for transition variables |
| * @param oldReferencingName the name of the old transition variable |
| * @param newReferencingName the name of the new transition variable |
| * @return all references to transition variables |
| */ |
| private static SortedSet<ColumnReference> getTransitionVariables( |
| Visitable node, String oldReferencingName, String newReferencingName) |
| throws StandardException |
| { |
| // First get all column references. |
| SortedSet<ColumnReference> refs = |
| ((QueryTreeNode) node).getOffsetOrderedNodes(ColumnReference.class); |
| |
| // Then remove all that are not referencing a transition variable. |
| Iterator<ColumnReference> it = refs.iterator(); |
| while (it.hasNext()) { |
| TableName tableName = it.next().getQualifiedTableName(); |
| if (!isTransitionVariable( |
| tableName, oldReferencingName, newReferencingName)) { |
| it.remove(); |
| } |
| } |
| |
| // Return what's left. Should be all references to transition |
| // variables. |
| return refs; |
| } |
| |
| /** |
| * Check if a table name is actually a transition variable. |
| * |
| * @param tableName the table name to check |
| * @param oldReferencingName the name of the old transition variable |
| * @param newReferencingName the name of the new transition variable |
| * @return {@code true} if the table name is a transition variable, |
| * {@code false} otherwise |
| */ |
| private static boolean isTransitionVariable(TableName tableName, |
| String oldReferencingName, String newReferencingName) { |
| if (tableName != null) { |
| if (tableName.hasSchema()) { |
| // DERBY-6540: Schema-qualified names are not transition |
| // variables. |
| return false; |
| } |
| |
| // If there is no schema, and the name is equal to the old or |
| // the new transition variable, then it is a transition variable. |
| String name = tableName.getTableName(); |
| if (name != null) { |
| return name.equals(oldReferencingName) |
| || name.equals(newReferencingName); |
| } |
| } |
| |
| // Otherwise, it is not a transition variable. |
| return false; |
| } |
| |
| /* |
| * The arrary passed will have either -1 or a column position as it's |
| * elements. If the array only has -1 as for all it's elements, then |
| * this method will return null. Otherwise, the method will create a |
| * new arrary with all -1 entries removed from the original arrary. |
| */ |
| private int[] justTheRequiredColumns(int[] columnsArrary, |
| TableDescriptor triggerTableDescriptor) { |
| int countOfColsRefedInArray = 0; |
| int numberOfColsInTriggerTable = triggerTableDescriptor.getNumberOfColumns(); |
| |
| //Count number of non -1 entries |
| for (int i=0; i < numberOfColsInTriggerTable; i++) { |
| if (columnsArrary[i] != -1) |
| countOfColsRefedInArray++; |
| } |
| |
| if (countOfColsRefedInArray > 0){ |
| int[] tempArrayOfNeededColumns = new int[countOfColsRefedInArray]; |
| int j=0; |
| for (int i=0; i < numberOfColsInTriggerTable; i++) { |
| if (columnsArrary[i] != -1) |
| tempArrayOfNeededColumns[j++] = columnsArrary[i]; |
| } |
| return tempArrayOfNeededColumns; |
| } else |
| return null; |
| } |
| |
| /* |
| ** Check for illegal combinations here: insert & old or |
| ** delete and new |
| */ |
| private void checkInvalidTriggerReference(String tableName, |
| String oldReferencingName, |
| String newReferencingName, |
| int triggerEventMask) throws StandardException |
| { |
| if (tableName.equals(oldReferencingName) && |
| (triggerEventMask & TriggerDescriptor.TRIGGER_EVENT_INSERT) == TriggerDescriptor.TRIGGER_EVENT_INSERT) |
| { |
| throw StandardException.newException(SQLState.LANG_TRIGGER_BAD_REF_MISMATCH, "INSERT", "new"); |
| } |
| else if (tableName.equals(newReferencingName) && |
| (triggerEventMask & TriggerDescriptor.TRIGGER_EVENT_DELETE) == TriggerDescriptor.TRIGGER_EVENT_DELETE) |
| { |
| throw StandardException.newException(SQLState.LANG_TRIGGER_BAD_REF_MISMATCH, "DELETE", "old"); |
| } |
| } |
| |
| /* |
| ** Make sure the given column name is found in the trigger |
| ** target table. Generate the appropriate SQL to get it. |
| ** |
| ** @return a string that is used to get the column using |
| ** getObject() on the desired result set and CAST it back |
| ** to the proper type in the SQL domain. |
| ** |
| ** @exception StandardException on invalid column name |
| */ |
| private String genColumnReferenceSQL( |
| TableDescriptor td, |
| String colName, |
| String tabName, |
| boolean isOldTable, |
| int colPositionInRuntimeResultSet |
| ) throws StandardException |
| { |
| ColumnDescriptor colDesc = null; |
| if ((colDesc = td.getColumnDescriptor(colName)) == |
| null) |
| { |
| throw StandardException.newException( |
| SQLState.LANG_COLUMN_NOT_FOUND, tabName+"."+colName); |
| } |
| |
| /* |
| ** Generate something like this: |
| ** |
| ** CAST (org.apache.derby.iapi.db.Factory:: |
| ** getTriggerExecutionContext().getNewRow(). |
| ** getObject(<colPosition>) AS DECIMAL(6,2)) |
| ** |
| ** Column position is used to avoid the wrong column being |
| ** selected problem (DERBY-1258) caused by the case insensitive |
| ** JDBC rules for fetching a column by name. |
| ** |
| ** The cast back to the SQL Domain may seem redundant |
| ** but we need it to make the column reference appear |
| ** EXACTLY like a regular column reference, so we need |
| ** the object in the SQL Domain and we need to have the |
| ** type information. Thus a user should be able to do |
| ** something like |
| ** |
| ** CREATE TRIGGER ... INSERT INTO T length(Column), ... |
| ** |
| */ |
| |
| DataTypeDescriptor dts = colDesc.getType(); |
| TypeId typeId = dts.getTypeId(); |
| |
| if (!typeId.isXMLTypeId()) |
| { |
| |
| StringBuffer methodCall = new StringBuffer(); |
| methodCall.append( |
| "CAST (org.apache.derby.iapi.db.Factory::getTriggerExecutionContext()."); |
| methodCall.append(isOldTable ? "getOldRow()" : "getNewRow()"); |
| methodCall.append(".getObject("); |
| methodCall.append(colPositionInRuntimeResultSet); |
| methodCall.append(") AS "); |
| |
| /* |
| ** getSQLString() returns <typeName> |
| ** for user types, so call getSQLTypeName in that |
| ** case. |
| */ |
| methodCall.append( |
| (typeId.userType() ? |
| typeId.getSQLTypeName() : dts.getSQLstring())); |
| |
| methodCall.append(") "); |
| |
| return methodCall.toString(); |
| } |
| else |
| { |
| /* DERBY-2350 |
| ** |
| ** Triggers currently use jdbc 1.2 to access columns. The default |
| ** uses getObject() which is not supported for an XML type until |
| ** jdbc 4. In the meantime use getString() and then call |
| ** XMLPARSE() on the string to get the type. See Derby issue and |
| ** http://wiki.apache.org/db-derby/TriggerImplementation , for |
| ** better long term solutions. Long term I think changing the |
| ** trigger architecture to not rely on jdbc, but instead on an |
| ** internal direct access interface to execution nodes would be |
| ** best future direction, but believe such a change appropriate |
| ** for a major release, not a bug fix. |
| ** |
| ** Rather than the above described code generation, use the |
| ** following for XML types to generate an XML column from the |
| ** old or new row. |
| ** |
| ** XMLPARSE(DOCUMENT |
| ** CAST (org.apache.derby.iapi.db.Factory:: |
| ** getTriggerExecutionContext().getNewRow(). |
| ** getString(<colPosition>) AS CLOB) |
| ** PRESERVE WHITESPACE) |
| */ |
| |
| StringBuffer methodCall = new StringBuffer(); |
| methodCall.append("XMLPARSE(DOCUMENT CAST( "); |
| methodCall.append( |
| "org.apache.derby.iapi.db.Factory::getTriggerExecutionContext()."); |
| methodCall.append(isOldTable ? "getOldRow()" : "getNewRow()"); |
| methodCall.append(".getString("); |
| methodCall.append(colPositionInRuntimeResultSet); |
| methodCall.append(") AS CLOB) PRESERVE WHITESPACE ) "); |
| |
| return methodCall.toString(); |
| } |
| } |
| |
| /** |
| * Get a TriggerDescriptor given its UUID. |
| * |
| * @param uuid The UUID |
| * |
| * @return The TriggerDescriptor for the constraint. |
| * |
| * @exception StandardException Thrown on failure |
| */ |
| public TriggerDescriptor getTriggerDescriptor(UUID uuid) |
| throws StandardException |
| { |
| TabInfoImpl ti = getNonCoreTI(SYSTRIGGERS_CATALOG_NUM); |
| DataValueDescriptor triggerIdOrderable = getIDValueAsCHAR(uuid); |
| |
| /* Set up the start/stop position for the scan */ |
| ExecIndexRow keyRow = exFactory.getIndexableRow(1); |
| keyRow.setColumn(1, triggerIdOrderable); |
| |
| return getDescriptorViaIndex( |
| SYSTRIGGERSRowFactory.SYSTRIGGERS_INDEX1_ID, |
| keyRow, |
| (ScanQualifier [][]) null, |
| ti, |
| (TupleDescriptor) null, |
| (List<TupleDescriptor>) null, |
| TriggerDescriptor.class, |
| false); |
| } |
| |
| /** |
| * Get the stored prepared statement descriptor given |
| * a sps name. |
| * |
| * @param name The sps name. |
| * @param sd The schema descriptor. |
| * |
| * @return The TriggerDescriptor for the constraint. |
| * |
| * @exception StandardException Thrown on failure |
| */ |
| public TriggerDescriptor getTriggerDescriptor(String name, SchemaDescriptor sd) |
| throws StandardException |
| { |
| DataValueDescriptor schemaIDOrderable; |
| DataValueDescriptor triggerNameOrderable; |
| TabInfoImpl ti = getNonCoreTI(SYSTRIGGERS_CATALOG_NUM); |
| |
| /* Use triggerNameOrderable and schemaIdOrderable in both start |
| * and stop position for scan. |
| */ |
| triggerNameOrderable = new SQLVarchar(name); |
| schemaIDOrderable = getIDValueAsCHAR(sd.getUUID()); |
| |
| /* Set up the start/stop position for the scan */ |
| ExecIndexRow keyRow = exFactory.getIndexableRow(2); |
| keyRow.setColumn(1, triggerNameOrderable); |
| keyRow.setColumn(2, schemaIDOrderable); |
| |
| return getDescriptorViaIndex( |
| SYSTRIGGERSRowFactory.SYSTRIGGERS_INDEX2_ID, |
| keyRow, |
| (ScanQualifier [][]) null, |
| ti, |
| (TupleDescriptor) null, |
| (List<TupleDescriptor>) null, |
| TriggerDescriptor.class, |
| false); |
| } |
| |
| /** |
| * Load up the trigger descriptor list for this table |
| * descriptor and return it. If the descriptor list |
| * is already loaded up, it is retuned without further |
| * ado. |
| * |
| * @param td The table descriptor. |
| * |
| * @return The ConstraintDescriptorList for the table |
| * |
| * @exception StandardException Thrown on failure |
| */ |
| public TriggerDescriptorList getTriggerDescriptors(TableDescriptor td) |
| throws StandardException |
| { |
| TriggerDescriptorList gdl; |
| |
| /* Build the TableDescriptor's TDL if it is currently empty */ |
| gdl = td.getTriggerDescriptorList(); |
| |
| /* |
| ** Synchronize the building of the TDL. The TDL itself is created |
| ** empty when the TD is created, so there is no need to synchronize |
| ** the getting of the TDL. |
| */ |
| synchronized(gdl) |
| { |
| if (!gdl.getScanned()) |
| { |
| getTriggerDescriptorsScan(td, false); |
| } |
| } |
| |
| return gdl; |
| } |
| |
| /** |
| * Populate the TriggerDescriptorList for the specified TableDescriptor. |
| * |
| * MT synchronization: it is assumed that the caller has synchronized |
| * on the CDL in the given TD. |
| * |
| * @param td The TableDescriptor. |
| * @param forUpdate Whether or not to open scan for update |
| * |
| * @exception StandardException Thrown on failure |
| */ |
| private void getTriggerDescriptorsScan(TableDescriptor td, boolean forUpdate) |
| throws StandardException |
| { |
| TriggerDescriptorList gdl = (td).getTriggerDescriptorList(); |
| DataValueDescriptor tableIDOrderable = null; |
| TabInfoImpl ti = getNonCoreTI(SYSTRIGGERS_CATALOG_NUM); |
| |
| /* Use tableIDOrderable in both start and stop positions for scan */ |
| tableIDOrderable = getIDValueAsCHAR(td.getUUID()); |
| |
| /* Set up the start/stop position for the scan */ |
| ExecIndexRow keyRow = (ExecIndexRow) exFactory.getIndexableRow(1); |
| |
| keyRow.setColumn(1, tableIDOrderable); |
| |
| getDescriptorViaIndex( |
| SYSTRIGGERSRowFactory.SYSTRIGGERS_INDEX3_ID, |
| keyRow, |
| (ScanQualifier [][]) null, |
| ti, |
| (TupleDescriptor) null, |
| gdl, |
| TriggerDescriptor.class, |
| forUpdate); |
| gdl.setScanned(true); |
| } |
| |
| /** |
| * Drops the given TriggerDescriptor. WARNING: does |
| * not drop its SPSes!!! |
| * |
| * @param descriptor The descriptor to drop |
| * @param tc The TransactionController. |
| * |
| * @exception StandardException Thrown on failure |
| */ |
| public void dropTriggerDescriptor |
| ( |
| TriggerDescriptor descriptor, |
| TransactionController tc |
| ) throws StandardException |
| { |
| DataValueDescriptor idOrderable; |
| TabInfoImpl ti = getNonCoreTI(SYSTRIGGERS_CATALOG_NUM); |
| |
| idOrderable = getIDValueAsCHAR(descriptor.getUUID()); |
| |
| /* Set up the start/stop position for the scan */ |
| ExecIndexRow keyRow = (ExecIndexRow) exFactory.getIndexableRow(1); |
| keyRow.setColumn(1, idOrderable); |
| |
| ti.deleteRow(tc, keyRow, SYSTRIGGERSRowFactory.SYSTRIGGERS_INDEX1_ID); |
| } |
| |
| /** |
| * Update the trigger descriptor in question. Updates |
| * every row in the base conglomerate that matches the uuid. |
| * |
| * @param triggerd The Trigger descriptor |
| * @param formerUUID The UUID for this column in SYSTRIGGERS, |
| * may differ from what is in triggerd if this |
| * is the column that is being set. |
| * @param colsToSet Array of ints of columns to be modified, |
| * 1 based. May be null (all cols). |
| * @param tc The TransactionController to use |
| * |
| * @exception StandardException Thrown on failure |
| */ |
| public void updateTriggerDescriptor |
| ( |
| TriggerDescriptor triggerd, |
| UUID formerUUID, |
| int[] colsToSet, |
| TransactionController tc |
| ) throws StandardException |
| { |
| ExecIndexRow keyRow1 = null; |
| ExecRow row; |
| DataValueDescriptor IDOrderable; |
| TabInfoImpl ti = getNonCoreTI(SYSTRIGGERS_CATALOG_NUM); |
| SYSTRIGGERSRowFactory rf = (SYSTRIGGERSRowFactory) ti.getCatalogRowFactory(); |
| |
| /* Use objectID in both start |
| * and stop position for index 1 scan. |
| */ |
| IDOrderable = getIDValueAsCHAR(formerUUID); |
| |
| /* Set up the start/stop position for the scan */ |
| keyRow1 = (ExecIndexRow) exFactory.getIndexableRow(1); |
| keyRow1.setColumn(1, IDOrderable); |
| |
| // build the row to be stuffed into SYSTRIGGERS. |
| row = rf.makeRow(triggerd, null); |
| |
| /* |
| ** Figure out if the index in systriggers needs |
| ** to be updated. |
| */ |
| if (SanityManager.DEBUG) |
| { |
| SanityManager.ASSERT(rf.getNumIndexes() == 3, |
| "There are more indexes on systriggers than expected, the code herein needs to change"); |
| } |
| |
| boolean[] bArray = new boolean[3]; |
| |
| /* |
| ** Do we need to update indexes? |
| */ |
| if (colsToSet == null) |
| { |
| bArray[0] = true; |
| bArray[1] = true; |
| bArray[2] = true; |
| } |
| else |
| { |
| /* |
| ** Check the specific columns for indexed |
| ** columns. |
| */ |
| for (int i = 0; i < colsToSet.length; i++) |
| { |
| switch (colsToSet[i]) |
| { |
| case SYSTRIGGERSRowFactory.SYSTRIGGERS_TRIGGERID: |
| bArray[0] = true; |
| break; |
| |
| case SYSTRIGGERSRowFactory.SYSTRIGGERS_TRIGGERNAME: |
| case SYSTRIGGERSRowFactory.SYSTRIGGERS_SCHEMAID: |
| bArray[1] = true; |
| break; |
| |
| case SYSTRIGGERSRowFactory.SYSTRIGGERS_TABLEID: |
| bArray[2] = true; |
| break; |
| } |
| } |
| } |
| |
| ti.updateRow(keyRow1, row, |
| SYSTRIGGERSRowFactory.SYSTRIGGERS_INDEX1_ID, |
| bArray, |
| colsToSet, |
| tc); |
| } |
| |
| |
| /** |
| * Get a ConstraintDescriptor given its UUID. Please |
| * use getConstraintDescriptorById() is you have the |
| * constraints table descriptor, it is much faster. |
| * |
| * @param uuid The UUID |
| * |
| * |
| * @return The ConstraintDescriptor for the constraint. |
| * |
| * @exception StandardException Thrown on failure |
| */ |
| public ConstraintDescriptor getConstraintDescriptor(UUID uuid) |
| throws StandardException |
| { |
| DataValueDescriptor UUIDStringOrderable; |
| TabInfoImpl ti = getNonCoreTI(SYSCONSTRAINTS_CATALOG_NUM); |
| |
| /* Use UUIDStringOrderable in both start and stop positions for scan */ |
| UUIDStringOrderable = getIDValueAsCHAR(uuid); |
| |
| /* Set up the start/stop position for the scan */ |
| ExecIndexRow keyRow = exFactory.getIndexableRow(1); |
| keyRow.setColumn(1, UUIDStringOrderable); |
| |
| return getConstraintDescriptorViaIndex( |
| SYSCONSTRAINTSRowFactory.SYSCONSTRAINTS_INDEX1_ID, |
| keyRow, |
| ti, |
| (TableDescriptor) null, |
| (ConstraintDescriptorList) null, |
| false); |
| } |
| |
| /** |
| * Get a ConstraintDescriptor given its name and schema ID. |
| * Please use getConstraintDescriptorByName() if you have the |
| * constraint's table descriptor, it is much faster. |
| * |
| * @param constraintName Constraint name. |
| * @param schemaID The schema UUID |
| * |
| * @return The ConstraintDescriptor for the constraint. |
| * |
| * @exception StandardException Thrown on failure |
| */ |
| public ConstraintDescriptor getConstraintDescriptor |
| ( |
| String constraintName, |
| UUID schemaID |
| ) |
| throws StandardException |
| { |
| DataValueDescriptor UUIDStringOrderable; |
| DataValueDescriptor constraintNameOrderable; |
| TabInfoImpl ti = getNonCoreTI(SYSCONSTRAINTS_CATALOG_NUM); |
| |
| /* Construct keys for both start and stop positions for scan */ |
| constraintNameOrderable = new SQLVarchar(constraintName); |
| UUIDStringOrderable = getIDValueAsCHAR(schemaID); |
| |
| /* Set up the start/stop position for the scan */ |
| ExecIndexRow keyRow = exFactory.getIndexableRow(2); |
| keyRow.setColumn(1, constraintNameOrderable); |
| keyRow.setColumn(2, UUIDStringOrderable); |
| |
| return getConstraintDescriptorViaIndex( |
| SYSCONSTRAINTSRowFactory.SYSCONSTRAINTS_INDEX2_ID, |
| keyRow, |
| ti, |
| (TableDescriptor) null, |
| (ConstraintDescriptorList) null, |
| false); |
| } |
| |
| /** |
| * Returns all the statistics descriptors for the given table. |
| * <p> |
| * NOTE: As opposed to most other data dictionary lookups, this operation is |
| * performed with isolation level READ_UNCOMMITTED. The reason is to avoid |
| * deadlocks with inserts into the statistics system table. |
| * |
| * @param td {@code TableDescriptor} for which I need statistics |
| * @return A list of tuple descriptors, possibly empty. |
| */ |
| public List<StatisticsDescriptor> getStatisticsDescriptors(TableDescriptor td) |
| throws StandardException |
| { |
| TabInfoImpl ti = getNonCoreTI(SYSSTATISTICS_CATALOG_NUM); |
| List<StatisticsDescriptor> statDescriptorList = newSList(); |
| DataValueDescriptor UUIDStringOrderable; |
| |
| /* set up the start/stop position for the scan */ |
| UUIDStringOrderable = getIDValueAsCHAR(td.getUUID()); |
| ExecIndexRow keyRow = exFactory.getIndexableRow(1); |
| keyRow.setColumn(1, UUIDStringOrderable); |
| |
| getDescriptorViaIndex(SYSSTATISTICSRowFactory.SYSSTATISTICS_INDEX1_ID, |
| keyRow, |
| (ScanQualifier [][])null, |
| ti, |
| (TupleDescriptor)null, |
| statDescriptorList, |
| StatisticsDescriptor.class, |
| false, |
| TransactionController.ISOLATION_READ_UNCOMMITTED, |
| getTransactionCompile()); |
| |
| return statDescriptorList; |
| } |
| |
| /** |
| * Load up the constraint descriptor list for this table |
| * descriptor and return it. If the descriptor list |
| * is already loaded up, it is retuned without further |
| * ado. If no table descriptor is passed in, then all |
| * constraint descriptors are retrieved. Note that in |
| * this case, the constraint descriptor objects may be |
| * duplicates of constraint descriptors that are hung |
| * off of the table descriptor cache. |
| * |
| * @param td The table descriptor. If null, |
| * all constraint descriptors are returned. |
| * |
| * |
| * @return The ConstraintDescriptorList for the table |
| * |
| * @exception StandardException Thrown on failure |
| */ |
| public ConstraintDescriptorList getConstraintDescriptors(TableDescriptor td) |
| throws StandardException |
| { |
| ConstraintDescriptorList cdl; |
| |
| if (td == null) |
| { |
| return getAllConstraintDescriptors(); |
| } |
| |
| /* RESOLVE - need to look at multi-user aspects of hanging constraint |
| * descriptor list off of table descriptor when we restore the cache. |
| */ |
| |
| /* Build the TableDescriptor's CDL if it is currently empty */ |
| cdl = td.getConstraintDescriptorList(); |
| |
| /* |
| ** Synchronize the building of the CDL. The CDL itself is created |
| ** empty when the TD is created, so there is no need to synchronize |
| ** the getting of the CDL. |
| */ |
| synchronized(cdl) |
| { |
| if (! cdl.getScanned()) |
| { |
| getConstraintDescriptorsScan(td, false); |
| } |
| } |
| |
| return cdl; |
| } |
| |
| /** |
| * Convert a constraint descriptor list into a list |
| * of active constraints, that is, constraints which |
| * must be enforced. For the Core product, these |
| * are just the constraints on the original list. |
| * However, during REFRESH we may have deferred some |
| * constraints until statement end. This method returns |
| * the corresponding list of constraints which AREN'T |
| * deferred. |
| * |
| * @param cdl The constraint descriptor list to wrap with |
| * an Active constraint descriptor list. |
| * |
| * @return The corresponding Active ConstraintDescriptorList |
| * |
| * @exception StandardException Thrown on failure |
| */ |
| public ConstraintDescriptorList getActiveConstraintDescriptors(ConstraintDescriptorList cdl) |
| throws StandardException |
| { return cdl; } |
| |
| /** |
| * Reports whether an individual constraint must be |
| * enforced. For the Core product, this routine always |
| * returns true. |
| * |
| * However, during REFRESH we may have deferred some |
| * constraints until statement end. This method returns |
| * false if the constraint deferred |
| * |
| * @param constraint the constraint to check |
| * |
| * |
| * @return The corresponding Active ConstraintDescriptorList |
| * |
| * @exception StandardException Thrown on failure |
| */ |
| public boolean activeConstraint( ConstraintDescriptor constraint ) |
| throws StandardException |
| { return true; } |
| |
| /** |
| * Get the constraint descriptor given a table and the UUID String |
| * of the backing index. |
| * |
| * @param td The table descriptor. |
| * @param uuid the UUID for the backing index. |
| * |
| * @return The ConstraintDescriptor for the constraint. |
| * |
| * @exception StandardException Thrown on failure |
| */ |
| public ConstraintDescriptor getConstraintDescriptor(TableDescriptor td, |
| UUID uuid) |
| throws StandardException |
| { |
| return getConstraintDescriptors(td).getConstraintDescriptor(uuid); |
| } |
| |
| |
| /** |
| * Get the constraint descriptor given a table and the UUID String |
| * of the constraint |
| * |
| * @param td The table descriptor. |
| * @param uuid The UUID for the constraint |
| * |
| * @return The ConstraintDescriptor for the constraint. |
| * |
| * @exception StandardException Thrown on failure |
| */ |
| public ConstraintDescriptor getConstraintDescriptorById |
| ( |
| TableDescriptor td, |
| UUID uuid |
| ) |
| throws StandardException |
| { |
| return getConstraintDescriptors(td).getConstraintDescriptorById(uuid); |
| } |
| |
| /** |
| * Get the constraint descriptor given a TableDescriptor and the constraint name. |
| * |
| * @param td The table descriptor. |
| * @param sd The schema descriptor for the constraint |
| * @param constraintName The constraint name. |
| * @param forUpdate Whether or not access is for update |
| * |
| * @return The ConstraintDescriptor for the constraint. |
| * |
| * @exception StandardException Thrown on failure |
| */ |
| public ConstraintDescriptor getConstraintDescriptorByName(TableDescriptor td, |
| SchemaDescriptor sd, |
| String constraintName, |
| boolean forUpdate) |
| throws StandardException |
| { |
| /* If forUpdate, then we need to actually read from the table. */ |
| if (forUpdate) |
| { |
| td.emptyConstraintDescriptorList(); |
| getConstraintDescriptorsScan(td, true); |
| } |
| return getConstraintDescriptors(td).getConstraintDescriptorByName(sd, constraintName); |
| } |
| |
| /** |
| * Populate the ConstraintDescriptorList for the specified TableDescriptor. |
| * |
| * MT synchronization: it is assumed that the caller has synchronized |
| * on the CDL in the given TD. |
| * |
| * @param td The TableDescriptor. |
| * @param forUpdate Whether or not to open scan for update |
| * |
| * @exception StandardException Thrown on failure |
| */ |
| private void getConstraintDescriptorsScan(TableDescriptor td, boolean forUpdate) |
| throws StandardException |
| { |
| ConstraintDescriptorList cdl = td.getConstraintDescriptorList(); |
| DataValueDescriptor tableIDOrderable = null; |
| TabInfoImpl ti = getNonCoreTI(SYSCONSTRAINTS_CATALOG_NUM); |
| |
| /* Use tableIDOrderable in both start and stop positions for scan */ |
| tableIDOrderable = getIDValueAsCHAR(td.getUUID()); |
| |
| /* Set up the start/stop position for the scan */ |
| ExecIndexRow keyRow = (ExecIndexRow) exFactory.getIndexableRow(1); |
| |
| keyRow.setColumn(1, tableIDOrderable); |
| |
| getConstraintDescriptorViaIndex( |
| SYSCONSTRAINTSRowFactory.SYSCONSTRAINTS_INDEX3_ID, |
| keyRow, |
| ti, |
| td, |
| cdl, |
| forUpdate); |
| cdl.setScanned(true); |
| } |
| |
| /** |
| * Return a (single or list of) ConstraintDescriptor(s) from |
| * SYSCONSTRAINTS where the access is from the index to the heap. |
| * |
| * @param indexId The id of the index (0 to # of indexes on table) to use |
| * @param keyRow The supplied ExecIndexRow for search |
| * @param ti The TabInfoImpl to use |
| * @param td The TableDescriptor, if supplied. |
| * @param dList The list to build, if supplied. If null, then caller expects |
| * a single descriptor |
| * @param forUpdate Whether or not to open scan for update |
| * |
| * @return The last matching descriptor |
| * |
| * @exception StandardException Thrown on error |
| */ |
| protected ConstraintDescriptor getConstraintDescriptorViaIndex( |
| int indexId, |
| ExecIndexRow keyRow, |
| TabInfoImpl ti, |
| TableDescriptor td, |
| ConstraintDescriptorList dList, |
| boolean forUpdate) |
| throws StandardException |
| { |
| SYSCONSTRAINTSRowFactory rf = (SYSCONSTRAINTSRowFactory) ti.getCatalogRowFactory(); |
| ConglomerateController heapCC; |
| ConstraintDescriptor cd = null; |
| ExecIndexRow indexRow1; |
| ExecRow outRow; |
| RowLocation baseRowLocation; |
| ScanController scanController; |
| TransactionController tc; |
| |
| // Get the current transaction controller |
| tc = getTransactionCompile(); |
| |
| outRow = rf.makeEmptyRow(); |
| |
| heapCC = |
| tc.openConglomerate( |
| ti.getHeapConglomerate(), false, 0, |
| TransactionController.MODE_RECORD, |
| TransactionController.ISOLATION_REPEATABLE_READ); |
| |
| |
| /* Scan the index and go to the data pages for qualifying rows to |
| * build the column descriptor. |
| */ |
| scanController = tc.openScan( |
| ti.getIndexConglomerate(indexId), // conglomerate to open |
| false, // don't hold open across commit |
| (forUpdate) ? TransactionController.OPENMODE_FORUPDATE : 0, |
| TransactionController.MODE_RECORD, |
| TransactionController.ISOLATION_REPEATABLE_READ, |
| (FormatableBitSet) null, // all fields as objects |
| keyRow.getRowArray(), // start position - exact key match. |
| ScanController.GE, // startSearchOperation |
| null, //scanQualifier, |
| keyRow.getRowArray(), // stop position - exact key match. |
| ScanController.GT); // stopSearchOperation |
| |
| while (scanController.next()) |
| { |
| SubConstraintDescriptor subCD = null; |
| |
| // create an index row template |
| indexRow1 = getIndexRowFromHeapRow( |
| ti.getIndexRowGenerator(indexId), |
| heapCC.newRowLocationTemplate(), |
| outRow); |
| |
| scanController.fetch(indexRow1.getRowArray()); |
| |
| baseRowLocation = (RowLocation) indexRow1.getColumn( |
| indexRow1.nColumns()); |
| |
| boolean base_row_exists = |
| heapCC.fetch( |
| baseRowLocation, outRow.getRowArray(), (FormatableBitSet) null); |
| |
| if (SanityManager.DEBUG) |
| { |
| // it can not be possible for heap row to disappear while |
| // holding scan cursor on index at ISOLATION_REPEATABLE_READ. |
| SanityManager.ASSERT(base_row_exists, "base row doesn't exist"); |
| } |
| |
| switch (rf.getConstraintType(outRow)) |
| { |
| case DataDictionary.PRIMARYKEY_CONSTRAINT: |
| case DataDictionary.FOREIGNKEY_CONSTRAINT: |
| case DataDictionary.UNIQUE_CONSTRAINT: |
| subCD = getSubKeyConstraint( |
| rf.getConstraintId(outRow), rf.getConstraintType(outRow)); |
| break; |
| |
| case DataDictionary.CHECK_CONSTRAINT: |
| subCD = getSubCheckConstraint( |
| rf.getConstraintId(outRow)); |
| break; |
| |
| default: |
| if (SanityManager.DEBUG) |
| { |
| SanityManager.THROWASSERT("unexpected value "+ |
| "from rf.getConstraintType(outRow)" + |
| rf.getConstraintType(outRow)); |
| } |
| } |
| |
| if (SanityManager.DEBUG) |
| { |
| SanityManager.ASSERT(subCD != null, |
| "subCD is expected to be non-null"); |
| } |
| |
| /* Cache the TD in the SCD so that |
| * the row factory doesn't need to go |
| * out to disk to get it. |
| */ |
| subCD.setTableDescriptor(td); |
| |
| cd = (ConstraintDescriptor) rf.buildDescriptor( |
| outRow, |
| subCD, |
| this); |
| |
| /* If dList is null, then caller only wants a single descriptor - we're done |
| * else just add the current descriptor to the list. |
| */ |
| if (dList == null) |
| { |
| break; |
| } |
| else |
| { |
| dList.add(cd); |
| } |
| } |
| scanController.close(); |
| heapCC.close(); |
| return cd; |
| } |
| |
| /** |
| * Return a (single or list of) catalog row descriptor(s) from |
| * SYSCONSTRAINTS through a heap scan |
| * |
| * @param scanQualifiers qualifiers |
| * @param ti The TabInfoImpl to use |
| * @param parentTupleDescriptor The parentDescriptor, if applicable. |
| * @param list The list to build, if supplied. |
| * If null, then caller expects a single descriptor |
| * |
| * @return The last matching descriptor |
| * |
| * @exception StandardException Thrown on error |
| */ |
| protected TupleDescriptor getConstraintDescriptorViaHeap( |
| ScanQualifier [][] scanQualifiers, |
| TabInfoImpl ti, |
| TupleDescriptor parentTupleDescriptor, |
| ConstraintDescriptorList list) |
| throws StandardException |
| { |
| SYSCONSTRAINTSRowFactory rf = (SYSCONSTRAINTSRowFactory) ti.getCatalogRowFactory(); |
| ExecRow outRow; |
| ScanController scanController; |
| TransactionController tc; |
| ConstraintDescriptor cd = null; |
| |
| // Get the current transaction controller |
| tc = getTransactionCompile(); |
| |
| outRow = rf.makeEmptyRow(); |
| |
| /* |
| ** Table scan |
| */ |
| scanController = tc.openScan( |
| ti.getHeapConglomerate(), // conglomerate to open |
| false, // don't hold open across commit |
| 0, // for read |
| TransactionController.MODE_TABLE, |
| TransactionController.ISOLATION_REPEATABLE_READ, |
| (FormatableBitSet) null, // all fields as objects |
| (DataValueDescriptor[]) null, // start position - first row |
| 0, // startSearchOperation - none |
| scanQualifiers, // scanQualifier, |
| (DataValueDescriptor[]) null, // stop position -through last row |
| 0); // stopSearchOperation - none |
| |
| try |
| { |
| while (scanController.fetchNext(outRow.getRowArray())) |
| { |
| SubConstraintDescriptor subCD = null; |
| |
| switch (rf.getConstraintType(outRow)) |
| { |
| case DataDictionary.PRIMARYKEY_CONSTRAINT: |
| case DataDictionary.FOREIGNKEY_CONSTRAINT: |
| case DataDictionary.UNIQUE_CONSTRAINT: |
| subCD = getSubKeyConstraint( |
| rf.getConstraintId(outRow), rf.getConstraintType(outRow)); |
| break; |
| |
| case DataDictionary.CHECK_CONSTRAINT: |
| subCD = getSubCheckConstraint( |
| rf.getConstraintId(outRow)); |
| break; |
| |
| default: |
| if (SanityManager.DEBUG) |
| { |
| SanityManager.THROWASSERT("unexpected value from "+ |
| " rf.getConstraintType(outRow) " |
| + rf.getConstraintType(outRow)); |
| } |
| } |
| |
| if (SanityManager.DEBUG) |
| { |
| SanityManager.ASSERT(subCD != null, |
| "subCD is expected to be non-null"); |
| } |
| cd = (ConstraintDescriptor) rf.buildDescriptor( |
| outRow, |
| subCD, |
| this); |
| |
| /* If dList is null, then caller only wants a single descriptor - we're done |
| * else just add the current descriptor to the list. |
| */ |
| if (list == null) |
| { |
| break; |
| } |
| else |
| { |
| list.add(cd); |
| } |
| } |
| } |
| finally |
| { |
| scanController.close(); |
| } |
| return cd; |
| } |
| |
| /** |
| * Return a table descriptor corresponding to the TABLEID |
| * field in SYSCONSTRAINTS where CONSTRAINTID matches |
| * the constraintId passsed in. |
| * |
| * @param constraintId The id of the constraint |
| * |
| * @return the corresponding table descriptor |
| * |
| * @exception StandardException Thrown on error |
| */ |
| public TableDescriptor getConstraintTableDescriptor(UUID constraintId) |
| throws StandardException |
| { |
| List<UUID> slist = getConstraints(constraintId, |
| SYSCONSTRAINTSRowFactory.SYSCONSTRAINTS_INDEX1_ID, |
| SYSCONSTRAINTSRowFactory.SYSCONSTRAINTS_TABLEID); |
| |
| if (slist.size() == 0) |
| { |
| return null; |
| } |
| |
| // get the table descriptor |
| return getTableDescriptor((UUID)slist.get(0)); |
| } |
| |
| /** |
| * Return a list of foreign keys constraints referencing |
| * this constraint. Returns both enforced and not enforced |
| * foreign keys. |
| * |
| * @param constraintId The id of the referenced constraint |
| * |
| * @return list of constraints, empty of there are none |
| * |
| * @exception StandardException Thrown on error |
| */ |
| public ConstraintDescriptorList getForeignKeys(UUID constraintId) |
| throws StandardException |
| { |
| TabInfoImpl ti = getNonCoreTI(SYSFOREIGNKEYS_CATALOG_NUM); |
| List<SubKeyConstraintDescriptor> fkList = newSList(); |
| |
| // Use constraintIDOrderable in both start and stop positions for scan |
| DataValueDescriptor constraintIDOrderable = getIDValueAsCHAR(constraintId); |
| |
| /* Set up the start/stop position for the scan */ |
| ExecIndexRow keyRow = (ExecIndexRow) exFactory.getIndexableRow(1); |
| keyRow.setColumn(1, constraintIDOrderable); |
| |
| getDescriptorViaIndex( |
| SYSFOREIGNKEYSRowFactory.SYSFOREIGNKEYS_INDEX2_ID, |
| keyRow, |
| (ScanQualifier [][]) null, |
| ti, |
| (TupleDescriptor) null, |
| fkList, |
| SubKeyConstraintDescriptor.class, |
| false); |
| |
| TableDescriptor td; |
| ConstraintDescriptorList cdl = new ConstraintDescriptorList(); |
| |
| for (SubKeyConstraintDescriptor cd : fkList) |
| { |
| td = getConstraintTableDescriptor(cd.getUUID()); |
| cdl.add(getConstraintDescriptors(td).getConstraintDescriptorById(cd.getUUID())); |
| } |
| |
| return cdl; |
| } |
| |
| /** |
| * Return an List which of the relevant column matching |
| * the indexed criteria. If nothing matches, returns an |
| * empty List (never returns null). |
| * |
| * @param uuid The id of the constraint |
| * @param indexId The index id in SYS.SYSCONSTRAINTS |
| * @param columnNum The column to retrieve |
| * |
| * @return a list of UUIDs in an List. |
| * |
| * @exception StandardException Thrown on error |
| */ |
| public List<UUID> getConstraints(UUID uuid, int indexId, int columnNum) |
| throws StandardException |
| { |
| ExecIndexRow indexRow1; |
| ExecRow outRow; |
| RowLocation baseRowLocation; |
| ConglomerateController heapCC = null; |
| ScanController scanController = null; |
| TransactionController tc; |
| TabInfoImpl ti = getNonCoreTI(SYSCONSTRAINTS_CATALOG_NUM); |
| SYSCONSTRAINTSRowFactory rf = (SYSCONSTRAINTSRowFactory) ti.getCatalogRowFactory(); |
| TableDescriptor td = null; |
| List<UUID> slist = new ArrayList<UUID>(); |
| |
| if (SanityManager.DEBUG) |
| { |
| SanityManager.ASSERT(indexId == SYSCONSTRAINTSRowFactory.SYSCONSTRAINTS_INDEX1_ID || |
| indexId == SYSCONSTRAINTSRowFactory.SYSCONSTRAINTS_INDEX3_ID, |
| "bad index id, must be one of the indexes on a uuid"); |
| SanityManager.ASSERT(columnNum > 0 && |
| columnNum <= SYSCONSTRAINTSRowFactory.SYSCONSTRAINTS_COLUMN_COUNT, |
| "invalid column number for column to be retrieved"); |
| } |
| |
| try |
| { |
| /* Use tableIDOrderable in both start and stop positions for scan */ |
| DataValueDescriptor orderable = getIDValueAsCHAR(uuid); |
| |
| /* Set up the start/stop position for the scan */ |
| ExecIndexRow keyRow = (ExecIndexRow) exFactory.getIndexableRow(1); |
| keyRow.setColumn(1, orderable); |
| |
| // Get the current transaction controller |
| tc = getTransactionCompile(); |
| |
| outRow = rf.makeEmptyRow(); |
| |
| heapCC = |
| tc.openConglomerate( |
| ti.getHeapConglomerate(), false, 0, |
| TransactionController.MODE_RECORD, |
| TransactionController.ISOLATION_REPEATABLE_READ); |
| |
| // create an index row template |
| indexRow1 = getIndexRowFromHeapRow( |
| ti.getIndexRowGenerator(indexId), |
| heapCC.newRowLocationTemplate(), |
| outRow); |
| |
| // just interested in one column |
| DataValueDescriptor[] rowTemplate = |
| new DataValueDescriptor[SYSCONSTRAINTSRowFactory.SYSCONSTRAINTS_COLUMN_COUNT]; |
| FormatableBitSet columnToGetSet = |
| new FormatableBitSet(SYSCONSTRAINTSRowFactory.SYSCONSTRAINTS_COLUMN_COUNT); |
| columnToGetSet.set(columnNum - 1); |
| |
| rowTemplate[columnNum - 1] = new SQLChar(); |
| |
| // Scan the index and go to the data pages for qualifying rows |
| scanController = tc.openScan( |
| ti.getIndexConglomerate(indexId),// conglomerate to open |
| false, // don't hold open across commit |
| 0, // for read |
| TransactionController.MODE_RECORD, |
| TransactionController.ISOLATION_REPEATABLE_READ,// RESOLVE: should be level 2 |
| (FormatableBitSet) null, // all fields as objects |
| keyRow.getRowArray(), // start position - exact key match. |
| ScanController.GE, // startSearchOperation |
| null, // scanQualifier (none) |
| keyRow.getRowArray(), // stop position - exact key match. |
| ScanController.GT); // stopSearchOperation |
| |
| while (scanController.fetchNext(indexRow1.getRowArray())) |
| { |
| baseRowLocation = (RowLocation) |
| indexRow1.getColumn(indexRow1.nColumns()); |
| |
| // get the row and grab the uuid |
| boolean base_row_exists = |
| heapCC.fetch( |
| baseRowLocation, rowTemplate, columnToGetSet); |
| |
| if (SanityManager.DEBUG) |
| { |
| // it can not be possible for heap row to disappear while |
| // holding scan cursor on index at ISOLATION_REPEATABLE_READ. |
| SanityManager.ASSERT(base_row_exists, "base row not found"); |
| } |
| |
| slist.add(uuidFactory.recreateUUID( |
| (String)((DataValueDescriptor)rowTemplate[columnNum - 1]).getObject())); |
| } |
| } |
| finally |
| { |
| if (heapCC != null) |
| { |
| heapCC.close(); |
| } |
| if (scanController != null) |
| { |
| scanController.close(); |
| } |
| } |
| return slist; |
| } |
| |
| /** |
| * Adds the given ConstraintDescriptor to the data dictionary, |
| * associated with the given table and constraint type. |
| * |
| * @param descriptor The descriptor to add |
| * @param tc The transaction controller |
| * |
| * @exception StandardException Thrown on error |
| */ |
| public void addConstraintDescriptor( |
| ConstraintDescriptor descriptor, |
| TransactionController tc) |
| throws StandardException |
| { |
| int type = descriptor.getConstraintType(); |
| |
| if (SanityManager.DEBUG) |
| { |
| if (!(type == DataDictionary.PRIMARYKEY_CONSTRAINT || |
| type == DataDictionary.FOREIGNKEY_CONSTRAINT || |
| type == DataDictionary.UNIQUE_CONSTRAINT || |
| type == DataDictionary.CHECK_CONSTRAINT)) |
| { |
| SanityManager.THROWASSERT("constraint type (" + type + |
| ") is unexpected value"); |
| } |
| } |
| |
| addDescriptor(descriptor, descriptor.getSchemaDescriptor(), |
| SYSCONSTRAINTS_CATALOG_NUM, false, |
| tc); |
| |
| switch (type) |
| { |
| case DataDictionary.PRIMARYKEY_CONSTRAINT: |
| case DataDictionary.FOREIGNKEY_CONSTRAINT: |
| case DataDictionary.UNIQUE_CONSTRAINT: |
| if (SanityManager.DEBUG) |
| { |
| if (!(descriptor instanceof KeyConstraintDescriptor)) |
| { |
| SanityManager.THROWASSERT( |
| "descriptor expected to be instanceof KeyConstraintDescriptor, " + |
| "not, " + descriptor.getClass().getName()); |
| } |
| } |
| |
| addSubKeyConstraint((KeyConstraintDescriptor) descriptor, tc); |
| break; |
| |
| case DataDictionary.CHECK_CONSTRAINT: |
| if (SanityManager.DEBUG) |
| { |
| if (!(descriptor instanceof CheckConstraintDescriptor)) |
| { |
| SanityManager.THROWASSERT("descriptor expected "+ |
| "to be instanceof CheckConstraintDescriptorImpl, " + |
| "not, " + descriptor.getClass().getName()); |
| } |
| } |
| |
| addDescriptor(descriptor, null, SYSCHECKS_CATALOG_NUM, true, tc); |
| break; |
| } |
| } |
| |
| /** |
| * Update the constraint descriptor in question. Updates |
| * every row in the base conglomerate. |
| * |
| * @param cd The Constraint descriptor |
| * @param formerUUID The UUID for this column in SYSCONSTRAINTS, |
| * may differ from what is in {@code cd} if this |
| * is the column that is being set. |
| * @param colsToSet Array of integers of columns to be modified, |
| * 1 based. May be null (all columns). |
| * @param tc The TransactionController to use |
| * |
| * @exception StandardException Thrown on failure |
| */ |
| public void updateConstraintDescriptor(ConstraintDescriptor cd, |
| UUID formerUUID, |
| int[] colsToSet, |
| TransactionController tc) |
| throws StandardException |
| { |
| ExecIndexRow keyRow1 = null; |
| ExecRow row; |
| DataValueDescriptor IDOrderable; |
| TabInfoImpl ti = getNonCoreTI(SYSCONSTRAINTS_CATALOG_NUM); |
| SYSCONSTRAINTSRowFactory rf = (SYSCONSTRAINTSRowFactory) ti.getCatalogRowFactory(); |
| |
| /* Use objectID/columnName in both start |
| * and stop position for index 1 scan. |
| */ |
| IDOrderable = getIDValueAsCHAR(formerUUID); |
| |
| /* Set up the start/stop position for the scan */ |
| keyRow1 = (ExecIndexRow) exFactory.getIndexableRow(1); |
| keyRow1.setColumn(1, IDOrderable); |
| |
| // build the row to be stuffed into SYSCONSTRAINTS. |
| row = rf.makeRow(cd, null); |
| |
| /* |
| ** Figure out if the index in sysconstraints needs |
| ** to be updated. |
| */ |
| if (SanityManager.DEBUG) |
| { |
| SanityManager.ASSERT(rf.getNumIndexes() == 3, |
| "There are more indexes on sysconstraints than expected, the code herein needs to change"); |
| } |
| |
| boolean[] bArray = new boolean[3]; |
| |
| /* |
| ** Do we need to update indexes? |
| */ |
| if (colsToSet == null) |
| { |
| bArray[0] = true; |
| bArray[1] = true; |
| bArray[2] = true; |
| } |
| else |
| { |
| /* |
| ** Check the specific columns for indexed |
| ** columns. |
| */ |
| for (int i = 0; i < colsToSet.length; i++) |
| { |
| switch (colsToSet[i]) |
| { |
| case SYSCONSTRAINTSRowFactory.SYSCONSTRAINTS_CONSTRAINTID: |
| bArray[0] = true; |
| break; |
| |
| case SYSCONSTRAINTSRowFactory.SYSCONSTRAINTS_CONSTRAINTNAME: |
| case SYSCONSTRAINTSRowFactory.SYSCONSTRAINTS_SCHEMAID: |
| bArray[1] = true; |
| break; |
| |
| case SYSCONSTRAINTSRowFactory.SYSCONSTRAINTS_TABLEID: |
| bArray[2] = true; |
| break; |
| } |
| } |
| } |
| |
| ti.updateRow(keyRow1, row, |
| SYSCONSTRAINTSRowFactory.SYSCONSTRAINTS_INDEX1_ID, |
| bArray, |
| colsToSet, |
| tc); |
| } |
| |
| /** |
| * Drops the given ConstraintDescriptor from the data dictionary. |
| * |
| * @param descriptor The descriptor to drop |
| * @param tc The TransactionController |
| * |
| * @exception StandardException Thrown on error |
| */ |
| public void dropConstraintDescriptor( |
| ConstraintDescriptor descriptor, |
| TransactionController tc) |
| throws StandardException |
| { |
| ExecIndexRow keyRow = null; |
| DataValueDescriptor schemaIDOrderable; |
| DataValueDescriptor constraintNameOrderable; |
| TabInfoImpl ti = getNonCoreTI(SYSCONSTRAINTS_CATALOG_NUM); |
| |
| switch (descriptor.getConstraintType()) |
| { |
| case DataDictionary.PRIMARYKEY_CONSTRAINT: |
| case DataDictionary.FOREIGNKEY_CONSTRAINT: |
| case DataDictionary.UNIQUE_CONSTRAINT: |
| dropSubKeyConstraint( |
| descriptor, |
| tc); |
| break; |
| |
| case DataDictionary.CHECK_CONSTRAINT: |
| dropSubCheckConstraint( |
| descriptor.getUUID(), |
| tc); |
| break; |
| } |
| |
| /* Use constraintNameOrderable and schemaIdOrderable in both start |
| * and stop position for index 2 scan. |
| */ |
| constraintNameOrderable = new SQLVarchar(descriptor.getConstraintName()); |
| schemaIDOrderable = getIDValueAsCHAR(descriptor.getSchemaDescriptor().getUUID()); |
| |
| /* Set up the start/stop position for the scan */ |
| keyRow = (ExecIndexRow) exFactory.getIndexableRow(2); |
| keyRow.setColumn(1, constraintNameOrderable); |
| keyRow.setColumn(2, schemaIDOrderable); |
| |
| ti.deleteRow( tc, keyRow, SYSCONSTRAINTSRowFactory.SYSCONSTRAINTS_INDEX2_ID ); |
| } |
| |
| /** |
| * Drops all ConstraintDescriptors from the data dictionary |
| * that are associated with the given table, |
| * |
| * @param table The table from which to drop all |
| * constraint descriptors |
| * @param tc The TransactionController |
| * |
| * @exception StandardException Thrown on error |
| */ |
| public void dropAllConstraintDescriptors(TableDescriptor table, |
| TransactionController tc) |
| throws StandardException |
| { |
| ConstraintDescriptorList cdl = getConstraintDescriptors(table); |
| |
| // Walk the table's CDL and drop each ConstraintDescriptor. |
| for (Iterator iterator = cdl.iterator(); iterator.hasNext(); ) |
| { |
| ConstraintDescriptor cd = (ConstraintDescriptor) iterator.next(); |
| dropConstraintDescriptor(cd, tc); |
| } |
| |
| /* |
| ** Null out the table's constraint descriptor list. NOTE: This is |
| ** not really necessary at the time of this writing (11/3/97), because |
| ** we do not cache data dictionary objects while DDL is going on, |
| ** but in the future it might be necessary. |
| */ |
| table.setConstraintDescriptorList(null); |
| } |
| |
| /** |
| * Get a SubKeyConstraintDescriptor from syskeys or sysforeignkeys for |
| * the specified constraint id. For primary foreign and and unique |
| * key constraints. |
| * |
| * @param constraintId The UUID for the constraint. |
| * @param type The type of the constraint |
| * (e.g. DataDictionary.FOREIGNKEY_CONSTRAINT) |
| * |
| * @return SubKeyConstraintDescriptor The Sub descriptor for the constraint. |
| * |
| * @exception StandardException Thrown on failure |
| */ |
| public SubKeyConstraintDescriptor getSubKeyConstraint(UUID constraintId, int type) |
| throws StandardException |
| { |
| DataValueDescriptor constraintIDOrderable = null; |
| TabInfoImpl ti; |
| int indexNum; |
| int baseNum; |
| |
| if (type == DataDictionary.FOREIGNKEY_CONSTRAINT) |
| { |
| baseNum = SYSFOREIGNKEYS_CATALOG_NUM; |
| indexNum = SYSFOREIGNKEYSRowFactory.SYSFOREIGNKEYS_INDEX1_ID; |
| } |
| else |
| { |
| baseNum = SYSKEYS_CATALOG_NUM; |
| indexNum = SYSKEYSRowFactory.SYSKEYS_INDEX1_ID; |
| } |
| ti = getNonCoreTI(baseNum); |
| |
| /* Use constraintIDOrderable in both start and stop positions for scan */ |
| constraintIDOrderable = getIDValueAsCHAR(constraintId); |
| |
| /* Set up the start/stop position for the scan */ |
| ExecIndexRow keyRow = (ExecIndexRow) exFactory.getIndexableRow(1); |
| keyRow.setColumn(1, constraintIDOrderable); |
| |
| return getDescriptorViaIndex( |
| indexNum, |
| keyRow, |
| (ScanQualifier [][]) null, |
| ti, |
| (TupleDescriptor) null, |
| (List<TupleDescriptor>) null, |
| SubKeyConstraintDescriptor.class, |
| false); |
| } |
| |
| /** |
| * Add the matching row to syskeys when adding a unique or primary key constraint |
| * |
| * @param descriptor The KeyConstraintDescriptor for the constraint. |
| * @param tc The TransactionController |
| * |
| * @exception StandardException Thrown on failure |
| */ |
| private void addSubKeyConstraint(KeyConstraintDescriptor descriptor, |
| TransactionController tc) |
| throws StandardException |
| { |
| ExecRow row; |
| TabInfoImpl ti; |
| |
| /* |
| ** Foreign keys get a row in SYSFOREIGNKEYS, and |
| ** all others get a row in SYSKEYS. |
| */ |
| if (descriptor.getConstraintType() |
| == DataDictionary.FOREIGNKEY_CONSTRAINT) |
| { |
| ForeignKeyConstraintDescriptor fkDescriptor = |
| (ForeignKeyConstraintDescriptor)descriptor; |
| |
| if (SanityManager.DEBUG) |
| { |
| if (!(descriptor instanceof ForeignKeyConstraintDescriptor)) |
| { |
| SanityManager.THROWASSERT("descriptor not an fk descriptor, is "+ |
| descriptor.getClass().getName()); |
| } |
| } |
| |
| ti = getNonCoreTI(SYSFOREIGNKEYS_CATALOG_NUM); |
| SYSFOREIGNKEYSRowFactory fkkeysRF = (SYSFOREIGNKEYSRowFactory)ti.getCatalogRowFactory(); |
| |
| row = fkkeysRF.makeRow(fkDescriptor, null); |
| |
| /* |
| ** Now we need to bump the reference count of the |
| ** constraint that this FK references |
| */ |
| ReferencedKeyConstraintDescriptor refDescriptor = |
| fkDescriptor.getReferencedConstraint(); |
| |
| refDescriptor.incrementReferenceCount(); |
| |
| int[] colsToSet = new int[1]; |
| colsToSet[0] = SYSCONSTRAINTSRowFactory.SYSCONSTRAINTS_REFERENCECOUNT; |
| |
| updateConstraintDescriptor(refDescriptor, |
| refDescriptor.getUUID(), |
| colsToSet, |
| tc); |
| } |
| else |
| { |
| ti = getNonCoreTI(SYSKEYS_CATALOG_NUM); |
| SYSKEYSRowFactory keysRF = (SYSKEYSRowFactory) ti.getCatalogRowFactory(); |
| |
| // build the row to be stuffed into SYSKEYS |
| row = keysRF.makeRow(descriptor, null); |
| } |
| |
| // insert row into catalog and all its indices |
| ti.insertRow(row, tc); |
| } |
| |
| /** |
| * Drop the matching row from syskeys when dropping a primary key |
| * or unique constraint. |
| * |
| * @param constraint the constraint |
| * @param tc The TransactionController |
| * |
| * @exception StandardException Thrown on failure |
| */ |
| private void dropSubKeyConstraint(ConstraintDescriptor constraint, TransactionController tc) |
| throws StandardException |
| { |
| ExecIndexRow keyRow1 = null; |
| DataValueDescriptor constraintIdOrderable; |
| TabInfoImpl ti; |
| int baseNum; |
| int indexNum; |
| |
| if (constraint.getConstraintType() |
| == DataDictionary.FOREIGNKEY_CONSTRAINT) |
| { |
| baseNum = SYSFOREIGNKEYS_CATALOG_NUM; |
| indexNum = SYSFOREIGNKEYSRowFactory.SYSFOREIGNKEYS_INDEX1_ID; |
| |
| /* |
| ** If we have a foreign key, we need to decrement the |
| ** reference count of the contraint that this FK references. |
| ** We need to do this *before* we drop the foreign key |
| ** because of the way FK.getReferencedConstraint() works. |
| */ |
| if (constraint.getConstraintType() |
| == DataDictionary.FOREIGNKEY_CONSTRAINT) |
| { |
| ReferencedKeyConstraintDescriptor refDescriptor = |
| (ReferencedKeyConstraintDescriptor) |
| getConstraintDescriptor( |
| ((ForeignKeyConstraintDescriptor)constraint). |
| getReferencedConstraintId()); |
| |
| if (refDescriptor != null) |
| { |
| refDescriptor.decrementReferenceCount(); |
| |
| int[] colsToSet = new int[1]; |
| colsToSet[0] = SYSCONSTRAINTSRowFactory.SYSCONSTRAINTS_REFERENCECOUNT; |
| |
| updateConstraintDescriptor(refDescriptor, |
| refDescriptor.getUUID(), |
| colsToSet, |
| tc); |
| } |
| } |
| } |
| else |
| { |
| baseNum = SYSKEYS_CATALOG_NUM; |
| indexNum = SYSKEYSRowFactory.SYSKEYS_INDEX1_ID; |
| } |
| |
| ti = getNonCoreTI(baseNum); |
| |
| /* Use constraintIdOrderable in both start |
| * and stop position for index 1 scan. |
| */ |
| constraintIdOrderable = getIDValueAsCHAR(constraint.getUUID()); |
| |
| /* Set up the start/stop position for the scan */ |
| keyRow1 = (ExecIndexRow) exFactory.getIndexableRow(1); |
| keyRow1.setColumn(1, constraintIdOrderable); |
| |
| ti.deleteRow( tc, keyRow1, indexNum); |
| } |
| |
| /** |
| * Get a SubCheckConstraintDescriptor from syschecks for |
| * the specified constraint id. (Useful for check constraints.) |
| * |
| * @param constraintId The UUID for the constraint. |
| * |
| * @return SubCheckConstraintDescriptor The Sub descriptor for the constraint. |
| * |
| * @exception StandardException Thrown on failure |
| */ |
| private SubCheckConstraintDescriptor getSubCheckConstraint(UUID constraintId) |
| throws StandardException |
| { |
| DataValueDescriptor constraintIDOrderable = null; |
| TabInfoImpl ti = getNonCoreTI(SYSCHECKS_CATALOG_NUM); |
| |
| /* Use constraintIDOrderable in both start and stop positions for scan */ |
| constraintIDOrderable = getIDValueAsCHAR(constraintId); |
| |
| /* Set up the start/stop position for the scan */ |
| ExecIndexRow keyRow = (ExecIndexRow) exFactory.getIndexableRow(1); |
| keyRow.setColumn(1, constraintIDOrderable); |
| |
| return getDescriptorViaIndex( |
| SYSCHECKSRowFactory.SYSCHECKS_INDEX1_ID, |
| keyRow, |
| (ScanQualifier [][]) null, |
| ti, |
| (TupleDescriptor) null, |
| (List<TupleDescriptor>) null, |
| SubCheckConstraintDescriptor.class, |
| false); |
| } |
| |
| /** |
| * Drop the matching row from syschecks when dropping a check constraint. |
| * |
| * @param constraintId The constraint id. |
| * @param tc The TransactionController |
| * |
| * @exception StandardException Thrown on failure |
| */ |
| private void dropSubCheckConstraint(UUID constraintId, TransactionController tc) |
| throws StandardException |
| { |
| ExecIndexRow checkRow1 = null; |
| DataValueDescriptor constraintIdOrderable; |
| TabInfoImpl ti = getNonCoreTI(SYSCHECKS_CATALOG_NUM); |
| |
| /* Use constraintIdOrderable in both start |
| * and stop position for index 1 scan. |
| */ |
| constraintIdOrderable = getIDValueAsCHAR(constraintId); |
| |
| /* Set up the start/stop position for the scan */ |
| checkRow1 = (ExecIndexRow) exFactory.getIndexableRow(1); |
| checkRow1.setColumn(1, constraintIdOrderable); |
| |
| ti.deleteRow( tc, checkRow1, SYSCHECKSRowFactory.SYSCHECKS_INDEX1_ID ); |
| } |
| |
| /** |
| * Get all of the ConglomerateDescriptors in the database and |
| * hash them by conglomerate number. |
| * This is useful as a performance optimization for the locking VTIs. |
| * NOTE: This method will scan SYS.SYSCONGLOMERATES at READ UNCOMMITTED. |
| * |
| * @param tc TransactionController for the transaction |
| * |
| * @return A Hashtable with all of the ConglomerateDescriptors |
| * in the database hashed by conglomerate number. |
| * |
| * @exception StandardException Thrown on failure |
| */ |
| public Hashtable<Long,ConglomerateDescriptor> hashAllConglomerateDescriptorsByNumber(TransactionController tc) |
| throws StandardException |
| { |
| Hashtable<Long,ConglomerateDescriptor> ht = new Hashtable<Long,ConglomerateDescriptor>(); |
| ConglomerateDescriptor cd = null; |
| ScanController scanController; |
| ExecRow outRow; |
| TabInfoImpl ti = coreInfo[SYSCONGLOMERATES_CORE_NUM]; |
| SYSCONGLOMERATESRowFactory rf = (SYSCONGLOMERATESRowFactory) ti.getCatalogRowFactory(); |
| |
| outRow = rf.makeEmptyRow(); |
| scanController = tc.openScan( |
| ti.getHeapConglomerate(), // conglomerate to open |
| false, // don't hold open across commit |
| 0, // for read |
| TransactionController.MODE_RECORD, // scans whole table. |
| TransactionController.ISOLATION_READ_UNCOMMITTED, |
| (FormatableBitSet) null, // all fields as objects |
| (DataValueDescriptor[]) null, //keyRow.getRowArray(), // start position - first row |
| ScanController.GE, // startSearchOperation |
| (ScanQualifier [][]) null, |
| (DataValueDescriptor[]) null, //keyRow.getRowArray(), // stop position - through last row |
| ScanController.GT); // stopSearchOperation |
| |
| // it is important for read uncommitted scans to use fetchNext() rather |
| // than fetch, so that the fetch happens while latch is held, otherwise |
| // the next() might position the scan on a row, but the subsequent |
| // fetch() may find the row deleted or purged from the table. |
| while (scanController.fetchNext(outRow.getRowArray())) |
| { |
| cd = (ConglomerateDescriptor) rf.buildDescriptor( |
| outRow, |
| (TupleDescriptor) null, |
| this ); |
| Long hashKey = cd.getConglomerateNumber(); |
| ht.put(hashKey, cd); |
| } |
| |
| scanController.close(); |
| |
| return ht; |
| } |
| |
| /** |
| * Get all of the TableDescriptors in the database and hash them |
| * by TableId This is useful as a performance optimization for the |
| * locking VTIs. NOTE: This method will scan SYS.SYSTABLES and |
| * SYS.SYSSCHEMAS at READ UNCOMMITTED. |
| * |
| * @param tc TransactionController for the transaction |
| * |
| * @return A Hashtable with all of the Table descriptors in the database |
| * hashed by TableId |
| * |
| * |
| * @exception StandardException Thrown on failure |
| */ |
| @SuppressWarnings("UseOfObsoleteCollectionType") |
| public Hashtable<UUID,TableDescriptor> hashAllTableDescriptorsByTableId(TransactionController tc) |
| throws StandardException |
| { |
| Hashtable<UUID,TableDescriptor> ht = new Hashtable<UUID,TableDescriptor>(); |
| ScanController scanController; |
| ExecRow outRow; |
| TabInfoImpl ti = coreInfo[SYSTABLES_CORE_NUM]; |
| SYSTABLESRowFactory |
| rf = (SYSTABLESRowFactory) ti.getCatalogRowFactory(); |
| |
| outRow = rf.makeEmptyRow(); |
| |
| scanController = tc.openScan( |
| ti.getHeapConglomerate(), // sys.systable |
| false, // don't hold open across commit |
| 0, // for read |
| TransactionController.MODE_RECORD,// scans whole table. |
| TransactionController.ISOLATION_READ_UNCOMMITTED, |
| (FormatableBitSet) null, // all fields as objects |
| (DataValueDescriptor[])null, // start position - first row |
| ScanController.GE, // startSearchOperation |
| (ScanQualifier[][])null, //scanQualifier, |
| (DataValueDescriptor[])null, //stop position-through last row |
| ScanController.GT); // stopSearchOperation |
| |
| // it is important for read uncommitted scans to use fetchNext() rather |
| // than fetch, so that the fetch happens while latch is held, otherwise |
| // the next() might position the scan on a row, but the subsequent |
| // fetch() may find the row deleted or purged from the table. |
| while(scanController.fetchNext(outRow.getRowArray())) |
| { |
| TableDescriptor td = (TableDescriptor) |
| rf.buildDescriptor( |
| outRow, |
| (TupleDescriptor)null, |
| this, |
| TransactionController.ISOLATION_READ_UNCOMMITTED); |
| ht.put(td.getUUID(), td); |
| } |
| scanController.close(); |
| return ht; |
| } |
| |
| /** |
| * Get a ConglomerateDescriptor given its UUID. If it is an index |
| * conglomerate shared by at least another duplicate index, this returns |
| * one of the ConglomerateDescriptors for those indexes. |
| * |
| * @param uuid The UUID |
| * |
| * |
| * @return A ConglomerateDescriptor for the conglomerate. |
| * |
| * @exception StandardException Thrown on failure |
| */ |
| public ConglomerateDescriptor getConglomerateDescriptor(UUID uuid) |
| throws StandardException |
| { |
| ConglomerateDescriptor[] cds = getConglomerateDescriptors(uuid); |
| if (cds.length == 0) |
| return null; |
| return cds[0]; |
| } |
| |
| /** |
| * Get an array of ConglomerateDescriptors given the UUID. If it is a |
| * heap conglomerate or an index conglomerate not shared by a duplicate |
| * index, the size of the return array is 1. If the uuid argument is null, then |
| * this method retrieves descriptors for all of the conglomerates in the database. |
| * |
| * @param uuid The UUID |
| * |
| * |
| * @return An array of ConglomerateDescriptors for the conglomerate. |
| * returns size 0 array if no such conglomerate. |
| * |
| * @exception StandardException Thrown on failure |
| */ |
| public ConglomerateDescriptor[] getConglomerateDescriptors(UUID uuid) |
| throws StandardException |
| { |
| DataValueDescriptor UUIDStringOrderable; |
| TabInfoImpl ti = coreInfo[SYSCONGLOMERATES_CORE_NUM]; |
| |
| List<ConglomerateDescriptor> cdl = newSList(); |
| |
| if ( uuid != null ) |
| { |
| /* Use UUIDStringOrderable in both start and stop positions for scan */ |
| UUIDStringOrderable = getIDValueAsCHAR(uuid); |
| |
| /* Set up the start/stop position for the scan */ |
| ExecIndexRow keyRow = exFactory.getIndexableRow(1); |
| keyRow.setColumn(1, UUIDStringOrderable); |
| |
| getDescriptorViaIndex( |
| SYSCONGLOMERATESRowFactory.SYSCONGLOMERATES_INDEX1_ID, |
| keyRow, |
| (ScanQualifier [][]) null, |
| ti, |
| (TupleDescriptor) null, |
| cdl, |
| ConglomerateDescriptor.class, |
| false); |
| } |
| else |
| { |
| getDescriptorViaHeap |
| ( |
| null, |
| (ScanQualifier[][]) null, |
| ti, |
| (TupleDescriptor) null, |
| cdl, |
| ConglomerateDescriptor.class |
| ); |
| } |
| |
| return cdl.toArray(new ConglomerateDescriptor[cdl.size()]); |
| |
| } |
| |
| /** |
| * Get a ConglomerateDescriptor given its conglomerate number. If it is an |
| * index conglomerate shared by at least another duplicate index, this |
| * returns one of the ConglomerateDescriptors for those indexes. |
| * |
| * @param conglomerateNumber The conglomerate number. |
| * |
| * |
| * @return A ConglomerateDescriptor for the conglomerate. Returns NULL if |
| * no such conglomerate. |
| * |
| * @exception StandardException Thrown on failure |
| */ |
| public ConglomerateDescriptor getConglomerateDescriptor( |
| long conglomerateNumber) |
| throws StandardException |
| { |
| ConglomerateDescriptor[] cds = getConglomerateDescriptors(conglomerateNumber); |
| if (cds.length == 0) |
| return null; |
| return cds[0]; |
| } |
| |
| /** |
| * Get an array of conglomerate descriptors for the given conglomerate |
| * number. If it is a heap conglomerate or an index conglomerate not |
| * shared by a duplicate index, the size of the return array is 1. |
| * |
| * @param conglomerateNumber The number for the conglomerate |
| * we're interested in |
| * |
| * @return An array of ConglomerateDescriptors that share the requested |
| * conglomerate. Returns size 0 array if no such conglomerate. |
| * |
| * @exception StandardException Thrown on failure |
| */ |
| public ConglomerateDescriptor[] getConglomerateDescriptors( |
| long conglomerateNumber) |
| throws StandardException |
| { |
| DataValueDescriptor conglomNumberOrderable = null; |
| TabInfoImpl ti = coreInfo[SYSCONGLOMERATES_CORE_NUM]; |
| SYSCONGLOMERATESRowFactory rf = (SYSCONGLOMERATESRowFactory) ti.getCatalogRowFactory(); |
| |
| conglomNumberOrderable = |
| new SQLLongint(conglomerateNumber); |
| |
| ScanQualifier[][] scanQualifier = exFactory.getScanQualifier(1); |
| scanQualifier[0][0].setQualifier( |
| rf.SYSCONGLOMERATES_CONGLOMERATENUMBER - 1, /* column number */ |
| conglomNumberOrderable, |
| Orderable.ORDER_OP_EQUALS, |
| false, |
| false, |
| false); |
| |
| ConglomerateDescriptorList cdl = new ConglomerateDescriptorList(); |
| getDescriptorViaHeap( |
| null, scanQualifier, ti, null, cdl, ConglomerateDescriptor.class); |
| |
| return cdl.toArray(new ConglomerateDescriptor[cdl.size()]); |
| } |
| |
| |
| /** |
| * Populate the ConglomerateDescriptorList for the |
| * specified TableDescriptor by scanning sysconglomerates. |
| * |
| * MT synchronization: it is assumed that the caller has synchronized |
| * on the CDL in the given TD. |
| * |
| * @param td The TableDescriptor. |
| * |
| * @exception StandardException Thrown on failure |
| */ |
| private void getConglomerateDescriptorsScan(TableDescriptor td) |
| throws StandardException |
| { |
| ConglomerateDescriptorList cdl = td.getConglomerateDescriptorList(); |
| |
| ExecIndexRow keyRow3 = null; |
| DataValueDescriptor tableIDOrderable; |
| TabInfoImpl ti = coreInfo[SYSCONGLOMERATES_CORE_NUM]; |
| |
| /* Use tableIDOrderable in both start and stop positions for scan */ |
| tableIDOrderable = getIDValueAsCHAR(td.getUUID()); |
| |
| /* Set up the start/stop position for the scan */ |
| keyRow3 = (ExecIndexRow) exFactory.getIndexableRow(1); |
| keyRow3.setColumn(1, tableIDOrderable); |
| |
| getDescriptorViaIndex( |
| SYSCONGLOMERATESRowFactory.SYSCONGLOMERATES_INDEX3_ID, |
| keyRow3, |
| (ScanQualifier [][]) null, |
| ti, |
| (TupleDescriptor) null, |
| cdl, |
| ConglomerateDescriptor.class, |
| false); |
| } |
| |
| /** |
| * Gets a conglomerate descriptor for the named index in the given schema, |
| * getting an exclusive row lock on the matching row in |
| * sys.sysconglomerates (for DDL concurrency) if requested. |
| * |
| * @param indexName The name of the index we're looking for |
| * @param sd The schema descriptor |
| * @param forUpdate Whether or not to get an exclusive row |
| * lock on the row in sys.sysconglomerates. |
| * |
| * @return A ConglomerateDescriptor describing the requested |
| * conglomerate. Returns NULL if no such conglomerate. |
| * |
| * @exception StandardException Thrown on failure |
| */ |
| public ConglomerateDescriptor getConglomerateDescriptor( |
| String indexName, |
| SchemaDescriptor sd, |
| boolean forUpdate) |
| throws StandardException |
| { |
| ExecIndexRow keyRow2 = null; |
| DataValueDescriptor nameOrderable; |
| DataValueDescriptor schemaIDOrderable = null; |
| TabInfoImpl ti = coreInfo[SYSCONGLOMERATES_CORE_NUM]; |
| |
| nameOrderable = new SQLVarchar(indexName); |
| schemaIDOrderable = getIDValueAsCHAR(sd.getUUID()); |
| |
| /* Set up the start/stop position for the scan */ |
| keyRow2 = exFactory.getIndexableRow(2); |
| keyRow2.setColumn(1, nameOrderable); |
| keyRow2.setColumn(2, schemaIDOrderable); |
| |
| return getDescriptorViaIndex( |
| SYSCONGLOMERATESRowFactory.SYSCONGLOMERATES_INDEX2_ID, |
| keyRow2, |
| (ScanQualifier [][]) null, |
| ti, |
| (TupleDescriptor) null, |
| (List<TupleDescriptor>) null, |
| ConglomerateDescriptor.class, |
| forUpdate); |
| } |
| |
| /** |
| * Drops a conglomerate descriptor |
| * |
| * @param conglomerate The ConglomerateDescriptor for the conglomerate |
| * @param tc TransactionController for the transaction |
| * |
| * @exception StandardException Thrown on failure |
| */ |
| public void dropConglomerateDescriptor( |
| ConglomerateDescriptor conglomerate, |
| TransactionController tc) |
| throws StandardException |
| { |
| ExecIndexRow keyRow2 = null; |
| DataValueDescriptor nameOrderable; |
| DataValueDescriptor schemaIDOrderable = null; |
| TabInfoImpl ti = coreInfo[SYSCONGLOMERATES_CORE_NUM]; |
| |
| nameOrderable = new SQLVarchar(conglomerate.getConglomerateName()); |
| schemaIDOrderable = getIDValueAsCHAR(conglomerate.getSchemaID()); |
| |
| /* Set up the start/stop position for the scan */ |
| keyRow2 = (ExecIndexRow) exFactory.getIndexableRow(2); |
| keyRow2.setColumn(1, nameOrderable); |
| keyRow2.setColumn(2, schemaIDOrderable); |
| |
| ti.deleteRow( tc, keyRow2, SYSCONGLOMERATESRowFactory.SYSCONGLOMERATES_INDEX2_ID ); |
| |
| } |
| |
| /** |
| * Drops all conglomerates associated with a table. |
| * |
| * @param td The TableDescriptor of the table |
| * @param tc TransactionController for the transaction |
| * |
| * @exception StandardException Thrown on failure |
| */ |
| |
| public void dropAllConglomerateDescriptors( |
| TableDescriptor td, |
| TransactionController tc) |
| throws StandardException |
| { |
| ExecIndexRow keyRow3 = null; |
| DataValueDescriptor tableIDOrderable; |
| TabInfoImpl ti = coreInfo[SYSCONGLOMERATES_CORE_NUM]; |
| |
| /* Use tableIDOrderable in both start |
| * and stop position for index 3 scan. |
| */ |
| tableIDOrderable = getIDValueAsCHAR(td.getUUID()); |
| |
| /* Set up the start/stop position for the scan */ |
| keyRow3 = (ExecIndexRow) exFactory.getIndexableRow(1); |
| keyRow3.setColumn(1, tableIDOrderable); |
| |
| |
| ti.deleteRow( tc, keyRow3, SYSCONGLOMERATESRowFactory.SYSCONGLOMERATES_INDEX3_ID ); |
| } |
| |
| /** |
| * Update the conglomerateNumber for a ConglomerateDescriptor. |
| * This is useful, in 1.3, when doing a bulkInsert into an |
| * empty table where we insert into a new conglomerate. |
| * (This will go away in 1.4.) |
| * |
| * @param cd The ConglomerateDescriptor |
| * @param conglomerateNumber The new conglomerate number |
| * @param tc The TransactionController to use |
| * |
| * @exception StandardException Thrown on failure |
| */ |
| public void updateConglomerateDescriptor(ConglomerateDescriptor cd, |
| long conglomerateNumber, |
| TransactionController tc) |
| throws StandardException |
| { |
| ConglomerateDescriptor[] cds = new ConglomerateDescriptor[1]; |
| cds[0] = cd; |
| updateConglomerateDescriptor(cds, conglomerateNumber, tc); |
| } |
| |
| /** |
| * Update all system schemas to have new authorizationId. This is needed |
| * while upgrading pre-10.2 databases to 10.2 or later versions. From 10.2, |
| * all system schemas would be owned by database owner's authorizationId. |
| * |
| * @param aid AuthorizationID of Database Owner |
| * @param tc TransactionController to use |
| * |
| * @exception StandardException Thrown on failure |
| */ |
| public void updateSystemSchemaAuthorization(String aid, |
| TransactionController tc) |
| throws StandardException |
| { |
| updateSchemaAuth(SchemaDescriptor.STD_SYSTEM_SCHEMA_NAME, aid, tc); |
| updateSchemaAuth(SchemaDescriptor.IBM_SYSTEM_SCHEMA_NAME, aid, tc); |
| |
| updateSchemaAuth(SchemaDescriptor.IBM_SYSTEM_CAT_SCHEMA_NAME, aid, tc); |
| updateSchemaAuth(SchemaDescriptor.IBM_SYSTEM_FUN_SCHEMA_NAME, aid, tc); |
| updateSchemaAuth(SchemaDescriptor.IBM_SYSTEM_PROC_SCHEMA_NAME, aid, tc); |
| updateSchemaAuth(SchemaDescriptor.IBM_SYSTEM_STAT_SCHEMA_NAME, aid, tc); |
| updateSchemaAuth(SchemaDescriptor.IBM_SYSTEM_NULLID_SCHEMA_NAME, aid, tc); |
| |
| updateSchemaAuth(SchemaDescriptor.STD_SQLJ_SCHEMA_NAME, aid, tc); |
| updateSchemaAuth(SchemaDescriptor.STD_SYSTEM_DIAG_SCHEMA_NAME, aid, tc); |
| updateSchemaAuth(SchemaDescriptor.STD_SYSTEM_UTIL_SCHEMA_NAME, aid, tc); |
| |
| // now reset our understanding of who owns the database |
| resetDatabaseOwner( tc ); |
| } |
| |
| /** |
| * Update authorizationId of specified schemaName |
| * |
| * @param schemaName Schema Name of system schema |
| * @param authorizationId authorizationId of new schema owner |
| * @param tc The TransactionController to use |
| * |
| * @exception StandardException Thrown on failure |
| */ |
| public void updateSchemaAuth(String schemaName, |
| String authorizationId, |
| TransactionController tc) |
| throws StandardException |
| { |
| ExecIndexRow keyRow; |
| DataValueDescriptor schemaNameOrderable; |
| TabInfoImpl ti = coreInfo[SYSSCHEMAS_CORE_NUM]; |
| |
| /* Use schemaNameOrderable in both start |
| * and stop position for index 1 scan. |
| */ |
| schemaNameOrderable = new SQLVarchar(schemaName); |
| |
| /* Set up the start/stop position for the scan */ |
| keyRow = (ExecIndexRow) exFactory.getIndexableRow(1); |
| keyRow.setColumn(1, schemaNameOrderable); |
| |
| SYSSCHEMASRowFactory rf = (SYSSCHEMASRowFactory) ti.getCatalogRowFactory(); |
| ExecRow row = rf.makeEmptyRow(); |
| |
| row.setColumn(SYSSCHEMASRowFactory.SYSSCHEMAS_SCHEMAAID, |
| new SQLVarchar(authorizationId)); |
| |
| boolean[] bArray = {false, false}; |
| |
| int[] colsToUpdate = {SYSSCHEMASRowFactory.SYSSCHEMAS_SCHEMAAID}; |
| |
| ti.updateRow(keyRow, row, |
| SYSSCHEMASRowFactory.SYSSCHEMAS_INDEX1_ID, |
| bArray, |
| colsToUpdate, |
| tc); |
| } |
| |
| /** |
| * Update the conglomerateNumber for an array of ConglomerateDescriptors. |
| * In case of more than one ConglomerateDescriptor, each descriptor |
| * should be updated separately, conglomerate id is not same for all |
| * the descriptors. Even when indexes are sharing the same |
| * conglomerate(conglomerate number), conglomerate ids are unique. |
| * |
| * This is useful, in 1.3, when doing a bulkInsert into an |
| * empty table where we insert into a new conglomerate. |
| * (This will go away in 1.4.) |
| * |
| * @param cds The array of ConglomerateDescriptors |
| * @param conglomerateNumber The new conglomerate number |
| * @param tc The TransactionController to use |
| * |
| * @exception StandardException Thrown on failure |
| */ |
| public void updateConglomerateDescriptor(ConglomerateDescriptor[] cds, |
| long conglomerateNumber, |
| TransactionController tc) |
| throws StandardException |
| { |
| ExecIndexRow keyRow1 = null; |
| ExecRow row; |
| DataValueDescriptor conglomIDOrderable; |
| TabInfoImpl ti = coreInfo[SYSCONGLOMERATES_CORE_NUM]; |
| SYSCONGLOMERATESRowFactory rf = (SYSCONGLOMERATESRowFactory) ti.getCatalogRowFactory(); |
| boolean[] bArray = {false, false, false}; |
| |
| for (int i = 0; i < cds.length; i++) |
| { |
| /* Use conglomIDOrderable in both start |
| * and stop position for index 1 scan. |
| */ |
| conglomIDOrderable = getIDValueAsCHAR(cds[i].getUUID()); |
| |
| /* Set up the start/stop position for the scan */ |
| keyRow1 = (ExecIndexRow) exFactory.getIndexableRow(1); |
| keyRow1.setColumn(1, conglomIDOrderable); |
| |
| cds[i].setConglomerateNumber(conglomerateNumber); |
| // build the row to be stuffed into SYSCONGLOMERATES. |
| row = rf.makeRow(cds[i], null); |
| |
| // update row in catalog (no indexes) |
| ti.updateRow(keyRow1, row, |
| SYSCONGLOMERATESRowFactory.SYSCONGLOMERATES_INDEX1_ID, |
| bArray, |
| (int[])null, |
| tc); |
| } |
| |
| } |
| |
| |
| /** |
| * Gets a list of the dependency descriptors for the given dependent's id. |
| * |
| * @param dependentID The ID of the dependent we're interested in |
| * |
| * @return List Returns a list of DependencyDescriptors. |
| * Returns an empty List if no stored dependencies for the |
| * dependent's ID. |
| * |
| * @exception StandardException Thrown on failure |
| */ |
| public List<DependencyDescriptor> getDependentsDescriptorList(String dependentID) |
| throws StandardException |
| { |
| List<DependencyDescriptor> ddlList = newSList(); |
| DataValueDescriptor dependentIDOrderable; |
| TabInfoImpl ti = getNonCoreTI(SYSDEPENDS_CATALOG_NUM); |
| |
| /* Use dependentIDOrderable in both start and stop positions for scan */ |
| dependentIDOrderable = new SQLChar(dependentID); |
| |
| /* Set up the start/stop position for the scan */ |
| ExecIndexRow keyRow = exFactory.getIndexableRow(1); |
| keyRow.setColumn(1, dependentIDOrderable); |
| |
| getDescriptorViaIndex( |
| SYSDEPENDSRowFactory.SYSDEPENDS_INDEX1_ID, |
| keyRow, |
| (ScanQualifier [][]) null, |
| ti, |
| (TupleDescriptor) null, |
| ddlList, |
| DependencyDescriptor.class, |
| false); |
| |
| return ddlList; |
| } |
| |
| /** |
| * Gets a list of the dependency descriptors for the given provider's id. |
| * |
| * @param providerID The ID of the provider we're interested in |
| * |
| * @return List Returns a list of DependencyDescriptors. |
| * Returns an empty List if no stored dependencies for the |
| * provider's ID. |
| * |
| * @exception StandardException Thrown on failure |
| */ |
| public List<DependencyDescriptor> getProvidersDescriptorList(String providerID) |
| throws StandardException |
| { |
| List<DependencyDescriptor> ddlList = newSList(); |
| DataValueDescriptor providerIDOrderable; |
| TabInfoImpl ti = getNonCoreTI(SYSDEPENDS_CATALOG_NUM); |
| |
| /* Use providerIDOrderable in both start and stop positions for scan */ |
| providerIDOrderable = new SQLChar(providerID); |
| |
| /* Set up the start/stop position for the scan */ |
| ExecIndexRow keyRow = exFactory.getIndexableRow(1); |
| keyRow.setColumn(1, providerIDOrderable); |
| |
| getDescriptorViaIndex( |
| SYSDEPENDSRowFactory.SYSDEPENDS_INDEX2_ID, |
| keyRow, |
| (ScanQualifier [][]) null, |
| ti, |
| (TupleDescriptor) null, |
| ddlList, |
| DependencyDescriptor.class, |
| false); |
| |
| return ddlList; |
| } |
| |
| /** |
| * Build and return an List with DependencyDescriptors for |
| * all of the stored dependencies. |
| * This is useful for consistency checking. |
| * |
| * @return List List of all DependencyDescriptors. |
| * |
| * @exception StandardException Thrown on failure |
| */ |
| public List<TupleDescriptor> getAllDependencyDescriptorsList() |
| throws StandardException |
| { |
| ScanController scanController; |
| TransactionController tc; |
| ExecRow outRow; |
| ExecRow templateRow; |
| List<TupleDescriptor> ddl = newSList(); |
| TabInfoImpl ti = getNonCoreTI(SYSDEPENDS_CATALOG_NUM); |
| SYSDEPENDSRowFactory rf = (SYSDEPENDSRowFactory) ti.getCatalogRowFactory(); |
| |
| |
| // Get the current transaction controller |
| tc = getTransactionCompile(); |
| |
| outRow = rf.makeEmptyRow(); |
| |
| scanController = tc.openScan( |
| ti.getHeapConglomerate(), // conglomerate to open |
| false, // don't hold open across commit |
| 0, // for read |
| TransactionController.MODE_TABLE, // scans entire table. |
| TransactionController.ISOLATION_REPEATABLE_READ, |
| (FormatableBitSet) null, // all fields as objects |
| null, // start position - first row |
| ScanController.GE, // startSearchOperation |
| null, |
| null, // stop position - through last row |
| ScanController.GT); // stopSearchOperation |
| |
| while (scanController.fetchNext(outRow.getRowArray())) |
| { |
| DependencyDescriptor dependencyDescriptor; |
| |
| dependencyDescriptor = (DependencyDescriptor) |
| rf.buildDescriptor(outRow, |
| (TupleDescriptor) null, |
| this); |
| |
| ddl.add(dependencyDescriptor); |
| } |
| |
| scanController.close(); |
| |
| return ddl; |
| } |
| |
| /** |
| * Drop a single dependency from the data dictionary. |
| * |
| * @param dd The DependencyDescriptor. |
| * @param tc TransactionController for the transaction |
| * |
| * @exception StandardException Thrown on failure |
| */ |
| public void dropStoredDependency(DependencyDescriptor dd, |
| TransactionController tc ) |
| throws StandardException |
| { |
| ExecIndexRow keyRow1 = null; |
| UUID dependentID = dd.getUUID(); |
| UUID providerID = dd.getProviderID(); |
| DataValueDescriptor dependentIDOrderable = getIDValueAsCHAR(dependentID); |
| TabInfoImpl ti = getNonCoreTI(SYSDEPENDS_CATALOG_NUM); |
| |
| /* Use dependentIDOrderable in both start |
| * and stop position for index 1 scan. |
| */ |
| keyRow1 = (ExecIndexRow) exFactory.getIndexableRow(1); |
| keyRow1.setColumn(1, dependentIDOrderable); |
| |
| // only drop the rows which have this providerID |
| TupleFilter filter = new DropDependencyFilter( providerID ); |
| |
| ti.deleteRows( tc, |
| keyRow1, // start row |
| ScanController.GE, |
| null, //qualifier |
| filter, // filter on base row |
| keyRow1, // stop row |
| ScanController.GT, |
| SYSDEPENDSRowFactory.SYSDEPENDS_INDEX1_ID ); |
| |
| } |
| |
| |
| /** |
| * Remove all of the stored dependencies for a given dependent's ID |
| * from the data dictionary. |
| * |
| * @param dependentsUUID Dependent's uuid |
| * @param tc TransactionController for the transaction |
| * |
| * @exception StandardException Thrown on failure |
| */ |
| public void dropDependentsStoredDependencies(UUID dependentsUUID, |
| TransactionController tc) |
| throws StandardException |
| { |
| dropDependentsStoredDependencies(dependentsUUID, tc, true); |
| } |
| |
| /** |
| * @inheritDoc |
| */ |
| public void dropDependentsStoredDependencies(UUID dependentsUUID, |
| TransactionController tc, |
| boolean wait) |
| throws StandardException |
| { |
| ExecIndexRow keyRow1 = null; |
| DataValueDescriptor dependentIDOrderable; |
| TabInfoImpl ti = getNonCoreTI(SYSDEPENDS_CATALOG_NUM); |
| |
| /* Use dependentIDOrderable in both start |
| * and stop position for index 1 scan. |
| */ |
| dependentIDOrderable = getIDValueAsCHAR(dependentsUUID); |
| |
| /* Set up the start/stop position for the scan */ |
| keyRow1 = (ExecIndexRow) exFactory.getIndexableRow(1); |
| keyRow1.setColumn(1, dependentIDOrderable); |
| |
| ti.deleteRow( tc, keyRow1, SYSDEPENDSRowFactory.SYSDEPENDS_INDEX1_ID, |
| wait ); |
| |
| } |
| |
| /** |
| * Get the UUID Factory. (No need to make the UUIDFactory a module.) |
| * |
| * @return UUIDFactory The UUID Factory for this DataDictionary. |
| */ |
| public UUIDFactory getUUIDFactory() |
| { |
| return uuidFactory; |
| } |
| |
| /** |
| * Get the alias descriptor for an ANSI UDT. |
| * |
| * @param tc The transaction to use: if null, use the compilation transaction |
| * @param dtd The UDT's type descriptor |
| * |
| * @return The UDT's alias descriptor if it is an ANSI UDT; null otherwise. |
| */ |
| public AliasDescriptor getAliasDescriptorForUDT( TransactionController tc, DataTypeDescriptor dtd ) throws StandardException |
| { |
| if ( tc == null ) { tc = getTransactionCompile(); } |
| |
| if ( dtd == null ) { return null; } |
| |
| BaseTypeIdImpl btii = dtd.getTypeId().getBaseTypeId(); |
| if ( !btii.isAnsiUDT() ) { return null; } |
| |
| SchemaDescriptor sd = getSchemaDescriptor( btii.getSchemaName(), tc, true ); |
| AliasDescriptor ad = getAliasDescriptor |
| ( sd.getUUID().toString(), btii.getUnqualifiedName(), AliasInfo.ALIAS_NAME_SPACE_UDT_AS_CHAR ); |
| |
| return ad; |
| } |
| |
| /** |
| * Get a AliasDescriptor given its UUID. |
| * |
| * @param uuid The UUID |
| * |
| * |
| * @return The AliasDescriptor for the alias. |
| * |
| * @exception StandardException Thrown on failure |
| */ |
| public AliasDescriptor getAliasDescriptor(UUID uuid) |
| throws StandardException |
| { |
| DataValueDescriptor UUIDStringOrderable; |
| TabInfoImpl ti = getNonCoreTI(SYSALIASES_CATALOG_NUM); |
| |
| /* Use UUIDStringOrderable in both start and stop positions for scan */ |
| UUIDStringOrderable = getIDValueAsCHAR(uuid); |
| |
| /* Set up the start/stop position for the scan */ |
| ExecIndexRow keyRow = exFactory.getIndexableRow(1); |
| keyRow.setColumn(1, UUIDStringOrderable); |
| |
| return getDescriptorViaIndex( |
| SYSALIASESRowFactory.SYSALIASES_INDEX2_ID, |
| keyRow, |
| (ScanQualifier [][]) null, |
| ti, |
| (TupleDescriptor) null, |
| (List<TupleDescriptor>) null, |
| AliasDescriptor.class, |
| false); |
| } |
| |
| /** |
| * Get a AliasDescriptor by alias name and name space. |
| * NOTE: caller responsible for handling no match. |
| * |
| @param schemaId schema identifier |
| * @param aliasName The alias name. |
| * @param nameSpace The alias type. |
| * |
| * @return AliasDescriptor AliasDescriptor for the alias name and name space |
| * |
| * @exception StandardException Thrown on failure |
| */ |
| public AliasDescriptor getAliasDescriptor(String schemaId, String aliasName, char nameSpace) |
| throws StandardException |
| { |
| DataValueDescriptor aliasNameOrderable; |
| DataValueDescriptor nameSpaceOrderable; |
| TabInfoImpl ti = getNonCoreTI(SYSALIASES_CATALOG_NUM); |
| |
| /* Use aliasNameOrderable and aliasTypeOrderable in both start |
| * and stop position for scan. |
| */ |
| aliasNameOrderable = new SQLVarchar(aliasName); |
| char[] charArray = new char[1]; |
| charArray[0] = nameSpace; |
| nameSpaceOrderable = new SQLChar(new String(charArray)); |
| |
| /* Set up the start/stop position for the scan */ |
| ExecIndexRow keyRow = exFactory.getIndexableRow(3); |
| keyRow.setColumn(1, new SQLChar(schemaId)); |
| keyRow.setColumn(2, aliasNameOrderable); |
| keyRow.setColumn(3, nameSpaceOrderable); |
| |
| return getDescriptorViaIndex( |
| SYSALIASESRowFactory.SYSALIASES_INDEX1_ID, |
| keyRow, |
| (ScanQualifier [][]) null, |
| ti, |
| (TupleDescriptor) null, |
| (List<TupleDescriptor>) null, |
| AliasDescriptor.class, |
| false); |
| } |
| |
| /** |
| Get the list of routines matching the schema and routine name. |
| While we only support a single alias for a given name,namespace just |
| return a list of zero or one item. |
| If the schema is SYSFUN then do not use the system catalogs, |
| but instead look up the routines from the in-memory table driven |
| by the contents of SYSFUN_FUNCTIONS. |
| */ |
| public java.util.List<AliasDescriptor> getRoutineList(String schemaID, String routineName, char nameSpace) |
| throws StandardException { |
| |
| // We expect to find just a single function, since we currently |
| // don't support multiple routines with the same name, but use a |
| // list to support future extension. |
| List<AliasDescriptor> list = new ArrayList<AliasDescriptor>(1); |
| |
| // Special in-memory table lookup for SYSFUN |
| if (schemaID.equals(SchemaDescriptor.SYSFUN_SCHEMA_UUID) |
| && nameSpace == AliasInfo.ALIAS_NAME_SPACE_FUNCTION_AS_CHAR) |
| { |
| for (int f = 0; f < DataDictionaryImpl.SYSFUN_FUNCTIONS.length; f++) |
| { |
| String[] details = DataDictionaryImpl.SYSFUN_FUNCTIONS[f]; |
| String name = details[0]; |
| if (!name.equals(routineName)) |
| continue; |
| |
| AliasDescriptor ad = sysfunDescriptors[f]; |
| if (ad == null) |
| { |
| // details[1] Return type |
| TypeDescriptor rt = |
| DataTypeDescriptor.getBuiltInDataTypeDescriptor(details[1]).getCatalogType(); |
| |
| boolean isDeterministic = Boolean.valueOf( details[ SYSFUN_DETERMINISTIC_INDEX ] ).booleanValue(); |
| boolean hasVarargs = Boolean.valueOf( details[ SYSFUN_VARARGS_INDEX ] ).booleanValue(); |
| |
| // Determine the number of arguments (could be zero). |
| int paramCount = details.length - SYSFUN_FIRST_PARAMETER_INDEX; |
| TypeDescriptor[] pt = new TypeDescriptor[paramCount]; |
| String[] paramNames = new String[paramCount]; |
| int[] paramModes = new int[paramCount]; |
| for (int i = 0; i < paramCount; i++) { |
| pt[i] = DataTypeDescriptor.getBuiltInDataTypeDescriptor( |
| details[SYSFUN_FIRST_PARAMETER_INDEX +i]).getCatalogType(); |
| paramNames[i] = "P" + (i +1); // Dummy names |
| // All parameters must be IN. |
| paramModes[i] = (ParameterMetaData.parameterModeIn); |
| } |
| |
| // details[3] = java method |
| RoutineAliasInfo ai = new RoutineAliasInfo(details[3], |
| paramCount, paramNames, |
| pt, paramModes, 0, |
| RoutineAliasInfo.PS_JAVA, RoutineAliasInfo.NO_SQL, isDeterministic, hasVarargs, |
| false, /* hasDefinersRights */ |
| false, rt); |
| |
| // details[2] = class name |
| ad = new AliasDescriptor(this, uuidFactory.createUUID(), name, |
| uuidFactory.recreateUUID(schemaID), |
| details[2], AliasInfo.ALIAS_TYPE_FUNCTION_AS_CHAR, |
| AliasInfo.ALIAS_NAME_SPACE_FUNCTION_AS_CHAR, |
| true, ai, null); |
| |
| sysfunDescriptors[f] = ad; |
| } |
| list.add(ad); |
| } |
| return list; |
| } |
| |
| AliasDescriptor ad = getAliasDescriptor(schemaID, routineName, nameSpace); |
| if ( ad !=null ) { list.add( ad ); } |
| |
| return list; |
| } |
| |
| /** |
| * Drop a AliasDescriptor from the DataDictionary |
| * |
| * @param ad The AliasDescriptor to drop |
| * @param tc The TransactionController |
| * |
| * @exception StandardException Thrown on failure |
| */ |
| |
| public void dropAliasDescriptor(AliasDescriptor ad, |
| TransactionController tc) |
| throws StandardException |
| { |
| TabInfoImpl ti = getNonCoreTI(SYSALIASES_CATALOG_NUM); |
| |
| /* Use aliasNameOrderable and nameSpaceOrderable in both start |
| * and stop position for index 1 scan. |
| */ |
| |
| char[] charArray = new char[1]; |
| charArray[0] = ad.getNameSpace(); |
| |
| /* Set up the start/stop position for the scan */ |
| ExecIndexRow keyRow1 = (ExecIndexRow) exFactory.getIndexableRow(3); |
| keyRow1.setColumn(1, getIDValueAsCHAR(ad.getSchemaUUID())); |
| keyRow1.setColumn(2, new SQLVarchar(ad.getDescriptorName())); |
| keyRow1.setColumn(3, new SQLChar(new String(charArray))); |
| |
| ti.deleteRow( tc, keyRow1, SYSALIASESRowFactory.SYSALIASES_INDEX1_ID ); |
| |
| } |
| |
| public void updateUser( UserDescriptor newDescriptor,TransactionController tc ) |
| throws StandardException |
| { |
| ExecIndexRow keyRow; |
| TabInfoImpl ti = getNonCoreTI( SYSUSERS_CATALOG_NUM ); |
| |
| /* Set up the start/stop position for the scan */ |
| keyRow = (ExecIndexRow) exFactory.getIndexableRow(1); |
| keyRow.setColumn( 1, new SQLVarchar( newDescriptor.getUserName() ) ); |
| |
| // this zeroes out the password in the UserDescriptor |
| ExecRow row = ti.getCatalogRowFactory().makeRow( newDescriptor, null ); |
| |
| boolean[] bArray = { false }; |
| |
| int[] colsToUpdate = |
| { |
| SYSUSERSRowFactory.HASHINGSCHEME_COL_NUM, |
| SYSUSERSRowFactory.PASSWORD_COL_NUM, |
| SYSUSERSRowFactory.LASTMODIFIED_COL_NUM, |
| }; |
| |
| ti.updateRow |
| ( |
| keyRow, row, |
| SYSUSERSRowFactory.SYSUSERS_INDEX1_ID, |
| bArray, colsToUpdate, tc |
| ); |
| } |
| |
| public UserDescriptor getUser( String userName ) |
| throws StandardException |
| { |
| // |
| // No sense looking for the SYSUSERS congomerate until the database |
| // is hard-upgraded to 10.9 or later. |
| // |
| dictionaryVersion.checkVersion( DD_VERSION_DERBY_10_9, "NATIVE AUTHENTICATION" ); |
| |
| ExecIndexRow keyRow; |
| TabInfoImpl ti = getNonCoreTI( SYSUSERS_CATALOG_NUM ); |
| |
| /* Set up the start/stop position for the scan */ |
| keyRow = (ExecIndexRow) exFactory.getIndexableRow(1); |
| keyRow.setColumn( 1, new SQLVarchar( userName ) ); |
| |
| return getDescriptorViaIndex |
| ( |
| SYSUSERSRowFactory.SYSUSERS_INDEX1_ID, |
| keyRow, |
| (ScanQualifier [][]) null, |
| ti, |
| (TupleDescriptor) null, |
| (List<TupleDescriptor>) null, |
| UserDescriptor.class, |
| false |
| ); |
| } |
| |
| public void dropUser( String userName, TransactionController tc ) |
| throws StandardException |
| { |
| TabInfoImpl ti = getNonCoreTI(SYSUSERS_CATALOG_NUM); |
| |
| /* Set up the start/stop position for the scan */ |
| ExecIndexRow keyRow1 = (ExecIndexRow) exFactory.getIndexableRow( 1 ); |
| keyRow1.setColumn( 1, new SQLVarchar( userName ) ); |
| |
| ti.deleteRow( tc, keyRow1, SYSUSERSRowFactory.SYSUSERS_INDEX1_ID ); |
| } |
| |
| // |
| // class implementation |
| // |
| |
| /** |
| * Initialize system catalogs. This is where we perform upgrade. It is our |
| * pious hope that we won't ever have to upgrade the core catalogs, other than |
| * to add fields inside Formatable columns in these catalogs. |
| * |
| * If we do have to upgrade the core catalogs, then we may need to move the |
| * loadCatalog calls into the upgrade machinery. It's do-able, just not pretty. |
| * |
| * |
| * @param tc TransactionController |
| * |
| * @exception StandardException Thrown on error |
| */ |
| private void loadDictionaryTables(TransactionController tc, |
| Properties startParams) |
| throws StandardException |
| { |
| // load the core catalogs first |
| loadCatalogs(coreInfo); |
| |
| dictionaryVersion = (DD_Version)tc.getProperty( |
| DataDictionary.CORE_DATA_DICTIONARY_VERSION); |
| |
| // NATIVE authentication allowed if the database is at least at level 10.9 |
| boolean nativeAuthenticationEnabled = PropertyUtil.nativeAuthenticationEnabled( startParams ); |
| if ( nativeAuthenticationEnabled ) |
| { |
| dictionaryVersion.checkVersion( DD_VERSION_DERBY_10_9, "NATIVE AUTHENTICATION" ); |
| } |
| |
| resetDatabaseOwner( tc ); |
| |
| softwareVersion.upgradeIfNeeded(dictionaryVersion, tc, startParams); |
| } |
| |
| /** |
| * Reset the database owner according to what is stored in the catalogs. |
| * This can change at upgrade time so we have factored this logic into |
| * a separately callable method. |
| * |
| * |
| * @param tc TransactionController |
| * |
| * @exception StandardException Thrown on error |
| */ |
| public void resetDatabaseOwner( TransactionController tc ) |
| throws StandardException |
| { |
| SchemaDescriptor sd = locateSchemaRow |
| (SchemaDescriptor.IBM_SYSTEM_SCHEMA_NAME, tc ); |
| authorizationDatabaseOwner = sd.getAuthorizationId(); |
| |
| systemSchemaDesc.setAuthorizationId( authorizationDatabaseOwner ); |
| sysIBMSchemaDesc.setAuthorizationId( authorizationDatabaseOwner ); |
| systemUtilSchemaDesc.setAuthorizationId( authorizationDatabaseOwner ); |
| } |
| |
| /** |
| * Initialize indices for an array of catalogs |
| * |
| * @exception StandardException Thrown on error |
| */ |
| private void loadCatalogs(TabInfoImpl[] catalogArray) |
| throws StandardException |
| { |
| int ictr; |
| int numIndexes; |
| int indexCtr; |
| TabInfoImpl catalog; |
| int catalogCount = catalogArray.length; |
| |
| /* Initialize the various variables associated with index scans of these catalogs */ |
| for (ictr = 0; ictr < catalogCount; ictr++) |
| { |
| // NOTE: This only works for core catalogs, which are initialized |
| // up front. |
| catalog = catalogArray[ictr]; |
| |
| numIndexes = catalog.getNumberOfIndexes(); |
| |
| for (indexCtr = 0; indexCtr < numIndexes; indexCtr++) |
| { |
| initSystemIndexVariables(catalog, indexCtr); |
| } |
| } |
| |
| } |
| |
| /* |
| ** Methods related to create |
| */ |
| |
| /** |
| Create all the required dictionary tables. Any classes that extend this class |
| and need to create new tables should override this method, and then |
| call this method as the first action in the new method, e.g. |
| <PRE> |
| protected Configuration createDictionaryTables(Configuration cfg, TransactionController tc, |
| DataDescriptorGenerator ddg) |
| throws StandardException |
| { |
| super.createDictionaryTables(params, tc, ddg); |
| |
| ... |
| } |
| </PRE> |
| |
| @exception StandardException Standard Derby error policy |
| */ |
| protected void createDictionaryTables(Properties params, TransactionController tc, |
| DataDescriptorGenerator ddg) |
| throws StandardException |
| { |
| /* |
| ** Create a new schema descriptor -- with no args |
| ** creates the system schema descriptor in which |
| ** all tables reside (SYS) |
| */ |
| systemSchemaDesc = |
| newSystemSchemaDesc( |
| SchemaDescriptor.STD_SYSTEM_SCHEMA_NAME, |
| SchemaDescriptor.SYSTEM_SCHEMA_UUID); |
| |
| /* Create the core tables and generate the UUIDs for their |
| * heaps (before creating the indexes). |
| * RESOLVE - This loop will eventually drive all of the |
| * work for creating the core tables. |
| */ |
| for (int coreCtr = 0; coreCtr < NUM_CORE; coreCtr++) |
| { |
| TabInfoImpl ti = coreInfo[coreCtr]; |
| |
| Properties heapProperties = ti.getCreateHeapProperties(); |
| |
| ti.setHeapConglomerate( |
| createConglomerate( |
| ti.getTableName(), |
| tc, |
| ti.getCatalogRowFactory().makeEmptyRow(), |
| heapProperties |
| ) |
| ); |
| |
| // bootstrap indexes on core tables before bootstraping the tables themselves |
| if (coreInfo[coreCtr].getNumberOfIndexes() > 0) |
| { |
| bootStrapSystemIndexes(systemSchemaDesc, tc, ddg, ti); |
| } |
| } |
| |
| // bootstrap the core tables into the data dictionary |
| for ( int ictr = 0; ictr < NUM_CORE; ictr++ ) |
| { |
| /* RESOLVE - need to do something with COLUMNTYPE in following table creating code */ |
| TabInfoImpl ti = coreInfo[ictr]; |
| |
| addSystemTableToDictionary(ti, systemSchemaDesc, tc, ddg); |
| } |
| |
| // Add the bootstrap information to the configuration |
| params.put(CFG_SYSTABLES_ID, |
| Long.toString( |
| coreInfo[SYSTABLES_CORE_NUM].getHeapConglomerate())); |
| params.put(CFG_SYSTABLES_INDEX1_ID, |
| Long.toString( |
| coreInfo[SYSTABLES_CORE_NUM].getIndexConglomerate( |
| ((SYSTABLESRowFactory) coreInfo[SYSTABLES_CORE_NUM]. |
| getCatalogRowFactory()).SYSTABLES_INDEX1_ID))); |
| params.put(CFG_SYSTABLES_INDEX2_ID, |
| Long.toString( |
| coreInfo[SYSTABLES_CORE_NUM].getIndexConglomerate( |
| ((SYSTABLESRowFactory) coreInfo[SYSTABLES_CORE_NUM]. |
| getCatalogRowFactory()).SYSTABLES_INDEX2_ID))); |
| |
| params.put(CFG_SYSCOLUMNS_ID, |
| Long.toString( |
| coreInfo[SYSCOLUMNS_CORE_NUM].getHeapConglomerate())); |
| params.put(CFG_SYSCOLUMNS_INDEX1_ID, |
| Long.toString( |
| coreInfo[SYSCOLUMNS_CORE_NUM].getIndexConglomerate( |
| ((SYSCOLUMNSRowFactory) coreInfo[SYSCOLUMNS_CORE_NUM]. |
| getCatalogRowFactory()).SYSCOLUMNS_INDEX1_ID))); |
| params.put(CFG_SYSCOLUMNS_INDEX2_ID, |
| Long.toString( |
| coreInfo[SYSCOLUMNS_CORE_NUM].getIndexConglomerate( |
| ((SYSCOLUMNSRowFactory) coreInfo[SYSCOLUMNS_CORE_NUM]. |
| getCatalogRowFactory()).SYSCOLUMNS_INDEX2_ID))); |
| |
| params.put(CFG_SYSCONGLOMERATES_ID, |
| Long.toString( |
| coreInfo[SYSCONGLOMERATES_CORE_NUM].getHeapConglomerate())); |
| params.put(CFG_SYSCONGLOMERATES_INDEX1_ID, |
| Long.toString( |
| coreInfo[SYSCONGLOMERATES_CORE_NUM].getIndexConglomerate( |
| ((SYSCONGLOMERATESRowFactory) coreInfo[SYSCONGLOMERATES_CORE_NUM]. |
| getCatalogRowFactory()).SYSCONGLOMERATES_INDEX1_ID))); |
| params.put(CFG_SYSCONGLOMERATES_INDEX2_ID, |
| Long.toString( |
| coreInfo[SYSCONGLOMERATES_CORE_NUM].getIndexConglomerate( |
| ((SYSCONGLOMERATESRowFactory) coreInfo[SYSCONGLOMERATES_CORE_NUM]. |
| getCatalogRowFactory()).SYSCONGLOMERATES_INDEX2_ID))); |
| params.put(CFG_SYSCONGLOMERATES_INDEX3_ID, |
| Long.toString( |
| coreInfo[SYSCONGLOMERATES_CORE_NUM].getIndexConglomerate( |
| ((SYSCONGLOMERATESRowFactory) coreInfo[SYSCONGLOMERATES_CORE_NUM]. |
| getCatalogRowFactory()).SYSCONGLOMERATES_INDEX3_ID))); |
| |
| params.put(CFG_SYSSCHEMAS_ID, |
| Long.toString( |
| coreInfo[SYSSCHEMAS_CORE_NUM].getHeapConglomerate())); |
| params.put(CFG_SYSSCHEMAS_INDEX1_ID, |
| Long.toString( |
| coreInfo[SYSSCHEMAS_CORE_NUM].getIndexConglomerate( |
| ((SYSSCHEMASRowFactory) coreInfo[SYSSCHEMAS_CORE_NUM]. |
| getCatalogRowFactory()).SYSSCHEMAS_INDEX1_ID))); |
| params.put(CFG_SYSSCHEMAS_INDEX2_ID, |
| Long.toString( |
| coreInfo[SYSSCHEMAS_CORE_NUM].getIndexConglomerate( |
| ((SYSSCHEMASRowFactory) coreInfo[SYSSCHEMAS_CORE_NUM]. |
| getCatalogRowFactory()).SYSSCHEMAS_INDEX2_ID))); |
| |
| //Add the SYSIBM Schema |
| sysIBMSchemaDesc = |
| addSystemSchema( |
| SchemaDescriptor.IBM_SYSTEM_SCHEMA_NAME, |
| SchemaDescriptor.SYSIBM_SCHEMA_UUID, tc); |
| |
| /* Create the non-core tables and generate the UUIDs for their |
| * heaps (before creating the indexes). |
| * RESOLVE - This loop will eventually drive all of the |
| * work for creating the non-core tables. |
| */ |
| for (int noncoreCtr = 0; noncoreCtr < NUM_NONCORE; noncoreCtr++) |
| { |
| int catalogNumber = noncoreCtr + NUM_CORE; |
| boolean isDummy = (catalogNumber == SYSDUMMY1_CATALOG_NUM); |
| |
| TabInfoImpl ti = getNonCoreTIByNumber(catalogNumber); |
| |
| makeCatalog(ti, isDummy ? sysIBMSchemaDesc : systemSchemaDesc, tc ); |
| |
| if (isDummy) |
| populateSYSDUMMY1(tc); |
| |
| // Clear the table entry for this non-core table, |
| // to allow it to be garbage-collected. The idea |
| // is that a running database might never need to |
| // reference a non-core table after it was created. |
| clearNoncoreTable(noncoreCtr); |
| } |
| |
| //Add ths System Schema |
| addDescriptor( |
| systemSchemaDesc, null, SYSSCHEMAS_CATALOG_NUM, false, tc); |
| |
| |
| // Add the following system Schema's to be compatible with DB2, |
| // currently Derby does not use them, but by creating them as |
| // system schema's it will insure applications can't create them, |
| // drop them, or create objects in them. This set includes: |
| // SYSCAT |
| // SYSFUN |
| // SYSPROC |
| // SYSSTAT |
| // NULLID |
| |
| //Add the SYSCAT Schema |
| addSystemSchema( |
| SchemaDescriptor.IBM_SYSTEM_CAT_SCHEMA_NAME, |
| SchemaDescriptor.SYSCAT_SCHEMA_UUID, tc); |
| |
| //Add the SYSFUN Schema |
| addSystemSchema( |
| SchemaDescriptor.IBM_SYSTEM_FUN_SCHEMA_NAME, |
| SchemaDescriptor.SYSFUN_SCHEMA_UUID, tc); |
| |
| //Add the SYSPROC Schema |
| addSystemSchema( |
| SchemaDescriptor.IBM_SYSTEM_PROC_SCHEMA_NAME, |
| SchemaDescriptor.SYSPROC_SCHEMA_UUID, tc); |
| |
| //Add the SYSSTAT Schema |
| addSystemSchema( |
| SchemaDescriptor.IBM_SYSTEM_STAT_SCHEMA_NAME, |
| SchemaDescriptor.SYSSTAT_SCHEMA_UUID, tc); |
| |
| //Add the NULLID Schema |
| addSystemSchema( |
| SchemaDescriptor.IBM_SYSTEM_NULLID_SCHEMA_NAME, |
| SchemaDescriptor.NULLID_SCHEMA_UUID, tc); |
| |
| //Add the SQLJ Schema |
| addSystemSchema( |
| SchemaDescriptor.STD_SQLJ_SCHEMA_NAME, |
| SchemaDescriptor.SQLJ_SCHEMA_UUID, tc); |
| |
| //Add the SYSCS_DIAG Schema |
| addSystemSchema( |
| SchemaDescriptor.STD_SYSTEM_DIAG_SCHEMA_NAME, |
| SchemaDescriptor.SYSCS_DIAG_SCHEMA_UUID, tc); |
| |
| //Add the SYSCS_UTIL Schema |
| addSystemSchema( |
| SchemaDescriptor.STD_SYSTEM_UTIL_SCHEMA_NAME, |
| SchemaDescriptor.SYSCS_UTIL_SCHEMA_UUID, tc); |
| |
| //Add the APP schema |
| SchemaDescriptor appSchemaDesc = new SchemaDescriptor(this, |
| SchemaDescriptor.STD_DEFAULT_SCHEMA_NAME, |
| SchemaDescriptor.DEFAULT_USER_NAME, |
| uuidFactory.recreateUUID( SchemaDescriptor.DEFAULT_SCHEMA_UUID), |
| false); |
| |
| addDescriptor(appSchemaDesc, null, SYSSCHEMAS_CATALOG_NUM, false, tc); |
| } |
| |
| /** |
| * Add a system schema to the database. |
| * <p> |
| * |
| * @param schema_name name of the schema to add. |
| * |
| * @exception StandardException Standard exception policy. |
| **/ |
| private SchemaDescriptor addSystemSchema( |
| String schema_name, |
| String schema_uuid, |
| TransactionController tc) |
| throws StandardException |
| { |
| // create the descriptor |
| SchemaDescriptor schema_desc = |
| new SchemaDescriptor( |
| this, |
| schema_name, |
| authorizationDatabaseOwner, |
| uuidFactory.recreateUUID(schema_uuid), |
| true); |
| |
| // add it to the catalog. |
| addDescriptor(schema_desc, null, SYSSCHEMAS_CATALOG_NUM, false, tc); |
| |
| return(schema_desc); |
| } |
| |
| /** called by the upgrade code (dd_xena etc) to add a new system catalog. |
| * |
| * @param tc TransactionController to use. |
| * @param catalogNumber catalogNumber |
| */ |
| protected void upgradeMakeCatalog(TransactionController tc, int catalogNumber) |
| throws StandardException |
| { |
| TabInfoImpl ti; |
| if (catalogNumber >= NUM_CORE) |
| ti = getNonCoreTIByNumber(catalogNumber); |
| else |
| ti = coreInfo[catalogNumber]; |
| |
| makeCatalog(ti, (catalogNumber == SYSDUMMY1_CATALOG_NUM) ? getSysIBMSchemaDescriptor() : |
| getSystemSchemaDescriptor(), tc); |
| } |
| |
| |
| /** |
| * Called by the upgrade code to upgrade the way we store jar files in the |
| * database.<p/> |
| * We now use UUID as part of the file name to avoid problems with path |
| * delimiters. Also, we henceforth use no schema subdirectories since there |
| * is no chance of name collision with the UUID. |
| * |
| * @param tc TransactionController to use. |
| */ |
| protected void upgradeJarStorage(TransactionController tc) |
| throws StandardException |
| { |
| TabInfoImpl ti = getNonCoreTI(SYSFILES_CATALOG_NUM); |
| SYSFILESRowFactory rf = (SYSFILESRowFactory)ti.getCatalogRowFactory(); |
| |
| ExecRow outRow = rf.makeEmptyRow(); |
| |
| /* |
| ** Table scan |
| */ |
| ScanController scanController = tc.openScan( |
| ti.getHeapConglomerate(), // conglomerate to open |
| false, // don't hold open across commit |
| 0, // for read |
| TransactionController.MODE_TABLE, |
| TransactionController.ISOLATION_REPEATABLE_READ, |
| (FormatableBitSet) null, // all fields as objects |
| (DataValueDescriptor[]) null, // start position - first row |
| 0, // startSearchOperation - none |
| (Qualifier[][]) null, // scanQualifier, |
| (DataValueDescriptor[]) null, // stop position -through last row |
| 0); // stopSearchOperation - none |
| |
| Map<String,Object> schemas = new HashMap<String,Object>(); |
| |
| try |
| { |
| while (scanController.fetchNext(outRow.getRowArray())) |
| { |
| FileInfoDescriptor fid = (FileInfoDescriptor)rf. |
| buildDescriptor(outRow, null, this); |
| schemas.put(fid.getSchemaDescriptor().getSchemaName(), null); |
| JarUtil.upgradeJar(tc, fid); |
| } |
| } |
| finally |
| { |
| scanController.close(); |
| } |
| |
| Iterator<String> i = schemas.keySet().iterator(); |
| FileResource fh = tc.getFileHandler(); |
| |
| // remove those directories with their contents |
| while(i.hasNext()) { |
| fh.removeJarDir( |
| FileResource.JAR_DIRECTORY_NAME + |
| File.separatorChar + |
| i.next()); |
| } |
| } |
| |
| /** |
| * The dirty work of creating a catalog. |
| * |
| * @param ti TabInfoImpl describing catalog to create. |
| * @param sd Schema to create catalogs in. |
| * @param tc Transaction context. |
| * |
| * @exception StandardException Standard Derby error policy |
| */ |
| private void makeCatalog( TabInfoImpl ti, |
| SchemaDescriptor sd, |
| TransactionController tc ) |
| throws StandardException |
| { |
| DataDescriptorGenerator ddg = getDataDescriptorGenerator(); |
| |
| Properties heapProperties = ti.getCreateHeapProperties(); |
| ti.setHeapConglomerate( |
| createConglomerate( |
| ti.getTableName(), |
| tc, |
| ti.getCatalogRowFactory().makeEmptyRowForCurrentVersion(), |
| heapProperties |
| ) |
| ); |
| |
| // bootstrap indexes on core tables before bootstrapping the tables themselves |
| if (ti.getNumberOfIndexes() > 0) |
| { |
| bootStrapSystemIndexes(sd, tc, ddg, ti); |
| } |
| |
| addSystemTableToDictionary(ti, sd, tc, ddg); |
| } |
| /** |
| * Upgrade an existing system catalog column's definition |
| * by setting it to the value it would have in a newly |
| * created database. This is only used to for a couple |
| * of columns that had incorrectly nullability. Other |
| * uses (e.g. changing column type) might require more work. |
| * |
| * @param columnNumber The column to change |
| * @param tc Transaction controller |
| * |
| * @exception StandardException Standard Derby error policy |
| */ |
| public void upgradeFixSystemColumnDefinition(CatalogRowFactory rowFactory, |
| int columnNumber, |
| TransactionController tc) |
| throws StandardException |
| { |
| SystemColumn theColumn; |
| SystemColumn[] columns = rowFactory.buildColumnList(); |
| SchemaDescriptor sd = getSystemSchemaDescriptor(); |
| |
| TableDescriptor td = getTableDescriptor(rowFactory.getCatalogName(), sd, tc); |
| |
| theColumn = columns[columnNumber - 1]; // from 1 to 0 based |
| ColumnDescriptor cd = makeColumnDescriptor(theColumn, columnNumber, td ); |
| String columnName = cd.getColumnName(); |
| int[] columnNameColArray = new int[1]; |
| columnNameColArray[0] = SYSCOLUMNSRowFactory.SYSCOLUMNS_COLUMNDATATYPE ; |
| updateColumnDescriptor(cd, |
| td.getUUID(), |
| columnName, |
| columnNameColArray, |
| tc); |
| |
| } |
| |
| |
| /** |
| * Upgrade an existing catalog by adding columns. |
| * |
| * @param rowFactory Associated with this catalog. |
| * @param newColumnIDs Array of 1-based column ids. |
| * @param tc Transaction controller |
| * |
| * @exception StandardException Standard Derby error policy |
| */ |
| public void upgrade_addColumns( CatalogRowFactory rowFactory, |
| int[] newColumnIDs, |
| TransactionController tc ) |
| throws StandardException |
| { |
| int columnID; |
| SystemColumn currentColumn; |
| |
| SystemColumn[] columns = rowFactory.buildColumnList(); |
| ExecRow templateRow = rowFactory.makeEmptyRowForCurrentVersion(); |
| int columnCount = newColumnIDs.length; |
| SchemaDescriptor sd = getSystemSchemaDescriptor(); |
| TableDescriptor td; |
| long conglomID; |
| |
| // Special case when adding a column to systables or syscolumns, |
| // since we can't go to systables/syscolumns to get the |
| // table/column descriptor until after we add and populate the new column. |
| if (rowFactory instanceof SYSTABLESRowFactory) |
| { |
| td = dataDescriptorGenerator.newTableDescriptor( |
| "SYSTABLES", |
| sd, |
| TableDescriptor.BASE_TABLE_TYPE, |
| TableDescriptor.ROW_LOCK_GRANULARITY); |
| td.setUUID(getUUIDForCoreTable("SYSTABLES", sd.getUUID().toString(), tc)); |
| conglomID = coreInfo[SYSTABLES_CORE_NUM].getHeapConglomerate(); |
| } |
| else if (rowFactory instanceof SYSCOLUMNSRowFactory) |
| { |
| td = dataDescriptorGenerator.newTableDescriptor( |
| "SYSCOLUMNS", |
| sd, |
| TableDescriptor.BASE_TABLE_TYPE, |
| TableDescriptor.ROW_LOCK_GRANULARITY); |
| td.setUUID(getUUIDForCoreTable("SYSCOLUMNS", sd.getUUID().toString(), tc)); |
| conglomID = coreInfo[SYSCOLUMNS_CORE_NUM].getHeapConglomerate(); |
| } |
| else |
| { |
| td = getTableDescriptor( rowFactory.getCatalogName(), sd, tc ); |
| conglomID = td.getHeapConglomerateId(); |
| } |
| |
| widenConglomerate( templateRow, newColumnIDs, conglomID, tc ); |
| |
| |
| ColumnDescriptor[] cdArray = new ColumnDescriptor[columnCount]; |
| for ( int ix = 0; ix < columnCount; ix++ ) |
| { |
| columnID = newColumnIDs[ix]; |
| currentColumn = columns[ columnID - 1 ]; // from 1 to 0 based |
| |
| cdArray[ix] = makeColumnDescriptor(currentColumn, columnID, td); |
| } |
| addDescriptorArray(cdArray, td, SYSCOLUMNS_CATALOG_NUM, false, tc); |
| |
| } |
| |
| /** |
| * Add invisible columns to an existing system catalog |
| * |
| * @param rowFactory Associated with this catalog. |
| * @param newColumnIDs Array of 1-based column ids. |
| * @param tc Transaction controller |
| * |
| * @exception StandardException Standard Derby error policy |
| */ |
| public void upgrade_addInvisibleColumns |
| ( |
| CatalogRowFactory rowFactory, |
| int[] newColumnIDs, |
| TransactionController tc |
| ) |
| throws StandardException |
| { |
| ExecRow templateRow = rowFactory.makeEmptyRowForCurrentVersion(); |
| SchemaDescriptor sd = getSystemSchemaDescriptor( ); |
| long conglomID = getTableDescriptor( rowFactory.getCatalogName(), sd, tc ).getHeapConglomerateId(); |
| |
| widenConglomerate( templateRow, newColumnIDs, conglomID, tc ); |
| } |
| |
| |
| /** |
| * Adds columns to the conglomerate underlying a system table. |
| * |
| * @param templateRow Ultimate shape of base row of table |
| * @param newColumnIDs Array of 1-based column ids |
| * @param conglomID heap id |
| * @param tc Transaction controller |
| * |
| * @exception StandardException Standard Derby error policy |
| */ |
| private void widenConglomerate |
| ( |
| ExecRow templateRow, |
| int[] newColumnIDs, |
| long conglomID, |
| TransactionController tc |
| ) |
| throws StandardException |
| { |
| int columnCount = newColumnIDs.length; |
| |
| for ( int ix = 0; ix < columnCount; ix++ ) |
| { |
| int columnID = newColumnIDs[ix]; |
| int storablePosition = columnID - 1; // from 1 to 0 based |
| |
| // system catalog columns always have UCS_BASIC collation. |
| |
| tc.addColumnToConglomerate( |
| conglomID, |
| storablePosition, |
| templateRow.getColumn( columnID), |
| StringDataValue.COLLATION_TYPE_UCS_BASIC); |
| } |
| |
| } |
| |
| /** |
| * Get the UUID for the specified system table. Prior |
| * to Plato, system tables did not have canonical UUIDs, so |
| * we need to scan systables to get the UUID when we |
| * are updating the core tables. |
| * |
| * @param tableName Name of the table |
| * @param schemaUUID UUID of schema |
| * @param tc TransactionController to user |
| * |
| * @return UUID The UUID of the core table. |
| * |
| * @exception StandardException Thrown on failure |
| */ |
| private UUID getUUIDForCoreTable(String tableName, |
| String schemaUUID, |
| TransactionController tc) |
| throws StandardException |
| { |
| ConglomerateController heapCC; |
| ExecRow row; |
| DataValueDescriptor schemaIDOrderable; |
| DataValueDescriptor tableNameOrderable; |
| ScanController scanController; |
| TabInfoImpl ti = coreInfo[SYSTABLES_CORE_NUM]; |
| SYSTABLESRowFactory rf = (SYSTABLESRowFactory) ti.getCatalogRowFactory(); |
| |
| // We only want the 1st column from the heap |
| row = exFactory.getValueRow(1); |
| |
| /* Use tableNameOrderable and schemaIdOrderable in both start |
| * and stop position for scan. |
| */ |
| tableNameOrderable = new SQLVarchar(tableName); |
| schemaIDOrderable = new SQLChar(schemaUUID); |
| |
| /* Set up the start/stop position for the scan */ |
| ExecIndexRow keyRow = exFactory.getIndexableRow(2); |
| keyRow.setColumn(1, tableNameOrderable); |
| keyRow.setColumn(2, schemaIDOrderable); |
| |
| heapCC = tc.openConglomerate( |
| ti.getHeapConglomerate(), false, 0, |
| TransactionController.MODE_RECORD, |
| TransactionController.ISOLATION_REPEATABLE_READ); |
| |
| ExecRow indexTemplateRow = rf.buildEmptyIndexRow( SYSTABLESRowFactory.SYSTABLES_INDEX1_ID, heapCC.newRowLocationTemplate() ); |
| |
| /* Scan the index and go to the data pages for qualifying rows to |
| * build the column descriptor. |
| */ |
| scanController = tc.openScan( |
| ti.getIndexConglomerate(SYSTABLESRowFactory.SYSTABLES_INDEX1_ID), // conglomerate to open |
| false, // don't hold open across commit |
| 0, |
| TransactionController.MODE_RECORD, |
| TransactionController.ISOLATION_REPEATABLE_READ, |
| (FormatableBitSet) null, // all fields as objects |
| keyRow.getRowArray(), // start position - first row |
| ScanController.GE, // startSearchOperation |
| (ScanQualifier[][]) null, //scanQualifier, |
| keyRow.getRowArray(), // stop position - through last row |
| ScanController.GT); // stopSearchOperation |
| |
| /* OK to fetch into the template row, |
| * since we won't be doing a next. |
| */ |
| if (scanController.fetchNext(indexTemplateRow.getRowArray())) |
| { |
| RowLocation baseRowLocation; |
| |
| |
| baseRowLocation = (RowLocation) indexTemplateRow.getColumn( |
| indexTemplateRow.nColumns()); |
| |
| /* 1st column is TABLEID (UUID - char(36)) */ |
| row.setColumn(SYSTABLESRowFactory.SYSTABLES_TABLEID, new SQLChar()); |
| FormatableBitSet bi = new FormatableBitSet(1); |
| bi.set(0); |
| boolean base_row_exists = |
| heapCC.fetch( |
| baseRowLocation, row.getRowArray(), (FormatableBitSet) null); |
| |
| if (SanityManager.DEBUG) |
| { |
| // it can not be possible for heap row to disappear while |
| // holding scan cursor on index at ISOLATION_REPEATABLE_READ. |
| SanityManager.ASSERT(base_row_exists, "base row not found"); |
| } |
| } |
| |
| scanController.close(); |
| heapCC.close(); |
| |
| return uuidFactory.recreateUUID(row.getColumn(1).toString()); |
| } |
| |
| |
| /** |
| * Initialize noncore columns to fixed values |
| * |
| * @param tc The TransactionController for the transaction to do the |
| * upgrade in. |
| * @param isCoreTable true if it is a core table |
| * @param tableNum the noncore table number |
| * @param columnsToUpdateSet a bit set of columns to update. ZERO BASED |
| * @param replaceRow an object array of Orderables for the new values |
| * |
| * @exception StandardException Thrown on error |
| */ |
| void upgrade_initSystemTableCols( |
| TransactionController tc, |
| boolean isCoreTable, |
| int tableNum, |
| FormatableBitSet columnsToUpdateSet, |
| DataValueDescriptor[] replaceRow |
| ) |
| throws StandardException |
| { |
| |
| TabInfoImpl ti = (isCoreTable) ? coreInfo[tableNum] : |
| getNonCoreTIByNumber(tableNum); |
| |
| if (!isCoreTable) |
| faultInTabInfo(ti); |
| |
| /* Scan the entire heap */ |
| ScanController sc = |
| tc.openScan( |
| ti.getHeapConglomerate(), |
| false, |
| TransactionController.OPENMODE_FORUPDATE, |
| TransactionController.MODE_TABLE, |
| TransactionController.ISOLATION_REPEATABLE_READ, |
| RowUtil.EMPTY_ROW_BITSET, |
| (DataValueDescriptor[]) null, |
| ScanController.NA, |
| (Qualifier[][]) null, |
| (DataValueDescriptor[]) null, |
| ScanController.NA); |
| |
| while (sc.next()) |
| { |
| /* Replace the column in the table */ |
| sc.replace(replaceRow, columnsToUpdateSet); |
| } |
| |
| sc.close(); |
| } |
| |
| |
| |
| /* |
| ******************************************************************************* |
| * |
| * See RepBasicDataDictionary for sample code on how to create a system |
| * table. |
| * |
| * What follows here is special code for the core catalogs. These are catalogs |
| * which have to exist before any other system tables are created. |
| * |
| * Creating a core catalog consists of two steps: 1) creating all the infrastructure |
| * needed to make generic systemTableCreation work, 2) actually populating the |
| * Data Dictionary and core conglomerates with tuples. |
| * |
| ******************************************************************************* |
| */ |
| |
| |
| /** |
| * Infrastructure work for indexes on catalogs. |
| * |
| @exception StandardException Standard Derby error policy |
| |
| */ |
| private void bootStrapSystemIndexes( |
| SchemaDescriptor sd, |
| TransactionController tc, |
| DataDescriptorGenerator ddg, |
| TabInfoImpl ti) |
| throws StandardException |
| { |
| ConglomerateDescriptor[] cgd = new ConglomerateDescriptor[ti.getNumberOfIndexes()]; |
| |
| /* Ordering problem with sysconglomerates. We need to create |
| * all of the conglomerates first before adding rows to |
| * sysconglomerates. (All of the conglomerates for sysconglomerates |
| * must be there before we can add to them.) |
| * |
| */ |
| for (int indexCtr = 0; indexCtr < ti.getNumberOfIndexes(); indexCtr++) |
| { |
| cgd[indexCtr] = bootstrapOneIndex( sd, tc, ddg, ti, indexCtr, ti.getHeapConglomerate() ); |
| } |
| |
| for (int indexCtr = 0; indexCtr < ti.getNumberOfIndexes(); indexCtr++) |
| { |
| addDescriptor(cgd[indexCtr], sd, |
| SYSCONGLOMERATES_CATALOG_NUM, false, tc); |
| } |
| } |
| |
| /** |
| * @see DataDictionary#computeAutoincRowLocations |
| */ |
| public RowLocation[] computeAutoincRowLocations(TransactionController tc, |
| TableDescriptor td) |
| throws StandardException |
| { |
| int size; |
| if (!(td.tableHasAutoincrement())) |
| return null; |
| |
| size = td.getNumberOfColumns(); |
| RowLocation[] rla = new RowLocation[size]; |
| |
| for (int i = 0; i < size; i++) |
| { |
| ColumnDescriptor cd = td.getColumnDescriptor(i + 1); |
| if (cd.isAutoincrement()) |
| rla[i] = computeRowLocation(tc, td, cd.getColumnName()); |
| } |
| return rla; |
| } |
| |
| |
| /** |
| * @see DataDictionary#getSetAutoincrementValue |
| */ |
| public NumberDataValue getSetAutoincrementValue( |
| RowLocation rl, |
| TransactionController tc, |
| boolean doUpdate, |
| NumberDataValue newValue, |
| boolean wait) |
| throws StandardException |
| { |
| int columnNum = SYSCOLUMNSRowFactory.SYSCOLUMNS_AUTOINCREMENTVALUE; |
| TabInfoImpl ti = coreInfo[SYSCOLUMNS_CORE_NUM]; |
| ConglomerateController heapCC = null; |
| SYSCOLUMNSRowFactory rf = (SYSCOLUMNSRowFactory) ti.getCatalogRowFactory(); |
| ExecRow row = rf.makeEmptyRow(); |
| |
| FormatableBitSet columnToRead = new |
| FormatableBitSet(SYSCOLUMNSRowFactory.SYSCOLUMNS_COLUMN_COUNT); |
| |
| // FormatableBitSet is 0 based. |
| columnToRead.set(columnNum - 1); // current value. |
| columnToRead.set(columnNum); // start value. |
| columnToRead.set(columnNum + 1); // increment value. |
| |
| try |
| { |
| /* if wait is true then we need to do a wait while trying to |
| open/fetch from the conglomerate. note we use wait both to |
| open as well as fetch from the conglomerate. |
| */ |
| heapCC = |
| tc.openConglomerate( |
| ti.getHeapConglomerate(), |
| false, |
| (TransactionController.OPENMODE_FORUPDATE | |
| ((wait) ? 0 : TransactionController.OPENMODE_LOCK_NOWAIT)), |
| TransactionController.MODE_RECORD, |
| TransactionController.ISOLATION_REPEATABLE_READ); |
| |
| // fetch the current value |
| boolean baseRowExists = |
| heapCC.fetch(rl, row.getRowArray(), columnToRead, wait); |
| if (SanityManager.DEBUG) { |
| // We're not prepared for a non-existing base row. |
| SanityManager.ASSERT(baseRowExists, "base row not found"); |
| } |
| |
| // while the Row interface is 1 based. |
| NumberDataValue currentAI = (NumberDataValue)row.getColumn(columnNum); |
| long currentAIValue = currentAI.getLong(); |
| |
| if (doUpdate) |
| { |
| // increment the value |
| NumberDataValue increment = (NumberDataValue)row.getColumn(columnNum + 2); |
| currentAI = currentAI.plus(currentAI, increment, currentAI); |
| row.setColumn(columnNum, currentAI); |
| |
| // store the new value in SYSCOLUMNS |
| FormatableBitSet columnToUpdate = new FormatableBitSet( |
| SYSCOLUMNSRowFactory.SYSCOLUMNS_COLUMN_COUNT); |
| columnToUpdate.set(columnNum - 1); // current value. |
| heapCC.replace(rl, row.getRowArray(), columnToUpdate); |
| } |
| |
| // but we return the "currentAIValue"-- i.e the value before |
| // incrementing it. |
| if (newValue != null) |
| { |
| // user has passed in an object; set the current value in there and |
| // return it. |
| newValue.setValue(currentAIValue); |
| return newValue; |
| } |
| |
| else |
| { |
| // reuse the object read from row. |
| currentAI.setValue(currentAIValue); |
| return currentAI; |
| } |
| } |
| finally |
| { |
| if (heapCC != null) |
| heapCC.close(); |
| } |
| } |
| |
| private ConglomerateDescriptor bootstrapOneIndex |
| ( |
| SchemaDescriptor sd, |
| TransactionController tc, |
| DataDescriptorGenerator ddg, |
| TabInfoImpl ti, |
| int indexNumber, |
| long heapConglomerateNumber |
| ) |
| throws StandardException |
| { |
| boolean isUnique; |
| ConglomerateController cc; |
| ExecRow baseRow; |
| ExecIndexRow indexableRow; |
| int numColumns; |
| long conglomId; |
| RowLocation rl; |
| CatalogRowFactory rf = ti.getCatalogRowFactory(); |
| IndexRowGenerator irg; |
| ConglomerateDescriptor conglomerateDescriptor; |
| |
| initSystemIndexVariables(ti, indexNumber); |
| |
| irg = ti.getIndexRowGenerator(indexNumber); |
| |
| numColumns = ti.getIndexColumnCount(indexNumber); |
| |
| /* Is the index unique */ |
| isUnique = ti.isIndexUnique(indexNumber); |
| |
| // create an index row template |
| indexableRow = irg.getIndexRowTemplate(); |
| |
| baseRow = rf.makeEmptyRowForCurrentVersion(); |
| |
| // Get a RowLocation template |
| cc = tc.openConglomerate( |
| heapConglomerateNumber, false, 0, |
| TransactionController.MODE_RECORD, |
| TransactionController.ISOLATION_REPEATABLE_READ); |
| |
| rl = cc.newRowLocationTemplate(); |
| cc.close(); |
| |
| // Get an index row based on the base row |
| irg.getIndexRow(baseRow, rl, indexableRow, (FormatableBitSet) null); |
| |
| // Describe the properties of the index to the store using Properties |
| // RESOLVE: The following properties assume a BTREE index. |
| Properties indexProperties = ti.getCreateIndexProperties(indexNumber); |
| |
| // Tell it the conglomerate id of the base table |
| indexProperties.put( |
| "baseConglomerateId", |
| Long.toString( heapConglomerateNumber ) ); |
| |
| // All indexes are unique because they contain the RowLocation. |
| // The number of uniqueness columns must include the RowLocation |
| // if the user did not specify a unique index. |
| indexProperties.put("nUniqueColumns", |
| Integer.toString( |
| isUnique ? numColumns : numColumns + 1)); |
| |
| // By convention, the row location column is the last column |
| indexProperties.put("rowLocationColumn", |
| Integer.toString(numColumns)); |
| |
| // For now, all columns are key fields, including the RowLocation |
| indexProperties.put("nKeyFields", |
| Integer.toString(numColumns + 1)); |
| |
| /* Create and add the conglomerate (index) */ |
| conglomId = tc.createConglomerate( |
| "BTREE", // we're requesting an index conglomerate |
| indexableRow.getRowArray(), |
| null, //default sort order |
| null, //default collation id's for collumns in all system congloms |
| indexProperties, // default properties |
| TransactionController.IS_DEFAULT); // not temporary |
| |
| conglomerateDescriptor = |
| ddg.newConglomerateDescriptor(conglomId, |
| rf.getIndexName(indexNumber), |
| true, |
| irg, |
| false, |
| rf.getCanonicalIndexUUID(indexNumber), |
| rf.getCanonicalTableUUID(), |
| sd.getUUID()); |
| ti.setIndexConglomerate( conglomerateDescriptor ); |
| |
| return conglomerateDescriptor; |
| } |
| |
| private void initSystemIndexVariables(TabInfoImpl ti, int indexNumber) |
| throws StandardException |
| { |
| int numCols = ti.getIndexColumnCount(indexNumber); |
| int[] baseColumnPositions = new int[numCols]; |
| |
| for (int colCtr = 0; colCtr < numCols; colCtr++) |
| { |
| baseColumnPositions[colCtr] = |
| ti.getBaseColumnPosition(indexNumber, colCtr); |
| } |
| |
| boolean[] isAscending = new boolean[baseColumnPositions.length]; |
| for (int i = 0; i < baseColumnPositions.length; i++) |
| isAscending[i] = true; |
| |
| IndexRowGenerator irg = null; |
| |
| irg = new IndexRowGenerator( |
| "BTREE", ti.isIndexUnique(indexNumber), |
| false, |
| false, |
| false, |
| baseColumnPositions, |
| isAscending, |
| baseColumnPositions.length); |
| |
| // For now, assume that all index columns are ordered columns |
| ti.setIndexRowGenerator(indexNumber, irg); |
| } |
| |
| /** |
| * Populate SYSDUMMY1 table with a single row. |
| * |
| * @exception StandardException Standard Derby error policy |
| */ |
| protected void populateSYSDUMMY1( |
| TransactionController tc) |
| throws StandardException |
| { |
| TabInfoImpl ti = getNonCoreTI(SYSDUMMY1_CATALOG_NUM); |
| ExecRow row = ti.getCatalogRowFactory().makeRow(null, null); |
| |
| int insertRetCode = ti.insertRow(row, tc); |
| } |
| |
| /** |
| * Clear all of the DataDictionary caches. |
| * |
| * @exception StandardException Standard Derby error policy |
| */ |
| public void clearCaches() throws StandardException |
| { |
| clearCaches( true ); |
| } |
| |
| /** |
| * Clear the DataDictionary caches, including the sequence caches if requested.. |
| * |
| * @exception StandardException Standard Derby error policy |
| */ |
| public void clearCaches( boolean clearSequenceCaches ) throws StandardException |
| { |
| nameTdCache.cleanAll(); |
| nameTdCache.ageOut(); |
| OIDTdCache.cleanAll(); |
| OIDTdCache.ageOut(); |
| if ( clearSequenceCaches ) { clearSequenceCaches(); } |
| if (spsNameCache != null) |
| { |
| //System.out.println("CLEARING SPS CACHE"); |
| spsNameCache.cleanAll(); |
| spsNameCache.ageOut(); |
| spsIdHash.clear(); |
| // spsTextHash.clear(); |
| } |
| } |
| |
| /** |
| Flush sequence caches to disk so that we don't leak unused, pre-allocated numbers. |
| */ |
| public void clearSequenceCaches() throws StandardException |
| { |
| sequenceGeneratorCache.cleanAll(); |
| sequenceGeneratorCache.ageOut(); |
| } |
| |
| |
| /** |
| Add the required entries to the data dictionary for a System table. |
| */ |
| |
| private void addSystemTableToDictionary(TabInfoImpl ti, |
| SchemaDescriptor sd, |
| TransactionController tc, |
| DataDescriptorGenerator ddg) |
| throws StandardException |
| { |
| CatalogRowFactory crf = ti.getCatalogRowFactory(); |
| |
| String name = ti.getTableName(); |
| long conglomId = ti.getHeapConglomerate(); |
| SystemColumn[] columnList = crf.buildColumnList(); |
| UUID heapUUID = crf.getCanonicalHeapUUID(); |
| String heapName = crf.getCanonicalHeapName(); |
| TableDescriptor td; |
| UUID toid; |
| int columnCount; |
| SystemColumn column; |
| |
| // add table to the data dictionary |
| |
| columnCount = columnList.length; |
| td = ddg.newTableDescriptor(name, sd, TableDescriptor.SYSTEM_TABLE_TYPE, |
| TableDescriptor.ROW_LOCK_GRANULARITY); |
| td.setUUID(crf.getCanonicalTableUUID()); |
| addDescriptor(td, sd, SYSTABLES_CATALOG_NUM, |
| false, tc); |
| toid = td.getUUID(); |
| |
| /* Add the conglomerate for the heap */ |
| ConglomerateDescriptor cgd = ddg.newConglomerateDescriptor(conglomId, |
| heapName, |
| false, |
| null, |
| false, |
| heapUUID, |
| toid, |
| sd.getUUID()); |
| |
| addDescriptor(cgd, sd, SYSCONGLOMERATES_CATALOG_NUM, false, tc); |
| |
| /* Create the columns */ |
| ColumnDescriptor[] cdlArray = new ColumnDescriptor[columnCount]; |
| |
| for (int columnNumber = 0; columnNumber < columnCount; columnNumber++) |
| { |
| column = columnList[columnNumber]; |
| |
| if (SanityManager.DEBUG) |
| { |
| if (column == null) |
| { |
| SanityManager.THROWASSERT("column "+columnNumber+" for table "+ti.getTableName()+" is null"); |
| } |
| } |
| cdlArray[columnNumber] = makeColumnDescriptor( column, |
| columnNumber + 1, td ); |
| } |
| addDescriptorArray(cdlArray, td, SYSCOLUMNS_CATALOG_NUM, false, tc); |
| |
| // now add the columns to the cdl of the table. |
| ColumnDescriptorList cdl = td.getColumnDescriptorList(); |
| for (int i = 0; i < columnCount; i++) |
| cdl.add(cdlArray[i]); |
| } |
| |
| /** |
| * Converts a SystemColumn to a ColumnDescriptor. |
| * |
| * @param column a SystemColumn |
| * @param columnPosition Position of the column in the table, one based. |
| * @param td descriptor for table that column lives in |
| * |
| * @return a ColumnDes*criptor |
| * |
| * @exception StandardException Standard Derby error policy |
| */ |
| private ColumnDescriptor makeColumnDescriptor( SystemColumn column, |
| int columnPosition, |
| TableDescriptor td ) |
| throws StandardException |
| { |
| //RESOLVEAUTOINCREMENT |
| return new ColumnDescriptor |
| (column.getName(), columnPosition, column.getType(), null, null, td, |
| (UUID) null, // No defaults yet for system columns |
| 0, 0 |
| ); |
| } |
| |
| |
| /** |
| * Create a conglomerate for a system table |
| * |
| * @param name Name of new catalog. |
| * @param tc Transaction context. |
| * @param rowTemplate Template for rows for the new table |
| * @param properties Properties for createConglomerate |
| * |
| * @return Conglomerate id. |
| |
| @exception StandardException Standard Derby error policy. |
| */ |
| private long createConglomerate(String name, TransactionController tc, |
| ExecRow rowTemplate, |
| Properties properties) |
| throws StandardException |
| { |
| long conglomId; |
| |
| conglomId = tc.createConglomerate( |
| "heap", // we're requesting a heap conglomerate |
| rowTemplate.getRowArray(), // row template |
| null, // default sort order |
| null, // default collation ids |
| properties, // default properties |
| TransactionController.IS_DEFAULT); // not temporary |
| |
| return conglomId; |
| } |
| |
| /** |
| * Converts a UUID to an DataValueDescriptor. |
| * |
| * @return the UUID converted to an DataValueDescriptor |
| * |
| */ |
| private static SQLChar getIDValueAsCHAR(UUID uuid) |
| { |
| String uuidString = uuid.toString(); |
| return new SQLChar(uuidString); |
| } |
| |
| /** |
| * Initialize catalog information. This method is overridden by children. |
| * @exception StandardException Thrown on error |
| */ |
| public void initializeCatalogInfo() |
| throws StandardException |
| { |
| initializeCoreInfo(); |
| initializeNoncoreInfo(); |
| } |
| |
| /** |
| * Initialized the core info array. |
| */ |
| private void initializeCoreInfo() |
| throws StandardException |
| { |
| TabInfoImpl[] lcoreInfo = coreInfo = new TabInfoImpl[NUM_CORE]; |
| |
| UUIDFactory luuidFactory = uuidFactory; |
| |
| lcoreInfo[SYSTABLES_CORE_NUM] = |
| new TabInfoImpl(new SYSTABLESRowFactory(luuidFactory, exFactory, dvf)); |
| lcoreInfo[SYSCOLUMNS_CORE_NUM] = |
| new TabInfoImpl(new SYSCOLUMNSRowFactory(luuidFactory, exFactory, dvf)); |
| lcoreInfo[SYSCONGLOMERATES_CORE_NUM] = |
| new TabInfoImpl(new SYSCONGLOMERATESRowFactory(luuidFactory, exFactory, dvf)); |
| lcoreInfo[SYSSCHEMAS_CORE_NUM] = |
| new TabInfoImpl(new SYSSCHEMASRowFactory(luuidFactory, exFactory, dvf)); |
| } |
| |
| /** |
| * Initialized the noncore info array. |
| */ |
| private void initializeNoncoreInfo() |
| { |
| noncoreInfo = new TabInfoImpl[NUM_NONCORE]; |
| } |
| |
| /** |
| * Get the TransactionController to use, when not |
| * passed in as a parameter. (This hides logic about |
| * whether or not we're at boot time in a single |
| * place. NOTE: There's no LCC at boot time.) |
| * NOTE: All <get> methods in the DD should call this method. |
| * |
| * @return TransactionController The TC to use. |
| * |
| * @exception StandardException Thrown on error |
| */ |
| public TransactionController getTransactionCompile() |
| throws StandardException |
| { |
| if (bootingTC != null) |
| { |
| if (SanityManager.DEBUG) |
| { |
| SanityManager.ASSERT(booting, "booting is expected to be true"); |
| } |
| return bootingTC; |
| } |
| else |
| { |
| if (SanityManager.DEBUG) |
| { |
| SanityManager.ASSERT(! booting, "booting is expected to be false"); |
| } |
| { |
| LanguageConnectionContext lcc = getLCC(); |
| return lcc.getTransactionCompile(); |
| } |
| } |
| } |
| |
| |
| /** |
| * Get the TransactionController to use, when not |
| * passed in as a parameter. (This hides logic about |
| * whether or not we're at boot time in a single |
| * place. NOTE: There's no LCC at boot time.) |
| * NOTE: All <get> methods in the DD should call this method. |
| * |
| * @return TransactionController The TC to use. |
| * |
| * @exception StandardException Thrown on error |
| */ |
| public TransactionController getTransactionExecute() |
| throws StandardException |
| { |
| if (bootingTC != null) |
| { |
| if (SanityManager.DEBUG) |
| { |
| SanityManager.ASSERT(booting, "booting is expected to be true"); |
| } |
| return bootingTC; |
| } |
| else |
| { |
| if (SanityManager.DEBUG) |
| { |
| SanityManager.ASSERT(! booting, "booting is expected to be false"); |
| } |
| { |
| LanguageConnectionContext lcc = getLCC(); |
| return lcc.getTransactionExecute(); |
| } |
| } |
| } |
| |
| /** |
| * Return a (single or list of) catalog row descriptor(s) from a |
| * system table where the access is from the index to the heap. |
| * |
| * @param indexId The id of the index (0 to # of indexes on table) to use |
| * @param keyRow The supplied ExecIndexRow for search |
| * @param ti The TabInfoImpl to use |
| * @param parentTupleDescriptor The parentDescriptor, if applicable. |
| * @param list The list to build, if supplied. If null, then |
| * caller expects a single descriptor |
| * @param returnType The type of descriptor to return |
| * @param forUpdate Whether or not to open the index for update. |
| * |
| * @return The last matching descriptor |
| * |
| * @exception StandardException Thrown on error |
| */ |
| private <T extends TupleDescriptor> T getDescriptorViaIndex( |
| int indexId, |
| ExecIndexRow keyRow, |
| ScanQualifier [][] scanQualifiers, |
| TabInfoImpl ti, |
| TupleDescriptor parentTupleDescriptor, |
| List<? super T> list, |
| Class<T> returnType, |
| boolean forUpdate) |
| throws StandardException |
| { |
| // Get the current transaction controller |
| TransactionController tc = getTransactionCompile(); |
| |
| return getDescriptorViaIndexMinion( |
| indexId, |
| keyRow, |
| scanQualifiers, |
| ti, |
| parentTupleDescriptor, |
| list, |
| returnType, |
| forUpdate, |
| TransactionController.ISOLATION_REPEATABLE_READ, |
| tc); |
| } |
| |
| /** |
| * Return a (single or list of) catalog row descriptor(s) from a |
| * system table where the access is from the index to the heap. |
| * |
| * This overload variant takes an explicit tc, in contrast to the normal |
| * one which uses the one returned by getTransactionCompile. |
| * |
| * @param indexId The id of the index (0 to # of indexes on table) to use |
| * @param keyRow The supplied ExecIndexRow for search |
| * @param ti The TabInfoImpl to use |
| * @param parentTupleDescriptor The parentDescriptor, if applicable. |
| * @param list The list to build, if supplied. If null, then |
| * caller expects a single descriptor |
| * @param returnType The type of descriptor to return |
| * @param forUpdate Whether or not to open the index for update. |
| * @param isolationLevel |
| * Use this explicit isolation level. Only |
| * ISOLATION_REPEATABLE_READ (normal usage) or |
| * ISOLATION_READ_UNCOMMITTED (corner cases) |
| * supported for now. |
| * @param tc Transaction controller |
| * |
| * @return The last matching descriptor. If isolationLevel is |
| * ISOLATION_READ_UNCOMMITTED, the base row may be gone by the |
| * time we access it via the index; in such a case a null is |
| * returned. |
| * |
| * @exception StandardException Thrown on error. |
| */ |
| private <T extends TupleDescriptor> T getDescriptorViaIndex( |
| int indexId, |
| ExecIndexRow keyRow, |
| ScanQualifier [][] scanQualifiers, |
| TabInfoImpl ti, |
| TupleDescriptor parentTupleDescriptor, |
| List<? super T> list, |
| Class<T> returnType, |
| boolean forUpdate, |
| int isolationLevel, |
| TransactionController tc) |
| throws StandardException |
| { |
| if (tc == null) { |
| tc = getTransactionCompile(); |
| } |
| |
| return getDescriptorViaIndexMinion(indexId, |
| keyRow, |
| scanQualifiers, |
| ti, |
| parentTupleDescriptor, |
| list, |
| returnType, |
| forUpdate, |
| isolationLevel, |
| tc); |
| } |
| |
| |
| private <T extends TupleDescriptor> T getDescriptorViaIndexMinion( |
| int indexId, |
| ExecIndexRow keyRow, |
| ScanQualifier [][] scanQualifiers, |
| TabInfoImpl ti, |
| TupleDescriptor parentTupleDescriptor, |
| List<? super T> list, |
| Class<T> returnType, |
| boolean forUpdate, |
| int isolationLevel, |
| TransactionController tc) |
| throws StandardException |
| { |
| CatalogRowFactory rf = ti.getCatalogRowFactory(); |
| ConglomerateController heapCC; |
| ExecIndexRow indexRow1; |
| ExecRow outRow; |
| RowLocation baseRowLocation; |
| ScanController scanController; |
| T td = null; |
| |
| if (SanityManager.DEBUG) { |
| SanityManager.ASSERT |
| (isolationLevel == |
| TransactionController.ISOLATION_REPEATABLE_READ || |
| isolationLevel == |
| TransactionController.ISOLATION_READ_UNCOMMITTED); |
| } |
| |
| outRow = rf.makeEmptyRow(); |
| |
| heapCC = tc.openConglomerate( |
| ti.getHeapConglomerate(), false, 0, |
| TransactionController.MODE_RECORD, |
| isolationLevel); |
| |
| /* Scan the index and go to the data pages for qualifying rows to |
| * build the column descriptor. |
| */ |
| scanController = tc.openScan( |
| ti.getIndexConglomerate(indexId), // conglomerate to open |
| false, // don't hold open across commit |
| (forUpdate) ? TransactionController.OPENMODE_FORUPDATE : 0, |
| TransactionController.MODE_RECORD, |
| isolationLevel, |
| (FormatableBitSet) null, // all fields as objects |
| keyRow.getRowArray(), // start position - first row |
| ScanController.GE, // startSearchOperation |
| scanQualifiers, //scanQualifier, |
| keyRow.getRowArray(), // stop position - through last row |
| ScanController.GT); // stopSearchOperation |
| |
| while (true) |
| { |
| // create an index row template |
| indexRow1 = getIndexRowFromHeapRow( |
| ti.getIndexRowGenerator(indexId), |
| heapCC.newRowLocationTemplate(), |
| outRow); |
| |
| // It is important for read uncommitted scans to use fetchNext() |
| // rather than fetch, so that the fetch happens while latch is |
| // held, otherwise the next() might position the scan on a row, |
| // but the subsequent fetch() may find the row deleted or purged |
| // from the table. |
| if (!scanController.fetchNext(indexRow1.getRowArray())) { |
| break; |
| } |
| |
| baseRowLocation = (RowLocation) indexRow1.getColumn( |
| indexRow1.nColumns()); |
| |
| // RESOLVE paulat - remove the try catch block when track 3677 is fixed |
| // just leave the contents of the try block |
| // adding to get more info on track 3677 |
| |
| boolean base_row_exists = false; |
| try |
| { |
| base_row_exists = |
| heapCC.fetch( |
| baseRowLocation, outRow.getRowArray(), (FormatableBitSet) null); |
| } |
| catch (RuntimeException re) |
| { |
| if (SanityManager.DEBUG) |
| { |
| if (re instanceof AssertFailure) |
| { |
| StringBuffer strbuf = new StringBuffer("Error retrieving base row in table "+ti.getTableName()); |
| strbuf.append(": An ASSERT was thrown when trying to locate a row matching index row "+indexRow1+" from index "+ti.getIndexName(indexId)+", conglom number "+ti.getIndexConglomerate(indexId)); |
| debugGenerateInfo(strbuf,tc,heapCC,ti,indexId); |
| } |
| } |
| throw re; |
| } |
| catch (StandardException se) |
| { |
| if (SanityManager.DEBUG) |
| { |
| // only look for a specific error i.e. that of record on page |
| // no longer exists |
| // do not want to catch lock timeout errors here |
| if (se.getSQLState().equals("XSRS9")) |
| { |
| StringBuffer strbuf = new StringBuffer("Error retrieving base row in table "+ti.getTableName()); |
| strbuf.append(": A StandardException was thrown when trying to locate a row matching index row "+indexRow1+" from index "+ti.getIndexName(indexId)+", conglom number "+ti.getIndexConglomerate(indexId)); |
| debugGenerateInfo(strbuf,tc,heapCC,ti,indexId); |
| } |
| } |
| throw se; |
| } |
| |
| if (SanityManager.DEBUG) |
| { |
| // it can not be possible for heap row to disappear while |
| // holding scan cursor on index at ISOLATION_REPEATABLE_READ. |
| if (! base_row_exists && |
| (isolationLevel == |
| TransactionController.ISOLATION_REPEATABLE_READ)) { |
| StringBuffer strbuf = new StringBuffer("Error retrieving base row in table "+ti.getTableName()); |
| strbuf.append(": could not locate a row matching index row "+indexRow1+" from index "+ti.getIndexName(indexId)+", conglom number "+ti.getIndexConglomerate(indexId)); |
| debugGenerateInfo(strbuf,tc,heapCC,ti,indexId); |
| // RESOLVE: for now, we are going to kill the VM |
| // to help debug this problem. |
| System.exit(1); |
| |
| // RESOLVE: not currently reached |
| //SanityManager.THROWASSERT(strbuf.toString()); |
| } |
| } |
| |
| if (!base_row_exists && |
| (isolationLevel == |
| TransactionController.ISOLATION_READ_UNCOMMITTED)) { |
| // If isolationLevel == ISOLATION_READ_UNCOMMITTED we may |
| // possibly see that the base row does not exist even if the |
| // index row did. This mode is currently only used by |
| // TableNameInfo's call to hashAllTableDescriptorsByTableId, |
| // cf. DERBY-3678, and by getStatisticsDescriptors, |
| // cf. DERBY-4881. |
| // |
| // For the former call, a table's schema descriptor is attempted |
| // read, and if the base row for the schema has gone between |
| // reading the index and the base table, the table that needs |
| // this information has gone, too. So, the table should not |
| // be needed for printing lock timeout or deadlock |
| // information, so we can safely just return an empty (schema) |
| // descriptor. Furthermore, neither Timeout or DeadLock |
| // diagnostics access the schema of a table descriptor, so it |
| // seems safe to just return an empty schema descriptor for |
| // the table. |
| // |
| // There is a theoretical chance another row may have taken |
| // the first one's place, but only if a compress of the base |
| // table managed to run between the time we read the index and |
| // the base row, which seems unlikely so we ignore that. |
| // |
| // Even the index row may be gone in the above use case, of |
| // course, and that case also returns an empty descriptor |
| // since no match is found. |
| |
| td = null; |
| |
| } else { |
| // normal case |
| td = returnType.cast( |
| rf.buildDescriptor(outRow, parentTupleDescriptor, this)); |
| } |
| |
| |
| |
| /* If list is null, then caller only wants a single descriptor - we're done |
| * else just add the current descriptor to the list. |
| */ |
| if (list == null) |
| { |
| break; |
| } |
| else if (td != null) |
| { |
| list.add(td); |
| } |
| } |
| scanController.close(); |
| heapCC.close(); |
| return td; |
| } |
| |
| |
| private void debugGenerateInfo(StringBuffer strbuf, |
| TransactionController tc, ConglomerateController heapCC, TabInfoImpl ti, |
| int indexId) |
| { |
| if (SanityManager.DEBUG) { |
| try |
| { |
| strbuf.append("\nadditional information: "); |
| |
| // print the lock table |
| // will get a NullPointerException if lcc doesn't yet exist e.g. at boot time |
| LanguageConnectionContext lcc = (LanguageConnectionContext) |
| getContext(LanguageConnectionContext.CONTEXT_ID); |
| if (lcc != null) |
| { |
| long currentTime = System.currentTimeMillis(); |
| //EXCLUDE-START-lockdiag- |
| Enumeration lockTable = lockFactory.makeVirtualLockTable(); |
| String lockTableString = Timeout.buildString(lockTable,currentTime); |
| strbuf.append("lock table at time of failure\n\n"); |
| strbuf.append(lockTableString); |
| //EXCLUDE-END-lockdiag- |
| } |
| |
| // consistency checking etc. |
| ConglomerateController btreeCC = |
| tc.openConglomerate( |
| ti.getIndexConglomerate(indexId), |
| false, |
| 0, TransactionController.MODE_RECORD, |
| TransactionController.ISOLATION_REPEATABLE_READ); |
| |
| btreeCC.debugConglomerate(); |
| heapCC.debugConglomerate(); |
| heapCC.checkConsistency(); |
| strbuf.append("\nheapCC.checkConsistency() = true"); |
| ConglomerateController indexCC = tc.openConglomerate( |
| ti.getIndexConglomerate(indexId), |
| false, |
| 0, |
| TransactionController.MODE_TABLE, |
| TransactionController.ISOLATION_REPEATABLE_READ); |
| indexCC.checkConsistency(); |
| strbuf.append("\nindexCC.checkConsistency() = true"); |
| |
| System.err.println("ASSERT FAILURE: "+strbuf.toString()); |
| System.out.println("ASSERT FAILURE: "+strbuf.toString()); |
| SanityManager.DEBUG_PRINT("ASSERT FAILURE", strbuf.toString()); |
| } |
| catch (StandardException se) |
| { |
| strbuf.append("\ngot the following error when doing extra consistency checks:\n"+se.toString()); |
| } |
| } |
| } |
| |
| |
| |
| /** |
| * Return a (single or list of) catalog row descriptor(s) from a |
| * system table where the access a heap scan |
| * |
| * @param columns which columns to fetch from the system |
| * table, or null to fetch all columns |
| * @param scanQualifiers qualifiers |
| * @param ti The TabInfoImpl to use |
| * @param parentTupleDescriptor The parentDescriptor, if applicable. |
| * @param list The list to build, if supplied. |
| * If null, then caller expects a single descriptor |
| * @param returnType The type of descriptor to look for |
| * |
| * @return The last matching descriptor |
| * |
| * @exception StandardException Thrown on error |
| */ |
| protected <T extends TupleDescriptor> T getDescriptorViaHeap( |
| FormatableBitSet columns, |
| ScanQualifier [][] scanQualifiers, |
| TabInfoImpl ti, |
| TupleDescriptor parentTupleDescriptor, |
| List<? super T> list, |
| Class<T> returnType) |
| throws StandardException |
| { |
| CatalogRowFactory rf = ti.getCatalogRowFactory(); |
| ExecRow outRow; |
| ScanController scanController; |
| TransactionController tc; |
| T td = null; |
| |
| // Get the current transaction controller |
| tc = getTransactionCompile(); |
| |
| outRow = rf.makeEmptyRow(); |
| |
| /* |
| ** Table scan |
| */ |
| scanController = tc.openScan( |
| ti.getHeapConglomerate(), // conglomerate to open |
| false, // don't hold open across commit |
| 0, // for read |
| TransactionController.MODE_TABLE, |
| TransactionController.ISOLATION_REPEATABLE_READ, |
| columns, |
| (DataValueDescriptor[]) null, // start position - first row |
| 0, // startSearchOperation - none |
| scanQualifiers, // scanQualifier, |
| (DataValueDescriptor[]) null, // stop position - through last row |
| 0); // stopSearchOperation - none |
| |
| while (scanController.fetchNext(outRow.getRowArray())) |
| { |
| td = returnType.cast( |
| rf.buildDescriptor(outRow, parentTupleDescriptor, this)); |
| |
| /* If dList is null, then caller only wants a single descriptor - we're done |
| * else just add the current descriptor to the list. |
| */ |
| if (list == null) |
| { |
| break; |
| } |
| else |
| { |
| list.add(td); |
| } |
| } |
| scanController.close(); |
| return td; |
| } |
| |
| /** |
| * Get a TabInfoImpl for a non-core table. |
| * (We fault in information about non-core tables as needed.) |
| * |
| * @param catalogNumber The index into noncoreTable[]. |
| * |
| * @exception StandardException Thrown on error |
| */ |
| private TabInfoImpl getNonCoreTI(int catalogNumber) |
| throws StandardException |
| { |
| TabInfoImpl ti = getNonCoreTIByNumber(catalogNumber); |
| |
| faultInTabInfo( ti ); |
| |
| return ti; |
| } |
| |
| /** returns the tabinfo for a non core system catalog. Input is a |
| * catalogNumber (defined in DataDictionary). |
| */ |
| protected TabInfoImpl getNonCoreTIByNumber(int catalogNumber) |
| throws StandardException |
| { |
| int nonCoreNum = catalogNumber - NUM_CORE; |
| |
| // Look up the TabInfoImpl in the array. This does not have to be |
| // synchronized, because getting a reference is atomic. |
| |
| TabInfoImpl retval = noncoreInfo[nonCoreNum]; |
| |
| if (retval == null) |
| { |
| // If we did not find the TabInfoImpl, get the right one and |
| // load it into the array. There is a small chance that |
| // two threads will do this at the same time. The code will |
| // work properly in that case, since storing a reference |
| // is atomic (although we could get extra object instantiation |
| // if two threads come through here at the same time. |
| UUIDFactory luuidFactory = uuidFactory; |
| |
| switch (catalogNumber) |
| { |
| case SYSCONSTRAINTS_CATALOG_NUM: |
| retval = new TabInfoImpl(new SYSCONSTRAINTSRowFactory( |
| luuidFactory, exFactory, dvf)); |
| break; |
| |
| case SYSKEYS_CATALOG_NUM: |
| retval = new TabInfoImpl(new SYSKEYSRowFactory( |
| luuidFactory, exFactory, dvf)); |
| break; |
| |
| case SYSDEPENDS_CATALOG_NUM: |
| retval = new TabInfoImpl(new SYSDEPENDSRowFactory( |
| luuidFactory, exFactory, dvf)); |
| break; |
| |
| case SYSVIEWS_CATALOG_NUM: |
| retval = new TabInfoImpl(new SYSVIEWSRowFactory( |
| luuidFactory, exFactory, dvf)); |
| break; |
| |
| case SYSCHECKS_CATALOG_NUM: |
| retval = new TabInfoImpl(new SYSCHECKSRowFactory( |
| luuidFactory, exFactory, dvf)); |
| break; |
| |
| case SYSFOREIGNKEYS_CATALOG_NUM: |
| retval = new TabInfoImpl(new SYSFOREIGNKEYSRowFactory( |
| luuidFactory, exFactory, dvf)); |
| break; |
| |
| case SYSSTATEMENTS_CATALOG_NUM: |
| retval = new TabInfoImpl(new SYSSTATEMENTSRowFactory( |
| luuidFactory, exFactory, dvf)); |
| break; |
| |
| case SYSFILES_CATALOG_NUM: |
| retval = new TabInfoImpl(new SYSFILESRowFactory( |
| luuidFactory, exFactory, dvf)); |
| break; |
| |
| case SYSALIASES_CATALOG_NUM: |
| retval = new TabInfoImpl(new SYSALIASESRowFactory( |
| luuidFactory, exFactory, dvf)); |
| break; |
| |
| case SYSTRIGGERS_CATALOG_NUM: |
| retval = new TabInfoImpl(new SYSTRIGGERSRowFactory( |
| this, luuidFactory, exFactory, dvf)); |
| break; |
| |
| case SYSSTATISTICS_CATALOG_NUM: |
| retval = new TabInfoImpl(new SYSSTATISTICSRowFactory( |
| luuidFactory, exFactory, dvf)); |
| break; |
| |
| case SYSDUMMY1_CATALOG_NUM: |
| retval = new TabInfoImpl(new SYSDUMMY1RowFactory( |
| luuidFactory, exFactory, dvf)); |
| break; |
| |
| case SYSTABLEPERMS_CATALOG_NUM: |
| retval = new TabInfoImpl(new SYSTABLEPERMSRowFactory( |
| luuidFactory, exFactory, dvf)); |
| break; |
| |
| case SYSCOLPERMS_CATALOG_NUM: |
| retval = new TabInfoImpl(new SYSCOLPERMSRowFactory( |
| luuidFactory, exFactory, dvf)); |
| break; |
| |
| case SYSROUTINEPERMS_CATALOG_NUM: |
| retval = new TabInfoImpl(new SYSROUTINEPERMSRowFactory( |
| luuidFactory, exFactory, dvf)); |
| break; |
| |
| case SYSROLES_CATALOG_NUM: |
| retval = new TabInfoImpl(new SYSROLESRowFactory( |
| luuidFactory, exFactory, dvf)); |
| |
| break; |
| |
| case SYSSEQUENCES_CATALOG_NUM: |
| retval = new TabInfoImpl(new SYSSEQUENCESRowFactory( |
| luuidFactory, exFactory, dvf)); |
| |
| break; |
| |
| case SYSPERMS_CATALOG_NUM: |
| retval = new TabInfoImpl(new SYSPERMSRowFactory( |
| luuidFactory, exFactory, dvf)); |
| |
| break; |
| |
| case SYSUSERS_CATALOG_NUM: |
| retval = new TabInfoImpl(new SYSUSERSRowFactory( |
| luuidFactory, exFactory, dvf)); |
| |
| break; |
| } |
| |
| initSystemIndexVariables(retval); |
| |
| noncoreInfo[nonCoreNum] = retval; |
| } |
| |
| return retval; |
| } |
| |
| protected void initSystemIndexVariables(TabInfoImpl ti) |
| throws StandardException |
| { |
| int numIndexes = ti.getNumberOfIndexes(); |
| |
| for (int indexCtr = 0; indexCtr < numIndexes; indexCtr++) |
| { |
| initSystemIndexVariables(ti, indexCtr); |
| } |
| } |
| |
| // Expected to be called only during boot time, so no synchronization. |
| private void clearNoncoreTable(int nonCoreNum) |
| { |
| noncoreInfo[nonCoreNum] = null; |
| } |
| |
| /** |
| * Finishes building a TabInfoImpl if it hasn't already been faulted in. |
| * NOP if TabInfoImpl has already been faulted in. |
| * |
| * @param ti TabInfoImpl to fault in. |
| * |
| * @exception StandardException Thrown on error |
| */ |
| private void faultInTabInfo(TabInfoImpl ti) |
| throws StandardException |
| { |
| int numIndexes; |
| |
| /* Most of the time, the noncoreInfo will be complete. |
| * It's okay to do an unsynchronized check and return |
| * if it is complete, since it never becomes "un-complete". |
| * If we change the code, for some reason, to allow |
| * it to become "un-complete" after being complete, |
| * then we will have to do a synchronized check here |
| * as well. |
| */ |
| if (ti.isComplete()) |
| { |
| return; |
| } |
| |
| /* The completing of the noncoreInfo entry must be synchronized. |
| * NOTE: We are assuming that we will not access a different |
| * noncoreInfo in the course of completing of this noncoreInfo, |
| * otherwise a deadlock could occur. |
| */ |
| synchronized(ti) |
| { |
| /* Now that we can run, the 1st thing that we must do |
| * is to verify that we still need to complete the |
| * object. (We may have been blocked on another user |
| * doing the same.) |
| */ |
| if (ti.isComplete()) |
| { |
| return; |
| } |
| |
| TableDescriptor td = getTableDescriptor(ti.getTableName(), |
| getSystemSchemaDescriptor(), null); |
| |
| // It's possible that the system table is not there right |
| // now. This can happen, for example, if we're in the |
| // process of upgrading a source or target to Xena, in |
| // which case SYSSYNCINSTANTS is dropped and re-created. |
| // Just return in this case, so we don't get a null pointer |
| // exception. |
| if (td == null) |
| { |
| return; |
| } |
| |
| ConglomerateDescriptor cd = null; |
| ConglomerateDescriptor[] cds = td.getConglomerateDescriptors(); |
| |
| /* Init the heap conglomerate here */ |
| for (int index = 0; index < cds.length; index++) |
| { |
| cd = cds[index]; |
| |
| if (! cd.isIndex()) |
| { |
| ti.setHeapConglomerate(cd.getConglomerateNumber()); |
| break; |
| } |
| } |
| |
| if (SanityManager.DEBUG) |
| { |
| if (cd == null) |
| { |
| SanityManager.THROWASSERT("No heap conglomerate found for " |
| + ti.getTableName()); |
| } |
| } |
| |
| /* Initialize the index conglomerates */ |
| numIndexes = ti.getCatalogRowFactory().getNumIndexes(); |
| if (numIndexes == 0) |
| { |
| return; |
| } |
| |
| /* For each index, we get its id from the CDL */ |
| ConglomerateDescriptor icd = null; |
| int indexCount = 0; |
| |
| for (int index = 0; index < cds.length; index++) |
| { |
| icd = cds[index]; |
| |
| if (icd.isIndex()) |
| { |
| ti.setIndexConglomerate(icd); |
| indexCount++; |
| } |
| continue; |
| } |
| |
| if (SanityManager.DEBUG) |
| { |
| if (indexCount != ti.getCatalogRowFactory().getNumIndexes()) |
| { |
| SanityManager.THROWASSERT("Number of indexes found (" + indexCount + |
| ") does not match the number expected (" + |
| ti.getCatalogRowFactory().getNumIndexes() + ")"); |
| } |
| } |
| } |
| } |
| |
| |
| /** |
| * Get an index row based on a row from the heap. |
| * |
| * @param irg IndexRowGenerator to use |
| * @param rl RowLocation for heap |
| * @param heapRow Row from the heap |
| * |
| * @return ExecIndexRow Index row. |
| * |
| * @exception StandardException Thrown on error |
| */ |
| public static ExecIndexRow getIndexRowFromHeapRow(IndexRowGenerator irg, |
| RowLocation rl, |
| ExecRow heapRow) |
| throws StandardException |
| { |
| ExecIndexRow indexRow; |
| |
| indexRow = irg.getIndexRowTemplate(); |
| // Get an index row based on the base row |
| irg.getIndexRow(heapRow, rl, indexRow, (FormatableBitSet) null); |
| |
| return indexRow; |
| } |
| |
| public int getEngineType() |
| { |
| return engineType; |
| } |
| |
| |
| /** |
| * Get the heap conglomerate number for SYS.SYSCOLUMNS. |
| * (Useful for adding new index to the table.) |
| * |
| * @return The heap conglomerate number for SYS.SYSCOLUMNS. |
| */ |
| public long getSYSCOLUMNSHeapConglomerateNumber() |
| { |
| return coreInfo[SYSCOLUMNS_CORE_NUM].getHeapConglomerate(); |
| } |
| |
| void addSYSCOLUMNSIndex2Property(TransactionController tc, long index2ConglomerateNumber) |
| { |
| startupParameters.put(CFG_SYSCOLUMNS_INDEX2_ID, |
| Long.toString(index2ConglomerateNumber)); |
| } |
| |
| /** |
| */ |
| private long getBootParameter(Properties startParams, String key, boolean required) |
| throws StandardException { |
| |
| String value = startParams.getProperty(key); |
| if (value == null) |
| { |
| if (! required) |
| { |
| return -1; |
| } |
| throw StandardException.newException(SQLState.PROPERTY_MISSING, key); |
| } |
| |
| try { |
| return Long.parseLong(value); |
| } catch (NumberFormatException nfe) { |
| throw StandardException.newException(SQLState.PROPERTY_INVALID_VALUE, key, value); |
| } |
| } |
| |
| /** |
| * Returns a unique system generated name of the form SQLyymmddhhmmssxxn |
| * yy - year, mm - month, dd - day of month, hh - hour, mm - minute, ss - second, |
| * xx - the first 2 digits of millisec because we don't have enough space to keep the exact millisec value, |
| * n - number between 0-9 |
| * |
| * The number at the end is to handle more than one system generated name request came at the same time. |
| * In that case, the timestamp will remain the same, we will just increment n at the end of the name. |
| * |
| * Following is how we get around the problem of more than 10 system generated name requestes at the same time: |
| * When the database boots up, we start a counter with value -1 for the last digit in the generated name. |
| * We also keep the time in millisec to keep track of when the last system name was generated. At the |
| * boot time, it will be default to 0L. In addition, we have a calendar object for the time in millisec |
| * That calendar object is used to fetch yy, mm, dd, etc for the string SQLyymmddhhmmssxxn |
| * |
| * When the first request for the system generated name comes, time of last system generated name will be less than |
| * the current time. We initialize the counter to 0, set the time of last system generated name to the |
| * current time truncated off to lower 10ms time. The first name request is the only time we know for sure the |
| * time of last system generated name will be less than the current time. After this first request, the next request |
| * could be at any time. We go through the following algorithm for every generated name request. |
| * |
| * First check if the current time(truncated off to lower 10ms) is greater than the timestamp for last system generated name |
| * |
| * If yes, then we change the timestamp for system generated name to the current timestamp and reset the counter to 0 |
| * and generate the name using the current timestamp and 0 as the number at the end of the generated name. |
| * |
| * If no, then it means this request for generated name has come at the same time as last one. |
| * Or it may come at a time less than the last generated name request. This could be because of seasonal time change |
| * or somebody manually changing the time on the computer. In any case, |
| * if the counter is less than 10(meaning this is not yet our 11th request for generated name at a given time), |
| * we use that in the generated name. But if the counter has reached 10(which means, this is the 11th name request |
| * at the same time), then we increment the system generated name timestamp by 10ms and reset the counter to 0 |
| * (notice, at this point, the timestamp for system generated names is not in sync with the real current time, but we |
| * need to have this mechanism to get around the problem of more than 10 generated name requests at a same physical time). |
| * |
| * @return system generated unique name |
| */ |
| public String getSystemSQLName() |
| { |
| StringBuffer generatedSystemSQLName = new StringBuffer("SQL"); |
| synchronized (this) { |
| //get the current timestamp |
| long timeNow = (System.currentTimeMillis()/10L)*10L; |
| |
| //if the current timestamp is greater than last constraint name generation time, then we reset the counter and |
| //record the new timestamp |
| if (timeNow > timeForLastSystemSQLName) { |
| systemSQLNameNumber = 0; |
| calendarForLastSystemSQLName.setTimeInMillis(timeNow); |
| timeForLastSystemSQLName = timeNow; |
| } else { |
| //the request has come at the same time as the last generated name request |
| //or it has come at a time less than the time the last generated name request. This can happen |
| //because of seasonal time change or manual update of computer time. |
| |
| //get the number that was last used for the last digit of generated name and increment it by 1. |
| systemSQLNameNumber++; |
| if (systemSQLNameNumber == 10) { //we have already generated 10 names at the last system generated timestamp value |
| //so reset the counter |
| systemSQLNameNumber = 0; |
| timeForLastSystemSQLName = timeForLastSystemSQLName + 10L; |
| //increment the timestamp for system generated names by 10ms |
| calendarForLastSystemSQLName.setTimeInMillis(timeForLastSystemSQLName); |
| } |
| } |
| |
| generatedSystemSQLName.append(twoDigits(calendarForLastSystemSQLName.get(Calendar.YEAR))); |
| //have to add 1 to the month value returned because the method give 0-January, 1-February and so on and so forth |
| generatedSystemSQLName.append(twoDigits(calendarForLastSystemSQLName.get(Calendar.MONTH)+1)); |
| generatedSystemSQLName.append(twoDigits(calendarForLastSystemSQLName.get(Calendar.DAY_OF_MONTH))); |
| generatedSystemSQLName.append(twoDigits(calendarForLastSystemSQLName.get(Calendar.HOUR_OF_DAY))); |
| generatedSystemSQLName.append(twoDigits(calendarForLastSystemSQLName.get(Calendar.MINUTE))); |
| generatedSystemSQLName.append(twoDigits(calendarForLastSystemSQLName.get(Calendar.SECOND))); |
| //because we don't have enough space to store the entire millisec value, just store the higher 2 digits. |
| generatedSystemSQLName.append(twoDigits((int) (calendarForLastSystemSQLName.get(Calendar.MILLISECOND)/10))); |
| generatedSystemSQLName.append(systemSQLNameNumber); |
| } |
| return generatedSystemSQLName.toString(); |
| } |
| |
| private static String twoDigits(int val) { |
| String retval; |
| |
| if (val < 10) { |
| retval = "0" + val; |
| } else { |
| int retvalLength = Integer.toString(val).length(); |
| retval = Integer.toString(val).substring(retvalLength-2); |
| } |
| |
| return retval; |
| } |
| |
| /** |
| * sets a new value in SYSCOLUMNS for a particular |
| * autoincrement column. |
| * |
| * @param tc Transaction Controller to use. |
| * @param columnName Name of the column. |
| * @param aiValue Value to write to SYSCOLUMNS. |
| * @param incrementNeeded whether to increment the value passed in by the |
| * user (aiValue) or not before writing it to SYSCOLUMNS. |
| */ |
| public void setAutoincrementValue(TransactionController tc, |
| UUID tableUUID, |
| String columnName, |
| long aiValue, boolean incrementNeeded) |
| throws StandardException |
| { |
| TabInfoImpl ti = coreInfo[SYSCOLUMNS_CORE_NUM]; |
| ExecIndexRow keyRow = null; |
| |
| keyRow = (ExecIndexRow)exFactory.getIndexableRow(2); |
| keyRow.setColumn(1, getIDValueAsCHAR(tableUUID)); |
| keyRow.setColumn(2, new SQLChar(columnName)); |
| |
| SYSCOLUMNSRowFactory rf = (SYSCOLUMNSRowFactory) ti.getCatalogRowFactory(); |
| ExecRow row = rf.makeEmptyRow(); |
| |
| boolean[] bArray = new boolean[2]; |
| for (int index = 0; index < 2; index++) |
| { |
| bArray[index] = false; |
| } |
| |
| int[] colsToUpdate = new int[1]; |
| |
| colsToUpdate[0] = SYSCOLUMNSRowFactory.SYSCOLUMNS_AUTOINCREMENTVALUE; |
| |
| if (incrementNeeded) |
| { |
| ExecRow readRow = ti.getRow(tc, keyRow, |
| SYSCOLUMNSRowFactory.SYSCOLUMNS_INDEX1_ID); |
| NumberDataValue increment = |
| (NumberDataValue)readRow.getColumn(SYSCOLUMNSRowFactory.SYSCOLUMNS_AUTOINCREMENTINC); |
| aiValue += increment.getLong(); |
| } |
| row.setColumn(SYSCOLUMNSRowFactory.SYSCOLUMNS_AUTOINCREMENTVALUE, |
| new SQLLongint(aiValue)); |
| |
| ti.updateRow(keyRow, row, |
| SYSCOLUMNSRowFactory.SYSCOLUMNS_INDEX1_ID, |
| bArray, |
| colsToUpdate, |
| tc); |
| } |
| |
| /** |
| * Computes the RowLocation in SYSCOLUMNS for a particular |
| * autoincrement column. |
| * |
| * @param tc Transaction Controller to use. |
| * @param td Table Descriptor. |
| * @param columnName Name of column which has autoincrement column. |
| * |
| * @exception StandardException thrown on failure. |
| */ |
| private RowLocation computeRowLocation(TransactionController tc, |
| TableDescriptor td, |
| String columnName) |
| throws StandardException |
| { |
| TabInfoImpl ti = coreInfo[SYSCOLUMNS_CORE_NUM]; |
| ExecIndexRow keyRow = null; |
| UUID tableUUID = td.getUUID(); |
| |
| keyRow = (ExecIndexRow)exFactory.getIndexableRow(2); |
| keyRow.setColumn(1, getIDValueAsCHAR(tableUUID)); |
| keyRow.setColumn(2, new SQLChar(columnName)); |
| return ti.getRowLocation(tc, keyRow, |
| SYSCOLUMNSRowFactory.SYSCOLUMNS_INDEX1_ID); |
| } |
| |
| /** |
| * Computes the RowLocation in SYSSEQUENCES for a particular sequence. Also |
| * constructs the sequence descriptor. |
| * |
| * @param tc Transaction Controller to use. |
| * @param sequenceIDstring UUID of the sequence as a string |
| * @param rowLocation OUTPUT param for returing the row location |
| * @param sequenceDescriptor OUTPUT param for return the sequence descriptor |
| * |
| * @exception StandardException thrown on failure. |
| */ |
| public void computeSequenceRowLocation |
| ( TransactionController tc, String sequenceIDstring, RowLocation[] rowLocation, SequenceDescriptor[] sequenceDescriptor ) |
| throws StandardException |
| { |
| TabInfoImpl ti = getNonCoreTI(SYSSEQUENCES_CATALOG_NUM); |
| ExecIndexRow keyRow = null; |
| |
| keyRow = (ExecIndexRow)exFactory.getIndexableRow(1); |
| keyRow.setColumn(1, new SQLChar( sequenceIDstring ) ); |
| |
| rowLocation[ 0 ] = ti.getRowLocation( tc, keyRow, SYSSEQUENCESRowFactory.SYSSEQUENCES_INDEX1_ID ); |
| |
| sequenceDescriptor[ 0 ] = |
| getDescriptorViaIndex |
| ( |
| SYSSEQUENCESRowFactory.SYSSEQUENCES_INDEX1_ID, |
| keyRow, |
| (ScanQualifier[][]) null, |
| ti, |
| (TupleDescriptor) null, |
| (List<TupleDescriptor>) null, |
| SequenceDescriptor.class, |
| false, |
| TransactionController.ISOLATION_REPEATABLE_READ, |
| tc); |
| } |
| |
| /** |
| * Set the current value of an ANSI/ISO sequence. This method does not perform |
| * any sanity checking but assumes that the caller knows what they are doing. If the |
| * old value on disk is not what we expect it to be, then we are in a race with another |
| * session. They won and we don't update the value on disk. However, if the old value |
| * is null, that is a signal to us that we should update the value on disk anyway. |
| * |
| * @param tc Transaction Controller to use. |
| * @param rowLocation Row in SYSSEQUENCES to update. |
| * @param wait True if we should wait for locks |
| * @param oldValue What we expect to find in the CURRENTVALUE column. |
| * @param newValue What to stuff into the CURRENTVALUE column. |
| * |
| * @return Returns true if the value was successfully updated, false if we lost a race with another session. |
| * |
| * @exception StandardException thrown on failure. |
| */ |
| public boolean updateCurrentSequenceValue |
| ( TransactionController tc, RowLocation rowLocation, boolean wait, Long oldValue, Long newValue ) |
| throws StandardException |
| { |
| int columnNum = SYSSEQUENCESRowFactory.SYSSEQUENCES_CURRENT_VALUE; |
| FormatableBitSet columnToUpdate = new FormatableBitSet( SYSSEQUENCESRowFactory.SYSSEQUENCES_COLUMN_COUNT ); |
| TabInfoImpl ti = getNonCoreTI( SYSSEQUENCES_CATALOG_NUM ); |
| ConglomerateController heapCC = null; |
| SYSSEQUENCESRowFactory rf = (SYSSEQUENCESRowFactory) ti.getCatalogRowFactory(); |
| ExecRow row = rf.makeEmptyRow(); |
| |
| // FormatableBitSet is 0 based. |
| columnToUpdate.set( columnNum - 1 ); // current value. |
| |
| try |
| { |
| /* if wait is true then we need to do a wait while trying to |
| open/fetch from the conglomerate. note we use wait both to |
| open as well as fetch from the conglomerate. |
| */ |
| heapCC = |
| tc.openConglomerate( |
| ti.getHeapConglomerate(), |
| false, |
| (TransactionController.OPENMODE_FORUPDATE | |
| ((wait) ? 0 : TransactionController.OPENMODE_LOCK_NOWAIT)), |
| TransactionController.MODE_RECORD, |
| TransactionController.ISOLATION_REPEATABLE_READ); |
| |
| boolean baseRowExists = heapCC.fetch( |
| rowLocation, row.getRowArray(), columnToUpdate, wait); |
| |
| // |
| // We will fail to find the row if it is still locked by the transaction |
| // which created the sequence. In that case, we will leak values |
| // the next time the generator is referenced. |
| // |
| if ( !baseRowExists ) { return false; } |
| |
| NumberDataValue oldValueOnDisk = (NumberDataValue) row.getColumn( columnNum ); |
| |
| SQLLongint expectedOldValue; |
| if ( oldValue == null ) { expectedOldValue = new SQLLongint(); } |
| else { expectedOldValue = new SQLLongint( oldValue.longValue() ); } |
| |
| // only update value if what's on disk is what we expected |
| if ( ( oldValue == null ) || ( expectedOldValue.compare( oldValueOnDisk ) == 0 ) ) |
| { |
| SQLLongint newValueOnDisk; |
| if ( newValue == null ) { newValueOnDisk = new SQLLongint(); } |
| else { newValueOnDisk = new SQLLongint( newValue.longValue() ); } |
| |
| row.setColumn( columnNum, newValueOnDisk ); |
| heapCC.replace( rowLocation, row.getRowArray(), columnToUpdate ); |
| |
| return true; |
| } |
| else |
| { |
| return false; |
| } |
| } |
| finally |
| { |
| if (heapCC != null) { heapCC.close(); } |
| } |
| } |
| |
| /** |
| * @see org.apache.derby.iapi.sql.dictionary.DataDictionary#getCurrentValueAndAdvance |
| */ |
| public void getCurrentValueAndAdvance |
| ( String sequenceUUIDstring, NumberDataValue returnValue ) |
| throws StandardException |
| { |
| SequenceUpdater sequenceUpdater = null; |
| |
| try { |
| sequenceUpdater = (SequenceUpdater) sequenceGeneratorCache.find( sequenceUUIDstring ); |
| |
| sequenceUpdater.getCurrentValueAndAdvance( returnValue ); |
| } |
| finally |
| { |
| if ( sequenceUpdater != null ) |
| { |
| sequenceGeneratorCache.release( sequenceUpdater ); |
| } |
| } |
| } |
| |
| public Long peekAtIdentity( String schemaName, String tableName ) |
| throws StandardException |
| { |
| LanguageConnectionContext lcc = getLCC(); |
| TransactionController tc = lcc.getTransactionExecute(); |
| SchemaDescriptor sd = getSchemaDescriptor( schemaName, tc, true ); |
| TableDescriptor td = getTableDescriptor( tableName, sd, tc ); |
| |
| if ( td == null ) |
| { |
| throw StandardException.newException |
| ( |
| SQLState.LANG_OBJECT_NOT_FOUND_DURING_EXECUTION, "TABLE", |
| ( schemaName + "." + tableName) |
| ); |
| } |
| |
| return peekAtSequence |
| ( |
| SchemaDescriptor.STD_SYSTEM_SCHEMA_NAME, |
| TableDescriptor.makeSequenceName( td.getUUID() ) |
| ); |
| } |
| |
| public Long peekAtSequence( String schemaName, String sequenceName ) |
| throws StandardException |
| { |
| String uuid = getSequenceID( schemaName, sequenceName ); |
| |
| if ( uuid == null ) |
| { |
| throw StandardException.newException(SQLState.LANG_OBJECT_NOT_FOUND_DURING_EXECUTION, "SEQUENCE", |
| ( schemaName + "." + sequenceName) ); |
| } |
| |
| SequenceUpdater sequenceUpdater = null; |
| |
| try { |
| sequenceUpdater = (SequenceUpdater) sequenceGeneratorCache.find( uuid ); |
| return sequenceUpdater.peekAtCurrentValue(); |
| } |
| finally |
| { |
| if ( sequenceUpdater != null ) |
| { |
| sequenceGeneratorCache.release( sequenceUpdater ); |
| } |
| } |
| } |
| |
| public BulkInsertCounter getBulkInsertCounter |
| ( String sequenceUUIDString, boolean restart ) |
| throws StandardException |
| { |
| SequenceUpdater sequenceUpdater = null; |
| |
| try { |
| sequenceUpdater = (SequenceUpdater) sequenceGeneratorCache.find( sequenceUUIDString ); |
| return sequenceUpdater.getBulkInsertUpdater( restart ); |
| } |
| finally |
| { |
| if ( sequenceUpdater != null ) |
| { |
| sequenceGeneratorCache.release( sequenceUpdater ); |
| } |
| } |
| } |
| |
| public void flushBulkInsertCounter |
| ( String sequenceUUIDString, BulkInsertCounter bic ) |
| throws StandardException |
| { |
| SequenceUpdater sequenceUpdater = null; |
| |
| try { |
| sequenceUpdater = (SequenceUpdater) sequenceGeneratorCache.find( sequenceUUIDString ); |
| sequenceUpdater.reset( bic.peekAtCurrentValue() ); |
| } |
| finally |
| { |
| if ( sequenceUpdater != null ) |
| { |
| sequenceGeneratorCache.release( sequenceUpdater ); |
| } |
| } |
| } |
| |
| |
| public RowLocation getRowLocationTemplate(LanguageConnectionContext lcc, |
| TableDescriptor td) |
| throws StandardException |
| { |
| RowLocation rl; |
| ConglomerateController heapCC = null; |
| |
| TransactionController tc = |
| lcc.getTransactionCompile(); |
| |
| long tableId = td.getHeapConglomerateId(); |
| heapCC = |
| tc.openConglomerate( |
| tableId, false, 0, tc.MODE_RECORD, tc.ISOLATION_READ_COMMITTED); |
| try |
| { |
| rl = heapCC.newRowLocationTemplate(); |
| } |
| finally |
| { |
| heapCC.close(); |
| } |
| |
| return rl; |
| } |
| |
| /** |
| * |
| * Add a table descriptor to the "other" cache. The other cache is |
| * determined by the type of the object c. |
| * |
| * @param td TableDescriptor to add to the other cache. |
| * @param c Cacheable Object which lets us figure out the other cache. |
| * |
| * @exception StandardException |
| */ |
| public void addTableDescriptorToOtherCache(TableDescriptor td, |
| Cacheable c) |
| throws StandardException |
| { |
| // get the other cache. if the entry we are setting in the cache is of |
| // type oidtdcacheable then use the nametdcache |
| CacheManager otherCache = |
| (c instanceof OIDTDCacheable) ? nameTdCache : OIDTdCache; |
| Object key; |
| TDCacheable otherCacheEntry = null; |
| |
| if (otherCache == nameTdCache) |
| key = new TableKey(td.getSchemaDescriptor().getUUID(), td.getName()); |
| else |
| key = td.getUUID(); |
| |
| try |
| { |
| // insert the entry into the the other cache. |
| otherCacheEntry = (TDCacheable)otherCache.create(key, td); |
| } |
| catch (StandardException se) |
| { |
| // if the object already exists in cache then somebody beat us to it |
| // otherwise throw the error. |
| if (!(se.getMessageId().equals(SQLState.OBJECT_EXISTS_IN_CACHE))) |
| throw se; |
| } |
| finally |
| { |
| if (otherCacheEntry != null) |
| otherCache.release(otherCacheEntry); |
| } |
| } |
| |
| |
| /** @see DataDictionary#dropStatisticsDescriptors */ |
| public void dropStatisticsDescriptors(UUID tableUUID, UUID referenceUUID, |
| TransactionController tc) |
| throws StandardException |
| { |
| TabInfoImpl ti = getNonCoreTI(SYSSTATISTICS_CATALOG_NUM); |
| DataValueDescriptor first, second; |
| first = getIDValueAsCHAR(tableUUID); |
| |
| ExecIndexRow keyRow; |
| if (referenceUUID != null) |
| { |
| keyRow = exFactory.getIndexableRow(2); |
| second = getIDValueAsCHAR(referenceUUID); |
| keyRow.setColumn(2, second); |
| } |
| else |
| { |
| keyRow = exFactory.getIndexableRow(1); |
| } |
| |
| keyRow.setColumn(1, first); |
| |
| ti.deleteRow(tc, keyRow, |
| SYSSTATISTICSRowFactory.SYSSTATISTICS_INDEX1_ID); |
| |
| } |
| |
| private static LanguageConnectionContext getLCC() { |
| return (LanguageConnectionContext) |
| getContextOrNull(LanguageConnectionContext.CONTEXT_ID); |
| } |
| |
| private SchemaDescriptor newSystemSchemaDesc( |
| String name, |
| String uuid) |
| { |
| return new SchemaDescriptor( |
| this, |
| name, |
| authorizationDatabaseOwner, |
| uuidFactory.recreateUUID(uuid), |
| true); |
| } |
| |
| private SchemaDescriptor newDeclaredGlobalTemporaryTablesSchemaDesc( String name) |
| { |
| return new SchemaDescriptor(this, |
| name, |
| authorizationDatabaseOwner, |
| (UUID) null, |
| false); |
| } |
| /** |
| Check to see if a database has been upgraded to the required |
| level in order to use a language feature. |
| |
| @param requiredMajorVersion Data Dictionary major version |
| @param feature Non-null to throw an error, null to return the state of the version match. |
| |
| @return True if the database has been upgraded to the required level, false otherwise. |
| */ |
| public boolean checkVersion(int requiredMajorVersion, String feature) throws StandardException { |
| |
| if (requiredMajorVersion == DataDictionary.DD_VERSION_CURRENT) { |
| requiredMajorVersion = softwareVersion.majorVersionNumber; |
| } |
| |
| return dictionaryVersion.checkVersion(requiredMajorVersion, feature); |
| } |
| |
| public boolean isReadOnlyUpgrade() { |
| return readOnlyUpgrade; |
| } |
| |
| /** |
| * Mark this database as a read only database whose stored prepared |
| * statements are invalid because some kind of upgrade is needed. |
| */ |
| void setReadOnlyUpgrade() { |
| readOnlyUpgrade = true; |
| } |
| |
| /** |
| ** Create system built-in metadata stored prepared statements. |
| */ |
| void createSystemSps(TransactionController tc) |
| throws StandardException |
| { |
| // DatabaseMetadata stored plans |
| createSPSSet(tc, false, getSystemSchemaDescriptor().getUUID()); |
| |
| // network server stored plans |
| createSPSSet(tc, true, getSysIBMSchemaDescriptor().getUUID()); |
| } |
| |
| /** |
| Create a set of stored prepared statements from a properties file. |
| Key is the statement name, value is the SQL statement. |
| */ |
| protected void createSPSSet(TransactionController tc, boolean net, UUID schemaID) |
| throws StandardException |
| { |
| Properties p = getQueryDescriptions(net); |
| Enumeration e = p.keys(); |
| //statement will get compiled on first execution |
| //Note: Don't change this to FALSE LCC is not available for compiling |
| boolean nocompile = true; |
| |
| while (e.hasMoreElements()) |
| { |
| String spsName = (String)e.nextElement(); |
| String spsText = p.getProperty(spsName); |
| SPSDescriptor spsd = new SPSDescriptor(this, spsName, |
| getUUIDFactory().createUUID(), |
| schemaID, |
| schemaID, |
| SPSDescriptor.SPS_TYPE_REGULAR, |
| !nocompile, // it is valid, unless nocompile |
| spsText, //sps text |
| !nocompile ); |
| |
| addSPSDescriptor(spsd, tc); |
| } |
| } |
| |
| |
| /** |
| * Generic create procedure routine. |
| * <p> |
| * Takes the input procedure and inserts it into the appropriate |
| * catalog. |
| * |
| * Assumes all arguments are "IN" type. |
| * |
| * @param routine_name name of the routine in java and the SQL |
| * procedure name. |
| * |
| * @param arg_names String array of procedure argument names in order. |
| * |
| * @param arg_types Internal SQL types of the arguments |
| * |
| * @param routine_sql_control |
| * One of the RoutineAliasInfo constants: |
| * MODIFIES_SQL_DATA |
| * READS_SQL_DATA |
| * CONTAINS_SQL |
| * NO_SQL |
| * |
| * @param isDeterministic True if the procedure/function is DETERMINISTIC |
| * |
| * @param return_type null for procedure. For functions the return type |
| * of the function. |
| * |
| * @param newlyCreatedRoutines evolving set of routines, some of which may need permissions later on |
| * @param tc an instance of the TransactionController |
| * |
| * @param procClass the fully qualified name of the class that contains |
| * java definitions for the stored procedures |
| * |
| * @return UUID UUID of system routine that got created. |
| * |
| * @exception StandardException Standard exception policy. |
| **/ |
| private final UUID createSystemProcedureOrFunction( |
| String routine_name, |
| UUID schema_uuid, |
| String[] arg_names, |
| TypeDescriptor[] arg_types, |
| int num_out_param, |
| int num_result_sets, |
| short routine_sql_control, |
| boolean isDeterministic, |
| boolean hasVarargs, |
| TypeDescriptor return_type, |
| HashSet<String> newlyCreatedRoutines, |
| TransactionController tc, |
| String procClass) |
| throws StandardException |
| { |
| int num_args = 0; |
| if (arg_names != null) |
| num_args = arg_names.length; |
| |
| if (SanityManager.DEBUG) |
| { |
| if (num_args != 0) |
| { |
| SanityManager.ASSERT(arg_names != null); |
| SanityManager.ASSERT(arg_types != null); |
| SanityManager.ASSERT(arg_names.length == arg_types.length); |
| } |
| } |
| |
| // all args are only "in" arguments |
| int[] arg_modes = null; |
| if (num_args != 0) |
| { |
| arg_modes = new int[num_args]; |
| int num_in_param = num_args - num_out_param; |
| for (int i = 0; i < num_in_param; i++) |
| arg_modes[i] = (ParameterMetaData.parameterModeIn); |
| for (int i = 0; i < num_out_param; i++) |
| arg_modes[num_in_param + i] = (ParameterMetaData.parameterModeOut); |
| } |
| |
| RoutineAliasInfo routine_alias_info = |
| new RoutineAliasInfo( |
| routine_name, // name of routine |
| num_args, // number of params |
| arg_names, // names of params |
| arg_types, // types of params |
| arg_modes, // all "IN" params |
| num_result_sets, // number of result sets |
| RoutineAliasInfo.PS_JAVA, // link to java routine |
| routine_sql_control, // one of: |
| // MODIFIES_SQL_DATA |
| // READS_SQL_DATA |
| // CONTAINS_SQL |
| // NO_SQL |
| isDeterministic, // whether the procedure/function is DETERMINISTIC |
| hasVarargs, // whether the procedure/function has VARARGS |
| false, // not definer's rights |
| true, // true - calledOnNullInput |
| return_type); |
| |
| UUID routine_uuid = getUUIDFactory().createUUID(); |
| AliasDescriptor ads = |
| new AliasDescriptor( |
| this, |
| routine_uuid, |
| routine_name, |
| schema_uuid, |
| procClass, |
| (return_type == null) ? |
| AliasInfo.ALIAS_TYPE_PROCEDURE_AS_CHAR : |
| AliasInfo.ALIAS_TYPE_FUNCTION_AS_CHAR, |
| (return_type == null) ? |
| AliasInfo.ALIAS_NAME_SPACE_PROCEDURE_AS_CHAR : |
| AliasInfo.ALIAS_NAME_SPACE_FUNCTION_AS_CHAR, |
| false, |
| routine_alias_info, null); |
| |
| addDescriptor( |
| ads, null, DataDictionary.SYSALIASES_CATALOG_NUM, false, tc); |
| |
| newlyCreatedRoutines.add( routine_name ); |
| |
| return routine_uuid; |
| } |
| |
| /** |
| * Generic create procedure routine. |
| * Takes the input procedure and inserts it into the appropriate |
| * catalog. |
| * |
| * Assumes all arguments are "IN" type. |
| * |
| * @param routine_name name of the routine in java and the SQL |
| * procedure name. |
| * |
| * @param arg_names String array of procedure argument names in order. |
| * |
| * @param arg_types Internal SQL types of the arguments |
| * |
| * @param routine_sql_control |
| * One of the RoutineAliasInfo constants: |
| * MODIFIES_SQL_DATA |
| * READS_SQL_DATA |
| * CONTAINS_SQL |
| * NO_SQL |
| * |
| * |
| * @param isDeterministic True if the procedure/function is DETERMINISTIC |
| * |
| * @param return_type null for procedure. For functions the return type |
| * of the function. |
| * |
| * @param newlyCreatedRoutines evolving set of routines, some of which may need permissions later on |
| * @param tc an instance of the TransactionController |
| * |
| * @return UUID UUID of system routine that got created. |
| * |
| * @throws StandardException Standard exception policy. |
| **/ |
| private final UUID createSystemProcedureOrFunction( |
| String routine_name, |
| UUID schema_uuid, |
| String[] arg_names, |
| TypeDescriptor[] arg_types, |
| int num_out_param, |
| int num_result_sets, |
| short routine_sql_control, |
| boolean isDeterministic, |
| boolean hasVarargs, |
| TypeDescriptor return_type, |
| HashSet<String> newlyCreatedRoutines, |
| TransactionController tc) |
| throws StandardException |
| { |
| UUID routine_uuid = createSystemProcedureOrFunction(routine_name, |
| schema_uuid, arg_names, arg_types, |
| num_out_param, num_result_sets, routine_sql_control, isDeterministic, hasVarargs, |
| return_type, newlyCreatedRoutines, tc, "org.apache.derby.catalog.SystemProcedures"); |
| return routine_uuid; |
| } |
| |
| /** |
| * Create system procedures |
| * <p> |
| * Used to add the system procedures to the database when |
| * it is created. System procedures are currently added to |
| * either SYSCS_UTIL or SQLJ schemas. |
| * <p> |
| * |
| * @param tc transaction controller to use. Counts on caller to |
| * commit. |
| * @param newlyCreatedRoutines evolving set of routines which may need to be given permissions later on |
| * |
| * @exception StandardException Standard exception policy. |
| **/ |
| private final void create_SYSCS_procedures( |
| TransactionController tc, HashSet<String> newlyCreatedRoutines ) |
| throws StandardException |
| { |
| // Types used for routine parameters and return types, all nullable. |
| TypeDescriptor varchar32672Type = DataTypeDescriptor.getCatalogType( |
| Types.VARCHAR, 32672); |
| |
| /* |
| ** SYSCS_UTIL routines. |
| */ |
| |
| // used to put procedure into the SYSCS_UTIL schema |
| UUID sysUtilUUID = getSystemUtilSchemaDescriptor().getUUID(); |
| |
| |
| // void SYSCS_UTIL.SYSCS_SET_DATABASE_PROPERTY( |
| // varchar(128), varchar(Limits.DB2_VARCHAR_MAXWIDTH)) |
| { |
| |
| // procedure argument names |
| String[] arg_names = { |
| "KEY", |
| "VALUE"}; |
| |
| // procedure argument types |
| TypeDescriptor[] arg_types = { |
| CATALOG_TYPE_SYSTEM_IDENTIFIER, |
| DataTypeDescriptor.getCatalogType( |
| Types.VARCHAR, Limits.DB2_VARCHAR_MAXWIDTH) |
| }; |
| |
| createSystemProcedureOrFunction( |
| "SYSCS_SET_DATABASE_PROPERTY", |
| sysUtilUUID, |
| arg_names, |
| arg_types, |
| 0, |
| 0, |
| RoutineAliasInfo.MODIFIES_SQL_DATA, |
| false, |
| false, |
| (TypeDescriptor) null, |
| newlyCreatedRoutines, |
| tc); |
| } |
| |
| |
| // void SYSCS_UTIL.SYSCS_COMPRESS_TABLE(varchar(128), varchar(128), SMALLINT) |
| { |
| // procedure argument names |
| String[] arg_names = {"SCHEMANAME", "TABLENAME", "SEQUENTIAL"}; |
| |
| // procedure argument types |
| TypeDescriptor[] arg_types = { |
| CATALOG_TYPE_SYSTEM_IDENTIFIER, |
| CATALOG_TYPE_SYSTEM_IDENTIFIER, |
| TypeDescriptor.SMALLINT |
| |
| }; |
| |
| createSystemProcedureOrFunction( |
| "SYSCS_COMPRESS_TABLE", |
| sysUtilUUID, |
| arg_names, |
| arg_types, |
| 0, |
| 0, |
| RoutineAliasInfo.MODIFIES_SQL_DATA, |
| false, |
| false, |
| (TypeDescriptor) null, |
| newlyCreatedRoutines, |
| tc); |
| } |
| |
| // void SYSCS_UTIL.SYSCS_CHECKPOINT_DATABASE() |
| { |
| createSystemProcedureOrFunction( |
| "SYSCS_CHECKPOINT_DATABASE", |
| sysUtilUUID, |
| null, |
| null, |
| 0, |
| 0, |
| RoutineAliasInfo.CONTAINS_SQL, |
| false, |
| false, |
| (TypeDescriptor) null, |
| newlyCreatedRoutines, |
| tc); |
| } |
| |
| // void SYSCS_UTIL.SYSCS_FREEZE_DATABASE() |
| { |
| createSystemProcedureOrFunction( |
| "SYSCS_FREEZE_DATABASE", |
| sysUtilUUID, |
| null, |
| null, |
| 0, |
| 0, |
| RoutineAliasInfo.CONTAINS_SQL, |
| false, |
| false, |
| (TypeDescriptor) null, |
| newlyCreatedRoutines, |
| tc); |
| } |
| |
| // void SYSCS_UTIL.SYSCS_UNFREEZE_DATABASE() |
| { |
| createSystemProcedureOrFunction( |
| "SYSCS_UNFREEZE_DATABASE", |
| sysUtilUUID, |
| null, |
| null, |
| 0, |
| 0, |
| RoutineAliasInfo.CONTAINS_SQL, |
| false, |
| false, |
| (TypeDescriptor) null, |
| newlyCreatedRoutines, |
| tc); |
| } |
| |
| // void SYSCS_UTIL.SYSCS_BACKUP_DATABASE(varchar Limits.DB2_VARCHAR_MAXWIDTH) |
| { |
| // procedure argument names |
| String[] arg_names = {"BACKUPDIR"}; |
| |
| // procedure argument types |
| TypeDescriptor[] arg_types = { |
| DataTypeDescriptor.getCatalogType( |
| Types.VARCHAR, Limits.DB2_VARCHAR_MAXWIDTH) |
| }; |
| |
| createSystemProcedureOrFunction( |
| "SYSCS_BACKUP_DATABASE", |
| sysUtilUUID, |
| arg_names, |
| arg_types, |
| 0, |
| 0, |
| RoutineAliasInfo.MODIFIES_SQL_DATA, |
| false, |
| false, |
| (TypeDescriptor) null, |
| newlyCreatedRoutines, |
| tc); |
| } |
| |
| // void SYSCS_UTIL.SYSCS_BACKUP_DATABASE_AND_ENABLE_LOG_ARCHIVE_MODE( |
| // varchar Limits.DB2_VARCHAR_MAXWIDTH, smallint) |
| { |
| // procedure argument names |
| String[] arg_names = {"BACKUPDIR", "DELETE_ARCHIVED_LOG_FILES"}; |
| |
| // procedure argument types |
| TypeDescriptor[] arg_types = { |
| DataTypeDescriptor.getCatalogType( |
| Types.VARCHAR, Limits.DB2_VARCHAR_MAXWIDTH), |
| TypeDescriptor.SMALLINT |
| }; |
| |
| createSystemProcedureOrFunction( |
| "SYSCS_BACKUP_DATABASE_AND_ENABLE_LOG_ARCHIVE_MODE", |
| sysUtilUUID, |
| arg_names, |
| arg_types, |
| 0, |
| 0, |
| RoutineAliasInfo.MODIFIES_SQL_DATA, |
| false, |
| false, |
| (TypeDescriptor) null, |
| newlyCreatedRoutines, |
| tc); |
| } |
| |
| // void SYSCS_UTIL.SYSCS_DISABLE_LOG_ARCHIVE_MODE(smallint) |
| { |
| // procedure argument names |
| String[] arg_names = {"DELETE_ARCHIVED_LOG_FILES"}; |
| |
| // procedure argument types |
| TypeDescriptor[] arg_types = {TypeDescriptor.SMALLINT}; |
| |
| createSystemProcedureOrFunction( |
| "SYSCS_DISABLE_LOG_ARCHIVE_MODE", |
| sysUtilUUID, |
| arg_names, |
| arg_types, |
| 0, |
| 0, |
| RoutineAliasInfo.MODIFIES_SQL_DATA, |
| false, |
| false, |
| (TypeDescriptor) null, |
| newlyCreatedRoutines, |
| tc); |
| } |
| |
| // void SYSCS_UTIL.SYSCS_SET_RUNTIMESTTISTICS(smallint) |
| { |
| // procedure argument names |
| String[] arg_names = {"ENABLE"}; |
| |
| // procedure argument types |
| TypeDescriptor[] arg_types = {TypeDescriptor.SMALLINT}; |
| |
| createSystemProcedureOrFunction( |
| "SYSCS_SET_RUNTIMESTATISTICS", |
| sysUtilUUID, |
| arg_names, |
| arg_types, |
| 0, |
| 0, |
| RoutineAliasInfo.CONTAINS_SQL, |
| false, |
| false, |
| (TypeDescriptor) null, |
| newlyCreatedRoutines, |
| tc); |
| } |
| |
| // void SYSCS_UTIL.SYSCS_SET_STATISTICS_TIMING(smallint) |
| { |
| // procedure argument names |
| String[] arg_names = {"ENABLE"}; |
| |
| // procedure argument types |
| TypeDescriptor[] arg_types = {TypeDescriptor.SMALLINT}; |
| |
| createSystemProcedureOrFunction( |
| "SYSCS_SET_STATISTICS_TIMING", |
| sysUtilUUID, |
| arg_names, |
| arg_types, |
| 0, |
| 0, |
| RoutineAliasInfo.CONTAINS_SQL, |
| false, |
| false, |
| (TypeDescriptor) null, |
| newlyCreatedRoutines, |
| tc); |
| } |
| |
| |
| // SYSCS_UTIL functions |
| // |
| // TODO (mikem) - |
| // the following need to be functions when that is supported. |
| // until then calling them will not work. |
| |
| // VARCHAR(Limits.DB2_VARCHAR_MAXWIDTH) |
| // SYSCS_UTIL.SYSCS_GET_DATABASE_PROPERTY(varchar(128)) |
| |
| { |
| // procedure argument names |
| String[] arg_names = {"KEY"}; |
| |
| // procedure argument types |
| TypeDescriptor[] arg_types = {CATALOG_TYPE_SYSTEM_IDENTIFIER}; |
| |
| createSystemProcedureOrFunction( |
| "SYSCS_GET_DATABASE_PROPERTY", |
| sysUtilUUID, |
| arg_names, |
| arg_types, |
| 0, |
| 0, |
| RoutineAliasInfo.READS_SQL_DATA, |
| false, |
| false, |
| DataTypeDescriptor.getCatalogType( |
| Types.VARCHAR, Limits.DB2_VARCHAR_MAXWIDTH), |
| newlyCreatedRoutines, |
| tc); |
| } |
| |
| // SMALLINT SYSCS_UTIL.SYSCS_CHECK_TABLE(varchar(128), varchar(128)) |
| { |
| // procedure argument names |
| String[] arg_names = {"SCHEMANAME", "TABLENAME"}; |
| |
| // procedure argument types |
| TypeDescriptor[] arg_types = { |
| CATALOG_TYPE_SYSTEM_IDENTIFIER, |
| CATALOG_TYPE_SYSTEM_IDENTIFIER |
| }; |
| |
| createSystemProcedureOrFunction( |
| "SYSCS_CHECK_TABLE", |
| sysUtilUUID, |
| arg_names, |
| arg_types, |
| 0, |
| 0, |
| RoutineAliasInfo.READS_SQL_DATA, |
| false, |
| false, |
| TypeDescriptor.INTEGER, |
| newlyCreatedRoutines, |
| tc); |
| } |
| |
| // CLOB SYSCS_UTIL.SYSCS_GET_RUNTIMESTATISTICS() |
| { |
| |
| createSystemProcedureOrFunction( |
| "SYSCS_GET_RUNTIMESTATISTICS", |
| sysUtilUUID, |
| null, |
| null, |
| 0, |
| 0, |
| RoutineAliasInfo.CONTAINS_SQL, |
| false, |
| false, |
| DataTypeDescriptor.getCatalogType( |
| Types.VARCHAR, Limits.DB2_VARCHAR_MAXWIDTH), |
| newlyCreatedRoutines, |
| |
| /* |
| TODO - mikem, wants to be a CLOB, but don't know how to do |
| that yet. Testing it with varchar for now. |
| DataTypeDescriptor.getCatalogType( |
| Types.CLOB, Limits.DB2_LOB_MAXWIDTH), |
| */ |
| tc); |
| } |
| |
| |
| /* |
| ** SQLJ routine. |
| */ |
| |
| UUID sqlJUUID = |
| getSchemaDescriptor( |
| SchemaDescriptor.STD_SQLJ_SCHEMA_NAME, tc, true).getUUID(); |
| |
| // SQLJ.INSTALL_JAR(URL VARCHAR(??), JAR VARCHAR(128), DEPLOY INT) |
| { |
| String[] arg_names = {"URL", "JAR", "DEPLOY"}; |
| |
| TypeDescriptor[] arg_types = { |
| DataTypeDescriptor.getCatalogType( |
| Types.VARCHAR, 256), |
| CATALOG_TYPE_SYSTEM_IDENTIFIER, |
| TypeDescriptor.INTEGER |
| }; |
| |
| createSystemProcedureOrFunction( |
| "INSTALL_JAR", |
| sqlJUUID, |
| arg_names, |
| arg_types, |
| 0, |
| 0, |
| RoutineAliasInfo.MODIFIES_SQL_DATA, |
| false, |
| false, |
| (TypeDescriptor) null, |
| newlyCreatedRoutines, |
| tc); |
| } |
| |
| // SQLJ.REPLACE_JAR(URL VARCHAR(??), JAR VARCHAR(128)) |
| { |
| String[] arg_names = {"URL", "JAR"}; |
| |
| TypeDescriptor[] arg_types = { |
| DataTypeDescriptor.getCatalogType( |
| Types.VARCHAR, 256), |
| CATALOG_TYPE_SYSTEM_IDENTIFIER |
| }; |
| |
| createSystemProcedureOrFunction( |
| "REPLACE_JAR", |
| sqlJUUID, |
| arg_names, |
| arg_types, |
| 0, |
| 0, |
| RoutineAliasInfo.MODIFIES_SQL_DATA, |
| false, |
| false, |
| (TypeDescriptor) null, |
| newlyCreatedRoutines, |
| tc); |
| } |
| |
| // SQLJ.REMOVE_JAR(JAR VARCHAR(128), UNDEPLOY INT) |
| { |
| String[] arg_names = {"JAR", "UNDEPLOY"}; |
| |
| TypeDescriptor[] arg_types = { |
| CATALOG_TYPE_SYSTEM_IDENTIFIER, |
| TypeDescriptor.INTEGER |
| }; |
| |
| createSystemProcedureOrFunction( |
| "REMOVE_JAR", |
| sqlJUUID, |
| arg_names, |
| arg_types, |
| 0, |
| 0, |
| RoutineAliasInfo.MODIFIES_SQL_DATA, |
| false, |
| false, |
| (TypeDescriptor) null, |
| newlyCreatedRoutines, |
| tc); |
| } |
| |
| /* SYSCS_EXPORT_TABLE (IN SCHEMANAME VARCHAR(128), |
| * IN TABLENAME VARCHAR(128), IN FILENAME VARCHAR(32672) , |
| * IN COLUMNDELIMITER CHAR(1), IN CHARACTERDELIMITER CHAR(1) , |
| * IN CODESET VARCHAR(128)) |
| */ |
| |
| |
| { |
| // procedure argument names |
| String[] arg_names = {"schemaName", "tableName" , |
| "fileName"," columnDelimiter", |
| "characterDelimiter", "codeset"}; |
| |
| // procedure argument types |
| TypeDescriptor[] arg_types = { |
| CATALOG_TYPE_SYSTEM_IDENTIFIER, |
| CATALOG_TYPE_SYSTEM_IDENTIFIER, |
| varchar32672Type, |
| DataTypeDescriptor.getCatalogType( |
| Types.CHAR, 1), |
| DataTypeDescriptor.getCatalogType( |
| Types.CHAR, 1), |
| CATALOG_TYPE_SYSTEM_IDENTIFIER |
| }; |
| |
| createSystemProcedureOrFunction( |
| "SYSCS_EXPORT_TABLE", |
| sysUtilUUID, |
| arg_names, |
| arg_types, |
| 0, |
| 0, |
| RoutineAliasInfo.READS_SQL_DATA, |
| false, |
| false, |
| (TypeDescriptor) null, |
| newlyCreatedRoutines, |
| tc); |
| } |
| |
| |
| /* SYSCS_EXPORT_QUERY (IN SELECTSTATEMENT VARCHAR(32672), |
| * IN FILENAME VARCHAR(32672) , |
| * IN COLUMNDELIMITER CHAR(1), IN CHARACTERDELIMITER CHAR(1) , |
| * IN CODESET VARCHAR(128)) |
| */ |
| { |
| // procedure argument names |
| String[] arg_names = {"selectStatement", "fileName", |
| " columnDelimiter", "characterDelimiter", |
| "codeset"}; |
| |
| // procedure argument types |
| TypeDescriptor[] arg_types = { |
| varchar32672Type, |
| varchar32672Type, |
| DataTypeDescriptor.getCatalogType( |
| Types.CHAR, 1), |
| DataTypeDescriptor.getCatalogType( |
| Types.CHAR, 1), |
| CATALOG_TYPE_SYSTEM_IDENTIFIER |
| }; |
| |
| createSystemProcedureOrFunction( |
| "SYSCS_EXPORT_QUERY", |
| sysUtilUUID, |
| arg_names, |
| arg_types, |
| 0, |
| 0, |
| RoutineAliasInfo.READS_SQL_DATA, |
| false, |
| false, |
| (TypeDescriptor) null, |
| newlyCreatedRoutines, |
| tc); |
| } |
| |
| |
| /* SYSCS_IMPORT_TABLE(IN SCHEMANAME VARCHAR(128), |
| * IN TABLENAME VARCHAR(128), IN FILENAME VARCHAR(32672), |
| * IN COLUMNDELIMITER CHAR(1), IN CHARACTERDELIMITER CHAR(1), |
| * IN CODESET VARCHAR(128) , IN REPLACE SMALLINT) |
| */ |
| { |
| // procedure argument names |
| String[] arg_names = {"schemaName", "tableName", "fileName", |
| " columnDelimiter", "characterDelimiter", |
| "codeset", "replace"}; |
| |
| // procedure argument types |
| |
| // procedure argument types |
| TypeDescriptor[] arg_types = { |
| CATALOG_TYPE_SYSTEM_IDENTIFIER, |
| CATALOG_TYPE_SYSTEM_IDENTIFIER, |
| varchar32672Type, |
| DataTypeDescriptor.getCatalogType( |
| Types.CHAR, 1), |
| DataTypeDescriptor.getCatalogType( |
| Types.CHAR, 1), |
| CATALOG_TYPE_SYSTEM_IDENTIFIER, |
| TypeDescriptor.SMALLINT, |
| }; |
| |
| |
| createSystemProcedureOrFunction( |
| "SYSCS_IMPORT_TABLE", |
| sysUtilUUID, |
| arg_names, |
| arg_types, |
| 0, |
| 0, |
| RoutineAliasInfo.MODIFIES_SQL_DATA, |
| false, |
| false, |
| (TypeDescriptor) null, |
| newlyCreatedRoutines, |
| tc); |
| } |
| |
| |
| /* SYSCS_IMPORT_DATA(IN SCHEMANAME VARCHAR(128), |
| * IN TABLENAME VARCHAR(128), IN INSERTCOLUMNLIST VARCHAR(32672), |
| * IN COLUMNINDEXES VARCHAR(32672), IN IN FILENAME VARCHAR(32672), |
| * IN COLUMNDELIMITER CHAR(1), IN CHARACTERDELIMITER CHAR(1), |
| * IN CODESET VARCHAR(128) , IN REPLACE SMALLINT) |
| */ |
| { |
| // procedure argument names |
| String[] arg_names = {"schemaName", "tableName", "insertColumnList","columnIndexes", |
| "fileName", " columnDelimiter", "characterDelimiter", |
| "codeset", "replace"}; |
| |
| // procedure argument types |
| |
| // procedure argument types |
| TypeDescriptor[] arg_types = { |
| CATALOG_TYPE_SYSTEM_IDENTIFIER, |
| CATALOG_TYPE_SYSTEM_IDENTIFIER, |
| varchar32672Type, |
| varchar32672Type, |
| varchar32672Type, |
| DataTypeDescriptor.getCatalogType( |
| Types.CHAR, 1), |
| DataTypeDescriptor.getCatalogType( |
| Types.CHAR, 1), |
| CATALOG_TYPE_SYSTEM_IDENTIFIER, |
| TypeDescriptor.SMALLINT, |
| }; |
| |
| |
| createSystemProcedureOrFunction( |
| "SYSCS_IMPORT_DATA", |
| sysUtilUUID, |
| arg_names, |
| arg_types, |
| 0, |
| 0, |
| RoutineAliasInfo.MODIFIES_SQL_DATA, |
| false, |
| false, |
| (TypeDescriptor) null, |
| newlyCreatedRoutines, |
| tc); |
| } |
| |
| |
| /* |
| * SYSCS_BULK_INSERT( |
| * IN SCHEMANAME VARCHAR(128), |
| * IN TABLENAME VARCHAR(128), |
| * IN VTINAME VARCHAR(32672), |
| * IN VTIARG VARCHAR(32672)) |
| */ |
| { |
| // procedure argument names |
| String[] arg_names = {"schemaName", "tableName", "vtiName","vtiArg"}; |
| |
| |
| // procedure argument types |
| TypeDescriptor[] arg_types = { |
| CATALOG_TYPE_SYSTEM_IDENTIFIER, |
| CATALOG_TYPE_SYSTEM_IDENTIFIER, |
| varchar32672Type, |
| varchar32672Type, |
| }; |
| |
| |
| createSystemProcedureOrFunction( |
| "SYSCS_BULK_INSERT", |
| sysUtilUUID, |
| arg_names, |
| arg_types, |
| 0, |
| 0, |
| RoutineAliasInfo.MODIFIES_SQL_DATA, |
| false, |
| false, |
| (TypeDescriptor) null, |
| newlyCreatedRoutines, |
| tc); |
| } |
| |
| // add 10.1 specific system procedures |
| create_10_1_system_procedures(tc, newlyCreatedRoutines, sysUtilUUID); |
| // add 10.2 specific system procedures |
| create_10_2_system_procedures(tc, newlyCreatedRoutines, sysUtilUUID); |
| // add 10.3 specific system procedures |
| create_10_3_system_procedures(tc, newlyCreatedRoutines ); |
| // add 10.5 specific system procedures |
| create_10_5_system_procedures(tc, newlyCreatedRoutines ); |
| // add 10.6 specific system procedures |
| create_10_6_system_procedures(tc, newlyCreatedRoutines ); |
| // add 10.9 specific system procedures |
| create_10_9_system_procedures( tc, newlyCreatedRoutines ); |
| // add 10.10 specific system procedures |
| create_10_10_system_procedures( tc, newlyCreatedRoutines ); |
| // add 10.11 specific system procedures |
| create_10_11_system_procedures( tc, newlyCreatedRoutines ); |
| // add 10.12 specific system procedures |
| create_10_12_system_procedures( tc, newlyCreatedRoutines ); |
| // add 10.13 specific system procedures |
| create_10_13_system_procedures( tc, newlyCreatedRoutines ); |
| } |
| |
| /** |
| * Create system procedures in SYSIBM |
| * <p> |
| * Used to add the system procedures to the database when |
| * it is created. Full upgrade from version 5.1 or earlier also |
| * calls this method. |
| * <p> |
| * |
| * @param newlyCreatedRoutines evolving set of routines which we're adding (some may need permissions later on) |
| * @param tc transaction controller to use. Counts on caller to |
| * commit. |
| * |
| * @exception StandardException Standard exception policy. |
| **/ |
| protected final void create_SYSIBM_procedures( |
| TransactionController tc, HashSet<String> newlyCreatedRoutines ) |
| throws StandardException |
| { |
| /* |
| ** SYSIBM routines. |
| */ |
| |
| // used to put procedure into the SYSIBM schema |
| UUID sysIBMUUID = getSysIBMSchemaDescriptor().getUUID(); |
| |
| |
| // SYSIBM.SQLCAMESSAGE( |
| { |
| |
| // procedure argument names |
| String[] arg_names = { |
| "SQLCODE", |
| "SQLERRML", |
| "SQLERRMC", |
| "SQLERRP", |
| "SQLERRD0", |
| "SQLERRD1", |
| "SQLERRD2", |
| "SQLERRD3", |
| "SQLERRD4", |
| "SQLERRD5", |
| "SQLWARN", |
| "SQLSTATE", |
| "FILE", |
| "LOCALE", |
| "MESSAGE", |
| "RETURNCODE"}; |
| |
| // procedure argument types |
| TypeDescriptor[] arg_types = { |
| TypeDescriptor.INTEGER, |
| TypeDescriptor.SMALLINT, |
| DataTypeDescriptor.getCatalogType( |
| Types.VARCHAR, MessageUtils.DB2_JCC_MAX_EXCEPTION_PARAM_LENGTH), |
| DataTypeDescriptor.getCatalogType(Types.CHAR, 8), |
| TypeDescriptor.INTEGER, |
| TypeDescriptor.INTEGER, |
| TypeDescriptor.INTEGER, |
| TypeDescriptor.INTEGER, |
| TypeDescriptor.INTEGER, |
| TypeDescriptor.INTEGER, |
| DataTypeDescriptor.getCatalogType(Types.CHAR, 11), |
| DataTypeDescriptor.getCatalogType(Types.CHAR, 5), |
| DataTypeDescriptor.getCatalogType(Types.VARCHAR, 50), |
| DataTypeDescriptor.getCatalogType(Types.CHAR, 5), |
| DataTypeDescriptor.getCatalogType(Types.VARCHAR, 2400), |
| TypeDescriptor.INTEGER |
| }; |
| |
| createSystemProcedureOrFunction( |
| "SQLCAMESSAGE", |
| sysIBMUUID, |
| arg_names, |
| arg_types, |
| 2, |
| 0, |
| RoutineAliasInfo.READS_SQL_DATA, |
| false, |
| false, |
| (TypeDescriptor) null, |
| newlyCreatedRoutines, |
| tc); |
| } |
| |
| // SYSIBM.SQLPROCEDURES(VARCHAR(128), VARCHAR(128), VARCHAR(128), VARCHAR(4000)) |
| { |
| |
| // procedure argument names |
| String[] arg_names = { |
| "CATALOGNAME", |
| "SCHEMANAME", |
| "PROCNAME", |
| "OPTIONS"}; |
| |
| // procedure argument types |
| TypeDescriptor[] arg_types = { |
| CATALOG_TYPE_SYSTEM_IDENTIFIER, |
| CATALOG_TYPE_SYSTEM_IDENTIFIER, |
| CATALOG_TYPE_SYSTEM_IDENTIFIER, |
| DataTypeDescriptor.getCatalogType(Types.VARCHAR, 4000)}; |
| |
| createSystemProcedureOrFunction( |
| "SQLPROCEDURES", |
| sysIBMUUID, |
| arg_names, |
| arg_types, |
| 0, |
| 1, |
| RoutineAliasInfo.READS_SQL_DATA, |
| false, |
| false, |
| (TypeDescriptor) null, |
| newlyCreatedRoutines, |
| tc); |
| } |
| |
| // SYSIBM.SQLTABLEPRIVILEGES(VARCHAR(128), VARCHAR(128), VARCHAR(128), VARCHAR(4000)) |
| { |
| |
| // procedure argument names |
| String[] arg_names = { |
| "CATALOGNAME", |
| "SCHEMANAME", |
| "TABLENAME", |
| "OPTIONS"}; |
| |
| // procedure argument types |
| TypeDescriptor[] arg_types = { |
| CATALOG_TYPE_SYSTEM_IDENTIFIER, |
| CATALOG_TYPE_SYSTEM_IDENTIFIER, |
| CATALOG_TYPE_SYSTEM_IDENTIFIER, |
| DataTypeDescriptor.getCatalogType(Types.VARCHAR, 4000)}; |
| |
| createSystemProcedureOrFunction( |
| "SQLTABLEPRIVILEGES", |
| sysIBMUUID, |
| arg_names, |
| arg_types, |
| 0, |
| 1, |
| RoutineAliasInfo.READS_SQL_DATA, |
| false, |
| false, |
| (TypeDescriptor) null, |
| newlyCreatedRoutines, |
| tc); |
| } |
| |
| // SYSIBM.SQLPRIMARYKEYS(VARCHAR(128), VARCHAR(128), VARCHAR(128), VARCHAR(4000)) |
| { |
| |
| // procedure argument names |
| String[] arg_names = { |
| "CATALOGNAME", |
| "SCHEMANAME", |
| "TABLENAME", |
| "OPTIONS"}; |
| |
| // procedure argument types |
| TypeDescriptor[] arg_types = { |
| CATALOG_TYPE_SYSTEM_IDENTIFIER, |
| CATALOG_TYPE_SYSTEM_IDENTIFIER, |
| CATALOG_TYPE_SYSTEM_IDENTIFIER, |
| DataTypeDescriptor.getCatalogType(Types.VARCHAR, 4000)}; |
| |
| createSystemProcedureOrFunction( |
| "SQLPRIMARYKEYS", |
| sysIBMUUID, |
| arg_names, |
| arg_types, |
| 0, |
| 1, |
| RoutineAliasInfo.READS_SQL_DATA, |
| false, |
| false, |
| (TypeDescriptor) null, |
| newlyCreatedRoutines, |
| tc); |
| } |
| |
| // SYSIBM.SQLTABLES(VARCHAR(128), VARCHAR(128), VARCHAR(128), VARCHAR(4000), VARCHAR(4000)) |
| { |
| |
| // procedure argument names |
| String[] arg_names = { |
| "CATALOGNAME", |
| "SCHEMANAME", |
| "TABLENAME", |
| "TABLETYPE", |
| "OPTIONS"}; |
| |
| // procedure argument types |
| TypeDescriptor[] arg_types = { |
| CATALOG_TYPE_SYSTEM_IDENTIFIER, |
| CATALOG_TYPE_SYSTEM_IDENTIFIER, |
| CATALOG_TYPE_SYSTEM_IDENTIFIER, |
| DataTypeDescriptor.getCatalogType(Types.VARCHAR, 4000), |
| DataTypeDescriptor.getCatalogType(Types.VARCHAR, 4000)}; |
| |
| createSystemProcedureOrFunction( |
| "SQLTABLES", |
| sysIBMUUID, |
| arg_names, |
| arg_types, |
| 0, |
| 1, |
| RoutineAliasInfo.READS_SQL_DATA, |
| false, |
| false, |
| (TypeDescriptor) null, |
| newlyCreatedRoutines, |
| tc); |
| } |
| |
| |
| // SYSIBM.SQLPROCEDURECOLS(VARCHAR(128), VARCHAR(128), VARCHAR(128), VARCHAR(128), VARCHAR(4000)) |
| { |
| |
| // procedure argument names |
| String[] arg_names = { |
| "CATALOGNAME", |
| "SCHEMANAME", |
| "PROCNAME", |
| "PARAMNAME", |
| "OPTIONS"}; |
| |
| // procedure argument types |
| TypeDescriptor[] arg_types = { |
| CATALOG_TYPE_SYSTEM_IDENTIFIER, |
| CATALOG_TYPE_SYSTEM_IDENTIFIER, |
| CATALOG_TYPE_SYSTEM_IDENTIFIER, |
| CATALOG_TYPE_SYSTEM_IDENTIFIER, |
| DataTypeDescriptor.getCatalogType(Types.VARCHAR, 4000)}; |
| |
| createSystemProcedureOrFunction( |
| "SQLPROCEDURECOLS", |
| sysIBMUUID, |
| arg_names, |
| arg_types, |
| 0, |
| 1, |
| RoutineAliasInfo.READS_SQL_DATA, |
| false, |
| false, |
| (TypeDescriptor) null, |
| newlyCreatedRoutines, |
| tc); |
| } |
| |
| // SYSIBM.SQLCOLUMNS(VARCHAR(128), VARCHAR(128), VARCHAR(128), VARCHAR(128), VARCHAR(4000)) |
| { |
| |
| // procedure argument names |
| String[] arg_names = { |
| "CATALOGNAME", |
| "SCHEMANAME", |
| "TABLENAME", |
| "COLUMNNAME", |
| "OPTIONS"}; |
| |
| // procedure argument types |
| TypeDescriptor[] arg_types = { |
| CATALOG_TYPE_SYSTEM_IDENTIFIER, |
| CATALOG_TYPE_SYSTEM_IDENTIFIER, |
| CATALOG_TYPE_SYSTEM_IDENTIFIER, |
| CATALOG_TYPE_SYSTEM_IDENTIFIER, |
| DataTypeDescriptor.getCatalogType(Types.VARCHAR, 4000)}; |
| |
| createSystemProcedureOrFunction( |
| "SQLCOLUMNS", |
| sysIBMUUID, |
| arg_names, |
| arg_types, |
| 0, |
| 1, |
| RoutineAliasInfo.READS_SQL_DATA, |
| false, |
| false, |
| (TypeDescriptor) null, |
| newlyCreatedRoutines, |
| tc); |
| } |
| |
| // SYSIBM.SQLCOLPRIVILEGES(VARCHAR(128), VARCHAR(128), VARCHAR(128), VARCHAR(128), VARCHAR(4000)) |
| { |
| |
| // procedure argument names |
| String[] arg_names = { |
| "CATALOGNAME", |
| "SCHEMANAME", |
| "TABLENAME", |
| "COLUMNNAME", |
| "OPTIONS"}; |
| |
| // procedure argument types |
| TypeDescriptor[] arg_types = { |
| CATALOG_TYPE_SYSTEM_IDENTIFIER, |
| CATALOG_TYPE_SYSTEM_IDENTIFIER, |
| CATALOG_TYPE_SYSTEM_IDENTIFIER, |
| CATALOG_TYPE_SYSTEM_IDENTIFIER, |
| DataTypeDescriptor.getCatalogType(Types.VARCHAR, 4000)}; |
| |
| createSystemProcedureOrFunction( |
| "SQLCOLPRIVILEGES", |
| sysIBMUUID, |
| arg_names, |
| arg_types, |
| 0, |
| 1, |
| RoutineAliasInfo.READS_SQL_DATA, |
| false, |
| false, |
| (TypeDescriptor) null, |
| newlyCreatedRoutines, |
| tc); |
| } |
| |
| // SYSIBM.SQLUDTS(VARCHAR(128), VARCHAR(128), VARCHAR(128), VARCHAR(128), VARCHAR(4000)) |
| { |
| |
| // procedure argument names |
| String[] arg_names = { |
| "CATALOGNAME", |
| "SCHEMAPATTERN", |
| "TYPENAMEPATTERN", |
| "UDTTYPES", |
| "OPTIONS"}; |
| |
| // procedure argument types |
| TypeDescriptor[] arg_types = { |
| CATALOG_TYPE_SYSTEM_IDENTIFIER, |
| CATALOG_TYPE_SYSTEM_IDENTIFIER, |
| CATALOG_TYPE_SYSTEM_IDENTIFIER, |
| CATALOG_TYPE_SYSTEM_IDENTIFIER, |
| DataTypeDescriptor.getCatalogType(Types.VARCHAR, 4000)}; |
| |
| createSystemProcedureOrFunction( |
| "SQLUDTS", |
| sysIBMUUID, |
| arg_names, |
| arg_types, |
| 0, |
| 1, |
| RoutineAliasInfo.READS_SQL_DATA, |
| false, |
| false, |
| (TypeDescriptor) null, |
| newlyCreatedRoutines, |
| tc); |
| } |
| |
| // SYSIBM.SQLFOREIGNKEYS(VARCHAR(128), VARCHAR(128), VARCHAR(128), VARCHAR(128), |
| // VARCHAR(128), VARCHAR(128), VARCHAR(4000)) |
| { |
| |
| // procedure argument names |
| String[] arg_names = { |
| "PKCATALOGNAME", |
| "PKSCHEMANAME", |
| "PKTABLENAME", |
| "FKCATALOGNAME", |
| "FKSCHEMANAME", |
| "FKTABLENAME", |
| "OPTIONS"}; |
| |
| // procedure argument types |
| TypeDescriptor[] arg_types = { |
| CATALOG_TYPE_SYSTEM_IDENTIFIER, |
| CATALOG_TYPE_SYSTEM_IDENTIFIER, |
| CATALOG_TYPE_SYSTEM_IDENTIFIER, |
| CATALOG_TYPE_SYSTEM_IDENTIFIER, |
| CATALOG_TYPE_SYSTEM_IDENTIFIER, |
| CATALOG_TYPE_SYSTEM_IDENTIFIER, |
| DataTypeDescriptor.getCatalogType(Types.VARCHAR, 4000)}; |
| |
| createSystemProcedureOrFunction( |
| "SQLFOREIGNKEYS", |
| sysIBMUUID, |
| arg_names, |
| arg_types, |
| 0, |
| 1, |
| RoutineAliasInfo.READS_SQL_DATA, |
| false, |
| false, |
| (TypeDescriptor) null, |
| newlyCreatedRoutines, |
| tc); |
| } |
| |
| // SYSIBM.SQLSPECIALCOLUMNS(SMALLINT, VARCHAR(128), VARCHAR(128), VARCHAR(128), |
| // SMALLINT, SMALLINT, VARCHAR(4000)) |
| { |
| |
| // procedure argument names |
| String[] arg_names = { |
| "COLTYPE", |
| "CATALOGNAME", |
| "SCHEMANAME", |
| "TABLENAME", |
| "SCOPE", |
| "NULLABLE", |
| "OPTIONS"}; |
| |
| // procedure argument types |
| TypeDescriptor[] arg_types = { |
| TypeDescriptor.SMALLINT, |
| CATALOG_TYPE_SYSTEM_IDENTIFIER, |
| CATALOG_TYPE_SYSTEM_IDENTIFIER, |
| CATALOG_TYPE_SYSTEM_IDENTIFIER, |
| TypeDescriptor.SMALLINT, |
| TypeDescriptor.SMALLINT, |
| DataTypeDescriptor.getCatalogType(Types.VARCHAR, 4000)}; |
| |
| createSystemProcedureOrFunction( |
| "SQLSPECIALCOLUMNS", |
| sysIBMUUID, |
| arg_names, |
| arg_types, |
| 0, |
| 1, |
| RoutineAliasInfo.READS_SQL_DATA, |
| false, |
| false, |
| (TypeDescriptor) null, |
| newlyCreatedRoutines, |
| tc); |
| } |
| |
| // SYSIBM.SQLGETTYPEINFO(SMALLINT, VARCHAR(4000)) |
| { |
| |
| // procedure argument names |
| String[] arg_names = { |
| "DATATYPE", |
| "OPTIONS"}; |
| |
| // procedure argument types |
| TypeDescriptor[] arg_types = { |
| TypeDescriptor.SMALLINT, |
| DataTypeDescriptor.getCatalogType(Types.VARCHAR, 4000)}; |
| |
| createSystemProcedureOrFunction( |
| "SQLGETTYPEINFO", |
| sysIBMUUID, |
| arg_names, |
| arg_types, |
| 0, |
| 1, |
| RoutineAliasInfo.READS_SQL_DATA, |
| false, |
| false, |
| (TypeDescriptor) null, |
| newlyCreatedRoutines, |
| tc); |
| } |
| |
| // SYSIBM.SQLSTATISTICS(VARCHAR(128), VARCHAR(128), VARCHAR(128), |
| // SMALLINT, SMALLINT, VARCHAR(4000)) |
| { |
| |
| // procedure argument names |
| String[] arg_names = { |
| "CATALOGNAME", |
| "SCHEMANAME", |
| "TABLENAME", |
| "UNIQUE", |
| "RESERVED", |
| "OPTIONS"}; |
| |
| // procedure argument types |
| TypeDescriptor[] arg_types = { |
| CATALOG_TYPE_SYSTEM_IDENTIFIER, |
| CATALOG_TYPE_SYSTEM_IDENTIFIER, |
| CATALOG_TYPE_SYSTEM_IDENTIFIER, |
| TypeDescriptor.SMALLINT, |
| TypeDescriptor.SMALLINT, |
| DataTypeDescriptor.getCatalogType(Types.VARCHAR, 4000)}; |
| |
| createSystemProcedureOrFunction( |
| "SQLSTATISTICS", |
| sysIBMUUID, |
| arg_names, |
| arg_types, |
| 0, |
| 1, |
| RoutineAliasInfo.READS_SQL_DATA, |
| false, |
| false, |
| (TypeDescriptor) null, |
| newlyCreatedRoutines, |
| tc); |
| } |
| |
| // void SYSIBM.METADATA() |
| { |
| createSystemProcedureOrFunction( |
| "METADATA", |
| sysIBMUUID, |
| null, |
| null, |
| 0, |
| 1, |
| RoutineAliasInfo.READS_SQL_DATA, |
| false, |
| false, |
| (TypeDescriptor) null, |
| newlyCreatedRoutines, |
| tc); |
| } |
| |
| } |
| |
| /** |
| * Grant PUBLIC access to specific system routines. Currently, this is |
| * done for some routines in SYSCS_UTIL schema. We grant access to routines |
| * which we have just added. Doing it this way lets us declare these |
| * routines in one place and re-use this logic during database creation and |
| * during upgrade. |
| * |
| * @param tc TransactionController to use |
| * @param authorizationID authorization ID of the permission grantor |
| * @throws StandardException Standard exception policy. |
| */ |
| public void grantPublicAccessToSystemRoutines(HashSet newlyCreatedRoutines, TransactionController tc, |
| String authorizationID) throws StandardException { |
| |
| // Get schema ID for SYSCS_UTIL schema |
| String schemaID = getSystemUtilSchemaDescriptor().getUUID().toString(); |
| |
| for(int i=0; i < sysUtilProceduresWithPublicAccess.length; i++) { |
| |
| String routineName = sysUtilProceduresWithPublicAccess[i]; |
| if ( !newlyCreatedRoutines.contains( routineName ) ) { continue; } |
| |
| grantPublicAccessToSystemRoutine(schemaID, |
| routineName, |
| AliasInfo.ALIAS_NAME_SPACE_PROCEDURE_AS_CHAR, |
| tc, authorizationID); |
| } |
| |
| for(int i=0; i < sysUtilFunctionsWithPublicAccess.length; i++) { |
| |
| String routineName = sysUtilFunctionsWithPublicAccess[i]; |
| if ( !newlyCreatedRoutines.contains( routineName ) ) { continue; } |
| |
| grantPublicAccessToSystemRoutine(schemaID, |
| routineName, |
| AliasInfo.ALIAS_NAME_SPACE_FUNCTION_AS_CHAR, |
| tc, authorizationID); |
| } |
| } |
| |
| |
| /** |
| * Grant PUBLIC access to a system routine. This method should be used only |
| * for granting access to a system routine (other than routines in SYSFUN |
| * schema). It expects the routine to be present in SYSALIASES catalog. |
| * |
| * @param schemaID Schema ID |
| * @param routineName Routine Name |
| * @param nameSpace Indicates whether the routine is a function/procedure. |
| * @param tc TransactionController to use |
| * @param authorizationID authorization ID of the permission grantor |
| * @throws StandardException Standard exception policy. |
| */ |
| private void grantPublicAccessToSystemRoutine(String schemaID, |
| String routineName, |
| char nameSpace, |
| TransactionController tc, |
| String authorizationID) |
| throws StandardException { |
| // For system routines, a valid alias descriptor will be returned. |
| AliasDescriptor ad = getAliasDescriptor(schemaID, routineName, |
| nameSpace); |
| // |
| // When upgrading from 10.1, it can happen that we haven't yet created |
| // all public procedures. We forgive that possibility here and just return. |
| // |
| if ( ad == null ) { return; } |
| |
| UUID routineUUID = ad.getUUID(); |
| createRoutinePermPublicDescriptor(routineUUID, tc, authorizationID); |
| } |
| |
| |
| /** |
| * Create RoutinePermDescriptor to grant access to PUBLIC for |
| * this system routine using the grantor specified in authorizationID. |
| * |
| * @param routineUUID uuid of the routine |
| * @param tc TransactionController to use |
| * @param authorizationID authorization ID of the permission grantor |
| * @throws StandardException Standard exception policy. |
| */ |
| void createRoutinePermPublicDescriptor( |
| UUID routineUUID, |
| TransactionController tc, |
| String authorizationID) throws StandardException |
| { |
| RoutinePermsDescriptor routinePermDesc = |
| new RoutinePermsDescriptor( |
| this, |
| "PUBLIC", |
| authorizationID, |
| routineUUID); |
| |
| addDescriptor( |
| routinePermDesc, null, DataDictionary.SYSROUTINEPERMS_CATALOG_NUM, false, tc); |
| } |
| |
| /** |
| * Create system procedures added in version 10.1. |
| * <p> |
| * Create 10.1 system procedures, called by either code creating new |
| * database, or code doing hard upgrade from previous version. |
| * <p> |
| * |
| * @param tc booting transaction |
| * @param newlyCreatedRoutines set of routines we are creating (used to add permissions later on) |
| * @param sysUtilUUID uuid of the SYSUTIL schema. |
| * |
| * @exception StandardException Standard exception policy. |
| **/ |
| void create_10_1_system_procedures( |
| TransactionController tc, |
| HashSet<String> newlyCreatedRoutines, |
| UUID sysUtilUUID) |
| throws StandardException |
| { |
| // void SYSCS_UTIL.SYSCS_INPLACE_COMPRESS_TABLE( |
| // IN SCHEMANAME VARCHAR(128), |
| // IN TABLENAME VARCHAR(128), |
| // IN PURGE_ROWS SMALLINT, |
| // IN DEFRAGMENT_ROWS SMALLINT, |
| // IN TRUNCATE_END SMALLINT |
| // ) |
| { |
| // procedure argument names |
| String[] arg_names = { |
| "SCHEMANAME", |
| "TABLENAME", |
| "PURGE_ROWS", |
| "DEFRAGMENT_ROWS", |
| "TRUNCATE_END"}; |
| |
| // procedure argument types |
| TypeDescriptor[] arg_types = { |
| CATALOG_TYPE_SYSTEM_IDENTIFIER, |
| CATALOG_TYPE_SYSTEM_IDENTIFIER, |
| TypeDescriptor.SMALLINT, |
| TypeDescriptor.SMALLINT, |
| TypeDescriptor.SMALLINT |
| }; |
| |
| createSystemProcedureOrFunction( |
| "SYSCS_INPLACE_COMPRESS_TABLE", |
| sysUtilUUID, |
| arg_names, |
| arg_types, |
| 0, |
| 0, |
| RoutineAliasInfo.MODIFIES_SQL_DATA, |
| false, |
| false, |
| (TypeDescriptor) null, |
| newlyCreatedRoutines, |
| tc); |
| } |
| } |
| |
| |
| /** |
| * Create system procedures added in version 10.2. |
| * <p> |
| * Create 10.2 system procedures, called by either code creating new |
| * database, or code doing hard upgrade from previous version. |
| * <p> |
| * |
| * @param tc booting transaction |
| * @param newlyCreatedRoutines set of routines we are creating (used to add permissions later on) |
| * @param sysUtilUUID uuid of the SYSUTIL schema. |
| * |
| * @exception StandardException Standard exception policy. |
| **/ |
| void create_10_2_system_procedures( |
| TransactionController tc, |
| HashSet<String> newlyCreatedRoutines, |
| UUID sysUtilUUID) |
| throws StandardException |
| { |
| |
| // void SYSCS_UTIL.SYSCS_BACKUP_DATABASE_NOWAIT( |
| // IN BACKUPDIR VARCHAR(Limits.DB2_VARCHAR_MAXWIDTH) |
| // ) |
| |
| { |
| // procedure argument names |
| String[] arg_names = {"BACKUPDIR"}; |
| |
| // procedure argument types |
| TypeDescriptor[] arg_types = { |
| DataTypeDescriptor.getCatalogType( |
| Types.VARCHAR, Limits.DB2_VARCHAR_MAXWIDTH) |
| }; |
| |
| createSystemProcedureOrFunction( |
| "SYSCS_BACKUP_DATABASE_NOWAIT", |
| sysUtilUUID, |
| arg_names, |
| arg_types, |
| 0, |
| 0, |
| RoutineAliasInfo.MODIFIES_SQL_DATA, |
| false, |
| false, |
| (TypeDescriptor) null, |
| newlyCreatedRoutines, |
| tc); |
| } |
| |
| // void |
| // SYSCS_UTIL.SYSCS_BACKUP_DATABASE_AND_ENABLE_LOG_ARCHIVE_MODE_NOWAIT( |
| // IN BACKUPDIR VARCHAR(Limits.DB2_VARCHAR_MAXWIDTH), |
| // IN DELETE_ARCHIVED_LOG_FILES SMALLINT |
| // ) |
| { |
| // procedure argument names |
| String[] arg_names = |
| {"BACKUPDIR", "DELETE_ARCHIVED_LOG_FILES"}; |
| |
| // procedure argument types |
| TypeDescriptor[] arg_types = { |
| DataTypeDescriptor.getCatalogType( |
| Types.VARCHAR, Limits.DB2_VARCHAR_MAXWIDTH), |
| TypeDescriptor.SMALLINT |
| }; |
| |
| createSystemProcedureOrFunction( |
| "SYSCS_BACKUP_DATABASE_AND_ENABLE_LOG_ARCHIVE_MODE_NOWAIT", |
| sysUtilUUID, |
| arg_names, |
| arg_types, |
| 0, |
| 0, |
| RoutineAliasInfo.MODIFIES_SQL_DATA, |
| false, |
| false, |
| (TypeDescriptor) null, |
| newlyCreatedRoutines, |
| tc); |
| } |
| |
| // SYSIBM.SQLFUNCTIONS(VARCHAR(128), VARCHAR(128), VARCHAR(128), |
| // VARCHAR(4000)) |
| { |
| |
| // procedure argument names |
| String[] arg_names = { |
| "CATALOGNAME", |
| "SCHEMANAME", |
| "FUNCNAME", |
| "OPTIONS"}; |
| |
| // procedure argument types |
| TypeDescriptor[] arg_types = { |
| CATALOG_TYPE_SYSTEM_IDENTIFIER, |
| CATALOG_TYPE_SYSTEM_IDENTIFIER, |
| CATALOG_TYPE_SYSTEM_IDENTIFIER, |
| DataTypeDescriptor.getCatalogType(Types.VARCHAR, 4000)}; |
| |
| createSystemProcedureOrFunction( |
| "SQLFUNCTIONS", |
| getSysIBMSchemaDescriptor().getUUID(), |
| arg_names, |
| arg_types, |
| 0, |
| 1, |
| RoutineAliasInfo.READS_SQL_DATA, |
| false, |
| false, |
| (TypeDescriptor) null, |
| newlyCreatedRoutines, |
| tc); |
| } |
| |
| // SYSIBM.SQLFUNCTIONPARAMS(VARCHAR(128), VARCHAR(128), |
| // VARCHAR(128), VARCHAR(128), VARCHAR(4000)) |
| { |
| |
| // procedure argument names |
| String[] arg_names = { |
| "CATALOGNAME", |
| "SCHEMANAME", |
| "FUNCNAME", |
| "PARAMNAME", |
| "OPTIONS"}; |
| |
| // procedure argument types |
| TypeDescriptor[] arg_types = { |
| CATALOG_TYPE_SYSTEM_IDENTIFIER, |
| CATALOG_TYPE_SYSTEM_IDENTIFIER, |
| CATALOG_TYPE_SYSTEM_IDENTIFIER, |
| CATALOG_TYPE_SYSTEM_IDENTIFIER, |
| DataTypeDescriptor.getCatalogType(Types.VARCHAR, 4000)}; |
| |
| createSystemProcedureOrFunction( |
| "SQLFUNCTIONPARAMS", |
| getSysIBMSchemaDescriptor().getUUID(), |
| arg_names, |
| arg_types, |
| 0, |
| 1, |
| RoutineAliasInfo.READS_SQL_DATA, |
| false, |
| false, |
| (TypeDescriptor) null, |
| newlyCreatedRoutines, |
| tc); |
| } |
| } |
| |
| /** |
| * Create system procedures added in version 10.3. |
| * Create 10.3 system procedures related to the LOB Methods , |
| * called by either code creating new |
| * database, or code doing hard upgrade from previous version. |
| * |
| * @param tc an instance of the TransactionController class. |
| * @param newlyCreatedRoutines set of routines we are creating (used to add permissions later on) |
| * |
| * @throws StandardException Standard exception policy. |
| **/ |
| private void create_10_3_system_procedures_SYSIBM( |
| TransactionController tc, |
| HashSet<String> newlyCreatedRoutines ) |
| throws StandardException { |
| //create 10.3 functions used by LOB methods. |
| UUID schema_uuid = getSysIBMSchemaDescriptor().getUUID(); |
| { |
| String[] arg_names = null; |
| |
| TypeDescriptor[] arg_types = null; |
| |
| createSystemProcedureOrFunction( |
| "CLOBCREATELOCATOR", |
| schema_uuid, |
| arg_names, |
| arg_types, |
| 0, |
| 0, |
| RoutineAliasInfo.CONTAINS_SQL, |
| false, |
| false, |
| TypeDescriptor.INTEGER, |
| newlyCreatedRoutines, |
| tc, |
| "org.apache.derby.impl.jdbc.LOBStoredProcedure"); |
| } |
| { |
| String[] arg_names = {"LOCATOR"}; |
| |
| TypeDescriptor[] arg_types = {TypeDescriptor.INTEGER}; |
| |
| createSystemProcedureOrFunction( |
| "CLOBRELEASELOCATOR", |
| schema_uuid, |
| arg_names, |
| arg_types, |
| 0, |
| 0, |
| RoutineAliasInfo.CONTAINS_SQL, |
| false, |
| false, |
| null, |
| newlyCreatedRoutines, |
| tc, |
| "org.apache.derby.impl.jdbc.LOBStoredProcedure"); |
| } |
| { |
| String[] arg_names = {"LOCATOR","SEARCHSTR","POS"}; |
| |
| // procedure argument types |
| TypeDescriptor[] arg_types = { |
| TypeDescriptor.INTEGER, |
| DataTypeDescriptor.getCatalogType( |
| Types.VARCHAR), |
| DataTypeDescriptor.getCatalogType( |
| Types.BIGINT) |
| }; |
| createSystemProcedureOrFunction( |
| "CLOBGETPOSITIONFROMSTRING", |
| schema_uuid, |
| arg_names, |
| arg_types, |
| 0, |
| 0, |
| RoutineAliasInfo.CONTAINS_SQL, |
| false, |
| false, |
| DataTypeDescriptor.getCatalogType( |
| Types.BIGINT), |
| newlyCreatedRoutines, |
| tc, |
| "org.apache.derby.impl.jdbc.LOBStoredProcedure"); |
| } |
| { |
| String[] arg_names = {"LOCATOR","SEARCHLOCATOR","POS"}; |
| |
| // procedure argument types |
| TypeDescriptor[] arg_types = { |
| TypeDescriptor.INTEGER, |
| TypeDescriptor.INTEGER, |
| DataTypeDescriptor.getCatalogType( |
| Types.BIGINT) |
| }; |
| createSystemProcedureOrFunction( |
| "CLOBGETPOSITIONFROMLOCATOR", |
| schema_uuid, |
| arg_names, |
| arg_types, |
| 0, |
| 0, |
| RoutineAliasInfo.CONTAINS_SQL, |
| false, |
| false, |
| DataTypeDescriptor.getCatalogType( |
| Types.BIGINT), |
| newlyCreatedRoutines, |
| tc, |
| "org.apache.derby.impl.jdbc.LOBStoredProcedure"); |
| } |
| { |
| String[] arg_names = {"LOCATOR"}; |
| |
| // procedure argument types |
| TypeDescriptor[] arg_types = {TypeDescriptor.INTEGER}; |
| createSystemProcedureOrFunction( |
| "CLOBGETLENGTH", |
| schema_uuid, |
| arg_names, |
| arg_types, |
| 0, |
| 0, |
| RoutineAliasInfo.CONTAINS_SQL, |
| false, |
| false, |
| DataTypeDescriptor.getCatalogType( |
| Types.BIGINT), |
| newlyCreatedRoutines, |
| tc, |
| "org.apache.derby.impl.jdbc.LOBStoredProcedure"); |
| } |
| { |
| String[] arg_names = {"LOCATOR","POS","LEN"}; |
| |
| // procedure argument types |
| TypeDescriptor[] arg_types = { |
| TypeDescriptor.INTEGER, |
| DataTypeDescriptor.getCatalogType( |
| Types.BIGINT), |
| TypeDescriptor.INTEGER |
| }; |
| createSystemProcedureOrFunction( |
| "CLOBGETSUBSTRING", |
| schema_uuid, |
| arg_names, |
| arg_types, |
| 0, |
| 0, |
| RoutineAliasInfo.CONTAINS_SQL, |
| false, |
| false, |
| DataTypeDescriptor.getCatalogType( |
| Types.VARCHAR, |
| Limits.MAX_CLOB_RETURN_LEN), |
| newlyCreatedRoutines, |
| tc, |
| "org.apache.derby.impl.jdbc.LOBStoredProcedure"); |
| } |
| { |
| String[] arg_names = {"LOCATOR","POS","LEN","REPLACESTR"}; |
| |
| // procedure argument types |
| TypeDescriptor[] arg_types = { |
| TypeDescriptor.INTEGER, |
| DataTypeDescriptor.getCatalogType( |
| Types.BIGINT), |
| TypeDescriptor.INTEGER, |
| DataTypeDescriptor.getCatalogType( |
| Types.VARCHAR) |
| }; |
| createSystemProcedureOrFunction( |
| "CLOBSETSTRING", |
| schema_uuid, |
| arg_names, |
| arg_types, |
| 0, |
| 0, |
| RoutineAliasInfo.CONTAINS_SQL, |
| false, |
| false, |
| null, |
| newlyCreatedRoutines, |
| tc, |
| "org.apache.derby.impl.jdbc.LOBStoredProcedure"); |
| } |
| { |
| String[] arg_names = {"LOCATOR","LEN"}; |
| |
| // procedure argument types |
| TypeDescriptor[] arg_types = { |
| TypeDescriptor.INTEGER, |
| DataTypeDescriptor.getCatalogType( |
| Types.BIGINT) |
| }; |
| createSystemProcedureOrFunction( |
| "CLOBTRUNCATE", |
| schema_uuid, |
| arg_names, |
| arg_types, |
| 0, |
| 0, |
| RoutineAliasInfo.CONTAINS_SQL, |
| false, |
| false, |
| null, |
| newlyCreatedRoutines, |
| tc, |
| "org.apache.derby.impl.jdbc.LOBStoredProcedure"); |
| } |
| |
| //Now create the Stored procedures required for BLOB |
| { |
| String[] arg_names = null; |
| |
| TypeDescriptor[] arg_types = null; |
| |
| createSystemProcedureOrFunction( |
| "BLOBCREATELOCATOR", |
| schema_uuid, |
| arg_names, |
| arg_types, |
| 0, |
| 0, |
| RoutineAliasInfo.CONTAINS_SQL, |
| false, |
| false, |
| TypeDescriptor.INTEGER, |
| newlyCreatedRoutines, |
| tc, |
| "org.apache.derby.impl.jdbc.LOBStoredProcedure"); |
| } |
| { |
| String[] arg_names = {"LOCATOR"}; |
| |
| TypeDescriptor[] arg_types = {TypeDescriptor.INTEGER}; |
| |
| createSystemProcedureOrFunction( |
| "BLOBRELEASELOCATOR", |
| schema_uuid, |
| arg_names, |
| arg_types, |
| 0, |
| 0, |
| RoutineAliasInfo.CONTAINS_SQL, |
| false, |
| false, |
| null, |
| newlyCreatedRoutines, |
| tc, |
| "org.apache.derby.impl.jdbc.LOBStoredProcedure"); |
| } |
| { |
| String[] arg_names = {"LOCATOR","SEARCHBYTES","POS"}; |
| |
| // procedure argument types |
| TypeDescriptor[] arg_types = { |
| TypeDescriptor.INTEGER, |
| DataTypeDescriptor.getCatalogType( |
| Types.VARBINARY), |
| DataTypeDescriptor.getCatalogType( |
| Types.BIGINT) |
| }; |
| createSystemProcedureOrFunction( |
| "BLOBGETPOSITIONFROMBYTES", |
| schema_uuid, |
| arg_names, |
| arg_types, |
| 0, |
| 0, |
| RoutineAliasInfo.CONTAINS_SQL, |
| false, |
| false, |
| DataTypeDescriptor.getCatalogType( |
| Types.BIGINT), |
| newlyCreatedRoutines, |
| tc, |
| "org.apache.derby.impl.jdbc.LOBStoredProcedure"); |
| } |
| { |
| String[] arg_names = {"LOCATOR","SEARCHLOCATOR","POS"}; |
| |
| // procedure argument types |
| TypeDescriptor[] arg_types = { |
| TypeDescriptor.INTEGER, |
| TypeDescriptor.INTEGER, |
| DataTypeDescriptor.getCatalogType( |
| Types.BIGINT) |
| }; |
| createSystemProcedureOrFunction( |
| "BLOBGETPOSITIONFROMLOCATOR", |
| schema_uuid, |
| arg_names, |
| arg_types, |
| 0, |
| 0, |
| RoutineAliasInfo.CONTAINS_SQL, |
| false, |
| false, |
| DataTypeDescriptor.getCatalogType( |
| Types.BIGINT), |
| newlyCreatedRoutines, |
| tc, |
| "org.apache.derby.impl.jdbc.LOBStoredProcedure"); |
| } |
| { |
| String[] arg_names = {"LOCATOR"}; |
| |
| // procedure argument types |
| TypeDescriptor[] arg_types = { |
| TypeDescriptor.INTEGER |
| }; |
| createSystemProcedureOrFunction( |
| "BLOBGETLENGTH", |
| schema_uuid, |
| arg_names, |
| arg_types, |
| 0, |
| 0, |
| RoutineAliasInfo.CONTAINS_SQL, |
| false, |
| false, |
| DataTypeDescriptor.getCatalogType( |
| Types.BIGINT), |
| newlyCreatedRoutines, |
| tc, |
| "org.apache.derby.impl.jdbc.LOBStoredProcedure"); |
| } |
| { |
| String[] arg_names = {"LOCATOR","POS","LEN"}; |
| |
| // procedure argument types |
| TypeDescriptor[] arg_types = { |
| TypeDescriptor.INTEGER, |
| DataTypeDescriptor.getCatalogType( |
| Types.BIGINT), |
| TypeDescriptor.INTEGER |
| }; |
| createSystemProcedureOrFunction( |
| "BLOBGETBYTES", |
| schema_uuid, |
| arg_names, |
| arg_types, |
| 0, |
| 0, |
| RoutineAliasInfo.CONTAINS_SQL, |
| false, |
| false, |
| DataTypeDescriptor.getCatalogType( |
| Types.VARBINARY, |
| Limits.MAX_BLOB_RETURN_LEN), |
| newlyCreatedRoutines, |
| tc, |
| "org.apache.derby.impl.jdbc.LOBStoredProcedure"); |
| } |
| { |
| String[] arg_names = {"LOCATOR","POS","LEN","REPLACEBYTES"}; |
| |
| // procedure argument types |
| TypeDescriptor[] arg_types = { |
| TypeDescriptor.INTEGER, |
| DataTypeDescriptor.getCatalogType( |
| Types.BIGINT), |
| TypeDescriptor.INTEGER, |
| DataTypeDescriptor.getCatalogType( |
| Types.VARBINARY) |
| }; |
| createSystemProcedureOrFunction( |
| "BLOBSETBYTES", |
| schema_uuid, |
| arg_names, |
| arg_types, |
| 0, |
| 0, |
| RoutineAliasInfo.CONTAINS_SQL, |
| false, |
| false, |
| null, |
| newlyCreatedRoutines, |
| tc, |
| "org.apache.derby.impl.jdbc.LOBStoredProcedure"); |
| } |
| { |
| String[] arg_names = {"LOCATOR","LEN"}; |
| |
| // procedure argument types |
| TypeDescriptor[] arg_types = { |
| TypeDescriptor.INTEGER, |
| DataTypeDescriptor.getCatalogType( |
| Types.BIGINT) |
| }; |
| createSystemProcedureOrFunction( |
| "BLOBTRUNCATE", |
| schema_uuid, |
| arg_names, |
| arg_types, |
| 0, |
| 0, |
| RoutineAliasInfo.CONTAINS_SQL, |
| false, |
| false, |
| null, |
| newlyCreatedRoutines, |
| tc, |
| "org.apache.derby.impl.jdbc.LOBStoredProcedure"); |
| } |
| } |
| |
| /** |
| * Create the System procedures that are added to 10.5. |
| * |
| * @param tc an instance of the TransactionController. |
| * @param newlyCreatedRoutines set of routines we are creating (used to add permissions later on) |
| * @throws StandardException Standard exception policy. |
| */ |
| void create_10_5_system_procedures(TransactionController tc, HashSet<String> newlyCreatedRoutines ) |
| throws StandardException |
| { |
| // Create the procedures in the SYSCS_UTIL schema. |
| UUID sysUtilUUID = getSystemUtilSchemaDescriptor().getUUID(); |
| |
| // void SYSCS_UTIL.SYSCS_UPDATE_STATISTICS(varchar(128), varchar(128), varchar(128)) |
| { |
| // procedure argument names |
| String[] arg_names = {"SCHEMANAME", "TABLENAME", "INDEXNAME"}; |
| |
| // procedure argument types |
| TypeDescriptor[] arg_types = { |
| CATALOG_TYPE_SYSTEM_IDENTIFIER, |
| CATALOG_TYPE_SYSTEM_IDENTIFIER, |
| CATALOG_TYPE_SYSTEM_IDENTIFIER |
| |
| }; |
| |
| createSystemProcedureOrFunction( |
| "SYSCS_UPDATE_STATISTICS", |
| sysUtilUUID, |
| arg_names, |
| arg_types, |
| 0, |
| 0, |
| RoutineAliasInfo.MODIFIES_SQL_DATA, |
| false, |
| false, |
| (TypeDescriptor) null, |
| newlyCreatedRoutines, |
| tc); |
| } |
| } |
| |
| /** |
| * Create the System procedures that are added to 10.6. |
| * |
| * @param tc an instance of the TransactionController. |
| * @throws StandardException Standard exception policy. |
| */ |
| void create_10_6_system_procedures(TransactionController tc, |
| HashSet<String> newlyCreatedRoutines) |
| throws StandardException |
| { |
| // Create the procedures in the SYSCS_UTIL schema. |
| UUID sysUtilUUID = getSystemUtilSchemaDescriptor().getUUID(); |
| // void SYSCS_UTIL.SYSCS_SET_XPLAIN_MODE(smallint mode) |
| { |
| // procedure argument names |
| String[] arg_names = {"ENABLE"}; |
| |
| // procedure argument types |
| TypeDescriptor[] arg_types = { |
| TypeDescriptor.INTEGER, |
| }; |
| |
| createSystemProcedureOrFunction( |
| "SYSCS_SET_XPLAIN_MODE", |
| sysUtilUUID, |
| arg_names, |
| arg_types, |
| 0, |
| 0, |
| RoutineAliasInfo.CONTAINS_SQL, |
| false, |
| false, |
| (TypeDescriptor) null, |
| newlyCreatedRoutines, |
| tc); |
| } |
| |
| // SMALLINT SYSCS_UTIL.SYSCS_GET_XPLAIN_MODE() |
| { |
| |
| createSystemProcedureOrFunction( |
| "SYSCS_GET_XPLAIN_MODE", |
| sysUtilUUID, |
| null, |
| null, |
| 0, |
| 0, |
| RoutineAliasInfo.READS_SQL_DATA, |
| false, |
| false, |
| TypeDescriptor.INTEGER, |
| newlyCreatedRoutines, |
| tc); |
| } |
| |
| |
| // void SYSCS_UTIL.SYSCS_SET_XPLAIN_SCHEMA(String schemaName) |
| { |
| // procedure argument names |
| String[] arg_names = {"SCHEMANAME"}; |
| |
| // procedure argument types |
| TypeDescriptor[] arg_types = { |
| CATALOG_TYPE_SYSTEM_IDENTIFIER, |
| }; |
| |
| createSystemProcedureOrFunction( |
| "SYSCS_SET_XPLAIN_SCHEMA", |
| sysUtilUUID, |
| arg_names, |
| arg_types, |
| 0, |
| 0, |
| RoutineAliasInfo.MODIFIES_SQL_DATA, |
| false, |
| false, |
| (TypeDescriptor) null, |
| newlyCreatedRoutines, |
| tc); |
| } |
| |
| // STRING SYSCS_UTIL.SYSCS_GET_XPLAIN_SCHEMA() |
| { |
| createSystemProcedureOrFunction( |
| "SYSCS_GET_XPLAIN_SCHEMA", |
| sysUtilUUID, |
| null, |
| null, |
| 0, |
| 0, |
| RoutineAliasInfo.READS_SQL_DATA, |
| false, |
| false, |
| CATALOG_TYPE_SYSTEM_IDENTIFIER, |
| newlyCreatedRoutines, |
| tc); |
| } |
| } |
| |
| /** |
| * Create the System procedures that are added in 10.3. |
| * |
| * @param tc an instance of the TransactionController. |
| * @param newlyCreatedRoutines set of routines we are creating (used to add permissions later on) |
| * @throws StandardException Standard exception policy. |
| */ |
| void create_10_3_system_procedures(TransactionController tc, HashSet<String> newlyCreatedRoutines ) |
| throws StandardException { |
| // Create the procedures in the SYSCS_UTIL schema. |
| create_10_3_system_procedures_SYSCS_UTIL(tc, newlyCreatedRoutines ); |
| //create the procedures in the SYSIBM schema |
| create_10_3_system_procedures_SYSIBM(tc, newlyCreatedRoutines ); |
| } |
| /** |
| * Create system procedures that are part of the |
| * SYSCS_UTIL schema added in version 10.3. |
| * <p> |
| * Create 10.3 system procedures, called by either code creating new |
| * database, or code doing hard upgrade from previous version. |
| * <p> |
| * |
| * @param tc an instance of the Transaction Controller. |
| * @param newlyCreatedRoutines set of routines we are creating (used to add permissions later on) |
| * @exception StandardException Standard exception policy. |
| **/ |
| void create_10_3_system_procedures_SYSCS_UTIL( TransactionController tc, HashSet<String> newlyCreatedRoutines ) |
| throws StandardException |
| { |
| UUID sysUtilUUID = getSystemUtilSchemaDescriptor().getUUID(); |
| /* SYSCS_EXPORT_TABLE_LOBS_TO_EXTFILE(IN SCHEMANAME VARCHAR(128), |
| * IN TABLENAME VARCHAR(128), IN FILENAME VARCHAR(32672) , |
| * IN COLUMNDELIMITER CHAR(1), IN CHARACTERDELIMITER CHAR(1) , |
| * IN CODESET VARCHAR(128), IN LOBSFILENAME VARCHAR(32672) ) |
| */ |
| |
| { |
| // procedure argument names |
| String[] arg_names = {"schemaName", "tableName" , |
| "fileName"," columnDelimiter", |
| "characterDelimiter", "codeset", |
| "lobsFileName"}; |
| |
| // procedure argument types |
| TypeDescriptor[] arg_types = { |
| CATALOG_TYPE_SYSTEM_IDENTIFIER, |
| CATALOG_TYPE_SYSTEM_IDENTIFIER, |
| DataTypeDescriptor.getCatalogType( |
| Types.VARCHAR, 32672), |
| DataTypeDescriptor.getCatalogType( |
| Types.CHAR, 1), |
| DataTypeDescriptor.getCatalogType( |
| Types.CHAR, 1), |
| CATALOG_TYPE_SYSTEM_IDENTIFIER, |
| DataTypeDescriptor.getCatalogType( |
| Types.VARCHAR, 32672) |
| }; |
| |
| createSystemProcedureOrFunction( |
| "SYSCS_EXPORT_TABLE_LOBS_TO_EXTFILE", |
| sysUtilUUID, |
| arg_names, |
| arg_types, |
| 0, |
| 0, |
| RoutineAliasInfo.READS_SQL_DATA, |
| false, |
| false, |
| (TypeDescriptor) null, |
| newlyCreatedRoutines, |
| tc); |
| } |
| |
| |
| /* SYSCS_EXPORT_QUERY_LOBS_TO_EXTFILE( |
| * IN SELECTSTATEMENT VARCHAR(32672), |
| * IN FILENAME VARCHAR(32672) , |
| * IN COLUMNDELIMITER CHAR(1), IN CHARACTERDELIMITER CHAR(1) , |
| * IN CODESET VARCHAR(128), IN LOBSFILENAME VARCHAR(32672)) |
| */ |
| { |
| // procedure argument names |
| String[] arg_names = {"selectStatement", "fileName", |
| " columnDelimiter", "characterDelimiter", |
| "codeset", "lobsFileName"}; |
| |
| // procedure argument types |
| TypeDescriptor[] arg_types = { |
| DataTypeDescriptor.getCatalogType( |
| Types.VARCHAR, 32672), |
| DataTypeDescriptor.getCatalogType( |
| Types.VARCHAR, 32672), |
| DataTypeDescriptor.getCatalogType( |
| Types.CHAR, 1), |
| DataTypeDescriptor.getCatalogType( |
| Types.CHAR, 1), |
| CATALOG_TYPE_SYSTEM_IDENTIFIER, |
| DataTypeDescriptor.getCatalogType( |
| Types.VARCHAR, 32672) |
| }; |
| |
| createSystemProcedureOrFunction( |
| "SYSCS_EXPORT_QUERY_LOBS_TO_EXTFILE", |
| sysUtilUUID, |
| arg_names, |
| arg_types, |
| 0, |
| 0, |
| RoutineAliasInfo.READS_SQL_DATA, |
| false, |
| false, |
| (TypeDescriptor) null, |
| newlyCreatedRoutines, |
| tc); |
| } |
| |
| |
| /* SYSCS_IMPORT_TABLE_LOBS_FROM_EXTFILE(IN SCHEMANAME VARCHAR(128), |
| * IN TABLENAME VARCHAR(128), IN FILENAME VARCHAR(32672), |
| * IN COLUMNDELIMITER CHAR(1), IN CHARACTERDELIMITER CHAR(1), |
| * IN CODESET VARCHAR(128) , IN REPLACE SMALLINT) |
| */ |
| { |
| // procedure argument names |
| String[] arg_names = {"schemaName", "tableName", "fileName", |
| " columnDelimiter", "characterDelimiter", |
| "codeset", "replace"}; |
| |
| // procedure argument types |
| TypeDescriptor[] arg_types = { |
| CATALOG_TYPE_SYSTEM_IDENTIFIER, |
| CATALOG_TYPE_SYSTEM_IDENTIFIER, |
| DataTypeDescriptor.getCatalogType( |
| Types.VARCHAR, 32672), |
| DataTypeDescriptor.getCatalogType( |
| Types.CHAR, 1), |
| DataTypeDescriptor.getCatalogType( |
| Types.CHAR, 1), |
| CATALOG_TYPE_SYSTEM_IDENTIFIER, |
| TypeDescriptor.SMALLINT, |
| }; |
| |
| createSystemProcedureOrFunction( |
| "SYSCS_IMPORT_TABLE_LOBS_FROM_EXTFILE", |
| sysUtilUUID, |
| arg_names, |
| arg_types, |
| 0, |
| 0, |
| RoutineAliasInfo.MODIFIES_SQL_DATA, |
| false, |
| false, |
| (TypeDescriptor) null, |
| newlyCreatedRoutines, |
| tc); |
| } |
| |
| /* SYSCS_IMPORT_DATA_LOBS_FROM_EXTFILE(IN SCHEMANAME VARCHAR(128), |
| * IN TABLENAME VARCHAR(128), IN INSERTCOLUMNLIST VARCHAR(32672), |
| * IN COLUMNINDEXES VARCHAR(32672), IN IN FILENAME VARCHAR(32672), |
| * IN COLUMNDELIMITER CHAR(1), IN CHARACTERDELIMITER CHAR(1), |
| * IN CODESET VARCHAR(128) , IN REPLACE SMALLINT) |
| */ |
| { |
| // procedure argument names |
| String[] arg_names = {"schemaName", "tableName", |
| "insertColumnList","columnIndexes", |
| "fileName", " columnDelimiter", |
| "characterDelimiter", |
| "codeset", "replace"}; |
| |
| // procedure argument types |
| TypeDescriptor[] arg_types = { |
| CATALOG_TYPE_SYSTEM_IDENTIFIER, |
| CATALOG_TYPE_SYSTEM_IDENTIFIER, |
| DataTypeDescriptor.getCatalogType( |
| Types.VARCHAR, 32672), |
| DataTypeDescriptor.getCatalogType( |
| Types.VARCHAR, 32672), |
| DataTypeDescriptor.getCatalogType( |
| Types.VARCHAR, 32672), |
| DataTypeDescriptor.getCatalogType( |
| Types.CHAR, 1), |
| DataTypeDescriptor.getCatalogType( |
| Types.CHAR, 1), |
| CATALOG_TYPE_SYSTEM_IDENTIFIER, |
| TypeDescriptor.SMALLINT, |
| }; |
| |
| |
| createSystemProcedureOrFunction( |
| "SYSCS_IMPORT_DATA_LOBS_FROM_EXTFILE", |
| sysUtilUUID, |
| arg_names, |
| arg_types, |
| 0, |
| 0, |
| RoutineAliasInfo.MODIFIES_SQL_DATA, |
| false, |
| false, |
| (TypeDescriptor) null, |
| newlyCreatedRoutines, |
| tc); |
| } |
| |
| |
| // void SYSCS_UTIL.SYSCS_RELOAD_SECURITY_POLICY() |
| { |
| createSystemProcedureOrFunction( |
| "SYSCS_RELOAD_SECURITY_POLICY", |
| sysUtilUUID, |
| null, |
| null, |
| 0, |
| 0, |
| RoutineAliasInfo.NO_SQL, |
| false, |
| false, |
| (TypeDescriptor) null, |
| newlyCreatedRoutines, |
| tc); |
| } |
| |
| // void SYSCS_UTIL.SYSCS_SET_USER_ACCESS(USER_NAME VARCHAR(128), |
| // CONNECTION_PERMISSION VARCHAR(128)) |
| { |
| TypeDescriptor[] arg_types = {CATALOG_TYPE_SYSTEM_IDENTIFIER, CATALOG_TYPE_SYSTEM_IDENTIFIER}; |
| |
| createSystemProcedureOrFunction( |
| "SYSCS_SET_USER_ACCESS", |
| sysUtilUUID, |
| new String[] {"USERNAME", "CONNECTIONPERMISSION"}, |
| arg_types, |
| 0, |
| 0, |
| RoutineAliasInfo.MODIFIES_SQL_DATA, |
| false, |
| false, |
| (TypeDescriptor) null, |
| newlyCreatedRoutines, |
| tc); |
| } |
| |
| // VARCHAR(128) SYSCS_UTIL.SYSCS_SET_USER_ACCESS(USER_NAME VARCHAR(128)) |
| { |
| TypeDescriptor[] arg_types = { CATALOG_TYPE_SYSTEM_IDENTIFIER }; |
| |
| createSystemProcedureOrFunction( |
| "SYSCS_GET_USER_ACCESS", |
| sysUtilUUID, |
| new String[] {"USERNAME"}, |
| arg_types, |
| 0, |
| 0, |
| RoutineAliasInfo.READS_SQL_DATA, |
| false, |
| false, |
| CATALOG_TYPE_SYSTEM_IDENTIFIER, |
| newlyCreatedRoutines, |
| tc); |
| } |
| |
| // void SYSCS_UTIL.SYSCS_EMPTY_STATEMENT_CACHE() |
| { |
| createSystemProcedureOrFunction( |
| "SYSCS_EMPTY_STATEMENT_CACHE", |
| sysUtilUUID, |
| (String[]) null, |
| (TypeDescriptor[]) null, |
| 0, |
| 0, |
| RoutineAliasInfo.NO_SQL, |
| false, |
| false, |
| (TypeDescriptor) null, |
| newlyCreatedRoutines, |
| tc); |
| } |
| |
| } |
| |
| /** |
| * <p> |
| * Create system procedures that are part of the |
| * SYSCS_UTIL schema added in version 10.9. These include the procedures for managing NATIVE credentials. |
| * See DERBY-866. |
| * </p> |
| * |
| * @param tc an instance of the Transaction Controller. |
| * @param newlyCreatedRoutines set of routines we are creating (used to add permissions later on) |
| **/ |
| void create_10_9_system_procedures( TransactionController tc, HashSet<String> newlyCreatedRoutines ) |
| throws StandardException |
| { |
| UUID sysUtilUUID = getSystemUtilSchemaDescriptor().getUUID(); |
| |
| // |
| // SYSCS_CREATE_USER( IN USERNAME VARCHAR(128), IN PASSWORD VARCHAR(32672) ) |
| // |
| |
| { |
| // procedure argument names |
| String[] arg_names = { "userName", "password" }; |
| |
| // procedure argument types |
| TypeDescriptor[] arg_types = |
| { |
| CATALOG_TYPE_SYSTEM_IDENTIFIER, |
| DataTypeDescriptor.getCatalogType( Types.VARCHAR, 32672 ) |
| }; |
| |
| createSystemProcedureOrFunction |
| ( |
| "SYSCS_CREATE_USER", |
| sysUtilUUID, |
| arg_names, |
| arg_types, |
| 0, |
| 0, |
| RoutineAliasInfo.MODIFIES_SQL_DATA, |
| false, |
| false, |
| (TypeDescriptor) null, |
| newlyCreatedRoutines, |
| tc |
| ); |
| } |
| |
| // |
| // SYSCS_RESET_PASSWORD( IN USERNAME VARCHAR(128), IN PASSWORD VARCHAR(32672) ) |
| // |
| |
| { |
| // procedure argument names |
| String[] arg_names = { "userName", "password" }; |
| |
| // procedure argument types |
| TypeDescriptor[] arg_types = |
| { |
| CATALOG_TYPE_SYSTEM_IDENTIFIER, |
| DataTypeDescriptor.getCatalogType( Types.VARCHAR, 32672 ) |
| }; |
| |
| createSystemProcedureOrFunction |
| ( |
| "SYSCS_RESET_PASSWORD", |
| sysUtilUUID, |
| arg_names, |
| arg_types, |
| 0, |
| 0, |
| RoutineAliasInfo.MODIFIES_SQL_DATA, |
| false, |
| false, |
| (TypeDescriptor) null, |
| newlyCreatedRoutines, |
| tc |
| ); |
| } |
| |
| // |
| // SYSCS_MODIFY_PASSWORD( IN PASSWORD VARCHAR(32672) ) |
| // |
| |
| { |
| // procedure argument names |
| String[] arg_names = { "password" }; |
| |
| // procedure argument types |
| TypeDescriptor[] arg_types = |
| { |
| DataTypeDescriptor.getCatalogType( Types.VARCHAR, 32672 ) |
| }; |
| |
| createSystemProcedureOrFunction |
| ( |
| "SYSCS_MODIFY_PASSWORD", |
| sysUtilUUID, |
| arg_names, |
| arg_types, |
| 0, |
| 0, |
| RoutineAliasInfo.MODIFIES_SQL_DATA, |
| false, |
| false, |
| (TypeDescriptor) null, |
| newlyCreatedRoutines, |
| tc |
| ); |
| } |
| |
| // |
| // SYSCS_DROP_USER( IN USERNAME VARCHAR(128) ) |
| // |
| |
| { |
| // procedure argument names |
| String[] arg_names = { "userName" }; |
| |
| // procedure argument types |
| TypeDescriptor[] arg_types = |
| { |
| CATALOG_TYPE_SYSTEM_IDENTIFIER |
| }; |
| |
| createSystemProcedureOrFunction |
| ( |
| "SYSCS_DROP_USER", |
| sysUtilUUID, |
| arg_names, |
| arg_types, |
| 0, |
| 0, |
| RoutineAliasInfo.MODIFIES_SQL_DATA, |
| false, |
| false, |
| (TypeDescriptor) null, |
| newlyCreatedRoutines, |
| tc |
| ); |
| } |
| |
| // BIGINT |
| // SYSCS_UTIL.SYSCS_PEEK_AT_SEQUENCE( VARCHAR(128), VARCHAR(128) ) |
| |
| { |
| // procedure argument names |
| String[] arg_names = { "schemaName", "sequenceName" }; |
| |
| // procedure argument types |
| TypeDescriptor[] arg_types = |
| { |
| CATALOG_TYPE_SYSTEM_IDENTIFIER, |
| CATALOG_TYPE_SYSTEM_IDENTIFIER |
| }; |
| |
| createSystemProcedureOrFunction( |
| "SYSCS_PEEK_AT_SEQUENCE", |
| sysUtilUUID, |
| arg_names, |
| arg_types, |
| 0, |
| 0, |
| RoutineAliasInfo.READS_SQL_DATA, |
| false, |
| false, |
| DataTypeDescriptor.getCatalogType( Types.BIGINT ), |
| newlyCreatedRoutines, |
| tc); |
| } |
| |
| // void SYSCS_UTIL.SYSCS_DROP_STATISTICS(varchar(128), varchar(128), varchar(128)) |
| { |
| // procedure argument names |
| String[] arg_names = {"SCHEMANAME", "TABLENAME", "INDEXNAME"}; |
| |
| // procedure argument types |
| TypeDescriptor[] arg_types = { |
| CATALOG_TYPE_SYSTEM_IDENTIFIER, |
| CATALOG_TYPE_SYSTEM_IDENTIFIER, |
| CATALOG_TYPE_SYSTEM_IDENTIFIER |
| |
| }; |
| |
| createSystemProcedureOrFunction( |
| "SYSCS_DROP_STATISTICS", |
| sysUtilUUID, |
| arg_names, |
| arg_types, |
| 0, |
| 0, |
| RoutineAliasInfo.MODIFIES_SQL_DATA, |
| false, |
| false, |
| (TypeDescriptor) null, |
| newlyCreatedRoutines, |
| tc); |
| } |
| |
| } |
| |
| /** |
| * <p> |
| * Create system procedures that are part of the SYSCS_UTIL schema, added in version 10.10. |
| * </p> |
| * |
| * @param tc an instance of the Transaction Controller. |
| * @param newlyCreatedRoutines set of routines we are creating (used to add permissions later on) |
| **/ |
| void create_10_10_system_procedures( TransactionController tc, HashSet<String> newlyCreatedRoutines ) |
| throws StandardException |
| { |
| UUID sysUtilUUID = getSystemUtilSchemaDescriptor().getUUID(); |
| TypeDescriptor varchar32672Type = DataTypeDescriptor.getCatalogType( Types.VARCHAR, 32672 ); |
| |
| // void SYSCS_UTIL.SYSCS_INVALIDATE_STORED_STATEMENTS() |
| { |
| createSystemProcedureOrFunction( |
| "SYSCS_INVALIDATE_STORED_STATEMENTS", |
| sysUtilUUID, |
| (String[]) null, |
| (TypeDescriptor[]) null, |
| 0, |
| 0, |
| RoutineAliasInfo.NO_SQL, |
| false, |
| false, |
| (TypeDescriptor) null, |
| newlyCreatedRoutines, |
| tc); |
| } |
| |
| // void SYSCS_UTIL.SYSCS_REGISTER_TOOL |
| { |
| // procedure argument names |
| String[] arg_names = { "toolName", "register", "optionalArgs" }; |
| |
| // procedure argument types |
| TypeDescriptor[] arg_types = |
| { |
| varchar32672Type, |
| DataTypeDescriptor.getCatalogType( Types.BOOLEAN ), |
| varchar32672Type, |
| }; |
| |
| createSystemProcedureOrFunction |
| ( |
| "SYSCS_REGISTER_TOOL", |
| sysUtilUUID, |
| arg_names, |
| arg_types, |
| 0, |
| 0, |
| RoutineAliasInfo.MODIFIES_SQL_DATA, |
| false, |
| true, |
| (TypeDescriptor) null, |
| newlyCreatedRoutines, |
| tc, |
| "org.apache.derby.catalog.Java5SystemProcedures" |
| ); |
| } |
| |
| } |
| |
| /** |
| * <p> |
| * Create system procedures that are part of the SYSCS_UTIL schema, added in version 10.11. |
| * </p> |
| * |
| * @param tc an instance of the Transaction Controller. |
| * @param newlyCreatedRoutines set of routines we are creating (used to add permissions later on) |
| **/ |
| void create_10_11_system_procedures( TransactionController tc, HashSet<String> newlyCreatedRoutines ) |
| throws StandardException |
| { |
| UUID sysUtilUUID = getSystemUtilSchemaDescriptor().getUUID(); |
| |
| // BIGINT |
| // SYSCS_UTIL.SYSCS_PEEK_AT_IDENTITY( VARCHAR(128), VARCHAR(128) ) |
| |
| { |
| // procedure argument names |
| String[] arg_names = { "schemaName", "tableName" }; |
| |
| // procedure argument types |
| TypeDescriptor[] arg_types = |
| { |
| CATALOG_TYPE_SYSTEM_IDENTIFIER, |
| CATALOG_TYPE_SYSTEM_IDENTIFIER |
| }; |
| |
| createSystemProcedureOrFunction( |
| "SYSCS_PEEK_AT_IDENTITY", |
| sysUtilUUID, |
| arg_names, |
| arg_types, |
| 0, |
| 0, |
| RoutineAliasInfo.READS_SQL_DATA, |
| false, |
| false, |
| DataTypeDescriptor.getCatalogType( Types.BIGINT ), |
| newlyCreatedRoutines, |
| tc); |
| } |
| } |
| |
| /** |
| * <p> |
| * Create system procedures that are part of the SYSCS_UTIL schema, added in version 10.12. |
| * </p> |
| * |
| * @param tc an instance of the Transaction Controller. |
| * @param newlyCreatedRoutines set of routines we are creating (used to add permissions later on) |
| **/ |
| void create_10_12_system_procedures( TransactionController tc, HashSet<String> newlyCreatedRoutines ) |
| throws StandardException |
| { |
| UUID sysUtilUUID = getSystemUtilSchemaDescriptor().getUUID(); |
| |
| // void SYSCS_UTIL.SYSCS_GET_DATABASE_NAME() |
| { |
| createSystemProcedureOrFunction( |
| "SYSCS_GET_DATABASE_NAME", |
| sysUtilUUID, |
| (String[]) null, |
| (TypeDescriptor[]) null, |
| 0, |
| 0, |
| RoutineAliasInfo.READS_SQL_DATA, |
| false, |
| false, |
| DataTypeDescriptor.getCatalogType( Types.VARCHAR ), |
| newlyCreatedRoutines, |
| tc); |
| } |
| } |
| |
| |
| /** |
| * <p> |
| * Create system procedures that are part of the SYSCS_UTIL schema, added in version 10.13. |
| * </p> |
| * |
| * @param tc an instance of the Transaction Controller. |
| * @param newlyCreatedRoutines set of routines we are creating (used to add permissions later on) |
| **/ |
| void create_10_13_system_procedures( TransactionController tc, HashSet<String> newlyCreatedRoutines ) |
| throws StandardException |
| { |
| UUID sysUtilUUID = getSystemUtilSchemaDescriptor().getUUID(); |
| TypeDescriptor varchar32672Type = DataTypeDescriptor.getCatalogType( Types.VARCHAR, 32672 ); |
| |
| /* SYSCS_IMPORT_TABLE_BULK(IN SCHEMANAME VARCHAR(128), |
| * IN TABLENAME VARCHAR(128), IN FILENAME VARCHAR(32672), |
| * IN COLUMNDELIMITER CHAR(1), IN CHARACTERDELIMITER CHAR(1), |
| * IN CODESET VARCHAR(128) , IN REPLACE SMALLINT |
| * IN SKIP SMALLINT ) |
| */ |
| { |
| // procedure argument names |
| String[] arg_names = {"schemaName", "tableName", "fileName", |
| " columnDelimiter", "characterDelimiter", |
| "codeset", "replace", "skip"}; |
| |
| // procedure argument types |
| TypeDescriptor[] arg_types = { |
| CATALOG_TYPE_SYSTEM_IDENTIFIER, |
| CATALOG_TYPE_SYSTEM_IDENTIFIER, |
| varchar32672Type, |
| DataTypeDescriptor.getCatalogType( |
| Types.CHAR, 1), |
| DataTypeDescriptor.getCatalogType( |
| Types.CHAR, 1), |
| CATALOG_TYPE_SYSTEM_IDENTIFIER, |
| TypeDescriptor.SMALLINT, |
| TypeDescriptor.SMALLINT |
| }; |
| |
| |
| createSystemProcedureOrFunction( |
| "SYSCS_IMPORT_TABLE_BULK", |
| sysUtilUUID, |
| arg_names, |
| arg_types, |
| 0, |
| 0, |
| RoutineAliasInfo.MODIFIES_SQL_DATA, |
| false, |
| false, |
| (TypeDescriptor) null, |
| newlyCreatedRoutines, |
| tc); |
| } |
| |
| |
| /* SYSCS_IMPORT_DATA_BULK(IN SCHEMANAME VARCHAR(128), |
| * IN TABLENAME VARCHAR(128), IN INSERTCOLUMNLIST VARCHAR(32672), |
| * IN COLUMNINDEXES VARCHAR(32672), IN IN FILENAME VARCHAR(32672), |
| * IN COLUMNDELIMITER CHAR(1), IN CHARACTERDELIMITER CHAR(1), |
| * IN CODESET VARCHAR(128) , IN REPLACE SMALLINT |
| * IN SKIP SMALLINT) |
| */ |
| { |
| // procedure argument names |
| String[] arg_names = {"schemaName", "tableName", "insertColumnList","columnIndexes", |
| "fileName", " columnDelimiter", "characterDelimiter", |
| "codeset", "replace", "skip"}; |
| |
| // procedure argument types |
| |
| // procedure argument types |
| TypeDescriptor[] arg_types = { |
| CATALOG_TYPE_SYSTEM_IDENTIFIER, |
| CATALOG_TYPE_SYSTEM_IDENTIFIER, |
| varchar32672Type, |
| varchar32672Type, |
| varchar32672Type, |
| DataTypeDescriptor.getCatalogType( |
| Types.CHAR, 1), |
| DataTypeDescriptor.getCatalogType( |
| Types.CHAR, 1), |
| CATALOG_TYPE_SYSTEM_IDENTIFIER, |
| TypeDescriptor.SMALLINT, |
| TypeDescriptor.SMALLINT |
| }; |
| |
| |
| createSystemProcedureOrFunction( |
| "SYSCS_IMPORT_DATA_BULK", |
| sysUtilUUID, |
| arg_names, |
| arg_types, |
| 0, |
| 0, |
| RoutineAliasInfo.MODIFIES_SQL_DATA, |
| false, |
| false, |
| (TypeDescriptor) null, |
| newlyCreatedRoutines, |
| tc); |
| } |
| |
| |
| |
| } |
| |
| |
| |
| /* |
| ** Priv block code to load net work server meta data queries. |
| */ |
| |
| private String spsSet; |
| private final synchronized Properties getQueryDescriptions(boolean net) { |
| spsSet = net ? "metadata_net.properties" : "/org/apache/derby/impl/jdbc/metadata.properties"; |
| return java.security.AccessController.doPrivileged(this); |
| } |
| |
| public final Properties run() { |
| // SECURITY PERMISSION - IP3 |
| Properties p = new Properties(); |
| try { |
| |
| // SECURITY PERMISSION - IP3 |
| InputStream is = getClass().getResourceAsStream(spsSet); |
| p.load(is); |
| is.close(); |
| } catch (IOException ioe) {} |
| return p; |
| } |
| |
| |
| private static <T> List<T> newSList() { |
| return Collections.synchronizedList(new LinkedList<T>()); |
| } |
| |
| /** |
| * Get one user's privileges on a table |
| * |
| * @param tableUUID |
| * @param authorizationId The user name |
| * |
| * @return a TablePermsDescriptor or null if the user has no permissions on the table. |
| * |
| * @exception StandardException |
| */ |
| public TablePermsDescriptor getTablePermissions( UUID tableUUID, String authorizationId) |
| throws StandardException |
| { |
| TablePermsDescriptor key = new TablePermsDescriptor( this, authorizationId, (String) null, tableUUID); |
| return (TablePermsDescriptor) getPermissions( key); |
| } // end of getTablePermissions |
| |
| /* @see org.apache.derby.iapi.sql.dictionary.DataDictionary#getTablePermissions */ |
| public TablePermsDescriptor getTablePermissions( UUID tablePermsUUID) |
| throws StandardException |
| { |
| TablePermsDescriptor key = new TablePermsDescriptor( this, tablePermsUUID); |
| return getUncachedTablePermsDescriptor( key ); |
| } |
| |
| private Object getPermissions( PermissionsDescriptor key) throws StandardException |
| { |
| // RESOLVE get a READ COMMITTED (shared) lock on the permission row |
| Cacheable entry = getPermissionsCache().find( key); |
| if( entry == null) |
| return null; |
| Object perms = entry.getIdentity(); |
| getPermissionsCache().release( entry); |
| return perms; |
| } |
| |
| /* @see org.apache.derby.iapi.sql.dictionary.DataDictionary#getColumnPermissions */ |
| public ColPermsDescriptor getColumnPermissions( UUID colPermsUUID) |
| throws StandardException |
| { |
| ColPermsDescriptor key = new ColPermsDescriptor( this, colPermsUUID); |
| return getUncachedColPermsDescriptor( key ); |
| } |
| |
| /** |
| * Get one user's column privileges for a table. |
| * |
| * @param tableUUID |
| * @param privType (as int) Authorizer.SELECT_PRIV, Authorizer.UPDATE_PRIV, or Authorizer.REFERENCES_PRIV |
| * @param forGrant |
| * @param authorizationId The user name |
| * |
| * @return a ColPermsDescriptor or null if the user has no separate column |
| * permissions of the specified type on the table. Note that the user may have been granted |
| * permission on all the columns of the table (no column list), in which case this routine |
| * will return null. You must also call getTablePermissions to see if the user has permission |
| * on a set of columns. |
| * |
| * @exception StandardException |
| */ |
| public ColPermsDescriptor getColumnPermissions( UUID tableUUID, |
| int privType, |
| boolean forGrant, |
| String authorizationId) |
| throws StandardException |
| { |
| String privTypeStr = forGrant ? colPrivTypeMapForGrant[privType] : colPrivTypeMap[privType]; |
| if( SanityManager.DEBUG) |
| SanityManager.ASSERT( privTypeStr != null, |
| "Invalid column privilege type: " + privType); |
| ColPermsDescriptor key = new ColPermsDescriptor( this, |
| authorizationId, |
| (String) null, |
| tableUUID, |
| privTypeStr); |
| return (ColPermsDescriptor) getPermissions( key); |
| } // end of getColumnPermissions |
| |
| /** |
| * Get one user's column privileges for a table. This routine gets called |
| * during revoke privilege processing |
| * |
| * @param tableUUID |
| * @param privTypeStr (as String) Authorizer.SELECT_PRIV, Authorizer.UPDATE_PRIV, or Authorizer.REFERENCES_PRIV |
| * @param forGrant |
| * @param authorizationId The user name |
| * |
| * @return a ColPermsDescriptor or null if the user has no separate column |
| * permissions of the specified type on the table. Note that the user may have been granted |
| * permission on all the columns of the table (no column list), in which case this routine |
| * will return null. You must also call getTablePermissions to see if the user has permission |
| * on a set of columns. |
| * |
| * @exception StandardException |
| */ |
| public ColPermsDescriptor getColumnPermissions( UUID tableUUID, |
| String privTypeStr, |
| boolean forGrant, |
| String authorizationId) |
| throws StandardException |
| { |
| ColPermsDescriptor key = new ColPermsDescriptor( this, |
| authorizationId, |
| (String) null, |
| tableUUID, |
| privTypeStr); |
| return (ColPermsDescriptor) getPermissions( key); |
| |
| } |
| |
| private static final String[] colPrivTypeMap; |
| private static final String[] colPrivTypeMapForGrant; |
| static { |
| colPrivTypeMap = new String[ Authorizer.PRIV_TYPE_COUNT]; |
| colPrivTypeMapForGrant = new String[ Authorizer.PRIV_TYPE_COUNT]; |
| colPrivTypeMap[ Authorizer.MIN_SELECT_PRIV] = "s"; |
| colPrivTypeMapForGrant[ Authorizer.MIN_SELECT_PRIV] = "S"; |
| colPrivTypeMap[ Authorizer.SELECT_PRIV] = "s"; |
| colPrivTypeMapForGrant[ Authorizer.SELECT_PRIV] = "S"; |
| colPrivTypeMap[ Authorizer.UPDATE_PRIV] = "u"; |
| colPrivTypeMapForGrant[ Authorizer.UPDATE_PRIV] = "U"; |
| colPrivTypeMap[ Authorizer.REFERENCES_PRIV] = "r"; |
| colPrivTypeMapForGrant[ Authorizer.REFERENCES_PRIV] = "R"; |
| } |
| |
| /** |
| * Get one user's permissions for a routine (function or procedure). |
| * |
| * @param routineUUID |
| * @param authorizationId The user's name |
| * |
| * @return The descriptor of the users permissions for the routine. |
| * |
| * @exception StandardException |
| */ |
| public RoutinePermsDescriptor getRoutinePermissions( UUID routineUUID, String authorizationId) |
| throws StandardException |
| { |
| RoutinePermsDescriptor key = new RoutinePermsDescriptor( this, authorizationId, (String) null, routineUUID); |
| |
| return (RoutinePermsDescriptor) getPermissions( key); |
| } // end of getRoutinePermissions |
| |
| /* @see org.apache.derby.iapi.sql.dictionary.DataDictionary#getRoutinePermissions */ |
| public RoutinePermsDescriptor getRoutinePermissions( UUID routinePermsUUID) |
| throws StandardException |
| { |
| RoutinePermsDescriptor key = new RoutinePermsDescriptor( this, routinePermsUUID); |
| return getUncachedRoutinePermsDescriptor( key ); |
| } |
| |
| /** |
| * Add or remove a permission to/from the permission database. |
| * |
| * @param add if true then the permission is added, if false the permission is removed |
| * @param perm |
| * @param grantee |
| * @param tc |
| * |
| * @return True means revoke has removed a privilege from system |
| * table and hence the caller of this method should send invalidation |
| * actions to PermssionDescriptor's dependents. |
| */ |
| public boolean addRemovePermissionsDescriptor( boolean add, |
| PermissionsDescriptor perm, |
| String grantee, |
| TransactionController tc) |
| throws StandardException |
| { |
| int catalogNumber = perm.getCatalogNumber(); |
| |
| // It is possible for grant statements to look like following |
| // grant execute on function f_abs to mamata2, mamata3; |
| // grant all privileges on t11 to mamata2, mamata3; |
| // This means that dd.addRemovePermissionsDescriptor will be called |
| // twice for TablePermsDescriptor and twice for RoutinePermsDescriptor, |
| // once for each grantee. |
| // First it's called for mamta2. When a row is inserted for mamta2 |
| // into the correct system table for the permission descriptor, the |
| // permission descriptor's uuid gets populated with the uuid of |
| // the row that just got inserted into the system table for mamta2 |
| // Now, when dd.addRemovePermissionsDescriptor gets called again for |
| // mamta3, the permission descriptor's uuid will still be set to |
| // the uuid that was used for mamta2. If we do not reset the |
| // uuid to null, we will think that there is a duplicate row getting |
| // inserted for the same uuid. In order to get around this, we should |
| // reset the UUID of passed PermissionDescriptor everytime this method |
| // is called. This way, there will be no leftover values from previous |
| // call of this method. |
| perm.setUUID(null); |
| perm.setGrantee( grantee); |
| TabInfoImpl ti = getNonCoreTI( catalogNumber); |
| PermissionsCatalogRowFactory rf = (PermissionsCatalogRowFactory) ti.getCatalogRowFactory(); |
| int primaryIndexNumber = rf.getPrimaryKeyIndexNumber(); |
| ConglomerateController heapCC = tc.openConglomerate( ti.getHeapConglomerate(), |
| false, // do not keep open across commits |
| 0, |
| TransactionController.MODE_RECORD, |
| TransactionController.ISOLATION_REPEATABLE_READ); |
| RowLocation rl = null; |
| try |
| { |
| rl = heapCC.newRowLocationTemplate(); |
| } |
| finally |
| { |
| heapCC.close(); |
| heapCC = null; |
| } |
| ExecIndexRow key = rf.buildIndexKeyRow( primaryIndexNumber, perm); |
| ExecRow existingRow = ti.getRow( tc, key, primaryIndexNumber); |
| if( existingRow == null) |
| { |
| if( ! add) |
| { |
| //we didn't find an entry in system catalog and this is revoke |
| //so that means there is nothing to revoke. Simply return. |
| //No need to reset permission descriptor's uuid because |
| //no row was ever found in system catalog for the given |
| //permission and hence uuid can't be non-null |
| return false; |
| } |
| else |
| { |
| //We didn't find an entry in system catalog and this is grant so |
| //so that means we have to enter a new row in system catalog for |
| //this grant. |
| ExecRow row = ti.getCatalogRowFactory().makeRow( perm, (TupleDescriptor) null); |
| int insertRetCode = ti.insertRow(row, tc); |
| if( SanityManager.DEBUG) |
| { |
| SanityManager.ASSERT( insertRetCode == TabInfoImpl.ROWNOTDUPLICATE, |
| "Race condition in inserting table privilege."); |
| } |
| } |
| } |
| else |
| { |
| // add/remove these permissions to/from the existing permissions |
| boolean[] colsChanged = new boolean[ existingRow.nColumns()]; |
| boolean[] indicesToUpdate = new boolean[ rf.getNumIndexes()]; |
| int changedColCount = 0; |
| if( add) |
| { |
| changedColCount = rf.orPermissions( existingRow, perm, colsChanged); |
| } |
| else |
| { |
| changedColCount = rf.removePermissions( existingRow, perm, colsChanged); |
| } |
| |
| if( changedColCount == 0) |
| { |
| //grant/revoke privilege didn't change anything and hence |
| //just return |
| return false; |
| } |
| if (!add) |
| { |
| //set the uuid of the passed permission descriptor to |
| //corresponding rows's uuid in permissions system table. The |
| //permission descriptor's uuid is required to have the |
| //dependency manager send the revoke privilege action to |
| //all the dependent objects on that permission descriptor. |
| rf.setUUIDOfThePassedDescriptor(existingRow, perm); |
| } |
| if( changedColCount < 0) |
| { |
| // No permissions left in the current row |
| ti.deleteRow( tc, key, primaryIndexNumber); |
| } |
| else if( changedColCount > 0) |
| { |
| int[] colsToUpdate = new int[changedColCount]; |
| changedColCount = 0; |
| for( int i = 0; i < colsChanged.length; i++) |
| { |
| if( colsChanged[i]) |
| colsToUpdate[ changedColCount++] = i + 1; |
| } |
| if( SanityManager.DEBUG) |
| { |
| SanityManager.ASSERT( |
| changedColCount == colsToUpdate.length, |
| "return value of " + rf.getClass().getName() + |
| ".orPermissions does not match the number of booleans it set in colsChanged."); |
| } |
| ti.updateRow(key, existingRow, primaryIndexNumber, |
| indicesToUpdate, colsToUpdate, tc); |
| } |
| } |
| // Remove cached permissions data. The cache may hold permissions data for this key even if |
| // the row in the permissions table is new. In that case the cache may have an entry indicating no |
| // permissions |
| removePermEntryInCache(perm); |
| |
| //If we are dealing with grant, then the caller does not need to send |
| //any invalidation actions to anyone and hence return false |
| if (add) |
| { |
| return false; |
| } |
| else |
| { |
| return true; |
| } |
| } // end of addPermissionsDescriptor |
| |
| /** |
| * Get a table permissions descriptor from the system tables, without going through the cache. |
| * This method is called to fill the permissions cache. |
| * |
| * @return a TablePermsDescriptor that describes the table permissions granted to the grantee, null |
| * if no table-level permissions have been granted to him on the table. |
| * |
| * @exception StandardException |
| */ |
| TablePermsDescriptor getUncachedTablePermsDescriptor( TablePermsDescriptor key) |
| throws StandardException |
| { |
| if (key.getObjectID() == null) |
| { |
| //the TABLEPERMSID for SYSTABLEPERMS is not known, so use |
| //table id, grantor and granteee to find TablePermsDescriptor |
| return |
| getUncachedPermissionsDescriptor( SYSTABLEPERMS_CATALOG_NUM, |
| SYSTABLEPERMSRowFactory.GRANTEE_TABLE_GRANTOR_INDEX_NUM, |
| key, |
| TablePermsDescriptor.class); |
| } else |
| { |
| //we know the TABLEPERMSID for SYSTABLEPERMS, so use that to |
| //find TablePermsDescriptor from the sytem table |
| return |
| getUncachedPermissionsDescriptor(SYSTABLEPERMS_CATALOG_NUM, |
| SYSTABLEPERMSRowFactory.TABLEPERMSID_INDEX_NUM, |
| key, TablePermsDescriptor.class); |
| } |
| } // end of getUncachedTablePermsDescriptor |
| |
| |
| /** |
| * Get a column permissions descriptor from the system tables, without going through the cache. |
| * This method is called to fill the permissions cache. |
| * |
| * |
| * @return a ColPermsDescriptor that describes the column permissions granted to the grantee, null |
| * if no column permissions have been granted to him on the table. |
| * |
| * @exception StandardException |
| */ |
| ColPermsDescriptor getUncachedColPermsDescriptor( ColPermsDescriptor key) |
| throws StandardException |
| { |
| if (key.getObjectID() == null) |
| { |
| //the COLPERMSID for SYSCOLPERMS is not known, so use tableid, |
| //privilege type, grantor and granteee to find ColPermsDescriptor |
| return |
| getUncachedPermissionsDescriptor( SYSCOLPERMS_CATALOG_NUM, |
| SYSCOLPERMSRowFactory.GRANTEE_TABLE_TYPE_GRANTOR_INDEX_NUM, |
| key, |
| ColPermsDescriptor.class); |
| }else |
| { |
| //we know the COLPERMSID for SYSCOLPERMS, so use that to |
| //find ColPermsDescriptor from the sytem table |
| return |
| getUncachedPermissionsDescriptor( SYSCOLPERMS_CATALOG_NUM, |
| SYSCOLPERMSRowFactory.COLPERMSID_INDEX_NUM, |
| key, |
| ColPermsDescriptor.class); |
| } |
| } // end of getUncachedColPermsDescriptor |
| |
| private <T extends PermissionsDescriptor> |
| T getUncachedPermissionsDescriptor( int catalogNumber, |
| int indexNumber, |
| T key, |
| Class<T> returnType) |
| throws StandardException |
| { |
| TabInfoImpl ti = getNonCoreTI( catalogNumber); |
| PermissionsCatalogRowFactory rowFactory = (PermissionsCatalogRowFactory) ti.getCatalogRowFactory(); |
| ExecIndexRow keyRow = rowFactory.buildIndexKeyRow( indexNumber, key); |
| return |
| getDescriptorViaIndex( indexNumber, |
| keyRow, |
| (ScanQualifier [][]) null, |
| ti, |
| (TupleDescriptor) null, |
| (List<TupleDescriptor>) null, |
| returnType, |
| false); |
| } // end of getUncachedPermissionsDescriptor |
| |
| /** |
| * Get a routine permissions descriptor from the system tables, without going through the cache. |
| * This method is called to fill the permissions cache. |
| * |
| * @return a RoutinePermsDescriptor that describes the table permissions granted to the grantee, null |
| * if no table-level permissions have been granted to him on the table. |
| * |
| * @exception StandardException |
| */ |
| RoutinePermsDescriptor getUncachedRoutinePermsDescriptor( RoutinePermsDescriptor key) |
| throws StandardException |
| { |
| if (key.getObjectID() == null) |
| { |
| //the ROUTINEPERMSID for SYSROUTINEPERMS is not known, so use aliasid, |
| //grantor and granteee to find RoutinePermsDescriptor |
| return |
| getUncachedPermissionsDescriptor( SYSROUTINEPERMS_CATALOG_NUM, |
| SYSROUTINEPERMSRowFactory.GRANTEE_ALIAS_GRANTOR_INDEX_NUM, |
| key, RoutinePermsDescriptor.class); |
| } else |
| { |
| //we know the ROUTINEPERMSID for SYSROUTINEPERMS, so use that to |
| //find RoutinePermsDescriptor from the sytem table |
| return |
| getUncachedPermissionsDescriptor(SYSROUTINEPERMS_CATALOG_NUM, |
| SYSROUTINEPERMSRowFactory.ROUTINEPERMSID_INDEX_NUM, |
| key, RoutinePermsDescriptor.class); |
| } |
| } // end of getUncachedRoutinePermsDescriptor |
| |
| private String[][] DIAG_VTI_TABLE_CLASSES = |
| { |
| {"LOCK_TABLE", "org.apache.derby.diag.LockTable"}, |
| {"STATEMENT_CACHE", "org.apache.derby.diag.StatementCache"}, |
| {"TRANSACTION_TABLE", "org.apache.derby.diag.TransactionTable"}, |
| {"ERROR_MESSAGES", "org.apache.derby.diag.ErrorMessages"}, |
| }; |
| |
| private String[][] DIAG_VTI_TABLE_FUNCTION_CLASSES = |
| { |
| {"SPACE_TABLE", "org.apache.derby.diag.SpaceTable"}, |
| {"ERROR_LOG_READER", "org.apache.derby.diag.ErrorLogReader"}, |
| {"STATEMENT_DURATION", "org.apache.derby.diag.StatementDuration"}, |
| {"CONTAINED_ROLES", "org.apache.derby.diag.ContainedRoles"}, |
| }; |
| |
| /** |
| * @see DataDictionary#getVTIClass(TableDescriptor, boolean) |
| */ |
| public String getVTIClass(TableDescriptor td, boolean asTableFunction) |
| throws StandardException |
| { |
| if (SchemaDescriptor.STD_SYSTEM_DIAG_SCHEMA_NAME.equals( |
| td.getSchemaName())) |
| { return getBuiltinVTIClass( td, asTableFunction ); } |
| else // see if it's a user-defined table function |
| { |
| String schemaName = td.getSchemaName(); |
| String functionName = td.getDescriptorName(); |
| SchemaDescriptor sd = getSchemaDescriptor( td.getSchemaName(), null, true ); |
| |
| if ( sd != null ) |
| { |
| AliasDescriptor ad = getAliasDescriptor( sd.getUUID().toString(), functionName, AliasInfo.ALIAS_TYPE_FUNCTION_AS_CHAR ); |
| |
| if ( (ad != null) && ad.isTableFunction() ) { return ad.getJavaClassName(); } |
| |
| throw StandardException.newException |
| ( SQLState.LANG_NOT_TABLE_FUNCTION, schemaName, functionName ); |
| } |
| } |
| |
| return null; |
| } |
| |
| /** |
| * @see DataDictionary#getBuiltinVTIClass(TableDescriptor, boolean) |
| */ |
| public String getBuiltinVTIClass(TableDescriptor td, boolean asTableFunction) |
| throws StandardException |
| { |
| if (SanityManager.DEBUG) |
| { |
| if (td.getTableType() != TableDescriptor.VTI_TYPE) |
| SanityManager.THROWASSERT("getVTIClass: Invalid table type " + td); |
| } |
| |
| /* First check to see if this is a system VTI. Note that if no schema was specified then the |
| * call to "td.getSchemaName()" will return the current schema. |
| */ |
| if (SchemaDescriptor.STD_SYSTEM_DIAG_SCHEMA_NAME.equals( |
| td.getSchemaName())) |
| { |
| String [][] vtiMappings = asTableFunction |
| ? DIAG_VTI_TABLE_FUNCTION_CLASSES |
| : DIAG_VTI_TABLE_CLASSES; |
| |
| for (int i = 0; i < vtiMappings.length; i++) |
| { |
| String[] entry = vtiMappings[i]; |
| if (entry[0].equals(td.getDescriptorName())) |
| return entry[1]; |
| } |
| } |
| |
| return null; |
| } |
| |
| |
| /** |
| * @see DataDictionary#getRoleGrantDescriptor(UUID) |
| */ |
| public RoleGrantDescriptor getRoleGrantDescriptor(UUID uuid) |
| throws StandardException |
| { |
| DataValueDescriptor UUIDStringOrderable; |
| |
| TabInfoImpl ti = getNonCoreTI(SYSROLES_CATALOG_NUM); |
| |
| /* Use UUIDStringOrderable in both start and stop position for |
| * scan. |
| */ |
| UUIDStringOrderable = getIDValueAsCHAR(uuid); |
| |
| /* Set up the start/stop position for the scan */ |
| ExecIndexRow keyRow = exFactory.getIndexableRow(1); |
| keyRow.setColumn(1, UUIDStringOrderable); |
| |
| return getDescriptorViaIndex( |
| SYSROLESRowFactory.SYSROLES_INDEX_UUID_IDX, |
| keyRow, |
| (ScanQualifier [][]) null, |
| ti, |
| (TupleDescriptor) null, |
| (List<TupleDescriptor>) null, |
| RoleGrantDescriptor.class, |
| false); |
| } |
| |
| |
| /** |
| * Get the target role definition by searching for a matching row |
| * in SYSROLES by rolename where isDef==true. Read only scan. |
| * Uses index on (rolename, isDef) columns. |
| * |
| * @param roleName The name of the role we're interested in. |
| * |
| * @return The descriptor (row) for the role |
| * @exception StandardException Thrown on error |
| * |
| * @see DataDictionary#getRoleDefinitionDescriptor |
| */ |
| public RoleGrantDescriptor getRoleDefinitionDescriptor(String roleName) |
| throws StandardException |
| { |
| DataValueDescriptor roleNameOrderable; |
| DataValueDescriptor isDefOrderable; |
| |
| TabInfoImpl ti = getNonCoreTI(SYSROLES_CATALOG_NUM); |
| |
| /* Use aliasNameOrderable , isDefOrderable in both start |
| * and stop position for scan. |
| */ |
| roleNameOrderable = new SQLVarchar(roleName); |
| isDefOrderable = new SQLVarchar("Y"); |
| |
| /* Set up the start/stop position for the scan */ |
| ExecIndexRow keyRow = exFactory.getIndexableRow(2); |
| keyRow.setColumn(1, roleNameOrderable); |
| keyRow.setColumn(2, isDefOrderable); |
| |
| return getDescriptorViaIndex( |
| SYSROLESRowFactory.SYSROLES_INDEX_ID_DEF_IDX, |
| keyRow, |
| (ScanQualifier [][]) null, |
| ti, |
| (TupleDescriptor) null, |
| (List<TupleDescriptor>) null, |
| RoleGrantDescriptor.class, |
| false); |
| } |
| |
| |
| /** |
| * Get the target role by searching for a matching row |
| * in SYSROLES by rolename, grantee and grantor. Read only scan. |
| * Uses index on roleid, grantee and grantor columns. |
| * |
| * @param roleName The name of the role we're interested in. |
| * @param grantee The grantee |
| * @param grantor The grantor |
| * |
| * @return The descriptor for the role grant |
| * |
| * @exception StandardException Thrown on error |
| * |
| * @see DataDictionary#getRoleGrantDescriptor(String, String, String) |
| */ |
| public RoleGrantDescriptor getRoleGrantDescriptor(String roleName, |
| String grantee, |
| String grantor) |
| throws StandardException |
| { |
| DataValueDescriptor roleNameOrderable; |
| DataValueDescriptor granteeOrderable; |
| DataValueDescriptor grantorOrderable; |
| |
| |
| TabInfoImpl ti = getNonCoreTI(SYSROLES_CATALOG_NUM); |
| |
| /* Use aliasNameOrderable, granteeOrderable and |
| * grantorOrderable in both start and stop position for scan. |
| */ |
| roleNameOrderable = new SQLVarchar(roleName); |
| granteeOrderable = new SQLVarchar(grantee); |
| grantorOrderable = new SQLVarchar(grantor); |
| |
| /* Set up the start/stop position for the scan */ |
| ExecIndexRow keyRow = exFactory.getIndexableRow(3); |
| keyRow.setColumn(1, roleNameOrderable); |
| keyRow.setColumn(2, granteeOrderable); |
| keyRow.setColumn(3, grantorOrderable); |
| |
| return getDescriptorViaIndex( |
| SYSROLESRowFactory.SYSROLES_INDEX_ID_EE_OR_IDX, |
| keyRow, |
| (ScanQualifier [][]) null, |
| ti, |
| (TupleDescriptor) null, |
| (List<TupleDescriptor>) null, |
| RoleGrantDescriptor.class, |
| false); |
| } |
| |
| |
| /** |
| * Check all dictionary tables and return true if there is any GRANT |
| * descriptor containing <code>authId</code> as its grantee. |
| * |
| * @param authId grantee for which a grant exists or not |
| * @param tc TransactionController for the transaction |
| * @return boolean true if such a grant exists |
| */ |
| public boolean existsGrantToAuthid(String authId, |
| TransactionController tc) |
| throws StandardException { |
| |
| return |
| (existsPermByGrantee( |
| authId, |
| tc, |
| SYSTABLEPERMS_CATALOG_NUM, |
| SYSTABLEPERMSRowFactory.GRANTEE_TABLE_GRANTOR_INDEX_NUM, |
| SYSTABLEPERMSRowFactory. |
| GRANTEE_COL_NUM_IN_GRANTEE_TABLE_GRANTOR_INDEX) || |
| existsPermByGrantee( |
| authId, |
| tc, |
| SYSCOLPERMS_CATALOG_NUM, |
| SYSCOLPERMSRowFactory.GRANTEE_TABLE_TYPE_GRANTOR_INDEX_NUM, |
| SYSCOLPERMSRowFactory. |
| GRANTEE_COL_NUM_IN_GRANTEE_TABLE_TYPE_GRANTOR_INDEX) || |
| existsPermByGrantee( |
| authId, |
| tc, |
| SYSROUTINEPERMS_CATALOG_NUM, |
| SYSROUTINEPERMSRowFactory.GRANTEE_ALIAS_GRANTOR_INDEX_NUM, |
| SYSROUTINEPERMSRowFactory. |
| GRANTEE_COL_NUM_IN_GRANTEE_ALIAS_GRANTOR_INDEX) || |
| existsRoleGrantByGrantee(authId, tc)); |
| } |
| |
| |
| /** |
| * Remove metadata stored prepared statements. |
| * @param tc the xact |
| * |
| * |
| */ |
| private void dropJDBCMetadataSPSes(TransactionController tc) throws StandardException |
| { |
| for (SPSDescriptor spsd : getAllSPSDescriptors()) |
| { |
| SchemaDescriptor sd = spsd.getSchemaDescriptor(); |
| |
| // don't drop statements in non-system schemas |
| if (!sd.isSystemSchema()) { |
| continue; |
| } |
| |
| dropSPSDescriptor(spsd, tc); |
| dropDependentsStoredDependencies(spsd.getUUID(), tc); |
| |
| } |
| } |
| |
| |
| /** |
| * Drop and recreate metadata stored prepared statements. |
| * |
| * @param tc the xact |
| * @throws StandardException |
| */ |
| public void updateMetadataSPSes(TransactionController tc) throws StandardException { |
| dropJDBCMetadataSPSes(tc); |
| createSystemSps(tc); |
| } |
| |
| /** |
| * Drops a sequence descriptor |
| * |
| * @param descriptor The descriptor to drop |
| * @param tc The TransactionController. |
| * @throws StandardException Thrown on failure |
| */ |
| public void dropSequenceDescriptor(SequenceDescriptor descriptor, TransactionController tc) |
| throws StandardException { |
| DataValueDescriptor sequenceIdOrderable; |
| TabInfoImpl ti = getNonCoreTI(SYSSEQUENCES_CATALOG_NUM); |
| |
| sequenceIdOrderable = getIDValueAsCHAR(descriptor.getUUID()); |
| |
| /* Set up the start/stop position for the scan */ |
| ExecIndexRow keyRow = (ExecIndexRow) exFactory.getIndexableRow(1); |
| keyRow.setColumn(1, sequenceIdOrderable); |
| |
| ti.deleteRow(tc, keyRow, SYSSEQUENCESRowFactory.SYSSEQUENCES_INDEX1_ID); |
| |
| dropSequenceID( descriptor ); |
| } |
| |
| public SequenceDescriptor getSequenceDescriptor(UUID uuid) throws StandardException { |
| DataValueDescriptor UUIDStringOrderable; |
| |
| TabInfoImpl ti = getNonCoreTI(SYSSEQUENCES_CATALOG_NUM); |
| |
| /* Use UUIDStringOrderable in both start and stop position for |
| * scan. |
| */ |
| UUIDStringOrderable = getIDValueAsCHAR(uuid); |
| |
| /* Set up the start/stop position for the scan */ |
| ExecIndexRow keyRow = exFactory.getIndexableRow(1); |
| keyRow.setColumn(1, UUIDStringOrderable); |
| |
| SequenceDescriptor sequenceDescriptor = |
| getDescriptorViaIndex( |
| SYSSEQUENCESRowFactory.SYSSEQUENCES_INDEX1_ID, |
| keyRow, |
| (ScanQualifier[][]) null, |
| ti, |
| (TupleDescriptor) null, |
| (List<TupleDescriptor>) null, |
| SequenceDescriptor.class, |
| false); |
| |
| putSequenceID( sequenceDescriptor ); |
| |
| return sequenceDescriptor; |
| } |
| |
| /** |
| * Get the sequence descriptor given a sequence name and a schema Id. |
| * |
| * @param sequenceName The sequence name, guaranteed to be unique only within its schema. |
| * @param sd The schema descriptor. |
| * @return The SequenceDescriptor for the constraints. |
| * @throws StandardException Thrown on failure |
| */ |
| public SequenceDescriptor getSequenceDescriptor(SchemaDescriptor sd, String sequenceName) |
| throws StandardException { |
| DataValueDescriptor schemaIDOrderable; |
| DataValueDescriptor sequenceNameOrderable; |
| TabInfoImpl ti = getNonCoreTI(SYSSEQUENCES_CATALOG_NUM); |
| |
| /* Use sequenceNameOrderable and schemaIdOrderable in both start |
| * and stop position for scan. |
| */ |
| sequenceNameOrderable = new SQLVarchar(sequenceName); |
| schemaIDOrderable = getIDValueAsCHAR(sd.getUUID()); |
| |
| /* Set up the start/stop position for the scan */ |
| ExecIndexRow keyRow = exFactory.getIndexableRow(2); |
| keyRow.setColumn(1, schemaIDOrderable); |
| keyRow.setColumn(2, sequenceNameOrderable); |
| |
| SequenceDescriptor sequenceDescriptor = |
| getDescriptorViaIndex( |
| SYSSEQUENCESRowFactory.SYSSEQUENCES_INDEX2_ID, |
| keyRow, |
| (ScanQualifier[][]) null, |
| ti, |
| (TupleDescriptor) null, |
| (List<TupleDescriptor>) null, |
| SequenceDescriptor.class, |
| false); |
| |
| putSequenceID( sequenceDescriptor ); |
| |
| return sequenceDescriptor; |
| } |
| |
| /** Map ( schemaName, sequenceName ) to sequenceID */ |
| private void putSequenceID( SequenceDescriptor sd ) |
| throws StandardException |
| { |
| if ( sd == null ) { return; } |
| |
| SchemaDescriptor schema = sd.getSchemaDescriptor(); |
| String schemaName = schema.getSchemaName(); |
| String sequenceName = sd.getSequenceName(); |
| String uuid = sd.getUUID().toString(); |
| |
| HashMap<String,String> sequencesInSchema = sequenceIDs.get( schemaName ); |
| if ( sequencesInSchema == null ) |
| { |
| sequencesInSchema = new HashMap<String,String>(); |
| sequenceIDs.put( schemaName, sequencesInSchema ); |
| } |
| |
| if ( sequencesInSchema.get( sequenceName ) == null ) |
| { |
| sequencesInSchema.put( sequenceName, uuid ); |
| } |
| } |
| |
| /** Drop a sequenceID from the ( schemaName, sequenceName ) map */ |
| private void dropSequenceID( SequenceDescriptor sd ) |
| throws StandardException |
| { |
| if ( sd == null ) { return; } |
| |
| SchemaDescriptor schema = sd.getSchemaDescriptor(); |
| String schemaName = schema.getSchemaName(); |
| String sequenceName = sd.getSequenceName(); |
| |
| HashMap<String,String> sequencesInSchema = (HashMap<String,String>) sequenceIDs.get( schemaName ); |
| if ( sequencesInSchema == null ) { return; } |
| |
| if ( sequencesInSchema.get( sequenceName ) == null ) { return; } |
| { |
| sequencesInSchema.remove( sequenceName ); |
| } |
| } |
| |
| /** |
| * <p> |
| * Get the uuid string of a sequence given its schema and sequence name. |
| * </p> |
| */ |
| private String getSequenceID( String schemaName, String sequenceName ) |
| throws StandardException |
| { |
| HashMap<String,String> sequencesInSchema = sequenceIDs.get( schemaName ); |
| if ( sequencesInSchema != null ) |
| { |
| String uuid = (String) sequencesInSchema.get( sequenceName ); |
| |
| if ( uuid != null ) { return uuid; } |
| } |
| |
| // oops, not saved in the sequenceID map yet. lookup the sequence. |
| // this will save the uuid in the sequenceID map. |
| SequenceDescriptor desc = getSequenceDescriptor |
| ( getSchemaDescriptor( schemaName, getTransactionCompile(), true ), sequenceName ); |
| |
| if ( desc == null ) { return null; } |
| else { return desc.getUUID().toString(); } |
| } |
| |
| /** |
| * Get an object's permission descriptor from the system tables, without going through the cache. |
| * This method is called to fill the permissions cache. |
| * |
| * @return a PermDescriptor that describes the table permissions granted to the grantee on an objcet |
| * , null if no table-level permissions have been granted to him on the table. |
| * @throws StandardException |
| */ |
| PermDescriptor getUncachedGenericPermDescriptor(PermDescriptor key) |
| throws StandardException |
| { |
| if (key.getObjectID() == null) |
| { |
| //the PERMISSSIONID for SYSRPERMS is not known, so use the id of the |
| //protected object plus the |
| //grantor and granteee to find a PermDescriptor |
| return |
| getUncachedPermissionsDescriptor(SYSPERMS_CATALOG_NUM, |
| SYSPERMSRowFactory.GRANTEE_OBJECTID_GRANTOR_INDEX_NUM, |
| key, PermDescriptor.class); |
| } else |
| { |
| //we know the PERMISSIONID for SYSPERMS, so use that to |
| //find a PermDescriptor from the sytem table |
| return |
| getUncachedPermissionsDescriptor(SYSPERMS_CATALOG_NUM, |
| SYSPERMSRowFactory.PERMS_UUID_IDX_NUM, |
| key, PermDescriptor.class); |
| } |
| |
| } // end of getUncachedGenericPermDescriptor |
| |
| /** |
| * Get permissions granted to one user for an object using the object's Id |
| * and the user's authorization Id. |
| * |
| * @param objectUUID The id of the protected object |
| * @param objectType Type of the object (e.g., SEQUENCE) |
| * @param privilege The kind of privilege needed (e.g., PermDescriptor.USAGE_PRIV) |
| * @param granteeAuthId The user or role who wants to have permission on this object |
| * |
| * @return The descriptor of the permissions for the object |
| * |
| * @exception StandardException |
| */ |
| public PermDescriptor getGenericPermissions(UUID objectUUID, String objectType, String privilege, String granteeAuthId) |
| throws StandardException |
| { |
| PermDescriptor key = new PermDescriptor( this, null, objectType, objectUUID, privilege, null, granteeAuthId, false ); |
| |
| return (PermDescriptor) getPermissions( key); |
| } |
| |
| /** |
| * Get one user's privileges for an object using the permUUID. |
| * |
| * @param permUUID |
| * @return The descriptor of the user's permissions for the object. |
| * @throws StandardException |
| */ |
| public PermDescriptor getGenericPermissions(UUID permUUID) |
| throws StandardException { |
| PermDescriptor key = new PermDescriptor(this, permUUID); |
| return getUncachedGenericPermDescriptor(key); |
| } |
| |
| /** |
| * Drops all permission descriptors for the object whose Id is given. |
| * |
| * @param objectID The UUID of the object from which to drop |
| * all the permission descriptors |
| * @param tc TransactionController for the transaction |
| * @throws StandardException Thrown on error |
| */ |
| public void dropAllPermDescriptors(UUID objectID, TransactionController tc) |
| throws StandardException { |
| TabInfoImpl ti = getNonCoreTI(SYSPERMS_CATALOG_NUM); |
| SYSPERMSRowFactory rf = (SYSPERMSRowFactory) ti.getCatalogRowFactory(); |
| DataValueDescriptor objIdOrderable; |
| ExecRow curRow; |
| PermissionsDescriptor perm; |
| |
| // In Derby authorization mode, permission catalogs may not be present |
| if (!usesSqlAuthorization) |
| return; |
| |
| /* Use objIDOrderable in both start and stop position for scan. */ |
| objIdOrderable = getIDValueAsCHAR(objectID); |
| |
| /* Set up the start/stop position for the scan */ |
| ExecIndexRow keyRow = exFactory.getIndexableRow(1); |
| keyRow.setColumn(1, objIdOrderable); |
| |
| while ((curRow = ti.getRow(tc, keyRow, rf.PERMS_OBJECTID_IDX_NUM)) != null) { |
| perm = (PermissionsDescriptor) rf.buildDescriptor(curRow, (TupleDescriptor) null, this); |
| removePermEntryInCache(perm); |
| |
| // Build new key based on UUID and drop the entry as we want to drop |
| // only this row |
| ExecIndexRow uuidKey; |
| uuidKey = rf.buildIndexKeyRow(rf.PERMS_UUID_IDX_NUM, perm); |
| ti.deleteRow(tc, uuidKey, rf.PERMS_UUID_IDX_NUM); |
| } |
| } |
| |
| /** {@inheritDoc} */ |
| public IndexStatisticsDaemon getIndexStatsRefresher(boolean asDaemon) { |
| if (indexStatsUpdateDisabled && asDaemon) { |
| return null; |
| } else { |
| return indexRefresher; |
| } |
| } |
| |
| /** {@inheritDoc} */ |
| public void disableIndexStatsRefresher() { |
| if (!indexStatsUpdateDisabled) { |
| indexStatsUpdateDisabled = true; |
| // NOTE: This will stop the automatic updates of index statistics, |
| // but users can still do this explicitly (i.e. by invoking |
| // the SYSCS_UTIL.SYSCS_UPDATE_STATISTICS system procedure). |
| indexRefresher.stop(); |
| } |
| } |
| |
| /** {@inheritDoc} */ |
| public boolean doCreateIndexStatsRefresher() { |
| // Note that we are using the index refresher to serve explicit calls |
| // to SYSCS_UTIL.SYSCS_UPDATE_STATISTICS. This means that we must |
| // always create the daemon (unless the database is read-only) even if |
| // automatic updates of the cardinality statistics are disabled. |
| return (indexRefresher == null); |
| } |
| |
| /** {@inheritDoc} */ |
| public void createIndexStatsRefresher(Database db, String dbName) { |
| // Check if the access factory is read-only. |
| if (af.isReadOnly()) { |
| indexStatsUpdateDisabled = true; |
| return; |
| } |
| |
| indexRefresher = new IndexStatisticsDaemonImpl( |
| Monitor.getStream(), indexStatsUpdateLogging, |
| indexStatsUpdateTracing, db, authorizationDatabaseOwner, |
| dbName); |
| } |
| |
| public DependableFinder getDependableFinder(int formatId) { |
| return new DDdependableFinder(formatId); |
| } |
| |
| public DependableFinder getColumnDependableFinder( |
| int formatId, byte[] columnBitMap) { |
| return new DDColumnDependableFinder(formatId, columnBitMap); |
| } |
| |
| /** |
| * Create sequence generators for all identity columns on upgrade to 10.11. |
| */ |
| void createIdentitySequences( TransactionController tc ) |
| throws StandardException |
| { |
| Hashtable<UUID,TableDescriptor> tableMap = hashAllTableDescriptorsByTableId( tc ); |
| |
| for ( UUID tableID : tableMap.keySet() ) |
| { |
| TableDescriptor td = getTableDescriptor( tableID ); |
| ColumnDescriptorList cdl = td.getColumnDescriptorList(); |
| |
| for ( ColumnDescriptor cd : cdl ) |
| { |
| if ( cd.isAutoincrement() ) |
| { |
| createIdentitySequence( td, cd, tc ); |
| } |
| } |
| } |
| } |
| |
| /** |
| * Create a sequence generator for an identity column on upgrade to 10.11. |
| */ |
| private void createIdentitySequence |
| ( |
| TableDescriptor td, |
| ColumnDescriptor cd, // the identity column |
| TransactionController tc |
| ) |
| throws StandardException |
| { |
| DataTypeDescriptor dtd = cd.getType(); |
| long[] bounds = dtd.getNumericBounds(); |
| long currentValue = cd.getAutoincValue(); |
| long initialValue = cd.getAutoincStart(); |
| long minValue = bounds[ DataTypeDescriptor.MIN_VALUE_IDX ]; |
| long maxValue = bounds[ DataTypeDescriptor.MAX_VALUE_IDX ]; |
| long stepValue = cd.getAutoincInc(); |
| SchemaDescriptor sd = getSystemSchemaDescriptor(); |
| |
| SequenceDescriptor seqDef = getDataDescriptorGenerator().newSequenceDescriptor |
| ( |
| sd, |
| getUUIDFactory().createUUID(), |
| TableDescriptor.makeSequenceName( td.getUUID() ), |
| dtd, |
| currentValue, |
| initialValue, |
| minValue, |
| maxValue, |
| stepValue, |
| false // whether the sequence can wrap-around |
| ); |
| |
| addDescriptor |
| ( |
| seqDef, |
| null, // parent |
| DataDictionary.SYSSEQUENCES_CATALOG_NUM, |
| false, // duplicatesAllowed |
| tc |
| ); |
| } |
| |
| /** |
| * Privileged lookup of the ContextService. Must be private so that user code |
| * can't call this entry point. |
| */ |
| private static ContextService getContextService() |
| { |
| if ( System.getSecurityManager() == null ) |
| { |
| return ContextService.getFactory(); |
| } |
| else |
| { |
| return AccessController.doPrivileged |
| ( |
| new PrivilegedAction<ContextService>() |
| { |
| public ContextService run() |
| { |
| return ContextService.getFactory(); |
| } |
| } |
| ); |
| } |
| } |
| |
| |
| /** |
| * Privileged lookup of a Context. Must be private so that user code |
| * can't call this entry point. |
| */ |
| private static Context getContextOrNull( final String contextID ) |
| { |
| if ( System.getSecurityManager() == null ) |
| { |
| return ContextService.getContextOrNull( contextID ); |
| } |
| else |
| { |
| return AccessController.doPrivileged |
| ( |
| new PrivilegedAction<Context>() |
| { |
| public Context run() |
| { |
| return ContextService.getContextOrNull( contextID ); |
| } |
| } |
| ); |
| } |
| } |
| |
| /** |
| * Privileged lookup of a Context. Must be private so that user code |
| * can't call this entry point. |
| */ |
| private static Context getContext( final String contextID ) |
| { |
| return AccessController.doPrivileged |
| ( |
| new PrivilegedAction<Context>() |
| { |
| public Context run() |
| { |
| return ContextService.getContext( contextID ); |
| } |
| } |
| ); |
| } |
| |
| /** |
| * Privileged Monitor lookup. Must be package private so that user code |
| * can't call this entry point. |
| */ |
| static ModuleFactory getMonitor() |
| { |
| return AccessController.doPrivileged |
| ( |
| new PrivilegedAction<ModuleFactory>() |
| { |
| public ModuleFactory run() |
| { |
| return Monitor.getMonitor(); |
| } |
| } |
| ); |
| } |
| |
| |
| /** |
| * Privileged startup. Must be private so that user code |
| * can't call this entry point. |
| */ |
| private static Object startSystemModule( final String factoryInterface ) |
| throws StandardException |
| { |
| try { |
| return AccessController.doPrivileged |
| ( |
| new PrivilegedExceptionAction<Object>() |
| { |
| public Object run() |
| throws StandardException |
| { |
| return Monitor.startSystemModule( factoryInterface ); |
| } |
| } |
| ); |
| } catch (PrivilegedActionException pae) |
| { |
| throw StandardException.plainWrapException( pae ); |
| } |
| } |
| |
| |
| /** |
| * Privileged startup. Must be private so that user code |
| * can't call this entry point. |
| */ |
| private static Object bootServiceModule |
| ( |
| final boolean create, final Object serviceModule, |
| final String factoryInterface, final Properties properties |
| ) |
| throws StandardException |
| { |
| try { |
| return AccessController.doPrivileged |
| ( |
| new PrivilegedExceptionAction<Object>() |
| { |
| public Object run() |
| throws StandardException |
| { |
| return Monitor.bootServiceModule( create, serviceModule, factoryInterface, properties ); |
| } |
| } |
| ); |
| } catch (PrivilegedActionException pae) |
| { |
| throw StandardException.plainWrapException( pae ); |
| } |
| } |
| |
| /** |
| * Privileged startup. Must be private so that user code |
| * can't call this entry point. |
| */ |
| private static Object findServiceModule( final Object serviceModule, final String factoryInterface) |
| throws StandardException |
| { |
| try { |
| return AccessController.doPrivileged |
| ( |
| new PrivilegedExceptionAction<Object>() |
| { |
| public Object run() |
| throws StandardException |
| { |
| return Monitor.findServiceModule( serviceModule, factoryInterface ); |
| } |
| } |
| ); |
| } catch (PrivilegedActionException pae) |
| { |
| throw StandardException.plainWrapException( pae ); |
| } |
| } |
| |
| } |