| /********************************************************************** |
| // @@@ START COPYRIGHT @@@ |
| // |
| // 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. |
| // |
| // @@@ END COPYRIGHT @@@ |
| **********************************************************************/ |
| |
| /* -*-C++-*- |
| ***************************************************************************** |
| * |
| * File: CmpSeabaseDDLschema.cpp |
| * Description: Implements ddl operations for Seabase schemas. |
| * |
| * |
| * Created: 10/30/2014 |
| * Language: C++ |
| * |
| * |
| ***************************************************************************** |
| */ |
| |
| |
| #include "CmpSeabaseDDLincludes.h" |
| #include "StmtDDLCreateSchema.h" |
| #include "StmtDDLDropSchema.h" |
| #include "StmtDDLAlterSchema.h" |
| #include "StmtDDLGive.h" |
| #include "ElemDDLColDefault.h" |
| #include "NumericType.h" |
| #include "ComUser.h" |
| #include "keycolumns.h" |
| #include "ElemDDLColRef.h" |
| #include "ElemDDLColName.h" |
| |
| #include "CmpDDLCatErrorCodes.h" |
| #include "Globals.h" |
| #include "CmpMain.h" |
| #include "Context.h" |
| #include "PrivMgrCommands.h" |
| #include "PrivMgrObjects.h" |
| #include <vector> |
| |
| static bool dropOneTable( |
| ExeCliInterface & cliInterface, |
| const char * catalogName, |
| const char * schemaName, |
| const char * objectName, |
| bool isVolatile, |
| bool ifExists, |
| bool ddlXns); |
| |
| static bool transferObjectPrivs( |
| const char * systemCatalogName, |
| const char * catalogName, |
| const char * schemaName, |
| const int32_t newOwnerID, |
| const char * newOwnerName); |
| |
| // ***************************************************************************** |
| // * * |
| // * Function: CmpSeabaseDDL::addSchemaObject * |
| // * * |
| // * Inserts a schema object row into the OBJECTS table. * |
| // * * |
| // ***************************************************************************** |
| // * * |
| // * Parameters: * |
| // * * |
| // * <cliInterface> ExeCliInterface & In * |
| // * is a reference to an Executor CLI interface handle. * |
| // * * |
| // * <schemaName> const ComSchemaName & In * |
| // * is a reference to a ComSchemaName instance. The catalog name must be * |
| // * set. * |
| // * * |
| // * <schemaClass> ComSchemaClass In * |
| // * is the class (private or shared) of the schema to be added. * |
| // * * |
| // * <ownerID> Int32 In * |
| // * is the authorization ID that will own the schema. * |
| // * * |
| // * <ignoreIfExists> NABoolean In * |
| // * do not return an error is schema already exists * |
| // ***************************************************************************** |
| // * * |
| // * Returns: status |
| // * * |
| // * 0: Schema was added * |
| // * -1: Schema was not added. A CLI error is put into the diags area. * |
| // * 1: Schema already exists and ignoreIfExists is specified. * |
| // * No error is added to the diags area. * |
| // * * |
| // ***************************************************************************** |
| int CmpSeabaseDDL::addSchemaObject( |
| ExeCliInterface & cliInterface, |
| const ComSchemaName & schemaName, |
| ComSchemaClass schemaClass, |
| Int32 ownerID, |
| NABoolean ignoreIfExists) |
| |
| { |
| |
| NAString catalogName = schemaName.getCatalogNamePartAsAnsiString(); |
| ComAnsiNamePart schemaNameAsComAnsi = schemaName.getSchemaNamePart(); |
| NAString schemaNamePart = schemaNameAsComAnsi.getInternalName(); |
| |
| ComObjectName objName(catalogName,schemaNamePart,NAString(SEABASE_SCHEMA_OBJECTNAME), |
| COM_TABLE_NAME,TRUE); |
| |
| if (isSeabaseReservedSchema(objName) && |
| !Get_SqlParser_Flags(INTERNAL_QUERY_FROM_EXEUTIL)) |
| { |
| *CmpCommon::diags() << DgSqlCode(-CAT_RESERVED_METADATA_SCHEMA_NAME) |
| << DgSchemaName(schemaName.getExternalName().data()); |
| return -1; |
| } |
| |
| NAString objectNamePart = objName.getObjectNamePartAsAnsiString(TRUE); |
| |
| Lng32 retcode = existsInSeabaseMDTable(&cliInterface,catalogName,schemaNamePart, |
| objectNamePart, COM_UNKNOWN_OBJECT, FALSE); |
| if (retcode < 0) |
| return -1; |
| |
| if (retcode == 1 ) // already exists |
| { |
| if (ignoreIfExists) |
| return 1; |
| else |
| *CmpCommon::diags() << DgSqlCode(-CAT_SCHEMA_ALREADY_EXISTS) |
| << DgSchemaName(schemaName.getExternalName().data()); |
| return -1; |
| } |
| |
| char buf[4000]; |
| |
| ComUID schemaUID; |
| |
| schemaUID.make_UID(); |
| |
| Int64 schemaObjectUID = schemaUID.get_value(); |
| |
| Int64 createTime = NA_JulianTimestamp(); |
| |
| NAString quotedSchName; |
| NAString quotedObjName; |
| |
| ToQuotedString(quotedSchName,schemaNamePart,FALSE); |
| ToQuotedString(quotedObjName,NAString(SEABASE_SCHEMA_OBJECTNAME),FALSE); |
| |
| char schemaObjectLit[3] = {0}; |
| |
| switch (schemaClass) |
| { |
| case COM_SCHEMA_CLASS_PRIVATE: |
| { |
| strncpy(schemaObjectLit,COM_PRIVATE_SCHEMA_OBJECT_LIT,2); |
| break; |
| } |
| case COM_SCHEMA_CLASS_SHARED: |
| { |
| strncpy(schemaObjectLit,COM_SHARED_SCHEMA_OBJECT_LIT,2); |
| break; |
| } |
| case COM_SCHEMA_CLASS_DEFAULT: |
| default: |
| { |
| // Schemas are private by default, but could choose a different |
| // default class here based on CQD or other attribute. |
| strncpy(schemaObjectLit,COM_PRIVATE_SCHEMA_OBJECT_LIT,2); |
| break; |
| } |
| } |
| |
| str_sprintf(buf, "insert into %s.\"%s\".%s values ('%s', '%s', '%s', '%s', %ld, %ld, %ld, '%s', '%s', %d, %d, 0)", |
| getSystemCatalog(),SEABASE_MD_SCHEMA,SEABASE_OBJECTS, |
| catalogName.data(), quotedSchName.data(), quotedObjName.data(), |
| schemaObjectLit, |
| schemaObjectUID, |
| createTime, |
| createTime, |
| COM_YES_LIT, // valid_def |
| COM_NO_LIT, // droppable |
| ownerID,ownerID); |
| |
| Int32 cliRC = cliInterface.executeImmediate(buf); |
| |
| if (cliRC < 0) |
| { |
| cliInterface.retrieveSQLDiagnostics(CmpCommon::diags()); |
| return -1; |
| } |
| |
| return 0; |
| |
| } |
| //******************* End of CmpSeabaseDDL::addSchemaObject ******************** |
| |
| // ***************************************************************************** |
| // * * |
| // * Function: CmpSeabaseDDL::createSeabaseSchema * |
| // * * |
| // * Implements the CREATE SCHEMA command. * |
| // * * |
| // ***************************************************************************** |
| // * * |
| // * Parameters: * |
| // * * |
| // * <createSchemaNode> StmtDDLCreateSchema * In * |
| // * is a pointer to a create schema parser node. * |
| // * * |
| // * <currentCatalogName> NAString & In * |
| // * is the name of the current catalog. * |
| // * * |
| // ***************************************************************************** |
| void CmpSeabaseDDL::createSeabaseSchema( |
| StmtDDLCreateSchema * createSchemaNode, |
| NAString & currentCatalogName) |
| |
| { |
| ComSchemaName schemaName (createSchemaNode->getSchemaName()); |
| |
| if (schemaName.getCatalogNamePart().isEmpty()) |
| schemaName.setCatalogNamePart(currentCatalogName); |
| |
| NAString catName = schemaName.getCatalogNamePartAsAnsiString(); |
| ComAnsiNamePart schNameAsComAnsi = schemaName.getSchemaNamePart(); |
| NAString schName = schNameAsComAnsi.getInternalName(); |
| |
| ExeCliInterface cliInterface(STMTHEAP, 0, NULL, |
| CmpCommon::context()->sqlSession()->getParentQid()); |
| ComSchemaClass schemaClass; |
| Int32 objectOwner = NA_UserIdDefault; |
| Int32 schemaOwner = NA_UserIdDefault; |
| |
| |
| // If creating the hive statistics schema, make owners |
| // the HIVE_ROLE_ID and skip authorization check. |
| // Schema is being created as part of an update statistics cmd |
| if (schName == HIVE_STATS_SCHEMA_NO_QUOTES && |
| Get_SqlParser_Flags(INTERNAL_QUERY_FROM_EXEUTIL)) |
| { |
| objectOwner = HIVE_ROLE_ID; |
| schemaOwner = HIVE_ROLE_ID; |
| } |
| else |
| { |
| int32_t retCode = verifyDDLCreateOperationAuthorized(&cliInterface, |
| SQLOperation::CREATE_SCHEMA, |
| catName, |
| schName, |
| schemaClass, |
| objectOwner, |
| schemaOwner); |
| if (retCode != 0) |
| { |
| handleDDLCreateAuthorizationError(retCode,catName,schName); |
| return; |
| } |
| } |
| |
| Int32 schemaOwnerID = NA_UserIdDefault; |
| |
| // If the AUTHORIZATION clause was not specified, the current user becomes |
| // the schema owner. |
| |
| if (createSchemaNode->getAuthorizationID().isNull()) |
| schemaOwnerID = ComUser::getCurrentUser(); |
| else |
| if (ComUser::getAuthIDFromAuthName(createSchemaNode->getAuthorizationID().data(), |
| schemaOwnerID) != 0) |
| { |
| *CmpCommon::diags() << DgSqlCode(-CAT_AUTHID_DOES_NOT_EXIST_ERROR) |
| << DgString0(createSchemaNode->getAuthorizationID().data()); |
| return; |
| } |
| |
| if (addSchemaObject(cliInterface, |
| schemaName, |
| createSchemaNode->getSchemaClass(), |
| schemaOwnerID, |
| createSchemaNode->createIfNotExists())) |
| return; |
| |
| // Create histogram tables for schema, if the schema is not volatile and |
| // not reserved |
| NAString tableNotCreated; |
| |
| if (!ComIsTrafodionReservedSchemaName(schName)) |
| { |
| if (createHistogramTables(&cliInterface, schemaName.getExternalName(), |
| FALSE, tableNotCreated)) |
| { |
| *CmpCommon::diags() << DgSqlCode(-CAT_HISTOGRAM_TABLE_NOT_CREATED) |
| << DgTableName(tableNotCreated.data()); |
| return; |
| } |
| } |
| |
| } |
| //***************** End of CmpSeabaseDDL::createSeabaseSchema ****************** |
| |
| // ***************************************************************************** |
| // * * |
| // * Function: CmpSeabaseDDL::describeSchema * |
| // * * |
| // * Provides text for SHOWDDL SCHEMA comnmand. * |
| // * * |
| // ***************************************************************************** |
| // * * |
| // * Parameters: * |
| // * * |
| // * <catalogName> const NAString & In * |
| // * is a reference to a catalog name. * |
| // * * |
| // * <schemaName> const NAString & In * |
| // * is a reference to a schema name. * |
| // * * |
| // * <output> NAString & Out * |
| // * passes back text for the SHOWDDL SCHEMA command, specifically the * |
| // * command to create the specified schema. * |
| // * * |
| // ***************************************************************************** |
| // * * |
| // * Returns: bool * |
| // * * |
| // * true: Text returned for specified schema. * |
| // * false: Could not retrieve information for specified schema. * |
| // * * |
| // ***************************************************************************** |
| bool CmpSeabaseDDL::describeSchema( |
| const NAString & catalogName, |
| const NAString & schemaName, |
| NABoolean isHiveRegistered, |
| std::vector<std::string> & outlines) |
| |
| { |
| |
| ExeCliInterface cliInterface(STMTHEAP, NULL, NULL, |
| CmpCommon::context()->sqlSession()->getParentQid()); |
| ComSchemaClass schemaClass; |
| Int32 objectOwner; |
| Int32 schemaOwner; |
| ComObjectType objectType; |
| |
| NABoolean isHive = FALSE; |
| NAString lcat(catalogName); |
| lcat.toLower(); |
| if (lcat == HIVE_SYSTEM_CATALOG_LC) |
| isHive = TRUE; |
| |
| NAString output; |
| if (isHive) |
| { |
| output = "/* Hive DDL */"; |
| outlines.push_back(output.data()); |
| |
| output = "create database "; |
| NAString lsch(schemaName); |
| lsch.toLower(); |
| output += lsch.data(); |
| output += ";"; |
| |
| outlines.push_back(output.data()); |
| |
| outlines.push_back(" "); |
| |
| if (isHiveRegistered) |
| { |
| output = "REGISTER /*INTERNAL*/ HIVE SCHEMA hive."; |
| output += lsch.data(); |
| output += ";"; |
| |
| outlines.push_back(output.data()); |
| } |
| |
| return true; |
| } |
| |
| CmpSeabaseDDL cmpSBD(STMTHEAP); |
| if (cmpSBD.switchCompiler()) |
| { |
| *CmpCommon::diags() << DgSqlCode(-CAT_UNABLE_TO_RETRIEVE_PRIVS); |
| return false; |
| } |
| |
| Int64 schemaUID = getObjectTypeandOwner(&cliInterface, |
| catalogName.data(), |
| schemaName.data(), |
| SEABASE_SCHEMA_OBJECTNAME, |
| objectType, |
| objectOwner); |
| |
| if (schemaUID < 0) |
| { |
| *CmpCommon::diags() << DgSqlCode(-CAT_SCHEMA_DOES_NOT_EXIST_ERROR) |
| << DgString0(catalogName) |
| << DgString1(schemaName); |
| cmpSBD.switchBackCompiler(); |
| return false; |
| } |
| |
| char username[MAX_USERNAME_LEN+1]; |
| Int32 lActualLen = 0; |
| Int16 status = ComUser::getAuthNameFromAuthID(objectOwner,username, |
| MAX_USERNAME_LEN+1,lActualLen); |
| if (status != FEOK) |
| { |
| *CmpCommon::diags() << DgSqlCode(-20235) // Error converting user ID. |
| << DgInt0(status) |
| << DgInt1(objectOwner); |
| cmpSBD.switchBackCompiler(); |
| return false; |
| } |
| |
| // Generate output text |
| output = "CREATE "; |
| switch (objectType) |
| { |
| case COM_PRIVATE_SCHEMA_OBJECT: |
| output += "PRIVATE"; |
| break; |
| case COM_SHARED_SCHEMA_OBJECT: |
| output += "SHARED"; |
| break; |
| default: |
| return false; |
| } |
| output += " SCHEMA \""; |
| output += catalogName.data(); |
| output += "\".\""; |
| output += schemaName.data(); |
| |
| // AUTHORIZATION clause is rarely used, but include it for replay. |
| output += "\" AUTHORIZATION \""; |
| output += username; |
| output += "\";"; |
| |
| outlines.push_back(output.data()); |
| |
| // Display Comment of schema |
| { |
| ComTdbVirtObjCommentInfo objCommentInfo; |
| if (cmpSBD.getSeabaseObjectComment(schemaUID, objectType, objCommentInfo, STMTHEAP)) |
| { |
| *CmpCommon::diags() << DgSqlCode(-CAT_UNABLE_TO_RETRIEVE_COMMENTS); |
| cmpSBD.switchBackCompiler(); |
| return -1; |
| } |
| |
| if (objCommentInfo.objectComment != NULL) |
| { |
| outlines.push_back(" "); |
| |
| output = "COMMENT ON SCHEMA "; |
| output += catalogName.data(); |
| output += "."; |
| output += schemaName.data(); |
| output += " IS '"; |
| output += objCommentInfo.objectComment; |
| output += "' ;"; |
| |
| outlines.push_back(output.data()); |
| } |
| } |
| |
| cmpSBD.switchBackCompiler(); |
| return true; |
| |
| } |
| //******************* End of CmpSeabaseDDL::describeSchema ********************* |
| |
| |
| |
| // ***************************************************************************** |
| // * * |
| // * Function: CmpSeabaseDDL::dropSeabaseSchema * |
| // * * |
| // * Implements the DROP SCHEMA command. * |
| // * * |
| // ***************************************************************************** |
| // * * |
| // * Parameters: * |
| // * * |
| // * <dropSchemaNode> StmtDDLDropSchema * In * |
| // * is a pointer to a create schema parser node. * |
| // * * |
| // ***************************************************************************** |
| void CmpSeabaseDDL::dropSeabaseSchema(StmtDDLDropSchema * dropSchemaNode) |
| |
| { |
| Lng32 cliRC = 0; |
| |
| ComSchemaName schemaName(dropSchemaNode->getSchemaName()); |
| NAString catName = schemaName.getCatalogNamePartAsAnsiString(); |
| ComAnsiNamePart schNameAsComAnsi = schemaName.getSchemaNamePart(); |
| NAString schName = schNameAsComAnsi.getInternalName(); |
| ComObjectName objName(catName,schName,NAString("dummy"),COM_TABLE_NAME,TRUE); |
| |
| ExeCliInterface cliInterface(STMTHEAP, 0, NULL, |
| CmpCommon::context()->sqlSession()->getParentQid()); |
| Int32 objectOwnerID = 0; |
| Int32 schemaOwnerID = 0; |
| ComObjectType objectType; |
| |
| bool isVolatile = (memcmp(schName.data(),"VOLATILE_SCHEMA",strlen("VOLATILE_SCHEMA")) == 0); |
| int32_t length = 0; |
| Int64 rowCount = 0; |
| bool someObjectsCouldNotBeDropped = false; |
| char errorObjs[1010]; |
| Queue * objectsQueue = NULL; |
| Queue * otherObjectsQueue = NULL; |
| |
| NABoolean dirtiedMetadata = FALSE; |
| |
| errorObjs[0] = 0; |
| |
| Int64 schemaUID = getObjectTypeandOwner(&cliInterface,catName.data(),schName.data(), |
| SEABASE_SCHEMA_OBJECTNAME,objectType,schemaOwnerID); |
| |
| // if schemaUID == -1, then either the schema does not exist or an unexpected error occurred |
| if (schemaUID == -1) |
| { |
| // If an error occurred, return |
| if (CmpCommon::diags()->getNumber(DgSqlCode::ERROR_) > 0) |
| goto label_error; |
| |
| // schema does not exist and IF EXISTS specified, then ignore and continue |
| if (dropSchemaNode->dropIfExists()) |
| goto label_error; |
| |
| // A Trafodion schema does not exist if the schema object row is not |
| // present: CATALOG-NAME.SCHEMA-NAME.__SCHEMA__. |
| *CmpCommon::diags() << DgSqlCode(-CAT_SCHEMA_DOES_NOT_EXIST_ERROR) |
| << DgString0(catName.data()) |
| << DgString1(schName.data()); |
| goto label_error; |
| } |
| |
| if (!isDDLOperationAuthorized(SQLOperation::DROP_SCHEMA, |
| schemaOwnerID,schemaOwnerID)) |
| { |
| *CmpCommon::diags() << DgSqlCode(-CAT_NOT_AUTHORIZED); |
| goto label_error; |
| } |
| |
| |
| if ((isSeabaseReservedSchema(objName) || |
| (schName == SEABASE_SYSTEM_SCHEMA)) && |
| !Get_SqlParser_Flags(INTERNAL_QUERY_FROM_EXEUTIL)) |
| { |
| *CmpCommon::diags() << DgSqlCode(-CAT_USER_CANNOT_DROP_SMD_SCHEMA) |
| << DgSchemaName(schemaName.getExternalName().data()); |
| goto label_error; |
| } |
| |
| // Can't drop a schema whose name begins with VOLATILE_SCHEMA unless the |
| // keyword VOLATILE was specified in the DROP SCHEMA command. |
| if (isVolatile && !dropSchemaNode->isVolatile()) |
| { |
| *CmpCommon::diags() << DgSqlCode(-CAT_RESERVED_METADATA_SCHEMA_NAME) |
| << DgTableName(schName); |
| goto label_error; |
| } |
| |
| // Get a list of all objects in the schema, excluding the schema object itself. |
| char query[4000]; |
| |
| // select objects in the schema to drop, don't return PRIMARY_KEY_CONSTRAINTS, |
| // they always get removed when the parent table is dropped. |
| // Filter out the LOB depenedent tables too - they will get dropped when |
| //the main LOB table is dropped. |
| str_sprintf(query,"SELECT distinct TRIM(object_name), TRIM(object_type) " |
| "FROM %s.\"%s\".%s " |
| "WHERE catalog_name = '%s' AND schema_name = '%s' AND " |
| "object_name <> '" SEABASE_SCHEMA_OBJECTNAME"' AND " |
| "object_type <> 'PK' " |
| "FOR READ COMMITTED ACCESS", |
| getSystemCatalog(),SEABASE_MD_SCHEMA,SEABASE_OBJECTS, |
| (char*)catName.data(),(char*)schName.data()); |
| |
| cliRC = cliInterface.fetchAllRows(objectsQueue, query, 0, FALSE, FALSE, TRUE); |
| if (cliRC < 0) |
| { |
| cliInterface.retrieveSQLDiagnostics(CmpCommon::diags()); |
| goto label_error; |
| } |
| |
| // Check to see if non histogram objects exist in schema, if so, then |
| // cascade is required |
| if (dropSchemaNode->getDropBehavior() == COM_RESTRICT_DROP_BEHAVIOR) |
| { |
| objectsQueue->position(); |
| for (size_t i = 0; i < objectsQueue->numEntries(); i++) |
| { |
| OutputInfo * vi = (OutputInfo*)objectsQueue->getNext(); |
| NAString objName = vi->get(0); |
| |
| if (!isHistogramTable(objName)) |
| { |
| OutputInfo * oi = (OutputInfo*)objectsQueue->getCurr(); |
| |
| *CmpCommon::diags() << DgSqlCode(-CAT_SCHEMA_IS_NOT_EMPTY) |
| << DgTableName(objName.data()); |
| goto label_error; |
| } |
| } |
| } |
| |
| // Drop procedures (SPJs), UDFs (functions), and views |
| objectsQueue->position(); |
| for (int idx = 0; idx < objectsQueue->numEntries(); idx++) |
| { |
| OutputInfo * vi = (OutputInfo*)objectsQueue->getNext(); |
| |
| char * objName = vi->get(0); |
| NAString objectTypeLit = vi->get(1); |
| ComObjectType objectType = PrivMgr::ObjectLitToEnum(objectTypeLit.data()); |
| char buf[1000]; |
| NAString objectTypeString; |
| NAString cascade = " "; |
| |
| switch (objectType) |
| { |
| // These object types are handled later and can be ignored for now. |
| case COM_BASE_TABLE_OBJECT: |
| case COM_INDEX_OBJECT: |
| case COM_CHECK_CONSTRAINT_OBJECT: |
| case COM_NOT_NULL_CONSTRAINT_OBJECT: |
| case COM_REFERENTIAL_CONSTRAINT_OBJECT: |
| case COM_SEQUENCE_GENERATOR_OBJECT: |
| case COM_UNIQUE_CONSTRAINT_OBJECT: |
| case COM_LIBRARY_OBJECT: |
| { |
| continue; |
| } |
| |
| // If the library where procedures and functions reside is dropped |
| // before its procedures and routines, then these objects may |
| // not exist anymore, use the IF EXISTS to prevent the drop from |
| // incurring errors. |
| case COM_STORED_PROCEDURE_OBJECT: |
| { |
| objectTypeString = "PROCEDURE IF EXISTS "; |
| break; |
| } |
| case COM_USER_DEFINED_ROUTINE_OBJECT: |
| { |
| objectTypeString = "FUNCTION IF EXISTS "; |
| cascade = "CASCADE"; |
| break; |
| } |
| case COM_VIEW_OBJECT: |
| { |
| objectTypeString = "VIEW"; |
| cascade = "CASCADE"; |
| break; |
| } |
| // These object types should not be seen. |
| case COM_MV_OBJECT: |
| case COM_MVRG_OBJECT: |
| case COM_TRIGGER_OBJECT: |
| case COM_LOB_TABLE_OBJECT: |
| case COM_TRIGGER_TABLE_OBJECT: |
| case COM_SYNONYM_OBJECT: |
| case COM_PRIVATE_SCHEMA_OBJECT: |
| case COM_SHARED_SCHEMA_OBJECT: |
| case COM_EXCEPTION_TABLE_OBJECT: |
| case COM_LOCK_OBJECT: |
| case COM_MODULE_OBJECT: |
| default: |
| SEABASEDDL_INTERNAL_ERROR("Unrecognized object type in schema"); |
| goto label_error; |
| } |
| |
| dirtiedMetadata = TRUE; |
| str_sprintf(buf, "drop %s \"%s\".\"%s\".\"%s\" %s", |
| objectTypeString.data(),(char*)catName.data(),(char*)schName.data(), |
| objName,cascade.data()); |
| |
| cliRC = cliInterface.executeImmediate(buf); |
| if (cliRC < 0 && cliRC != -CAT_OBJECT_DOES_NOT_EXIST_IN_TRAFODION) |
| { |
| appendErrorObjName(errorObjs, objName); |
| if (dropSchemaNode->ddlXns()) |
| goto label_error; |
| else |
| someObjectsCouldNotBeDropped = true; |
| } |
| } |
| |
| // Drop libraries in the schema |
| objectsQueue->position(); |
| for (int idx = 0; idx < objectsQueue->numEntries(); idx++) |
| { |
| OutputInfo * vi = (OutputInfo*)objectsQueue->getNext(); |
| |
| char * objName = vi->get(0); |
| NAString objType = vi->get(1); |
| |
| if (objType == COM_LIBRARY_OBJECT_LIT) |
| { |
| char buf [1000]; |
| |
| dirtiedMetadata = TRUE; |
| str_sprintf(buf, "DROP LIBRARY \"%s\".\"%s\".\"%s\" CASCADE", |
| (char*)catName.data(), (char*)schName.data(), objName); |
| cliRC = cliInterface.executeImmediate(buf); |
| |
| if (cliRC < 0 && cliRC != -CAT_OBJECT_DOES_NOT_EXIST_IN_TRAFODION) |
| { |
| appendErrorObjName(errorObjs, objName); |
| if (dropSchemaNode->ddlXns()) |
| goto label_error; |
| else |
| someObjectsCouldNotBeDropped = true; |
| |
| } |
| } |
| } |
| |
| // Drop all tables in the schema. This will also drop any associated constraints. |
| |
| objectsQueue->position(); |
| for (int idx = 0; idx < objectsQueue->numEntries(); idx++) |
| { |
| OutputInfo * vi = (OutputInfo*)objectsQueue->getNext(); |
| |
| NAString objName = vi->get(0); |
| NAString objType = vi->get(1); |
| |
| // drop user objects first |
| if (objType == COM_BASE_TABLE_OBJECT_LIT) |
| { |
| // Histogram tables are dropped later. Sample tables |
| // are dropped when their corresponding tables are dropped |
| // so we don't need to drop them directly. Also, |
| // avoid any tables that match LOB dependent tablenames |
| // (there is no special type for these tables). |
| if (!isHistogramTable(objName) && |
| !isSampleTable(objName) && |
| !isLOBDependentNameMatch(objName)) |
| { |
| dirtiedMetadata = TRUE; |
| if (dropOneTable(cliInterface,(char*)catName.data(), |
| (char*)schName.data(),(char*)objName.data(), |
| isVolatile, FALSE,dropSchemaNode->ddlXns())) |
| { |
| appendErrorObjName(errorObjs, objName.data()); |
| if (dropSchemaNode->ddlXns()) |
| goto label_error; |
| else |
| someObjectsCouldNotBeDropped = true; |
| } |
| } |
| } |
| } |
| |
| // If there are any user tables having the LOB dependent name pattern, they |
| // will still be around. Drop those. The real LOB dependent tables, would |
| //have been dropped in the previous step |
| |
| |
| objectsQueue->position(); |
| for (int idx = 0; idx < objectsQueue->numEntries(); idx++) |
| { |
| OutputInfo * vi = (OutputInfo*)objectsQueue->getNext(); |
| |
| NAString objName = vi->get(0); |
| NAString objType = vi->get(1); |
| |
| if (objType == COM_BASE_TABLE_OBJECT_LIT) |
| { |
| if (!isHistogramTable(objName) && isLOBDependentNameMatch(objName)) |
| { |
| dirtiedMetadata = TRUE; |
| // Pass in TRUE for "ifExists" since the lobDependent tables |
| // would have already been dropped and we don't want those to |
| // raise errors. We just want to catch any user tables that |
| // happen to have the same name patterns. |
| if (dropOneTable(cliInterface,(char*)catName.data(), |
| (char*)schName.data(),(char*)objName.data(), |
| isVolatile,TRUE, dropSchemaNode->ddlXns())) |
| { |
| appendErrorObjName(errorObjs, objName.data()); |
| if (dropSchemaNode->ddlXns()) |
| goto label_error; |
| else |
| someObjectsCouldNotBeDropped = true; |
| } |
| } |
| } |
| } |
| |
| // Drop any remaining indexes. |
| |
| str_sprintf(query,"SELECT TRIM(object_name), TRIM(object_type) " |
| "FROM %s.\"%s\".%s " |
| "WHERE catalog_name = '%s' AND " |
| " schema_name = '%s' AND " |
| " object_type = '%s' " |
| "FOR READ COMMITTED ACCESS ", |
| getSystemCatalog(),SEABASE_MD_SCHEMA,SEABASE_OBJECTS, |
| (char*)catName.data(),(char*)schName.data(), |
| COM_INDEX_OBJECT_LIT); |
| cliRC = cliInterface.fetchAllRows(otherObjectsQueue,query,0,FALSE,FALSE,TRUE); |
| if (cliRC < 0) |
| { |
| cliInterface.retrieveSQLDiagnostics(CmpCommon::diags()); |
| goto label_error; |
| } |
| |
| otherObjectsQueue->position(); |
| for (int idx = 0; idx < otherObjectsQueue->numEntries(); idx++) |
| { |
| OutputInfo * vi = (OutputInfo*)otherObjectsQueue->getNext(); |
| char * objName = vi->get(0); |
| NAString objType = vi->get(1); |
| |
| if (objType == COM_INDEX_OBJECT_LIT) |
| { |
| char buf [1000]; |
| |
| dirtiedMetadata = TRUE; |
| str_sprintf(buf, "DROP INDEX \"%s\".\"%s\".\"%s\" CASCADE", |
| (char*)catName.data(), (char*)schName.data(), objName); |
| cliRC = cliInterface.executeImmediate(buf); |
| |
| if (cliRC < 0 && cliRC != -CAT_OBJECT_DOES_NOT_EXIST_IN_TRAFODION) |
| { |
| appendErrorObjName(errorObjs, objName); |
| if (dropSchemaNode->ddlXns()) |
| goto label_error; |
| else |
| someObjectsCouldNotBeDropped = true; |
| |
| } |
| } |
| } |
| |
| // Drop any remaining sequences. |
| |
| str_sprintf(query,"SELECT TRIM(object_name), TRIM(object_type) " |
| "FROM %s.\"%s\".%s " |
| "WHERE catalog_name = '%s' AND " |
| " schema_name = '%s' AND " |
| " object_type = '%s' " |
| "FOR READ COMMITTED ACCESS ", |
| getSystemCatalog(),SEABASE_MD_SCHEMA,SEABASE_OBJECTS, |
| (char*)catName.data(),(char*)schName.data(), |
| COM_SEQUENCE_GENERATOR_OBJECT_LIT); |
| |
| cliRC = cliInterface.fetchAllRows(otherObjectsQueue,query,0,FALSE,FALSE,TRUE); |
| if (cliRC < 0) |
| { |
| cliInterface.retrieveSQLDiagnostics(CmpCommon::diags()); |
| goto label_error; |
| } |
| |
| otherObjectsQueue->position(); |
| for (int idx = 0; idx < otherObjectsQueue->numEntries(); idx++) |
| { |
| OutputInfo * vi = (OutputInfo*)otherObjectsQueue->getNext(); |
| char * objName = vi->get(0); |
| NAString objType = vi->get(1); |
| |
| if (objType == COM_SEQUENCE_GENERATOR_OBJECT_LIT) |
| { |
| char buf [1000]; |
| |
| dirtiedMetadata = TRUE; |
| str_sprintf(buf, "DROP SEQUENCE \"%s\".\"%s\".\"%s\"", |
| (char*)catName.data(), (char*)schName.data(), objName); |
| cliRC = cliInterface.executeImmediate(buf); |
| |
| if (cliRC < 0 && cliRC != -CAT_OBJECT_DOES_NOT_EXIST_IN_TRAFODION) |
| { |
| appendErrorObjName(errorObjs, objName); |
| if (dropSchemaNode->ddlXns()) |
| goto label_error; |
| else |
| someObjectsCouldNotBeDropped = true; |
| |
| } |
| } |
| } |
| |
| // Drop histogram tables last |
| objectsQueue->position(); |
| for (size_t i = 0; i < objectsQueue->numEntries(); i++) |
| { |
| OutputInfo * vi = (OutputInfo*)objectsQueue->getNext(); |
| NAString objName = vi->get(0); |
| |
| if (isHistogramTable(objName)) |
| { |
| dirtiedMetadata = TRUE; |
| if (dropOneTable(cliInterface,(char*)catName.data(), |
| (char*)schName.data(),(char*)objName.data(), |
| isVolatile, FALSE, dropSchemaNode->ddlXns())) |
| { |
| appendErrorObjName(errorObjs, objName.data()); |
| |
| if (dropSchemaNode->ddlXns()) |
| goto label_error; |
| else |
| someObjectsCouldNotBeDropped = true; |
| } |
| } |
| } |
| |
| if (someObjectsCouldNotBeDropped) |
| { |
| NAString reason; |
| reason = "Reason: Some objects could not be dropped in schema " |
| + schName + ". ObjectsInSchema: " |
| + errorObjs; |
| *CmpCommon::diags() << DgSqlCode(-CAT_UNABLE_TO_DROP_SCHEMA) |
| << DgSchemaName(catName + "." + schName) |
| << DgString0(reason); |
| goto label_error; |
| } |
| |
| // For volatile schemas, sometimes only the objects get dropped. |
| // If the dropObjectsOnly flag is set, just exit now, we are done. |
| if (dropSchemaNode->dropObjectsOnly()) |
| return; |
| |
| // Verify all objects in the schema have been dropped. |
| str_sprintf(query,"SELECT COUNT(*) " |
| "FROM %s.\"%s\".%s " |
| "WHERE catalog_name = '%s' AND schema_name = '%s' AND " |
| "object_name <> '" SEABASE_SCHEMA_OBJECTNAME"'" |
| "FOR READ COMMITTED ACCESS", |
| getSystemCatalog(),SEABASE_MD_SCHEMA,SEABASE_OBJECTS, |
| (char*)catName.data(),(char*)schName.data()); |
| |
| cliRC = cliInterface.executeImmediate(query,(char*)&rowCount,&length,FALSE); |
| |
| if (cliRC < 0) |
| { |
| cliInterface.retrieveSQLDiagnostics(CmpCommon::diags()); |
| goto label_error; |
| } |
| |
| if (rowCount > 0) |
| { |
| CmpCommon::diags()->clear(); |
| |
| str_sprintf(query,"SELECT TRIM(object_name) " |
| "FROM %s.\"%s\".%s " |
| "WHERE catalog_name = '%s' AND schema_name = '%s' AND " |
| "object_name <> '" SEABASE_SCHEMA_OBJECTNAME"' AND " |
| "object_type <> 'PK' " |
| "FOR READ COMMITTED ACCESS", |
| getSystemCatalog(),SEABASE_MD_SCHEMA,SEABASE_OBJECTS, |
| (char*)catName.data(),(char*)schName.data()); |
| |
| cliRC = cliInterface.fetchAllRows(objectsQueue, query, 0, FALSE, FALSE, TRUE); |
| if (cliRC < 0) |
| { |
| cliInterface.retrieveSQLDiagnostics(CmpCommon::diags()); |
| goto label_error; |
| } |
| |
| for (int i = 0; i < objectsQueue->numEntries(); i++) |
| { |
| OutputInfo * vi = (OutputInfo*)objectsQueue->getNext(); |
| NAString objName = vi->get(0); |
| |
| appendErrorObjName(errorObjs, objName.data()); |
| } |
| |
| NAString reason; |
| reason = "Reason: schema " |
| + schName + " is not empty. ObjectsInSchema: " |
| + errorObjs; |
| *CmpCommon::diags() << DgSqlCode(-CAT_UNABLE_TO_DROP_SCHEMA) |
| << DgSchemaName(catName + "." + schName) |
| << DgString0(reason); |
| goto label_error; |
| } |
| |
| // After all objects in the schema have been dropped, drop the schema object itself. |
| |
| char buf [1000]; |
| |
| dirtiedMetadata = TRUE; |
| str_sprintf(buf,"DELETE FROM %s.\"%s\".%s " |
| "WHERE CATALOG_NAME = '%s' AND SCHEMA_NAME = '%s' AND " |
| "OBJECT_NAME = '" SEABASE_SCHEMA_OBJECTNAME"'", |
| getSystemCatalog(),SEABASE_MD_SCHEMA,SEABASE_OBJECTS, |
| (char*)catName.data(),(char*)schName.data()); |
| cliRC = cliInterface.executeImmediate(buf); |
| if (cliRC < 0 && cliRC != -CAT_OBJECT_DOES_NOT_EXIST_IN_TRAFODION) |
| { |
| NAString reason; |
| reason = "Reason: Delete of object " + |
| NAString(SEABASE_SCHEMA_OBJECTNAME) + " failed."; |
| *CmpCommon::diags() << DgSqlCode(-CAT_UNABLE_TO_DROP_SCHEMA) |
| << DgSchemaName(catName + "." + schName) |
| << DgString0(reason); |
| goto label_error; |
| } |
| |
| //Drop comment in TEXT table for schema |
| str_sprintf(buf, "delete from %s.\"%s\".%s where text_uid = %ld", |
| getSystemCatalog(),SEABASE_MD_SCHEMA,SEABASE_TEXT, |
| schemaUID); |
| cliRC = cliInterface.executeImmediate(buf); |
| if (cliRC < 0) |
| { |
| cliInterface.retrieveSQLDiagnostics(CmpCommon::diags()); |
| goto label_error; |
| } |
| |
| // Everything succeeded, return |
| return; |
| |
| label_error: |
| // If metadata has not been changed, just return |
| if (!dirtiedMetadata) |
| { |
| return; |
| } |
| |
| // Add an error asking for user to cleanup schema |
| *CmpCommon::diags() << DgSqlCode(-CAT_ATTEMPT_CLEANUP_SCHEMA) |
| << DgSchemaName(catName + "." + schName); |
| |
| return; |
| } |
| //****************** End of CmpSeabaseDDL::dropSeabaseSchema ******************* |
| |
| |
| // ***************************************************************************** |
| // * * |
| // * Function: CmpSeabaseDDL::alterSeabaseSchema * |
| // * * |
| // * Implements the ALTER SCHEMA command. * |
| // * * |
| // ***************************************************************************** |
| // * * |
| // * Parameters: * |
| // * * |
| // * <alterSchemaNode> StmtDDLAlterSchema * In * |
| // * is a pointer to a create schema parser node. * |
| // * * |
| // ***************************************************************************** |
| void CmpSeabaseDDL::alterSeabaseSchema(StmtDDLAlterSchema * alterSchemaNode) |
| |
| { |
| Lng32 cliRC = 0; |
| |
| ComSchemaName schemaName(alterSchemaNode->getSchemaName()); |
| NAString catName = schemaName.getCatalogNamePartAsAnsiString(); |
| ComAnsiNamePart schNameAsComAnsi = schemaName.getSchemaNamePart(); |
| NAString schName = schNameAsComAnsi.getInternalName(); |
| ComObjectName objName(catName,schName,NAString("dummy"),COM_TABLE_NAME,TRUE); |
| |
| ExeCliInterface cliInterface(STMTHEAP, 0, NULL, |
| CmpCommon::context()->sqlSession()->getParentQid()); |
| Int32 objectOwnerID = 0; |
| Int32 schemaOwnerID = 0; |
| ComObjectType objectType; |
| |
| bool isVolatile = (memcmp(schName.data(),"VOLATILE_SCHEMA",strlen("VOLATILE_SCHEMA")) == 0); |
| int32_t length = 0; |
| Int64 rowCount = 0; |
| bool someObjectsCouldNotBeAltered = false; |
| char errorObjs[1010]; |
| Queue * objectsQueue = NULL; |
| Queue * otherObjectsQueue = NULL; |
| |
| NABoolean dirtiedMetadata = FALSE; |
| Int32 checkErr = 0; |
| |
| StmtDDLAlterTableStoredDesc::AlterStoredDescType sdo = |
| alterSchemaNode->getStoredDescOperation(); |
| |
| errorObjs[0] = 0; |
| |
| Int64 schemaUID = getObjectTypeandOwner(&cliInterface,catName.data(),schName.data(), |
| SEABASE_SCHEMA_OBJECTNAME,objectType,schemaOwnerID); |
| |
| // if schemaUID == -1, then either the schema does not exist or an unexpected error occurred |
| if (schemaUID == -1) |
| { |
| // If an error occurred, return |
| if (CmpCommon::diags()->getNumber(DgSqlCode::ERROR_) > 0) |
| goto label_error; |
| |
| // A Trafodion schema does not exist if the schema object row is not |
| // present: CATALOG-NAME.SCHEMA-NAME.__SCHEMA__. |
| *CmpCommon::diags() << DgSqlCode(-CAT_SCHEMA_DOES_NOT_EXIST_ERROR) |
| << DgString0(catName.data()) |
| << DgString1(schName.data()); |
| goto label_error; |
| } |
| |
| if (!isDDLOperationAuthorized(SQLOperation::ALTER_SCHEMA, |
| schemaOwnerID,schemaOwnerID)) |
| { |
| *CmpCommon::diags() << DgSqlCode(-CAT_NOT_AUTHORIZED); |
| goto label_error; |
| } |
| |
| if ((isSeabaseReservedSchema(objName) || |
| (schName == SEABASE_SYSTEM_SCHEMA)) && |
| !Get_SqlParser_Flags(INTERNAL_QUERY_FROM_EXEUTIL)) |
| { |
| *CmpCommon::diags() << DgSqlCode(-CAT_USER_CANNOT_DROP_SMD_SCHEMA) |
| << DgSchemaName(schemaName.getExternalName().data()); |
| goto label_error; |
| } |
| |
| // Can't alter a schema whose name begins with VOLATILE_SCHEMA unless the |
| // keyword VOLATILE was specified in the ALTER SCHEMA command. |
| if (isVolatile && !alterSchemaNode->isVolatile()) |
| { |
| *CmpCommon::diags() << DgSqlCode(-CAT_RESERVED_METADATA_SCHEMA_NAME) |
| << DgTableName(schName); |
| goto label_error; |
| } |
| |
| if (alterSchemaNode->isDropAllTables()) |
| { |
| // should not reach here, is transformed to DropSchema during parsing |
| *CmpCommon::diags() << DgSqlCode(-3242) |
| << DgString0("Should not reach here. Should have been transformed to DropSchema during parsing."); |
| goto label_error; |
| } |
| |
| if (alterSchemaNode->isRenameSchema()) |
| { |
| // Not yet supported |
| *CmpCommon::diags() << DgSqlCode(-3242) |
| << DgString0("Cannot rename a schema."); |
| goto label_error; |
| } |
| |
| if (NOT alterSchemaNode->isAlterStoredDesc()) |
| { |
| // unsupported option |
| *CmpCommon::diags() << DgSqlCode(-3242) |
| << DgString0("Unsupported option specified."); |
| goto label_error; |
| } |
| |
| // Get a list of all objects in the schema, excluding the schema object itself. |
| char query[4000]; |
| |
| // select objects in the schema to alter |
| str_sprintf(query,"SELECT distinct TRIM(object_name), TRIM(object_type), object_uid " |
| "FROM %s.\"%s\".%s " |
| "WHERE catalog_name = '%s' AND schema_name = '%s' AND " |
| "object_name <> '" SEABASE_SCHEMA_OBJECTNAME"' AND " |
| "(object_type = 'BT' OR " |
| " object_type = 'VI') " |
| "FOR READ COMMITTED ACCESS", |
| getSystemCatalog(),SEABASE_MD_SCHEMA,SEABASE_OBJECTS, |
| (char*)catName.data(),(char*)schName.data()); |
| |
| cliRC = cliInterface.fetchAllRows(objectsQueue, query, 0, FALSE, FALSE, TRUE); |
| if (cliRC < 0) |
| { |
| cliInterface.retrieveSQLDiagnostics(CmpCommon::diags()); |
| goto label_error; |
| } |
| |
| objectsQueue->position(); |
| for (int idx = 0; idx < objectsQueue->numEntries(); idx++) |
| { |
| OutputInfo * vi = (OutputInfo*)objectsQueue->getNext(); |
| |
| NAString objName = vi->get(0); |
| NAString objType = vi->get(1); |
| Int64 objUID = *(Int64*)vi->get(2); |
| |
| if (sdo == StmtDDLAlterTableStoredDesc::GENERATE) |
| { |
| cliRC = |
| updateObjectRedefTime(&cliInterface, |
| getSystemCatalog(), schName, objName, |
| COM_BASE_TABLE_OBJECT_LIT, |
| -1, objUID, TRUE); |
| if (cliRC < 0) |
| { |
| // append error and move on to next one |
| appendErrorObjName(errorObjs, objName); |
| someObjectsCouldNotBeAltered = true; |
| |
| CmpCommon::diags()->clear(); |
| } |
| } |
| else if (sdo == StmtDDLAlterTableStoredDesc::DELETE) |
| { |
| cliRC = deleteFromTextTable |
| (&cliInterface, objUID, COM_STORED_DESC_TEXT, 0); |
| if (cliRC < 0) |
| { |
| // append error and move on to next one |
| appendErrorObjName(errorObjs, objName); |
| someObjectsCouldNotBeAltered = true; |
| |
| CmpCommon::diags()->clear(); |
| } |
| |
| } // delete stored desc |
| else if (sdo == StmtDDLAlterTableStoredDesc::ENABLE) |
| { |
| Int64 flags = MD_OBJECTS_DISABLE_STORED_DESC; |
| cliRC = updateObjectFlags(&cliInterface, objUID, flags, TRUE); |
| if (cliRC < 0) |
| { |
| appendErrorObjName(errorObjs, objName); |
| someObjectsCouldNotBeAltered = true; |
| |
| CmpCommon::diags()->clear(); |
| } |
| } |
| else if (sdo == StmtDDLAlterTableStoredDesc::DISABLE) |
| { |
| Int64 flags = MD_OBJECTS_DISABLE_STORED_DESC; |
| cliRC = updateObjectFlags(&cliInterface, objUID, flags, FALSE); |
| if (cliRC < 0) |
| { |
| appendErrorObjName(errorObjs, objName); |
| someObjectsCouldNotBeAltered = true; |
| |
| CmpCommon::diags()->clear(); |
| } |
| } |
| else if (sdo == StmtDDLAlterTableStoredDesc::CHECK) |
| { |
| cliRC = checkAndGetStoredObjectDesc(&cliInterface, objUID, NULL); |
| CmpCommon::diags()->clear(); |
| if (cliRC < 0) |
| { |
| checkErr = cliRC; |
| appendErrorObjName(errorObjs, objName); |
| someObjectsCouldNotBeAltered = true; |
| } |
| } |
| |
| } // for |
| |
| if (someObjectsCouldNotBeAltered) |
| { |
| NAString reason; |
| if (sdo == StmtDDLAlterTableStoredDesc::CHECK) |
| { |
| reason = "Reason: Following objects failed stored descriptor check"; |
| if (checkErr == -1) |
| reason += " (object could not be accessed) "; |
| else if (checkErr == -2) |
| reason += " (object does not exist) "; |
| else if (checkErr == -3) |
| reason += " (change in stored structures) "; |
| reason += ": "; |
| reason += errorObjs; |
| } |
| else |
| reason = "Reason: Some objects could not be accessed in schema " |
| + schName + ". ObjectsInSchema: " |
| + errorObjs; |
| *CmpCommon::diags() << DgSqlCode(-CAT_UNABLE_TO_ALTER_SCHEMA) |
| << DgSchemaName(catName + "." + schName) |
| << DgString0(reason); |
| goto label_error; |
| } |
| |
| // Everything succeeded, return |
| return; |
| |
| label_error: |
| return; |
| } |
| //****************** End of CmpSeabaseDDL::alterSeabaseSchema ***************** |
| |
| |
| // ***************************************************************************** |
| // * * |
| // * Function: CmpSeabaseDDL::giveSeabaseSchema * |
| // * * |
| // * Implements the GIVE SCHEMA command. * |
| // * * |
| // ***************************************************************************** |
| // * * |
| // * Parameters: * |
| // * * |
| // * <giveSchemaNode> StmtDDLGiveSchema * In * |
| // * is a pointer to a create schema parser node. * |
| // * * |
| // * <currentCatalogName> NAString & In * |
| // * is the name of the current catalog. * |
| // * * |
| // ***************************************************************************** |
| void CmpSeabaseDDL::giveSeabaseSchema( |
| StmtDDLGiveSchema * giveSchemaNode, |
| NAString & currentCatalogName) |
| |
| { |
| |
| ComDropBehavior dropBehavior = giveSchemaNode->getDropBehavior(); |
| NAString catalogName = giveSchemaNode->getCatalogName(); |
| NAString schemaName = giveSchemaNode->getSchemaName(); |
| |
| if (catalogName.isNull()) |
| catalogName = currentCatalogName; |
| |
| ExeCliInterface cliInterface(STMTHEAP, 0, NULL, |
| CmpCommon::context()->sqlSession()->getParentQid()); |
| Int32 objectOwnerID = 0; |
| Int32 schemaOwnerID = 0; |
| ComObjectType objectType; |
| |
| Int64 schemaUID = getObjectTypeandOwner(&cliInterface,catalogName.data(), |
| schemaName.data(),SEABASE_SCHEMA_OBJECTNAME, |
| objectType,schemaOwnerID); |
| |
| if (schemaUID == -1) |
| { |
| // A Trafodion schema does not exist if the schema object row is not |
| // present: CATALOG-NAME.SCHEMA-NAME.__SCHEMA__. |
| *CmpCommon::diags() << DgSqlCode(-CAT_SCHEMA_DOES_NOT_EXIST_ERROR) |
| << DgString0(catalogName.data()) |
| << DgString1(schemaName.data()); |
| return; |
| } |
| |
| // ***************************************************************************** |
| // * * |
| // * A schema owner can give their own schema to another authID, but they * |
| // * cannot give the objects in a shared schema to another authID. Only * |
| // * DB__ROOT or a user with the ALTER_SCHEMA privilege can change the owners * |
| // * of objects in a shared schema. So if the schema is private, or if only * |
| // * the schema is being given, we do standard authentication checking. But * |
| // * if giving all the objects in a shared schema, we change the check ID to * |
| // * the default user to force the ALTER_SCHEMA privilege check. * |
| // * * |
| // ***************************************************************************** |
| |
| int32_t checkID = schemaOwnerID; |
| |
| if (objectType == COM_SHARED_SCHEMA_OBJECT && |
| dropBehavior == COM_CASCADE_DROP_BEHAVIOR) |
| checkID = NA_UserIdDefault; |
| |
| if (!isDDLOperationAuthorized(SQLOperation::ALTER_SCHEMA,checkID,checkID)) |
| { |
| *CmpCommon::diags() << DgSqlCode(-CAT_NOT_AUTHORIZED); |
| return; |
| } |
| |
| ComObjectName objName(catalogName,schemaName,NAString("dummy"),COM_TABLE_NAME,TRUE); |
| |
| if (isSeabaseReservedSchema(objName) && |
| !Get_SqlParser_Flags(INTERNAL_QUERY_FROM_EXEUTIL)) |
| { |
| *CmpCommon::diags() << DgSqlCode(-CAT_USER_CANNOT_DROP_SMD_SCHEMA) |
| << DgSchemaName(schemaName.data()); |
| return; |
| } |
| |
| bool isVolatile = (memcmp(schemaName.data(),"VOLATILE_SCHEMA",strlen("VOLATILE_SCHEMA")) == 0); |
| |
| // Can't give a schema whose name begins with VOLATILE_SCHEMA. |
| if (isVolatile) |
| { |
| *CmpCommon::diags() << DgSqlCode(-CAT_RESERVED_METADATA_SCHEMA_NAME) |
| << DgTableName(schemaName); |
| return; |
| } |
| |
| int32_t newOwnerID = -1; |
| |
| if (ComUser::getAuthIDFromAuthName(giveSchemaNode->getAuthID().data(), |
| newOwnerID) != 0) |
| { |
| *CmpCommon::diags() << DgSqlCode(-CAT_AUTHID_DOES_NOT_EXIST_ERROR) |
| << DgString0(giveSchemaNode->getAuthID().data()); |
| return; |
| } |
| |
| // ***************************************************************************** |
| // * * |
| // * Drop behavior is only relevant for shared schemas. For shared schemas, * |
| // * ownership of the schema OR the schema and all its objects may be given to * |
| // * another authorization ID. For private schemas, all objects are owned by * |
| // * the schema owner, so the drop behavior is always CASCADE. * |
| // * * |
| // * NOTE: The syntax for drop behavior always defaults to RESTRICT; for * |
| // * private schemas this is simply ignored, as opposed to requiring * |
| // * users to always specify CASCASE. * |
| // * * |
| // ***************************************************************************** |
| |
| Lng32 cliRC = 0; |
| char buf[4000]; |
| |
| if (objectType == COM_SHARED_SCHEMA_OBJECT && |
| dropBehavior == COM_RESTRICT_DROP_BEHAVIOR) |
| { |
| str_sprintf(buf,"UPDATE %s.\"%s\".%s " |
| "SET object_owner = %d " |
| "WHERE object_UID = %ld", |
| getSystemCatalog(),SEABASE_MD_SCHEMA,SEABASE_OBJECTS, |
| newOwnerID,schemaUID); |
| cliRC = cliInterface.executeImmediate(buf); |
| if (cliRC < 0) |
| cliInterface.retrieveSQLDiagnostics(CmpCommon::diags()); |
| |
| return; |
| } |
| // |
| // At this point, we are giving all objects in the schema (as well as the |
| // schema itself) to the new authorization ID. If authentication is enabled, |
| // update the privileges first. |
| // |
| if (isAuthorizationEnabled()) |
| { |
| int32_t rc = transferObjectPrivs(getSystemCatalog(),catalogName.data(), |
| schemaName.data(),newOwnerID, |
| giveSchemaNode->getAuthID().data()); |
| if (rc != 0) |
| { |
| if (CmpCommon::diags()->getNumber(DgSqlCode::ERROR_) == 0) |
| { |
| //TODO: add error |
| |
| } |
| return; |
| } |
| } |
| |
| // Now update the object owner for all objects in the schema. |
| |
| str_sprintf(buf,"UPDATE %s.\"%s\".%s " |
| "SET object_owner = %d " |
| "WHERE catalog_name = '%s' AND schema_name = '%s'", |
| getSystemCatalog(),SEABASE_MD_SCHEMA,SEABASE_OBJECTS, |
| newOwnerID,catalogName.data(),schemaName.data()); |
| cliRC = cliInterface.executeImmediate(buf); |
| if (cliRC < 0) |
| { |
| cliInterface.retrieveSQLDiagnostics(CmpCommon::diags()); |
| return; |
| } |
| |
| // Verify all objects in the schema have been given to the new owner. |
| str_sprintf(buf,"SELECT COUNT(*) " |
| "FROM %s.\"%s\".%s " |
| "WHERE catalog_name = '%s' AND schema_name = '%s' AND " |
| "object_name <> '" SEABASE_SCHEMA_OBJECTNAME"' AND " |
| "object_owner <> %d " |
| "FOR READ COMMITTED ACCESS", |
| getSystemCatalog(),SEABASE_MD_SCHEMA,SEABASE_OBJECTS, |
| catalogName.data(),schemaName.data(),newOwnerID); |
| |
| int32_t length = 0; |
| Int64 rowCount = 0; |
| |
| cliRC = cliInterface.executeImmediate(buf,(char*)&rowCount,&length,FALSE); |
| |
| if (cliRC < 0) |
| { |
| cliInterface.retrieveSQLDiagnostics(CmpCommon::diags()); |
| return; |
| } |
| |
| if (rowCount > 0) |
| { |
| SEABASEDDL_INTERNAL_ERROR("Not all objects in schema were given"); |
| return; |
| } |
| |
| } |
| //****************** End of CmpSeabaseDDL::giveSeabaseSchema ******************* |
| |
| |
| |
| // ***************************************************************************** |
| // Private/static functions |
| // ***************************************************************************** |
| |
| |
| // ***************************************************************************** |
| // * * |
| // * Function: createHistogramTables * |
| // * * |
| // * Creates all the histogram tables * |
| // * * |
| // ***************************************************************************** |
| // * * |
| // * Parameters: * |
| // * * |
| // * <cliInterface> ExeCliInterface * In * |
| // * is a reference to an Executor CLI interface handle. * |
| // * * |
| // * <schemaName> NAString & In * |
| // * is the catalog.schema of the histogram table to create. * |
| // * * |
| // * <ignoreIfExists> NABoolean In * |
| // * do not return an error if table already exists * |
| // * * |
| // * <tableNotCreeated> NAString & Out * |
| // * returns the name of first histogram table that could not be created * |
| // * * |
| // ***************************************************************************** |
| // * * |
| // * Returns: Int32 * |
| // * * |
| // * -mainSQLCODE: Could not create histogram tables. * |
| // * 0: Create was successful. * |
| // * * |
| // ***************************************************************************** |
| short CmpSeabaseDDL::createHistogramTables( |
| ExeCliInterface *cliInterface, |
| const NAString &schemaName, |
| const NABoolean ignoreIfExists, |
| NAString &tableNotCreated) |
| { |
| Int32 cliRC = 0; |
| tableNotCreated = ""; |
| |
| // allMDHistInfo (CmpSeabaseDDLmd.h) is the list of all histogram tables, |
| // MDTableInfo describes the table attributes, |
| // create each table found in the list |
| Int32 numHistTables = sizeof(allMDHistInfo) / sizeof(MDTableInfo); |
| NAString prefixText = ignoreIfExists ? "IF NOT EXISTS " : ""; |
| for (Int32 i = 0; i < numHistTables; i++) |
| { |
| const MDTableInfo &mdh = allMDHistInfo[i]; |
| Int32 qryArraySize = mdh.sizeOfnewDDL / sizeof(QString); |
| |
| // Concatenate the create table text into a single string |
| NAString concatenatedQuery; |
| for (Int32 j = 0; j < qryArraySize; j++) |
| { |
| NAString tempStr = mdh.newDDL[j].str; |
| concatenatedQuery += tempStr.strip(NAString::leading, ' '); |
| } |
| |
| // qualify create table text with (optional) "IF NOT EXISTS" & schema name |
| // and place in front of the table name: |
| // "create table <textInsertion> hist-table ..." |
| std::string tableDDL (concatenatedQuery.data()); |
| NAString textInsertion = prefixText + schemaName + "."; |
| size_t pos = tableDDL.find_first_of(mdh.newName); |
| if (pos == string::npos) |
| { |
| NAString errorText ("Unexpected error occurred while parsing create text for histogram table "); |
| errorText += mdh.newName; |
| SEABASEDDL_INTERNAL_ERROR(errorText.data()); |
| tableNotCreated = mdh.newName; |
| return -CAT_INTERNAL_EXCEPTION_ERROR; |
| } |
| tableDDL = tableDDL.insert(pos, textInsertion.data()); |
| |
| // If the caller does not send in cliInterface, instantiate one now |
| ExeCliInterface cli; |
| if (cliInterface == NULL) |
| { |
| ExeCliInterface newCli(STMTHEAP, NULL, NULL, |
| CmpCommon::context()->sqlSession()->getParentQid()); |
| cli = newCli; |
| } |
| else |
| cli = *cliInterface; |
| |
| // Create the table |
| cliRC = cli.executeImmediate(tableDDL.c_str()); |
| if (cliRC < 0) |
| { |
| cli.retrieveSQLDiagnostics(CmpCommon::diags()); |
| tableNotCreated = mdh.newName; |
| return cliRC; |
| } |
| } |
| return 0; |
| } |
| //************************ End of createHistogramTables ************************ |
| |
| |
| // ***************************************************************************** |
| // * * |
| // * Function: adjustHiveExternalSchemas * |
| // * * |
| // * Changes the ownership and privilege grants to DB__HIVEROLE * |
| // * * |
| // ***************************************************************************** |
| // * * |
| // * Parameters: * |
| // * * |
| // * <cliInterface> ExeCliInterface * In * |
| // * is a reference to an Executor CLI interface handle. * |
| // ***************************************************************************** |
| // * * |
| // * Returns: Int32 * |
| // * * |
| // * 0: Adjustment was successful * |
| // * -1: Adjustment failed * |
| // * * |
| // ***************************************************************************** |
| short CmpSeabaseDDL::adjustHiveExternalSchemas(ExeCliInterface *cliInterface) |
| { |
| char buf[sizeof(SEABASE_MD_SCHEMA) + |
| sizeof(SEABASE_OBJECTS) + |
| strlen(getSystemCatalog()) + 300]; |
| |
| // get all the objects in special hive schemas |
| sprintf(buf, "SELECT catalog_name, schema_name, object_name, object_uid, object_type, object_owner " |
| " from %s.\"%s\".%s WHERE schema_name like '_HV_%c_'", |
| getSystemCatalog(), SEABASE_MD_SCHEMA, SEABASE_OBJECTS, '%'); |
| |
| Queue * objectsQueue = NULL; |
| Int32 cliRC = cliInterface->fetchAllRows(objectsQueue, buf, 0, FALSE, FALSE, TRUE); |
| if (cliRC < 0) |
| { |
| cliInterface->retrieveSQLDiagnostics(CmpCommon::diags()); |
| return -1; |
| } |
| |
| // adjust owner and privilege information for external hive objects |
| objectsQueue->position(); |
| for (size_t i = 0; i < objectsQueue->numEntries(); i++) |
| { |
| OutputInfo * vi = (OutputInfo*)objectsQueue->getNext(); |
| NAString catName = vi->get(0); |
| NAString schName = vi->get(1); |
| NAString objName = vi->get(2); |
| Int64 objUID = *(Int64*)vi->get(3); |
| NAString objectTypeLit = vi->get(4); |
| Int32 objOwner = *(Int32*)vi->get(5); |
| ComObjectType objType = PrivMgr::ObjectLitToEnum(objectTypeLit.data()); |
| |
| // If object owner is already the HIVE_ROLE_ID, then we are done. |
| if (objOwner == HIVE_ROLE_ID) |
| continue; |
| else |
| { |
| // only need to adjust privileges on securable items |
| if (PrivMgr::isSecurableObject(objType)) |
| { |
| ComObjectName tblName(catName, schName, objName, COM_TABLE_NAME, |
| ComAnsiNamePart::INTERNAL_FORMAT, STMTHEAP); |
| |
| NAString extTblName = tblName.getExternalName(TRUE); |
| |
| // remove existing privs on object |
| if (!deletePrivMgrInfo(extTblName, objUID, objType)) |
| return -1; |
| |
| // add owner privs |
| if (!insertPrivMgrInfo(objUID, extTblName, objType, |
| HIVE_ROLE_ID, HIVE_ROLE_ID, ComUser::getCurrentUser())) |
| return -1; |
| } |
| |
| // update schema_owner and objectOwner for object |
| sprintf(buf,"UPDATE %s.\"%s\".%s SET object_owner = %d " |
| ", schema_owner = %d WHERE object_uid = %ld ", |
| getSystemCatalog(),SEABASE_MD_SCHEMA,SEABASE_OBJECTS, |
| HIVE_ROLE_ID, HIVE_ROLE_ID, objUID); |
| cliRC = cliInterface->executeImmediate(buf); |
| if (cliRC < 0) |
| { |
| cliInterface->retrieveSQLDiagnostics(CmpCommon::diags()); |
| return -1; |
| } |
| } |
| } |
| |
| return 0; |
| } |
| //********************* End of adjustHiveExternalTables ************************ |
| |
| // ***************************************************************************** |
| // * * |
| // * Function: dropOneTable * |
| // * * |
| // * Drops a table and all its dependent objects. * |
| // * * |
| // ***************************************************************************** |
| // * * |
| // * Parameters: * |
| // * * |
| // * <cliInterface> ExeCliInterface & In * |
| // * is a reference to an Executor CLI interface handle. * |
| // * * |
| // * <catalogName> const char * In * |
| // * is the catalog of the table to drop. * |
| // * * |
| // * <schemaName> const char * In * |
| // * is the schema of the table to drop. * |
| // * * |
| // * <objectName> const char * In * |
| // * is the name of the table to drop. * |
| // * * |
| // * <isVolatile> bool In * |
| // * is true if the object is volatile or part of a volatile schema. * |
| // * * |
| // ***************************************************************************** |
| // * * |
| // * Returns: bool * |
| // * * |
| // * true: Could not drop table or one of its dependent objects. * |
| // * false: Drop successful or could not set CQD for NATable cache reload. * |
| // * * |
| // ***************************************************************************** |
| static bool dropOneTable( |
| ExeCliInterface & cliInterface, |
| const char * catalogName, |
| const char * schemaName, |
| const char * objectName, |
| bool isVolatile, |
| bool ifExists, |
| bool ddlXns) |
| |
| { |
| |
| char buf [1000]; |
| |
| bool someObjectsCouldNotBeDropped = false; |
| |
| char volatileString[20] = {0}; |
| char ifExistsString[20] = {0}; |
| Lng32 cliRC = 0; |
| |
| |
| |
| if (isVolatile && |
| strcmp(objectName, HBASE_HIST_NAME) != 0 && |
| strcmp(objectName, HBASE_HISTINT_NAME) != 0 && |
| strcmp(objectName, HBASE_PERS_SAMP_NAME) != 0) |
| strcpy(volatileString,"VOLATILE"); |
| |
| if (ifExists) |
| strcpy(ifExistsString,"IF EXISTS"); |
| |
| if (ComIsTrafodionExternalSchemaName(schemaName)) |
| str_sprintf(buf,"DROP EXTERNAL TABLE \"%s\" FOR \"%s\".\"%s\".\"%s\" CASCADE", |
| objectName,catalogName,schemaName,objectName); |
| else |
| str_sprintf(buf,"DROP %s TABLE %s \"%s\".\"%s\".\"%s\" CASCADE", |
| volatileString, ifExistsString, catalogName,schemaName,objectName); |
| |
| ULng32 savedParserFlags = Get_SqlParser_Flags(0xFFFFFFFF); |
| |
| try |
| { |
| Set_SqlParser_Flags(INTERNAL_QUERY_FROM_EXEUTIL); |
| |
| cliRC = cliInterface.executeImmediate(buf); |
| } |
| catch (...) |
| { |
| // Restore parser flags settings to what they originally were |
| Assign_SqlParser_Flags(savedParserFlags); |
| |
| throw; |
| } |
| |
| // Restore parser flags settings to what they originally were |
| Assign_SqlParser_Flags(savedParserFlags); |
| |
| if (cliRC < 0 && cliRC != -CAT_OBJECT_DOES_NOT_EXIST_IN_TRAFODION) |
| { |
| cliInterface.retrieveSQLDiagnostics(CmpCommon::diags()); |
| |
| someObjectsCouldNotBeDropped = true; |
| } |
| |
| // remove NATable entry for this table |
| CorrName cn(objectName,STMTHEAP,schemaName,catalogName); |
| |
| ActiveSchemaDB()->getNATableDB()->removeNATable |
| (cn, |
| ComQiScope::REMOVE_FROM_ALL_USERS, COM_BASE_TABLE_OBJECT, |
| ddlXns, FALSE); |
| |
| return someObjectsCouldNotBeDropped; |
| |
| } |
| //**************************** End of dropOneTable ***************************** |
| |
| // ***************************************************************************** |
| // * * |
| // * Function: transferObjectPrivs * |
| // * * |
| // * Transfers object privs from current owner to new owner. * |
| // * * |
| // ***************************************************************************** |
| // * * |
| // * Parameters: * |
| // * * |
| // * <systemCatalogName> const char * In * |
| // * is the location of the system catalog. * |
| // * * |
| // * <catalogName> const char * In * |
| // * is the catalog of the schema whose objects are getting a new owner. * |
| // * * |
| // * <schemaName> const char * In * |
| // * is the schema whose objects are getting a new owner. * |
| // * * |
| // * <newOwnerID> const int32_t In * |
| // * is the ID of the new owner for the objects. * |
| // * * |
| // * <newOwnerName const char * In * |
| // * is the database username or role name of the new owner for the objects.* |
| // * * |
| // ***************************************************************************** |
| // * * |
| // * Returns: bool * |
| // * * |
| // * true: Privileges for object(s) transferred to new owner. * |
| // * false: Privileges for object(s) NOT transferred to new owner. * |
| // * * |
| // ***************************************************************************** |
| static bool transferObjectPrivs( |
| const char * systemCatalogName, |
| const char * catalogName, |
| const char * schemaName, |
| const int32_t newOwnerID, |
| const char * newOwnerName) |
| |
| |
| { |
| |
| PrivStatus privStatus = STATUS_GOOD; |
| |
| // Initiate the privilege manager interface class |
| NAString privMgrMDLoc; |
| |
| CONCAT_CATSCH(privMgrMDLoc,systemCatalogName,SEABASE_PRIVMGR_SCHEMA); |
| |
| PrivMgrCommands privInterface(std::string(privMgrMDLoc.data()),CmpCommon::diags()); |
| |
| std::vector<UIDAndOwner> objectRows; |
| std::string whereClause(" WHERE catalog_name = '"); |
| |
| whereClause += catalogName; |
| whereClause += "' AND schema_name = '"; |
| whereClause += schemaName; |
| whereClause += "'"; |
| |
| std::string orderByClause(" ORDER BY OBJECT_OWNER"); |
| std::string metadataLocation(systemCatalogName); |
| |
| metadataLocation += ".\""; |
| metadataLocation += SEABASE_MD_SCHEMA; |
| metadataLocation += "\""; |
| |
| PrivMgrObjects objects(metadataLocation,CmpCommon::diags()); |
| |
| privStatus = objects.fetchUIDandOwner(whereClause,orderByClause,objectRows); |
| |
| if (privStatus != STATUS_GOOD || objectRows.size() == 0) |
| return false; |
| |
| int32_t lastOwner = objectRows[0].ownerID; |
| std::vector<int64_t> objectUIDs; |
| |
| for (size_t i = 0; i < objectRows.size(); i++) |
| { |
| if (objectRows[i].ownerID != lastOwner) |
| { |
| privStatus = privInterface.givePrivForObjects(lastOwner, |
| newOwnerID, |
| newOwnerName, |
| objectUIDs); |
| |
| objectUIDs.clear(); |
| } |
| objectUIDs.push_back(objectRows[i].UID); |
| lastOwner = objectRows[i].ownerID; |
| } |
| |
| privStatus = privInterface.givePrivForObjects(lastOwner, |
| newOwnerID, |
| newOwnerName, |
| objectUIDs); |
| |
| return true; |
| |
| } |
| //************************ End of transferObjectPrivs ************************** |