blob: a620624d9c00d33e25e826d63e0fe41204a268a3 [file] [log] [blame]
/**********************************************************************
// @@@ 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: CmpSeabaseDDLtable.cpp
* Description: Implements ddl operations for Seabase tables.
*
*
* Created: 6/30/2013
* Language: C++
*
*
*****************************************************************************
*/
#include "CmpSeabaseDDLincludes.h"
#include "CmpSeabaseDDLauth.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 "PrivMgrRoles.h"
#include "PrivMgrComponentPrivileges.h"
#include "StmtDDLonHiveObjects.h"
#include "RelExeUtil.h"
#include "TrafDDLdesc.h"
#include "CmpDescribe.h"
static bool checkSpecifiedPrivs(
ElemDDLPrivActArray & privActsArray,
const char * externalObjectName,
ComObjectType objectType,
NATable * naTable,
std::vector<PrivType> & objectPrivs,
std::vector<ColPrivSpec> & colPrivs);
static bool ElmPrivToPrivType(
OperatorTypeEnum elmPriv,
PrivType & privType,
bool forRevoke = false);
static bool hasValue(
const std::vector<ColPrivSpec> & container,
PrivType value);
static bool hasValue(
const std::vector<PrivType> & container,
PrivType value);
static bool isMDGrantRevokeOK(
const std::vector<PrivType> & objectPrivs,
const std::vector<ColPrivSpec> & colPrivs,
bool isGrant);
static bool isValidPrivTypeForObject(
ComObjectType objectType,
PrivType privType);
void CmpSeabaseDDL::convertVirtTableColumnInfoToDescStruct(
const ComTdbVirtTableColumnInfo * colInfo,
const ComObjectName * objectName,
TrafDesc * column_desc)
{
char * col_name = new(STMTHEAP) char[strlen(colInfo->colName) + 1];
strcpy(col_name, colInfo->colName);
column_desc->columnsDesc()->colname = col_name;
column_desc->columnsDesc()->colnumber = colInfo->colNumber;
column_desc->columnsDesc()->datatype = colInfo->datatype;
column_desc->columnsDesc()->length = colInfo->length;
if (!(DFS2REC::isInterval(colInfo->datatype)))
column_desc->columnsDesc()->scale = colInfo->scale;
else
column_desc->columnsDesc()->scale = 0;
column_desc->columnsDesc()->precision = colInfo->precision;
column_desc->columnsDesc()->datetimestart = (rec_datetime_field) colInfo->dtStart;
column_desc->columnsDesc()->datetimeend = (rec_datetime_field) colInfo->dtEnd;
if (DFS2REC::isDateTime(colInfo->datatype) || DFS2REC::isInterval(colInfo->datatype))
column_desc->columnsDesc()->datetimefractprec = colInfo->scale;
else
column_desc->columnsDesc()->datetimefractprec = 0;
if (DFS2REC::isInterval(colInfo->datatype))
column_desc->columnsDesc()->intervalleadingprec = colInfo->precision;
else
column_desc->columnsDesc()->intervalleadingprec = 0 ;
column_desc->columnsDesc()->setNullable(colInfo->nullable);
column_desc->columnsDesc()->setUpshifted(colInfo->upshifted);
column_desc->columnsDesc()->character_set = (CharInfo::CharSet) colInfo->charset;
switch (colInfo->columnClass)
{
case COM_USER_COLUMN:
column_desc->columnsDesc()->colclass = 'U';
break;
case COM_SYSTEM_COLUMN:
column_desc->columnsDesc()->colclass = 'S';
break;
default:
CMPASSERT(0);
}
column_desc->columnsDesc()->setDefaultClass(colInfo->defaultClass);
column_desc->columnsDesc()->colFlags = colInfo->colFlags;
column_desc->columnsDesc()->pictureText =
(char *)STMTHEAP->allocateMemory(340);
NAType::convertTypeToText(column_desc->columnsDesc()->pictureText, //OUT
column_desc->columnsDesc()->datatype,
column_desc->columnsDesc()->length,
column_desc->columnsDesc()->precision,
column_desc->columnsDesc()->scale,
column_desc->columnsDesc()->datetimeStart(),
column_desc->columnsDesc()->datetimeEnd(),
column_desc->columnsDesc()->datetimefractprec,
column_desc->columnsDesc()->intervalleadingprec,
column_desc->columnsDesc()->isUpshifted(),
column_desc->columnsDesc()->isCaseInsensitive(),
(CharInfo::CharSet)column_desc->columnsDesc()->character_set,
(CharInfo::Collation) 1, // default collation
NULL, // displayDataType
0); // displayCaseSpecific
column_desc->columnsDesc()->offset = -1; // not present in colInfo
column_desc->columnsDesc()->setCaseInsensitive(FALSE); // not present in colInfo
column_desc->columnsDesc()->encoding_charset = (CharInfo::CharSet) column_desc->columnsDesc()->character_set ; // not present in colInfo so we go with the column's charset here.
column_desc->columnsDesc()->collation_sequence = (CharInfo::Collation)1; // not present in colInfo, so we go with default collation here (used in buildEncodeTree for some error handling)
column_desc->columnsDesc()->defaultvalue = NULL ; // not present in colInfo
column_desc->columnsDesc()->computed_column_text = NULL; // not present in colInfo
}
TrafDesc * CmpSeabaseDDL::convertVirtTableColumnInfoArrayToDescStructs(
const ComObjectName * objectName,
const ComTdbVirtTableColumnInfo * colInfoArray,
Lng32 numCols)
{
TrafDesc * prev_column_desc = NULL;
TrafDesc * first_column_desc = NULL;
for (Int32 i = 0; i < numCols; i++)
{
const ComTdbVirtTableColumnInfo* colInfo = &(colInfoArray[i]);
// TrafAllocateDDLdesc() requires that HEAP (STMTHEAP)
// be used for operator new herein
TrafDesc * column_desc = TrafAllocateDDLdesc(DESC_COLUMNS_TYPE, NULL);
if (prev_column_desc != NULL)
prev_column_desc->next = column_desc;
else
first_column_desc = column_desc;
prev_column_desc = column_desc;
convertVirtTableColumnInfoToDescStruct(colInfo, objectName, column_desc);
}
return first_column_desc;
}
TrafDesc * CmpSeabaseDDL::convertVirtTableKeyInfoArrayToDescStructs(
const ComTdbVirtTableKeyInfo *keyInfoArray,
const ComTdbVirtTableColumnInfo *colInfoArray,
Lng32 numKeys)
{
TrafDesc * prev_key_desc = NULL;
TrafDesc * first_key_desc = NULL;
for (Int32 i = 0; i < numKeys; i++)
{
const ComTdbVirtTableColumnInfo * colInfo = &(colInfoArray[keyInfoArray[i].tableColNum]);
TrafDesc * key_desc = TrafAllocateDDLdesc(DESC_KEYS_TYPE, NULL);
if (prev_key_desc != NULL)
prev_key_desc->next = key_desc;
else
first_key_desc = key_desc;
prev_key_desc = key_desc;
key_desc->keysDesc()->tablecolnumber = keyInfoArray[i].tableColNum;
key_desc->keysDesc()->keyseqnumber = i;
key_desc->keysDesc()->setDescending(keyInfoArray[i].ordering != 0 ? TRUE : FALSE);
}
return first_key_desc;
}
void CmpSeabaseDDL::createSeabaseTableLike(ExeCliInterface * cliInterface,
StmtDDLCreateTable * createTableNode,
NAString &currCatName, NAString &currSchName)
{
Lng32 retcode = 0;
ComObjectName tgtTableName(createTableNode->getTableName(), COM_TABLE_NAME);
ComAnsiNamePart currCatAnsiName(currCatName);
ComAnsiNamePart currSchAnsiName(currSchName);
tgtTableName.applyDefaults(currCatAnsiName, currSchAnsiName);
const NAString extTgtTableName = tgtTableName.getExternalName(TRUE);
ComObjectName srcTableName(createTableNode->getLikeSourceTableName(), COM_TABLE_NAME);
srcTableName.applyDefaults(currCatAnsiName, currSchAnsiName);
NABoolean srcSchNameSpecified =
(NOT createTableNode->getOrigLikeSourceTableName().getSchemaName().isNull());
NAString srcCatNamePart = srcTableName.getCatalogNamePartAsAnsiString();
NAString srcSchNamePart = srcTableName.getSchemaNamePartAsAnsiString(TRUE);
NAString srcObjNamePart = srcTableName.getObjectNamePartAsAnsiString(TRUE);
NAString extSrcTableName = srcTableName.getExternalName(TRUE);
NAString srcTabName = srcTableName.getExternalName(TRUE);
retcode = lookForTableInMD(cliInterface,
srcCatNamePart, srcSchNamePart, srcObjNamePart,
srcSchNameSpecified, FALSE,
srcTableName, srcTabName, extSrcTableName);
if (retcode < 0)
{
processReturn();
return;
}
CorrName cn(srcObjNamePart,
STMTHEAP,
srcSchNamePart,
srcCatNamePart);
ElemDDLColRefArray &keyArray =
(createTableNode->getIsConstraintPKSpecified() ?
createTableNode->getPrimaryKeyColRefArray() :
(createTableNode->getStoreOption() == COM_KEY_COLUMN_LIST_STORE_OPTION ?
createTableNode->getKeyColumnArray() :
createTableNode->getPrimaryKeyColRefArray()));
NAString keyClause;
if ((keyArray.entries() > 0) &&
((createTableNode->getIsConstraintPKSpecified()) ||
(createTableNode->getStoreOption() == COM_KEY_COLUMN_LIST_STORE_OPTION)))
{
if (createTableNode->getIsConstraintPKSpecified())
keyClause = " primary key ( ";
else if (createTableNode->getStoreOption() == COM_KEY_COLUMN_LIST_STORE_OPTION)
keyClause = " store by ( ";
for (CollIndex i = 0; i < keyArray.entries(); i++)
{
NAString colName = keyArray[i]->getColumnName();
// Generate a delimited identifier if source colName is delimited
// Launchpad bug: 1383531
colName/*InExternalFormat*/ = ToAnsiIdentifier (colName/*InInternalFormat*/);
keyClause += colName;
if (i < (keyArray.entries() - 1))
keyClause += ", ";
}
keyClause += ")";
}
// Check for other common options that are currently not supported
// with CREATE TABLE LIKE. Those could all be passed into
// CmpDescribeSeabaseTable as strings if we wanted to support them.
if (NOT keyClause.isNull())
{
*CmpCommon::diags() << DgSqlCode(-3111)
<< DgString0("PRIMARY KEY/STORE BY");
return;
}
if (createTableNode->isPartitionSpecified() ||
createTableNode->isPartitionBySpecified())
{
*CmpCommon::diags() << DgSqlCode(-3111)
<< DgString0("PARTITION BY");
return;
}
if (createTableNode->isDivisionClauseSpecified())
{
*CmpCommon::diags() << DgSqlCode(-3111)
<< DgString0("DIVISION BY");
return;
}
if (createTableNode->isHbaseOptionsSpecified())
{
*CmpCommon::diags() << DgSqlCode(-3111)
<< DgString0("HBASE table options");
return;
}
ParDDLLikeOptsCreateTable &likeOptions = createTableNode->getLikeOptions();
if (NOT likeOptions.getLikeOptHiveOptions().isNull())
{
*CmpCommon::diags() << DgSqlCode(-3242)
<< DgString0("Hive options cannot be specified for this table.");
return;
}
char * buf = NULL;
ULng32 buflen = 0;
if (srcCatNamePart.index(HIVE_SYSTEM_CATALOG, 0, NAString::ignoreCase) == 0)
retcode = CmpDescribeHiveTable(cn, 3/*createlike*/, buf, buflen, STMTHEAP,
likeOptions.getIsLikeOptColumnLengthLimit());
else
retcode = CmpDescribeSeabaseTable(cn, 3/*createlike*/, buf, buflen, STMTHEAP,
NULL, NULL,
likeOptions.getIsWithHorizontalPartitions(),
likeOptions.getIsWithoutSalt(),
likeOptions.getIsWithoutDivision(),
likeOptions.getIsWithoutRowFormat(),
likeOptions.getIsWithoutLobColumns(),
likeOptions.getIsLikeOptColumnLengthLimit(),
TRUE);
if (retcode)
return;
NAString query = "create table ";
query += extTgtTableName;
query += " ";
NABoolean done = FALSE;
Lng32 curPos = 0;
while (NOT done)
{
short len = *(short*)&buf[curPos];
NAString frag(&buf[curPos+sizeof(short)],
len - ((buf[curPos+len-1]== '\n') ? 1 : 0));
query += frag;
curPos += ((((len+sizeof(short))-1)/8)+1)*8;
if (curPos >= buflen)
done = TRUE;
}
if (NOT keyClause.isNull())
{
// add the keyClause
query += keyClause;
}
const NAString * saltClause = likeOptions.getSaltClause();
if (saltClause)
{
query += saltClause->data();
}
// send any user CQDs down
Lng32 retCode = sendAllControls(FALSE, FALSE, TRUE);
Lng32 cliRC = 0;
cliRC = cliInterface->executeImmediate((char*)query.data());
if (cliRC < 0)
{
cliInterface->retrieveSQLDiagnostics(CmpCommon::diags());
return;
}
return;
}
// ----------------------------------------------------------------------------
// Method: createSeabaseTableExternal
//
// This method creates a Trafodion table that represents a Hive or HBase table
//
// in:
// cliInterface - references to the cli execution structure
// createTableNode - representation of the CREATE TABLE statement
// tgtTableName - the Trafodion external table name to create
// srcTableName - the native source table
//
// returns: 0 - successful, -1 error
//
// any error detected is added to the diags area
// ----------------------------------------------------------------------------
short CmpSeabaseDDL::createSeabaseTableExternal(
ExeCliInterface &cliInterface,
StmtDDLCreateTable * createTableNode,
const ComObjectName &tgtTableName,
const ComObjectName &srcTableName)
{
Int32 retcode = 0;
NABoolean isHive = tgtTableName.isExternalHive();
// go create the schema - if it does not already exist.
NAString createSchemaStmt ("CREATE SCHEMA IF NOT EXISTS ");
createSchemaStmt += tgtTableName.getCatalogNamePartAsAnsiString();
createSchemaStmt += ".";
createSchemaStmt += tgtTableName.getSchemaNamePartAsAnsiString();
if (isAuthorizationEnabled())
{
createSchemaStmt += " AUTHORIZATION ";
createSchemaStmt += (isHive) ? DB__HIVEROLE : DB__HBASEROLE;
}
Lng32 cliRC = cliInterface.executeImmediate((char*)createSchemaStmt.data());
if (cliRC < 0)
{
cliInterface.retrieveSQLDiagnostics(CmpCommon::diags());
return -1;
}
const NAString catalogNamePart = tgtTableName.getCatalogNamePartAsAnsiString();
const NAString schemaNamePart = tgtTableName.getSchemaNamePartAsAnsiString(TRUE);
const NAString objectNamePart = tgtTableName.getObjectNamePartAsAnsiString(TRUE);
// Make sure current user has privileges
Int32 objectOwnerID = SUPER_USER;
Int32 schemaOwnerID = SUPER_USER;
ComSchemaClass schemaClass;
retcode = verifyDDLCreateOperationAuthorized(&cliInterface,
SQLOperation::CREATE_TABLE,
catalogNamePart,
schemaNamePart,
schemaClass,
objectOwnerID,
schemaOwnerID);
if (retcode != 0)
{
handleDDLCreateAuthorizationError(retcode,catalogNamePart,schemaNamePart);
return -1;
}
if (createTableNode->mapToHbaseTable())
return 0;
const NAString extTgtTableName = tgtTableName.getExternalName(TRUE);
const NAString srcCatNamePart = srcTableName.getCatalogNamePartAsAnsiString();
const NAString srcSchNamePart = srcTableName.getSchemaNamePartAsAnsiString(TRUE);
const NAString srcObjNamePart = srcTableName.getObjectNamePartAsAnsiString(TRUE);
CorrName cnSrc(srcObjNamePart, STMTHEAP, srcSchNamePart, srcCatNamePart);
// build the structures needed to create the table
// tableInfo contains data inserted into OBJECTS and TABLES
ComTdbVirtTableTableInfo * tableInfo = new(STMTHEAP) ComTdbVirtTableTableInfo[1];
tableInfo->tableName = NULL;
tableInfo->createTime = 0;
tableInfo->redefTime = 0;
tableInfo->objUID = 0;
tableInfo->isAudited = 1;
tableInfo->validDef = 1;
tableInfo->hbaseCreateOptions = NULL;
tableInfo->numSaltPartns = 0;
tableInfo->rowFormat = COM_UNKNOWN_FORMAT_TYPE;
if (isHive)
{
tableInfo->objectFlags = SEABASE_OBJECT_IS_EXTERNAL_HIVE;
}
else
{
tableInfo->objectFlags = SEABASE_OBJECT_IS_EXTERNAL_HBASE;
if (createTableNode->isImplicitExternal())
tableInfo->objectFlags |= SEABASE_OBJECT_IS_IMPLICIT_EXTERNAL;
}
tableInfo->tablesFlags = 0;
if (isAuthorizationEnabled())
{
if (tgtTableName.isExternalHive())
{
tableInfo->objOwnerID = HIVE_ROLE_ID;
tableInfo->schemaOwnerID = HIVE_ROLE_ID;
}
else
{
tableInfo->objOwnerID = HBASE_ROLE_ID;
tableInfo->schemaOwnerID = HBASE_ROLE_ID;
}
}
else
{
tableInfo->objOwnerID = SUPER_USER;
tableInfo->schemaOwnerID = SUPER_USER;
}
// Column information
Lng32 datatype, length, precision, scale, dtStart, dtEnd, nullable, upshifted;
NAString charset;
CharInfo::Collation collationSequence = CharInfo::DefaultCollation;
ULng32 hbaseColFlags;
NABoolean alignedFormat = FALSE;
Lng32 serializedOption = -1;
Int32 numCols = 0;
ComTdbVirtTableColumnInfo * colInfoArray = NULL;
ElemDDLColDefArray &colArray = createTableNode->getColDefArray();
ElemDDLColRefArray &keyArray =
(createTableNode->getIsConstraintPKSpecified() ?
createTableNode->getPrimaryKeyColRefArray() :
(createTableNode->getStoreOption() == COM_KEY_COLUMN_LIST_STORE_OPTION ?
createTableNode->getKeyColumnArray() :
createTableNode->getPrimaryKeyColRefArray()));
// Get a description of the source table
BindWA bindWA(ActiveSchemaDB(), CmpCommon::context(), FALSE/*inDDL*/);
NATable *naTable = bindWA.getNATable(cnSrc);
if (naTable == NULL || bindWA.errStatus())
{
*CmpCommon::diags()
<< DgSqlCode(-4082)
<< DgTableName(cnSrc.getExposedNameAsAnsiString());
return -1;
}
if ((naTable->isHiveTable()) &&
(naTable->getViewText()) &&
(!Get_SqlParser_Flags(INTERNAL_QUERY_FROM_EXEUTIL)))
{
*CmpCommon::diags()
<< DgSqlCode(-3242)
<< DgString0("Cannot create external table on a native Hive view.");
return -1;
}
// cqd HIVE_USE_EXT_TABLE_ATTRS:
// if OFF, col or key attrs cannot be specified during ext table creation.
// if ON, col attrs could be specified.
// if ALL, col and key attrs could be specified
NABoolean extTableAttrsSpecified = FALSE;
if (colArray.entries() > 0)
{
if (CmpCommon::getDefault(HIVE_USE_EXT_TABLE_ATTRS) == DF_OFF)
{
*CmpCommon::diags()
<< DgSqlCode(-3242)
<< DgString0("Cannot specify column attributes for external tables.");
return -1;
}
extTableAttrsSpecified = TRUE;
CmpSeabaseDDL::setMDflags
(tableInfo->tablesFlags, MD_TABLES_HIVE_EXT_COL_ATTRS);
}
if (keyArray.entries() > 0)
{
if (CmpCommon::getDefault(HIVE_USE_EXT_TABLE_ATTRS) != DF_ALL)
{
*CmpCommon::diags()
<< DgSqlCode(-3242)
<< DgString0("Cannot specify key attribute for external tables.");
return -1;
}
extTableAttrsSpecified = TRUE;
CmpSeabaseDDL::setMDflags
(tableInfo->tablesFlags, MD_TABLES_HIVE_EXT_KEY_ATTRS);
}
// convert column array from NATable into a ComTdbVirtTableColumnInfo struct
NAColumnArray naColArray;
const NAColumnArray &origColArray = naTable->getNAColumnArray();
for (CollIndex c=0; c<origColArray.entries(); c++)
naColArray.insert(origColArray[c]);
numCols = naColArray.entries();
// make sure all columns specified in colArray are part of naColArray
if (colArray.entries() > 0)
{
for (CollIndex colIndex = 0; colIndex < colArray.entries(); colIndex++)
{
const ElemDDLColDef *edcd = colArray[colIndex];
if (naColArray.getColumnPosition((NAString&)edcd->getColumnName()) < 0)
{
// not found. return error.
*CmpCommon::diags() << DgSqlCode(-1009)
<< DgColumnName(ToAnsiIdentifier(edcd->getColumnName()));
return -1;
}
}
}
colInfoArray = new(STMTHEAP) ComTdbVirtTableColumnInfo[numCols];
for (CollIndex index = 0; index < numCols; index++)
{
const NAColumn *naCol = naColArray[index];
const NAType * type = naCol->getType();
// if colArray has been specified, then look for this column in
// that array and use the type specified there.
Int32 colIndex = -1;
if ((colArray.entries() > 0) &&
((colIndex = colArray.getColumnIndex(naCol->getColName())) >= 0))
{
ElemDDLColDef *edcd = colArray[colIndex];
type = edcd->getColumnDataType();
}
// call: CmpSeabaseDDL::getTypeInfo to get column details
retcode = getTypeInfo(type, alignedFormat, serializedOption,
datatype, length, precision, scale, dtStart, dtEnd, upshifted, nullable,
charset, collationSequence, hbaseColFlags);
if (retcode)
return -1;
if (length > CmpCommon::getDefaultNumeric(TRAF_MAX_CHARACTER_COL_LENGTH))
{
*CmpCommon::diags()
<< DgSqlCode(-4247)
<< DgInt0(length)
<< DgInt1(CmpCommon::getDefaultNumeric(TRAF_MAX_CHARACTER_COL_LENGTH))
<< DgString0(naCol->getColName().data());
return -1;
}
colInfoArray[index].colName = naCol->getColName().data();
colInfoArray[index].colNumber = index;
colInfoArray[index].columnClass = COM_USER_COLUMN;
colInfoArray[index].datatype = datatype;
colInfoArray[index].length = length;
colInfoArray[index].nullable = nullable;
colInfoArray[index].charset = (SQLCHARSET_CODE)CharInfo::getCharSetEnum(charset);
colInfoArray[index].precision = precision;
colInfoArray[index].scale = scale;
colInfoArray[index].dtStart = dtStart;
colInfoArray[index].dtEnd = dtEnd;
colInfoArray[index].upshifted = upshifted;
colInfoArray[index].colHeading = NULL;
colInfoArray[index].hbaseColFlags = naCol->getHbaseColFlags();
colInfoArray[index].defaultClass = COM_NULL_DEFAULT;
colInfoArray[index].defVal = NULL;
colInfoArray[index].hbaseColFam = naCol->getHbaseColFam();
colInfoArray[index].hbaseColQual = naCol->getHbaseColQual();
strcpy(colInfoArray[index].paramDirection, COM_UNKNOWN_PARAM_DIRECTION_LIT);
colInfoArray[index].isOptional = FALSE;
colInfoArray[index].colFlags = 0;
}
ComTdbVirtTableKeyInfo * keyInfoArray = NULL;
Lng32 numKeys = 0;
numKeys = keyArray.entries();
if (numKeys > 0)
{
if (isHive)
{
*CmpCommon::diags()
<< DgSqlCode(-4222)
<< DgString0("\"PRIMARY KEY on external hive table\"");
return -1;
}
keyInfoArray = new(STMTHEAP) ComTdbVirtTableKeyInfo[numKeys];
if (buildKeyInfoArray(NULL, (NAColumnArray*)&naColArray, &keyArray,
colInfoArray, keyInfoArray, TRUE))
{
*CmpCommon::diags()
<< DgSqlCode(-CAT_UNABLE_TO_CREATE_OBJECT)
<< DgTableName(extTgtTableName);
return -1;
}
}
NABoolean registerHiveObject =
(cnSrc.isHive() &&
CmpCommon::getDefault(HIVE_NO_REGISTER_OBJECTS) == DF_OFF);
// if source table is a hive table and not already registered, register
// it in traf metadata
if (registerHiveObject)
{
char buf[2000];
str_sprintf(buf, "register internal hive table if not exists %s.%s.%s",
srcCatNamePart.data(),
srcSchNamePart.data(),
srcObjNamePart.data());
Lng32 cliRC = cliInterface.executeImmediate(buf);
if (cliRC < 0)
{
cliInterface.retrieveSQLDiagnostics(CmpCommon::diags());
return -1;
}
} // ishive
Int64 objUID = -1;
cliRC = 0;
// Update traf MD tables with info about this table.
// But do not insert priv info if object is to be registered.
// That will happen during hive object registration.
if (updateSeabaseMDTable(&cliInterface,
catalogNamePart, schemaNamePart, objectNamePart,
COM_BASE_TABLE_OBJECT,
COM_NO_LIT,
tableInfo,
numCols,
colInfoArray,
0 /*numKeys*/,
NULL /*keyInfoArray*/,
0, NULL,
objUID /*returns generated UID*/,
(NOT registerHiveObject)))
{
*CmpCommon::diags()
<< DgSqlCode(-CAT_UNABLE_TO_CREATE_OBJECT)
<< DgTableName(extTgtTableName);
return -1;
}
cliRC = updateObjectValidDef(&cliInterface,
catalogNamePart, schemaNamePart, objectNamePart,
COM_BASE_TABLE_OBJECT_LIT, COM_YES_LIT);
if (cliRC < 0)
{
*CmpCommon::diags()
<< DgSqlCode(-CAT_UNABLE_TO_CREATE_OBJECT)
<< DgTableName(extTgtTableName);
return -1;
}
// remove cached definition - this code exists in other create stmte,
// is it required?
CorrName cnTgt(objectNamePart, STMTHEAP, schemaNamePart, catalogNamePart);
ActiveSchemaDB()->getNATableDB()->removeNATable
(cnTgt,
ComQiScope::REMOVE_MINE_ONLY,
COM_BASE_TABLE_OBJECT,
createTableNode->ddlXns(), FALSE);
return 0;
}
short CmpSeabaseDDL::genPKeyName(StmtDDLAddConstraintPK *addPKNode,
const char * catName,
const char * schName,
const char * objName,
NAString &pkeyName)
{
ComObjectName tableName( (addPKNode ? addPKNode->getTableName() : " "), COM_TABLE_NAME);
ElemDDLConstraintPK *constraintNode =
(addPKNode ? (addPKNode->getConstraint())->castToElemDDLConstraintPK() : NULL);
ComString specifiedConstraint;
ComString constraintName;
if( !constraintNode || (constraintNode->getConstraintName().isNull()))
{
specifiedConstraint.append( catName);
specifiedConstraint.append(".");
specifiedConstraint.append("\"");
specifiedConstraint.append( schName);
specifiedConstraint.append("\"");
specifiedConstraint.append(".");
ComString oName = "\"";
oName += objName;
oName += "\"";
Lng32 status = ToInternalIdentifier ( oName // in/out - from external- to internal-format
, TRUE // in - NABoolean upCaseInternalNameIfRegularIdent
, TRUE // in - NABoolean acceptCircumflex
);
ComDeriveRandomInternalName ( ComGetNameInterfaceCharSet()
, /*internalFormat*/oName // in - const ComString &
, /*internalFormat*/constraintName // out - ComString &
, STMTHEAP
);
// Generate a delimited identifier if objectName was delimited
constraintName/*InExternalFormat*/ = ToAnsiIdentifier (constraintName/*InInternalFormat*/);
specifiedConstraint.append(constraintName);
}
else
{
specifiedConstraint = constraintNode->
getConstraintNameAsQualifiedName().getQualifiedNameAsAnsiString();
}
pkeyName = specifiedConstraint;
return 0;
}
short CmpSeabaseDDL::updatePKeyInfo(
StmtDDLAddConstraintPK *addPKNode,
const char * catName,
const char * schName,
const char * objName,
const Int32 ownerID,
const Int32 schemaOwnerID,
Lng32 numKeys,
Int64 * outPkeyUID,
Int64 * outTableUID,
const ComTdbVirtTableKeyInfo * keyInfoArray,
ExeCliInterface *cliInterface)
{
Lng32 retcode = 0;
Lng32 cliRC = 0;
char buf[4000];
// update primary key constraint info
NAString pkeyStr;
if (genPKeyName(addPKNode, catName, schName, objName, pkeyStr))
{
return -1;
}
Int64 createTime = NA_JulianTimestamp();
ComUID comUID;
comUID.make_UID();
Int64 pkeyUID = comUID.get_value();
if (outPkeyUID)
*outPkeyUID = pkeyUID;
ComObjectName pkeyName(pkeyStr);
const NAString catalogNamePart = pkeyName.getCatalogNamePartAsAnsiString();
const NAString schemaNamePart = pkeyName.getSchemaNamePartAsAnsiString(TRUE);
const NAString objectNamePart = pkeyName.getObjectNamePartAsAnsiString(TRUE);
NAString quotedSchName;
ToQuotedString(quotedSchName, NAString(schemaNamePart), FALSE);
NAString quotedObjName;
ToQuotedString(quotedObjName, NAString(objectNamePart), FALSE);
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,
catalogNamePart.data(), quotedSchName.data(), quotedObjName.data(),
COM_PRIMARY_KEY_CONSTRAINT_OBJECT_LIT,
pkeyUID,
createTime,
createTime,
" ",
COM_NO_LIT,
ownerID,
schemaOwnerID);
cliRC = cliInterface->executeImmediate(buf);
if (cliRC < 0)
{
cliInterface->retrieveSQLDiagnostics(CmpCommon::diags());
*CmpCommon::diags() << DgSqlCode(-1423)
<< DgString0(SEABASE_OBJECTS);
return -1;
}
Int64 tableUID =
getObjectUID(cliInterface,
catName, schName, objName,
COM_BASE_TABLE_OBJECT_LIT);
if (outTableUID)
*outTableUID = tableUID;
Int64 validatedTime = NA_JulianTimestamp();
Int64 flags = 0;
// if pkey is specified to be not_serialized, then set it.
// if this is an hbase mapped table and pkey serialization is not specified,
// then set to not_serialized.
NABoolean notSerializedPK = FALSE;
if ((addPKNode->getAlterTableAction()->castToElemDDLConstraintPK()->ser() ==
ComPkeySerialization::COM_NOT_SERIALIZED) ||
(ComIsHbaseMappedSchemaName(schName) &&
(addPKNode->getAlterTableAction()->castToElemDDLConstraintPK()->ser() ==
ComPkeySerialization::COM_SER_NOT_SPECIFIED)))
notSerializedPK = TRUE;
if (notSerializedPK)
{
CmpSeabaseDDL::setMDflags
(flags, CmpSeabaseDDL::MD_TABLE_CONSTRAINTS_PKEY_NOT_SERIALIZED_FLG);
}
Int64 indexUID = 0;
str_sprintf(buf, "insert into %s.\"%s\".%s values (%ld, %ld, '%s', '%s', '%s', '%s', '%s', '%s', %ld, %d, %ld, %ld )",
getSystemCatalog(), SEABASE_MD_SCHEMA, SEABASE_TABLE_CONSTRAINTS,
tableUID, pkeyUID,
COM_PRIMARY_KEY_CONSTRAINT_LIT,
COM_NO_LIT,
COM_NO_LIT,
COM_NO_LIT,
COM_YES_LIT,
COM_YES_LIT,
validatedTime,
numKeys,
indexUID,
flags);
cliRC = cliInterface->executeImmediate(buf);
if (cliRC < 0)
{
cliInterface->retrieveSQLDiagnostics(CmpCommon::diags());
*CmpCommon::diags() << DgSqlCode(-1423)
<< DgString0(SEABASE_TABLE_CONSTRAINTS);
return -1;
}
if (keyInfoArray)
{
for (Lng32 i = 0; i < numKeys; i++)
{
str_sprintf(buf, "insert into %s.\"%s\".%s values (%ld, '%s', %d, %d, %d, %d, 0)",
getSystemCatalog(), SEABASE_MD_SCHEMA, SEABASE_KEYS,
pkeyUID,
keyInfoArray[i].colName,
i+1,
keyInfoArray[i].tableColNum,
0,
0);
cliRC = cliInterface->executeImmediate(buf);
if (cliRC < 0)
{
cliInterface->retrieveSQLDiagnostics(CmpCommon::diags());
*CmpCommon::diags() << DgSqlCode(-1423)
<< DgString0(SEABASE_KEYS);
return -1;
}
}
}
return 0;
}
// ----------------------------------------------------------------------------
// Method: getPKeyInfoForTable
//
// This method reads the metadata to get the primary key constraint name and UID
// for a table.
//
// Params:
// In: catName, schName, objName describing the table
// In: cliInterface - pointer to the cli handle
// Out: constrName and constrUID
//
// Returns 0 if found, -1 otherwise
// ComDiags is set up with error
// ----------------------------------------------------------------------------
short CmpSeabaseDDL::getPKeyInfoForTable (
const char *catName,
const char *schName,
const char *objName,
ExeCliInterface *cliInterface,
NAString &constrName,
Int64 &constrUID)
{
char query[4000];
constrUID = -1;
// get constraint info
str_sprintf(query, "select O.object_name, C.constraint_uid "
"from %s.\"%s\".%s O, %s.\"%s\".%s C "
"where O.object_uid = C.constraint_uid "
" and C.constraint_type = '%s' and C.table_uid = "
" (select object_uid from %s.\"%s\".%s "
" where catalog_name = '%s' "
" and schema_name = '%s' "
" and object_name = '%s')",
getSystemCatalog(), SEABASE_MD_SCHEMA, SEABASE_OBJECTS,
getSystemCatalog(), SEABASE_MD_SCHEMA, SEABASE_TABLE_CONSTRAINTS,
COM_PRIMARY_KEY_CONSTRAINT_LIT,
getSystemCatalog(), SEABASE_MD_SCHEMA, SEABASE_OBJECTS,
catName, schName, objName);
Queue * constrInfoQueue = NULL;
Lng32 cliRC = cliInterface->fetchAllRows(constrInfoQueue, query, 0, FALSE, FALSE, TRUE);
if (cliRC < 0)
{
cliInterface->retrieveSQLDiagnostics(CmpCommon::diags());
processReturn();
return -1;
}
assert (constrInfoQueue->numEntries() == 1);
constrInfoQueue->position();
OutputInfo * vi = (OutputInfo*)constrInfoQueue->getNext();
char * pConstrName = (char*)vi->get(0);
constrName = pConstrName;
constrUID = *(Int64*)vi->get(1);
return 0;
}
short CmpSeabaseDDL::constraintErrorChecks(
ExeCliInterface * cliInterface,
StmtDDLAddConstraint *addConstrNode,
NATable * naTable,
ComConstraintType ct,
NAList<NAString> &keyColList)
{
const NAString &addConstrName = addConstrNode->
getConstraintNameAsQualifiedName().getQualifiedNameAsAnsiString();
// make sure that there is no other constraint on this table with this name.
NABoolean foundConstr = FALSE;
const CheckConstraintList &checkList = naTable->getCheckConstraints();
for (Int32 i = 0; i < checkList.entries(); i++)
{
CheckConstraint *checkConstr = (CheckConstraint*)checkList[i];
const NAString &tableConstrName =
checkConstr->getConstraintName().getQualifiedNameAsAnsiString();
if (addConstrName == tableConstrName)
{
foundConstr = TRUE;
}
} // for
if (NOT foundConstr)
{
const AbstractRIConstraintList &ariList = naTable->getUniqueConstraints();
for (Int32 i = 0; i < ariList.entries(); i++)
{
AbstractRIConstraint *ariConstr = (AbstractRIConstraint*)ariList[i];
const NAString &tableConstrName =
ariConstr->getConstraintName().getQualifiedNameAsAnsiString();
if (addConstrName == tableConstrName)
{
foundConstr = TRUE;
}
} // for
}
if (NOT foundConstr)
{
const AbstractRIConstraintList &ariList = naTable->getRefConstraints();
for (Int32 i = 0; i < ariList.entries(); i++)
{
AbstractRIConstraint *ariConstr = (AbstractRIConstraint*)ariList[i];
const NAString &tableConstrName =
ariConstr->getConstraintName().getQualifiedNameAsAnsiString();
if (addConstrName == tableConstrName)
{
foundConstr = TRUE;
}
} // for
}
if (NOT foundConstr)
{
const NAString &constrCatName = addConstrNode->
getConstraintNameAsQualifiedName().getCatalogName();
const NAString &constrSchName = addConstrNode->
getConstraintNameAsQualifiedName().getSchemaName();
const NAString &constrObjName = addConstrNode->
getConstraintNameAsQualifiedName().getObjectName();
// check to see if this constraint was defined on some other table and
// exists in metadata
Lng32 retcode = existsInSeabaseMDTable(cliInterface,
constrCatName, constrSchName, constrObjName,
COM_UNKNOWN_OBJECT, FALSE, FALSE);
if (retcode == 1) // exists
{
foundConstr = TRUE;
}
}
if (foundConstr)
{
*CmpCommon::diags()
<< DgSqlCode(-1043)
<< DgConstraintName(addConstrName);
processReturn();
return -1;
}
if ((ct == COM_UNIQUE_CONSTRAINT) ||
(ct == COM_FOREIGN_KEY_CONSTRAINT) ||
(ct == COM_PRIMARY_KEY_CONSTRAINT))
{
const NAColumnArray & naColArray = naTable->getNAColumnArray();
// Now process each column defined in the parseColList to see if
// it exists in the table column list and it isn't a duplicate.
NABitVector seenIt;
NAString keyColNameStr;
for (CollIndex i = 0; i < keyColList.entries(); i++)
{
NAColumn * nac = naColArray.getColumn(keyColList[i]);
if (! nac)
{
*CmpCommon::diags() << DgSqlCode(-1009)
<< DgColumnName( ToAnsiIdentifier(keyColList[i]));
return -1;
}
if (nac->isSystemColumn())
{
*CmpCommon::diags() << DgSqlCode((ct == COM_FOREIGN_KEY_CONSTRAINT) ?
-CAT_SYSTEM_COL_NOT_ALLOWED_IN_RI_CNSTRNT :
-CAT_SYSTEM_COL_NOT_ALLOWED_IN_UNIQUE_CNSTRNT)
<< DgColumnName(ToAnsiIdentifier(keyColList[i]))
<< DgTableName(addConstrNode->getTableName());
return -1;
}
// If column is a LOB column , error
Lng32 datatype = nac->getType()->getFSDatatype();
if ((datatype == REC_BLOB) || (datatype == REC_CLOB))
{
*CmpCommon::diags() << DgSqlCode(-CAT_LOB_COL_CANNOT_BE_INDEX_OR_KEY)
<< DgColumnName( ToAnsiIdentifier(keyColList[i]));
processReturn();
return -1;
}
Lng32 colNumber = nac->getPosition();
// If the column has already been found, return error
if( seenIt.contains(colNumber))
{
*CmpCommon::diags() << DgSqlCode(-CAT_REDUNDANT_COLUMN_REF_PK)
<< DgColumnName( ToAnsiIdentifier(keyColList[i]));
return -1;
}
seenIt.setBit(colNumber);
}
if (ct == COM_UNIQUE_CONSTRAINT)
{
// Compare the column list from parse tree to the unique and primary
// key constraints already defined for the table. The new unique
// constraint list must be distinct. The order of the existing constraint
// does not have to be in the same order as the new constraint.
//
if (naTable->getCorrespondingConstraint(keyColList,
TRUE, // unique constraint
NULL))
{
*CmpCommon::diags() << DgSqlCode(-CAT_DUPLICATE_UNIQUE_CONSTRAINT_ON_SAME_COL);
return -1;
}
}
}
return 0;
}
short CmpSeabaseDDL::genUniqueName(StmtDDLAddConstraint *addUniqueNode,
NAString &uniqueName)
{
ComObjectName tableName( addUniqueNode->getTableName(), COM_TABLE_NAME);
ElemDDLConstraint *constraintNode =
(addUniqueNode->getConstraint())->castToElemDDLConstraint();
ComString specifiedConstraint;
ComString constraintName;
if( constraintNode->getConstraintName().isNull() )
{
specifiedConstraint.append( tableName.getCatalogNamePartAsAnsiString() );
specifiedConstraint.append(".");
specifiedConstraint.append( tableName.getSchemaNamePartAsAnsiString() );
specifiedConstraint.append(".");
ComString oName = tableName.getObjectNamePartAsAnsiString() ;
Lng32 status = ToInternalIdentifier ( oName // in/out - from external- to internal-format
, TRUE // in - NABoolean upCaseInternalNameIfRegularIdent
, TRUE // in - NABoolean acceptCircumflex
);
ComDeriveRandomInternalName ( ComGetNameInterfaceCharSet()
, /*internalFormat*/oName // in - const ComString &
, /*internalFormat*/constraintName // out - ComString &
, STMTHEAP
);
// Generate a delimited identifier if objectName was delimited
constraintName/*InExternalFormat*/ = ToAnsiIdentifier (constraintName/*InInternalFormat*/);
specifiedConstraint.append(constraintName);
}
else
{
specifiedConstraint = constraintNode->
getConstraintNameAsQualifiedName().getQualifiedNameAsAnsiString();
}
uniqueName = specifiedConstraint;
return 0;
}
short CmpSeabaseDDL::updateConstraintMD(
NAList<NAString> &keyColList,
NAList<NAString> &keyColOrderList,
NAString &uniqueStr,
Int64 tableUID,
Int64 constrUID,
NATable * naTable,
ComConstraintType ct,
NABoolean enforced,
ExeCliInterface *cliInterface)
{
Lng32 retcode = 0;
Lng32 cliRC = 0;
char buf[4000];
const NAColumnArray & naColArray = naTable->getNAColumnArray();
Int64 createTime = NA_JulianTimestamp();
ComObjectName uniqueName(uniqueStr);
const NAString catalogNamePart = uniqueName.getCatalogNamePartAsAnsiString();
const NAString schemaNamePart = uniqueName.getSchemaNamePartAsAnsiString(TRUE);
const NAString objectNamePart = uniqueName.getObjectNamePartAsAnsiString(TRUE);
NAString quotedSchName;
ToQuotedString(quotedSchName, NAString(schemaNamePart), FALSE);
NAString quotedObjName;
ToQuotedString(quotedObjName, NAString(objectNamePart), FALSE);
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,
catalogNamePart.data(), quotedSchName.data(), quotedObjName.data(),
((ct == COM_UNIQUE_CONSTRAINT) ? COM_UNIQUE_CONSTRAINT_OBJECT_LIT :
((ct == COM_FOREIGN_KEY_CONSTRAINT) ? COM_REFERENTIAL_CONSTRAINT_OBJECT_LIT : COM_CHECK_CONSTRAINT_OBJECT_LIT)),
constrUID,
createTime,
createTime,
" ",
COM_NO_LIT,
naTable->getOwner(),
naTable->getSchemaOwner());
cliRC = cliInterface->executeImmediate(buf);
if (cliRC < 0)
{
cliInterface->retrieveSQLDiagnostics(CmpCommon::diags());
return -1;
}
Int64 indexUID = 0;
str_sprintf(buf, "insert into %s.\"%s\".%s values (%ld, %ld, '%s', '%s', '%s', '%s', '%s', '%s', %ld, %d, %ld, 0 )",
getSystemCatalog(), SEABASE_MD_SCHEMA, SEABASE_TABLE_CONSTRAINTS,
tableUID, constrUID,
((ct == COM_UNIQUE_CONSTRAINT) ? COM_UNIQUE_CONSTRAINT_LIT :
((ct == COM_FOREIGN_KEY_CONSTRAINT) ? COM_FOREIGN_KEY_CONSTRAINT_LIT : COM_CHECK_CONSTRAINT_LIT)),
COM_NO_LIT,
COM_NO_LIT,
COM_NO_LIT,
(enforced ? COM_YES_LIT : COM_NO_LIT),
COM_YES_LIT,
createTime,
keyColList.entries(),
indexUID);
cliRC = cliInterface->executeImmediate(buf);
if (cliRC < 0)
{
cliInterface->retrieveSQLDiagnostics(CmpCommon::diags());
return -1;
}
for (Lng32 i = 0; i < keyColList.entries(); i++)
{
NAColumn * nac = naColArray.getColumn(keyColList[i]);
Lng32 colNumber = nac->getPosition();
str_sprintf(buf, "insert into %s.\"%s\".%s values (%ld, '%s', %d, %d, %d, %d, 0)",
getSystemCatalog(), SEABASE_MD_SCHEMA, SEABASE_KEYS,
constrUID,
keyColList[i].data(),
i+1,
colNumber,
(keyColOrderList[i] == "DESC" ? 1 : 0),
0);
cliRC = cliInterface->executeImmediate(buf);
if (cliRC < 0)
{
cliInterface->retrieveSQLDiagnostics(CmpCommon::diags());
return -1;
}
}
return 0;
}
short CmpSeabaseDDL::updateRIConstraintMD(
Int64 ringConstrUID,
Int64 refdConstrUID,
ExeCliInterface *cliInterface)
{
Lng32 retcode = 0;
Lng32 cliRC = 0;
char buf[4000];
str_sprintf(buf, "insert into %s.\"%s\".%s values (%ld, %ld, '%s', '%s', '%s', 0 )",
getSystemCatalog(), SEABASE_MD_SCHEMA, SEABASE_REF_CONSTRAINTS,
ringConstrUID, refdConstrUID,
COM_FULL_MATCH_OPTION_LIT,
COM_RESTRICT_UPDATE_RULE_LIT,
COM_RESTRICT_DELETE_RULE_LIT);
cliRC = cliInterface->executeImmediate(buf);
if (cliRC < 0)
{
cliInterface->retrieveSQLDiagnostics(CmpCommon::diags());
return -1;
}
str_sprintf(buf, "insert into %s.\"%s\".%s values (%ld, %ld, 0)",
getSystemCatalog(), SEABASE_MD_SCHEMA, SEABASE_UNIQUE_REF_CONSTR_USAGE,
refdConstrUID, ringConstrUID);
cliRC = cliInterface->executeImmediate(buf);
if (cliRC < 0)
{
cliInterface->retrieveSQLDiagnostics(CmpCommon::diags());
return -1;
}
return 0;
}
short CmpSeabaseDDL::updateIndexInfo(
NAList<NAString> &ringKeyColList,
NAList<NAString> &ringKeyColOrderList,
NAList<NAString> &refdKeyColList,
NAString &uniqueStr,
Int64 constrUID,
const char * catName,
const char * schName,
const char * objName,
NATable * naTable,
NABoolean isUnique, // TRUE: uniq constr. FALSE: ref constr.
NABoolean noPopulate,
NABoolean isEnforced,
NABoolean sameSequenceOfCols,
ExeCliInterface *cliInterface)
{
// Now we need to determine if an index has to be created for
// the unique or ref constraint.
NABoolean createIndex = TRUE;
NAString existingIndexName;
if (naTable->getCorrespondingIndex(ringKeyColList,
TRUE, // explicit index only
isUnique, //TRUE, look for unique index.
TRUE, //isUnique, //TRUE, look for primary key.
(NOT isUnique), // TRUE, look for any index or pkey
TRUE, // exclude system computed cols like salt, division
sameSequenceOfCols,
&existingIndexName))
createIndex = FALSE;
// if constraint is not to be enforced, then do not create an index.
if (createIndex && (NOT isEnforced))
return 0;
ComObjectName indexName(createIndex ? uniqueStr : existingIndexName);
const NAString catalogNamePart = indexName.getCatalogNamePartAsAnsiString();
const NAString schemaNamePart = indexName.getSchemaNamePartAsAnsiString(TRUE);
const NAString objectNamePart = indexName.getObjectNamePartAsAnsiString(TRUE);
NAString quotedSchName;
ToQuotedString(quotedSchName, NAString(schemaNamePart), FALSE);
NAString quotedObjName;
ToQuotedString(quotedObjName, NAString(objectNamePart), FALSE);
char buf[5000];
Lng32 cliRC;
Int64 tableUID = naTable->objectUid().castToInt64();
if (createIndex)
{
NAString keyColNameStr;
for (CollIndex i = 0; i < ringKeyColList.entries(); i++)
{
keyColNameStr += "\"";
keyColNameStr += ringKeyColList[i];
keyColNameStr += "\" ";
keyColNameStr += ringKeyColOrderList[i];
if (i+1 < ringKeyColList.entries())
keyColNameStr += ", ";
}
char noPopStr[100];
if (noPopulate)
strcpy(noPopStr, " no populate ");
else
strcpy(noPopStr, " ");
if (isUnique)
str_sprintf(buf, "create unique index \"%s\" on \"%s\".\"%s\".\"%s\" ( %s ) %s",
quotedObjName.data(),
catName, schName, objName,
keyColNameStr.data(),
noPopStr);
else
str_sprintf(buf, "create index \"%s\" on \"%s\".\"%s\".\"%s\" ( %s ) %s",
quotedObjName.data(),
catName, schName, objName,
keyColNameStr.data(),
noPopStr);
cliRC = cliInterface->executeImmediate(buf);
if (cliRC < 0)
{
cliInterface->retrieveSQLDiagnostics(CmpCommon::diags());
return -1;
}
// update indexes table and mark this index as an implicit index.
str_sprintf(buf, "update %s.\"%s\".%s set is_explicit = 0 where base_table_uid = %ld and index_uid = (select object_uid from %s.\"%s\".%s where catalog_name = '%s' and schema_name = '%s' and object_name = '%s' and object_type = 'IX') ",
getSystemCatalog(), SEABASE_MD_SCHEMA, SEABASE_INDEXES,
tableUID,
getSystemCatalog(), SEABASE_MD_SCHEMA, SEABASE_OBJECTS,
catName, schemaNamePart.data(), objectNamePart.data());
cliRC = cliInterface->executeImmediate(buf);
if (cliRC < 0)
{
cliInterface->retrieveSQLDiagnostics(CmpCommon::diags());
return -1;
}
if (noPopulate)
{
if (updateObjectValidDef(cliInterface,
catalogNamePart, schemaNamePart, objectNamePart,
COM_INDEX_OBJECT_LIT,
COM_YES_LIT))
{
return -1;
}
}
}
// update table_constraints table with the uid of this index.
Int64 indexUID =
getObjectUID(cliInterface,
catName, schemaNamePart, objectNamePart,
COM_INDEX_OBJECT_LIT);
if (indexUID < 0)
{
// primary key. Clear diags area since getObjectUID sets up diags entry.
CmpCommon::diags()->clear();
}
str_sprintf(buf, "update %s.\"%s\".%s set index_uid = %ld where table_uid = %ld and constraint_uid = %ld and constraint_type = '%s'",
getSystemCatalog(), SEABASE_MD_SCHEMA, SEABASE_TABLE_CONSTRAINTS,
indexUID,
tableUID, constrUID,
(isUnique ? COM_UNIQUE_CONSTRAINT_LIT : COM_FOREIGN_KEY_CONSTRAINT_LIT));
cliRC = cliInterface->executeImmediate(buf);
if (cliRC < 0)
{
cliInterface->retrieveSQLDiagnostics(CmpCommon::diags());
return -1;
}
return 0;
}
//RETURN: -1 in case of error. -2, if specified object doesnt exist in MD.
short CmpSeabaseDDL::setupAndErrorChecks
(NAString &tabName, QualifiedName &origTableName,
NAString &currCatName, NAString &currSchName,
NAString &catalogNamePart, NAString &schemaNamePart, NAString &objectNamePart,
NAString &extTableName, NAString &extNameForHbase,
CorrName &cn,
NATable* *naTable,
NABoolean volTabSupported,
NABoolean hbaseMapSupported,
ExeCliInterface *cliInterface,
const ComObjectType objectType,
SQLOperation operation,
NABoolean isExternal)
{
Lng32 cliRC = 0;
Lng32 retcode = 0;
ComObjectName tableName(tabName, COM_TABLE_NAME);
ComAnsiNamePart currCatAnsiName(currCatName);
ComAnsiNamePart currSchAnsiName(currSchName);
tableName.applyDefaults(currCatAnsiName, currSchAnsiName);
NABoolean schNameSpecified = (NOT origTableName.getSchemaName().isNull());
if (isExternal)
{
// Convert the native name to its Trafodion form
tabName = ComConvertNativeNameToTrafName
(tableName.getCatalogNamePartAsAnsiString(),
tableName.getSchemaNamePartAsAnsiString(),
tableName.getObjectNamePartAsAnsiString());
ComObjectName adjustedName(tabName, COM_TABLE_NAME);
tableName = adjustedName;
}
catalogNamePart = tableName.getCatalogNamePartAsAnsiString();
schemaNamePart = tableName.getSchemaNamePartAsAnsiString(TRUE);
objectNamePart = tableName.getObjectNamePartAsAnsiString(TRUE);
extTableName = tableName.getExternalName(TRUE);
extNameForHbase = catalogNamePart + "." + schemaNamePart + "." + objectNamePart;
if ((isSeabaseReservedSchema(tableName)) &&
(!Get_SqlParser_Flags(INTERNAL_QUERY_FROM_EXEUTIL)))
{
*CmpCommon::diags() << DgSqlCode(-CAT_CANNOT_ALTER_DEFINITION_METADATA_SCHEMA);
processReturn();
return -1;
}
retcode = lookForTableInMD(cliInterface,
catalogNamePart, schemaNamePart, objectNamePart,
schNameSpecified, FALSE,
tableName, tabName, extTableName,
objectType);
if (retcode < 0)
{
processReturn();
return -1;
}
if (retcode == 0) // doesn't exist
{
if (objectType == COM_BASE_TABLE_OBJECT)
*CmpCommon::diags() << DgSqlCode(-1127)
<< DgTableName(extTableName);
else
*CmpCommon::diags() << DgSqlCode(-1389)
<< DgString0(extTableName);
processReturn();
return -2;
}
Int32 objectOwnerID = 0;
Int32 schemaOwnerID = 0;
if (naTable)
{
ActiveSchemaDB()->getNATableDB()->useCache();
BindWA bindWA(ActiveSchemaDB(), CmpCommon::context(), FALSE/*inDDL*/);
cn = CorrName(objectNamePart, STMTHEAP, schemaNamePart, catalogNamePart);
*naTable = bindWA.getNATableInternal(cn);
if (*naTable == NULL || bindWA.errStatus())
{
*CmpCommon::diags()
<< DgSqlCode(-4082)
<< DgTableName(cn.getExposedNameAsAnsiString());
processReturn();
return -1;
}
objectOwnerID = (*naTable)->getOwner();
schemaOwnerID = (*naTable)->getSchemaOwner();
// Make sure user has the privilege to perform the alter column
if (!isDDLOperationAuthorized(operation,
objectOwnerID, schemaOwnerID))
{
*CmpCommon::diags() << DgSqlCode(-CAT_NOT_AUTHORIZED);
processReturn ();
return -1;
}
// return an error if trying to alter a column from a volatile table
if ((NOT volTabSupported) && (naTable && (*naTable)->isVolatileTable()))
{
*CmpCommon::diags() << DgSqlCode(-CAT_REGULAR_OPERATION_ON_VOLATILE_OBJECT);
processReturn ();
return -1;
}
if ((NOT hbaseMapSupported) && (naTable && (*naTable)->isHbaseMapTable()))
{
// not supported
*CmpCommon::diags() << DgSqlCode(-3242)
<< DgString0("This feature not available for an HBase mapped table.");
processReturn();
return -1;
}
}
return 0;
}
static void resetHbaseSerialization(NABoolean hbaseSerialization,
NAString &hbVal)
{
if (hbaseSerialization)
{
ActiveSchemaDB()->getDefaults().validateAndInsert
("hbase_serialization", hbVal, FALSE);
}
}
// RETURN: -1, no need to cleanup. -2, caller need to call cleanup
// 0, all ok.
short CmpSeabaseDDL::createSeabaseTable2(
ExeCliInterface &cliInterface,
StmtDDLCreateTable * createTableNode,
NAString &currCatName, NAString &currSchName,
NABoolean isCompound,
Int64 &outObjUID)
{
Lng32 retcode = 0;
Lng32 cliRC = 0;
ComObjectName tableName(createTableNode->getTableName());
ComAnsiNamePart currCatAnsiName(currCatName);
ComAnsiNamePart currSchAnsiName(currSchName);
// external table to be mapped to an existing hbase table
NABoolean hbaseMapFormat = FALSE;
// format of data in hbase mapped table: native or string.
// See ComRowFormat in common/ComSmallDefs.h for details.
NABoolean hbaseMappedDataFormatIsString = FALSE;
// Make some additional checks if creating an external hive table
ComObjectName *srcTableName = NULL;
if ((createTableNode->isExternal()) &&
(NOT createTableNode->mapToHbaseTable()))
{
// The schema name of the target table, if specified, must match the
// schema name of the source table
NAString origSchemaName =
createTableNode->getOrigTableNameAsQualifiedName().getSchemaName();
srcTableName = new(STMTHEAP) ComObjectName
(createTableNode->getLikeSourceTableName(), COM_TABLE_NAME);
srcTableName->applyDefaults(currCatAnsiName, currSchAnsiName);
if (srcTableName->getCatalogNamePartAsAnsiString() == HBASE_SYSTEM_CATALOG)
{
*CmpCommon::diags()
<< DgSqlCode(-3242)
<< DgString0("Cannot create external table on a native HBase table without the MAP TO option.");
return -1;
}
// Convert the native table name to its trafodion name
NAString tabName = ComConvertNativeNameToTrafName
(srcTableName->getCatalogNamePartAsAnsiString(),
srcTableName->getSchemaNamePartAsAnsiString(),
tableName.getObjectNamePartAsAnsiString());
ComObjectName adjustedName(tabName, COM_TABLE_NAME);
NAString type = "HIVE";
tableName = adjustedName;
// Verify that the name with prepending is not too long
if (tableName.getSchemaNamePartAsAnsiString(TRUE).length() >
ComMAX_ANSI_IDENTIFIER_INTERNAL_LEN)
{
*CmpCommon::diags()
<< DgSqlCode(-CAT_EXTERNAL_SCHEMA_NAME_TOO_LONG)
<< DgString0(type.data())
<< DgTableName(tableName.getSchemaNamePartAsAnsiString(FALSE))
<< DgInt0(ComMAX_ANSI_IDENTIFIER_INTERNAL_LEN - sizeof(HIVE_EXT_SCHEMA_PREFIX));
return -1;
}
if ((origSchemaName.length() > 0)&&
(origSchemaName != srcTableName->getSchemaNamePart().getExternalName()))
{
*CmpCommon::diags()
<< DgSqlCode(-CAT_EXTERNAL_NAME_MISMATCH)
<< DgString0 (type.data())
<< DgTableName(origSchemaName)
<< DgString1((srcTableName->getSchemaNamePart().getExternalName()));
return -1;
}
// For now the object name of the target table must match the
// object name of the source table
if (tableName.getObjectNamePart().getExternalName() !=
srcTableName->getObjectNamePart().getExternalName())
{
*CmpCommon::diags()
<< DgSqlCode(-CAT_EXTERNAL_NAME_MISMATCH)
<< DgString0 (type.data())
<< DgTableName(tableName.getObjectNamePart().getExternalName())
<< DgString1((srcTableName->getObjectNamePart().getExternalName()));
return -1;
}
} // external hive table
// Make some additional checks if creating an external hbase mapped table
if ((createTableNode->isExternal()) &&
(createTableNode->mapToHbaseTable()))
{
if (CmpCommon::getDefault(TRAF_HBASE_MAPPED_TABLES) == DF_OFF)
{
*CmpCommon::diags() << DgSqlCode(-3242)
<< DgString0("HBase mapped tables not supported.");
return -1;
}
srcTableName = new(STMTHEAP) ComObjectName
(createTableNode->getLikeSourceTableName(), COM_TABLE_NAME);
ComAnsiNamePart hbCat(HBASE_SYSTEM_CATALOG);
ComAnsiNamePart hbSch(HBASE_SYSTEM_SCHEMA);
srcTableName->applyDefaults(hbCat, hbSch);
hbaseMapFormat = TRUE;
hbaseMappedDataFormatIsString =
createTableNode->isHbaseDataFormatString();
ComAnsiNamePart trafCat(TRAFODION_SYSCAT_LIT);
ComAnsiNamePart trafSch(NAString(HBASE_EXT_MAP_SCHEMA),
ComAnsiNamePart::INTERNAL_FORMAT);
tableName.setCatalogNamePart(trafCat);
tableName.setSchemaNamePart(trafSch);
// For now the object name of the target table must match the
// object name of the source table
if (tableName.getObjectNamePart().getExternalName() !=
srcTableName->getObjectNamePart().getExternalName())
{
*CmpCommon::diags()
<< DgSqlCode(-CAT_EXTERNAL_NAME_MISMATCH)
<< DgString0 ("HBASE")
<< DgTableName(tableName.getObjectNamePart().getExternalName())
<< DgString1((srcTableName->getObjectNamePart().getExternalName()));
return -1;
}
} // external hbase mapped table
const NAString catalogNamePart = tableName.getCatalogNamePartAsAnsiString();
const NAString schemaNamePart = tableName.getSchemaNamePartAsAnsiString(TRUE);
const NAString objectNamePart = tableName.getObjectNamePartAsAnsiString(TRUE);
const NAString extTableName = tableName.getExternalName(TRUE);
const NAString extNameForHbase =
(hbaseMapFormat ? "" :
catalogNamePart + "." + schemaNamePart + "." + objectNamePart);
ExpHbaseInterface * ehi = allocEHI();
if (ehi == NULL)
{
processReturn();
return -1;
}
if ((isSeabaseReservedSchema(tableName)) &&
(!Get_SqlParser_Flags(INTERNAL_QUERY_FROM_EXEUTIL)))
{
*CmpCommon::diags() << DgSqlCode(-CAT_CREATE_TABLE_NOT_ALLOWED_IN_SMD)
<< DgTableName(extTableName);
deallocEHI(ehi);
processReturn();
return -1;
}
retcode = existsInSeabaseMDTable(&cliInterface,
catalogNamePart, schemaNamePart, objectNamePart,
COM_UNKNOWN_OBJECT, FALSE);
if (retcode < 0)
{
deallocEHI(ehi);
processReturn();
return -1;
}
if (retcode == 1) // already exists
{
if (NOT createTableNode->createIfNotExists())
{
if (createTableNode->isVolatile())
*CmpCommon::diags() << DgSqlCode(-1390)
<< DgString0(objectNamePart);
else
*CmpCommon::diags() << DgSqlCode(-1390)
<< DgString0(extTableName);
}
deallocEHI(ehi);
processReturn();
return -1;
}
// If creating an external table, go perform operation
if (createTableNode->isExternal())
{
retcode = createSeabaseTableExternal
(cliInterface, createTableNode, tableName, *srcTableName);
if (retcode != 0 && CmpCommon::diags()->getNumber(DgSqlCode::ERROR_) == 0)
SEABASEDDL_INTERNAL_ERROR("creating external HIVE table");
if (NOT hbaseMapFormat)
{
deallocEHI(ehi);
processReturn();
return retcode;
}
}
// make sure the table to be mapped exists
if (hbaseMapFormat)
{
HbaseStr hbaseTable;
hbaseTable.val = (char*)objectNamePart.data();
hbaseTable.len = objectNamePart.length();
if (ehi->exists(hbaseTable) == 0) // does not exist in hbase
{
*CmpCommon::diags() << DgSqlCode(-4260)
<< DgString0(objectNamePart);
deallocEHI(ehi);
processReturn();
return -1;
}
}
ElemDDLColDefArray &colArray = createTableNode->getColDefArray();
ElemDDLColRefArray &keyArray =
(createTableNode->getIsConstraintPKSpecified() ?
createTableNode->getPrimaryKeyColRefArray() :
(createTableNode->getStoreOption() == COM_KEY_COLUMN_LIST_STORE_OPTION ?
createTableNode->getKeyColumnArray() :
createTableNode->getPrimaryKeyColRefArray()));
if ((NOT ((createTableNode->isExternal()) &&
(createTableNode->mapToHbaseTable()))) &&
((createTableNode->getIsConstraintPKSpecified()) &&
(createTableNode->getAddConstraintPK()) &&
(createTableNode->getAddConstraintPK()->getAlterTableAction()->castToElemDDLConstraintPK()->notSerialized())))
{
*CmpCommon::diags() << DgSqlCode(-3242)
<< DgString0("NOT SERIALIZED option cannot be specified for primary key of this table.");
return -1;
}
Int32 objectOwnerID = SUPER_USER;
Int32 schemaOwnerID = SUPER_USER;
ComSchemaClass schemaClass;
retcode = verifyDDLCreateOperationAuthorized(&cliInterface,
SQLOperation::CREATE_TABLE,
catalogNamePart,
schemaNamePart,
schemaClass,
objectOwnerID,
schemaOwnerID);
if (retcode != 0)
{
handleDDLCreateAuthorizationError(retcode,catalogNamePart,schemaNamePart);
deallocEHI(ehi);
processReturn();
return -1;
}
// If the schema name specified is external HIVE or HBase name, users cannot
// create them.
if (ComIsTrafodionExternalSchemaName(schemaNamePart) &&
(!Get_SqlParser_Flags(INTERNAL_QUERY_FROM_EXEUTIL)) &&
(NOT hbaseMapFormat))
{
// error.
*SqlParser_Diags << DgSqlCode(-CAT_CREATE_TABLE_NOT_ALLOWED_IN_SMD)
<< DgTableName(extTableName.data());
return -1;
}
if (createTableNode->getIsLikeOptionSpecified())
{
createSeabaseTableLike(&cliInterface,
createTableNode, currCatName, currSchName);
deallocEHI(ehi);
processReturn();
return -1;
}
// For shared schemas, histogram tables should be owned by the schema owner,
// not the first user to run UPDATE STATISTICS in the schema.
if (schemaClass == COM_SCHEMA_CLASS_SHARED && isHistogramTable(objectNamePart))
objectOwnerID = schemaOwnerID;
// check if SYSKEY is specified as a column name.
for (Lng32 i = 0; i < colArray.entries(); i++)
{
if ((CmpCommon::getDefault(TRAF_ALLOW_RESERVED_COLNAMES) == DF_OFF) &&
(ComTrafReservedColName(colArray[i]->getColumnName())))
{
*CmpCommon::diags() << DgSqlCode(-CAT_RESERVED_COLUMN_NAME)
<< DgString0(colArray[i]->getColumnName());
deallocEHI(ehi);
processReturn();
return -1;
}
}
NABoolean implicitPK = FALSE;
NAString syskeyColName("SYSKEY");
SQLLargeInt * syskeyType = new(STMTHEAP) SQLLargeInt(STMTHEAP, TRUE, FALSE);
ElemDDLColDef syskeyColDef(NULL, &syskeyColName, syskeyType, NULL,
STMTHEAP);
ElemDDLColRef edcr("SYSKEY", COM_ASCENDING_ORDER);
syskeyColDef.setColumnClass(COM_SYSTEM_COLUMN);
NAString hbRowIdColName("ROW_ID");
SQLVarChar * hbRowIdType = new(STMTHEAP) SQLVarChar(STMTHEAP, 1000, FALSE);
ElemDDLColDef hbRowIdColDef(NULL, &hbRowIdColName, hbRowIdType, NULL,
STMTHEAP);
ElemDDLColRef hbcr("ROW_ID", COM_ASCENDING_ORDER);
hbRowIdColDef.setColumnClass(COM_SYSTEM_COLUMN);
CollIndex numSysCols = 0;
CollIndex numSaltCols = 0;
CollIndex numDivCols = 0;
if (((createTableNode->getStoreOption() == COM_KEY_COLUMN_LIST_STORE_OPTION) &&
(NOT createTableNode->getIsConstraintPKSpecified())) ||
(keyArray.entries() == 0))
{
if (hbaseMapFormat)
{
// for now, return error if pkey is not specified.
*CmpCommon::diags() << DgSqlCode(-4259);
deallocEHI(ehi);
processReturn();
return -1;
colArray.insertAt(0, &hbRowIdColDef);
keyArray.insert(&hbcr);
}
else
{
colArray.insertAt(0, &syskeyColDef);
keyArray.insert(&edcr);
}
implicitPK = TRUE;
numSysCols++;
}
int numSaltPartns = 0; // # of "_SALT_" values
int numSplits = 0; // # of initial region splits
Lng32 numSaltPartnsFromCQD =
CmpCommon::getDefaultNumeric(TRAF_NUM_OF_SALT_PARTNS);
if ((createTableNode->getSaltOptions()) ||
((numSaltPartnsFromCQD > 0) &&
(NOT implicitPK)))
{
if (hbaseMapFormat)
{
// salt option not supported on hbase map table
*CmpCommon::diags() << DgSqlCode(-4259);
deallocEHI(ehi);
processReturn();
return -1;
}
// add a system column SALT INTEGER NOT NULL with a computed
// default value HASH2PARTFUNC(<salting cols> FOR <num salt partitions>)
ElemDDLSaltOptionsClause * saltOptions = createTableNode->getSaltOptions();
ElemDDLColRefArray *saltArray = createTableNode->getSaltColRefArray();
NAString saltExprText("HASH2PARTFUNC(");
NABoolean firstSaltCol = TRUE;
char numSaltPartnsStr[20];
if (saltArray == NULL || saltArray->entries() == 0)
{
// if no salting columns are specified, use all key columns
saltArray = &keyArray;
}
else
{
// Validate that salting columns refer to real key columns
for (CollIndex s=0; s<saltArray->entries(); s++)
if (keyArray.getColumnIndex((*saltArray)[s]->getColumnName()) < 0)
{
*CmpCommon::diags() << DgSqlCode(-1195)
<< DgColumnName((*saltArray)[s]->getColumnName());
deallocEHI(ehi);
processReturn();
return -1;
}
}
for (CollIndex i=0; i<saltArray->entries(); i++)
{
const NAString &colName = (*saltArray)[i]->getColumnName();
ComAnsiNamePart cnp(colName, ComAnsiNamePart::INTERNAL_FORMAT);
Lng32 colIx = colArray.getColumnIndex(colName);
if (colIx < 0)
{
*CmpCommon::diags() << DgSqlCode(-1009)
<< DgColumnName(colName);
deallocEHI(ehi);
processReturn();
return -1;
}
NAType *colType = colArray[colIx]->getColumnDataType();
NAString typeText;
short rc = colType->getMyTypeAsText(&typeText, FALSE);
// don't include SYSKEY in the list of salt columns
if (colName != "SYSKEY")
{
if (firstSaltCol)
firstSaltCol = FALSE;
else
saltExprText += ",";
saltExprText += "CAST(";
if (NOT cnp.isDelimitedIdentifier())
saltExprText += "\"";
saltExprText += cnp.getExternalName();
if (NOT cnp.isDelimitedIdentifier())
saltExprText += "\"";
saltExprText += " AS ";
saltExprText += typeText;
if (!colType->supportsSQLnull())
saltExprText += " NOT NULL";
saltExprText += ")";
if (colType->getTypeQualifier() == NA_NUMERIC_TYPE &&
!(((NumericType *) colType)->isExact()))
{
*CmpCommon::diags() << DgSqlCode(-1120);
deallocEHI(ehi);
processReturn();
return -1;
}
}
else if (saltArray != &keyArray || saltArray->entries() == 1)
{
// SYSKEY was explicitly specified in salt column or is the only column,
// this is an error
*CmpCommon::diags() << DgSqlCode(-1195)
<< DgColumnName((*saltArray)[i]->getColumnName());
deallocEHI(ehi);
processReturn();
return -1;
}
}
numSaltPartns =
(saltOptions ? saltOptions->getNumPartitions() : numSaltPartnsFromCQD);
saltExprText += " FOR ";
sprintf(numSaltPartnsStr,"%d", numSaltPartns);
saltExprText += numSaltPartnsStr;
saltExprText += ")";
if (numSaltPartns <= 1 || numSaltPartns > 1024)
{
// number of salt partitions is out of bounds
*CmpCommon::diags() << DgSqlCode(-CAT_INVALID_NUM_OF_SALT_PARTNS)
<< DgInt0(2)
<< DgInt1(1024);
deallocEHI(ehi);
processReturn();
return -1;
}
NAString saltColName(ElemDDLSaltOptionsClause::getSaltSysColName());
SQLInt * saltType = new(STMTHEAP) SQLInt(STMTHEAP, FALSE, FALSE);
ElemDDLColDefault *saltDef =
new(STMTHEAP) ElemDDLColDefault(
ElemDDLColDefault::COL_COMPUTED_DEFAULT);
saltDef->setComputedDefaultExpr(saltExprText);
ElemDDLColDef * saltColDef =
new(STMTHEAP) ElemDDLColDef(NULL, &saltColName, saltType, saltDef,
STMTHEAP);
ElemDDLColRef * edcrs =
new(STMTHEAP) ElemDDLColRef(saltColName, COM_ASCENDING_ORDER);
saltColDef->setColumnClass(COM_SYSTEM_COLUMN);
// add this new salt column at the end
// and also as key column 0
colArray.insert(saltColDef);
keyArray.insertAt(0, edcrs);
numSysCols++;
numSaltCols++;
numSplits = numSaltPartns - 1;
}
// is hbase data stored in varchar format
if (hbaseMapFormat && hbaseMappedDataFormatIsString)
{
// cannot specify serialized primary key
if (createTableNode->getAddConstraintPK()->getAlterTableAction()->
castToElemDDLConstraintPK()->serialized())
{
*CmpCommon::diags() << DgSqlCode(-3242)
<< DgString0("SERIALIZED option cannot be specified for primary key of this table.");
return -1;
}
// must have only one varchar primary key col
if (keyArray.entries() > 1)
{
*CmpCommon::diags() << DgSqlCode(-3242)
<< DgString0("Only one column can be specified as the primary key of this table.");
return -1;
}
Lng32 tableColNum =
(Lng32)colArray.getColumnIndex(keyArray[0]->getColumnName());
NAType *colType = colArray[tableColNum]->getColumnDataType();
if (NOT DFS2REC::isAnyVarChar(colType->getFSDatatype()))
{
*CmpCommon::diags() << DgSqlCode(-3242)
<< DgString0("Primary key column must be specified as varchar datatype for this table.");
return -1;
}
}
// create table in seabase
ParDDLFileAttrsCreateTable &fileAttribs =
createTableNode->getFileAttributes();
NABoolean alignedFormat = FALSE;
if (fileAttribs.isRowFormatSpecified() == TRUE)
{
if (fileAttribs.getRowFormat() == ElemDDLFileAttrRowFormat::eALIGNED)
{
alignedFormat = TRUE;
}
}
else if(CmpCommon::getDefault(TRAF_ALIGNED_ROW_FORMAT) == DF_ON)
{
if ( NOT isSeabaseReservedSchema(tableName))
{
// aligned format default does not apply to hbase map tables
if (NOT hbaseMapFormat)
alignedFormat = TRUE;
}
}
if (hbaseMapFormat && alignedFormat)
{
// not supported
*CmpCommon::diags() << DgSqlCode(-3242)
<< DgString0("Aligned format cannot be specified for an HBase mapped table.");
deallocEHI(ehi);
processReturn();
return -1;
}
const NAString &defaultColFam = fileAttribs.getColFam();
// allow nullable clustering key or unique constraints based on the
// CQD settings. If a volatile table is being created and cqd
// VOLATILE_TABLE_FIND_SUITABLE_KEY is ON, then allow it.
// If ALLOW_NULLABLE_UNIQUE_KEY_CONSTRAINT is set, then allow it.
NABoolean allowNullableUniqueConstr = FALSE;
if ((CmpCommon::getDefault(VOLATILE_TABLE_FIND_SUITABLE_KEY) != DF_OFF) &&
(createTableNode->isVolatile()))
allowNullableUniqueConstr = TRUE;
if ((createTableNode->getIsConstraintPKSpecified()) &&
(createTableNode->getAddConstraintPK()->getAlterTableAction()->castToElemDDLConstraintPK()->isNullableSpecified()))
allowNullableUniqueConstr = TRUE;
int numIterationsToCompleteColumnList = 1;
Lng32 numCols = 0;
Lng32 numKeys = 0;
ComTdbVirtTableColumnInfo * colInfoArray = NULL;
ComTdbVirtTableKeyInfo * keyInfoArray = NULL;
Lng32 identityColPos = -1;
std::vector<NAString> userColFamVec;
std::vector<NAString> trafColFamVec;
// if hbase map format, turn off global serialization default.
NABoolean hbaseSerialization = FALSE;
NAString hbVal;
if (hbaseMapFormat)
{
if (CmpCommon::getDefault(HBASE_SERIALIZATION) == DF_ON)
{
NAString value("OFF");
hbVal = "ON";
ActiveSchemaDB()->getDefaults().validateAndInsert(
"hbase_serialization", value, FALSE);
hbaseSerialization = TRUE;
}
}
// build colInfoArray and keyInfoArray, this may take two
// iterations if we need to add a divisioning column
for (int iter=0; iter < numIterationsToCompleteColumnList; iter++)
{
numCols = colArray.entries();
numKeys = keyArray.entries();
colInfoArray = new(STMTHEAP) ComTdbVirtTableColumnInfo[numCols];
keyInfoArray = new(STMTHEAP) ComTdbVirtTableKeyInfo[numKeys];
if (buildColInfoArray(COM_BASE_TABLE_OBJECT,
FALSE, // not a metadata, histogram or repository object
&colArray, colInfoArray, implicitPK,
alignedFormat, &identityColPos,
(hbaseMapFormat ? NULL : &userColFamVec),
&trafColFamVec,
defaultColFam.data()))
{
resetHbaseSerialization(hbaseSerialization, hbVal);
processReturn();
return -1;
}
if (buildKeyInfoArray(&colArray, NULL,
&keyArray, colInfoArray, keyInfoArray,
allowNullableUniqueConstr))
{
resetHbaseSerialization(hbaseSerialization, hbVal);
processReturn();
return -1;
}
if (iter == 0 && createTableNode->isDivisionClauseSpecified())
{
// We need the colArray to be able to bind the divisioning
// expression, check it and compute its type. Once we have the
// type, we will add a divisioning column of that type and
// also add that column to the key. Then we will need to go
// through this loop once more and create the updated colArray.
numIterationsToCompleteColumnList = 2;
NAColumnArray *naColArrayForBindingDivExpr = new(STMTHEAP) NAColumnArray(STMTHEAP);
NAColumnArray *keyColArrayForBindingDivExpr = new(STMTHEAP) NAColumnArray(STMTHEAP);
ItemExprList * divExpr = createTableNode->getDivisionExprList();
ElemDDLColRefArray *divColNamesFromDDL = createTableNode->getDivisionColRefArray();
CmpSeabaseDDL::convertColAndKeyInfoArrays(
numCols,
colInfoArray,
numKeys,
keyInfoArray,
naColArrayForBindingDivExpr,
keyColArrayForBindingDivExpr);
for (CollIndex d=0; d<divExpr->entries(); d++)
{
NABoolean exceptionOccurred = FALSE;
ComColumnOrdering divKeyOrdering = COM_ASCENDING_ORDER;
ItemExpr *boundDivExpr =
bindDivisionExprAtDDLTime((*divExpr)[d],
keyColArrayForBindingDivExpr,
STMTHEAP);
if (!boundDivExpr)
{
resetHbaseSerialization(hbaseSerialization, hbVal);
processReturn();
return -1;
}
if (boundDivExpr->getOperatorType() == ITM_INVERSE)
{
divKeyOrdering = COM_DESCENDING_ORDER;
boundDivExpr = boundDivExpr->child(0);
if (boundDivExpr->getOperatorType() == ITM_INVERSE)
{
// in rare cases we could have two inverse operators
// stacked on top of each other, indicating ascending
divKeyOrdering = COM_ASCENDING_ORDER;
boundDivExpr = boundDivExpr->child(0);
}
}
try
{
// put this into a try/catch block because it could throw
// an exception when type synthesis fails and that would leave
// the transaction begun by the DDL operation in limbo
boundDivExpr->synthTypeAndValueId();
}
catch (...)
{
// diags area should be set, if not, set it
if (CmpCommon::diags()->getNumber(DgSqlCode::ERROR_) == 0)
*CmpCommon::diags() << DgSqlCode(-4243)
<< DgString0("(expression with unknown type)");
exceptionOccurred = TRUE;
}
if (exceptionOccurred ||
boundDivExpr->getValueId() == NULL_VALUE_ID)
{
resetHbaseSerialization(hbaseSerialization, hbVal);
processReturn();
return -1;
}
if (validateDivisionByExprForDDL(boundDivExpr))
{
resetHbaseSerialization(hbaseSerialization, hbVal);
processReturn();
return -1;
}
// Add a divisioning column to the list of columns and the key
char buf[16];
snprintf(buf, sizeof(buf), "_DIVISION_%d_", d+1);
NAString divColName(buf);
// if the division column name was specified in the DDL, use that instead
if (divColNamesFromDDL && divColNamesFromDDL->entries() > d)
divColName = (*divColNamesFromDDL)[d]->getColumnName();
NAType * divColType =
boundDivExpr->getValueId().getType().newCopy(STMTHEAP);
ElemDDLColDefault *divColDefault =
new(STMTHEAP) ElemDDLColDefault(
ElemDDLColDefault::COL_COMPUTED_DEFAULT);
NAString divExprText;
boundDivExpr->unparse(divExprText, PARSER_PHASE, COMPUTED_COLUMN_FORMAT);
divColDefault->setComputedDefaultExpr(divExprText);
ElemDDLColDef * divColDef =
new(STMTHEAP) ElemDDLColDef(NULL, &divColName, divColType, divColDefault,
STMTHEAP);
ElemDDLColRef * edcrs =
new(STMTHEAP) ElemDDLColRef(divColName, divKeyOrdering);
divColDef->setColumnClass(COM_SYSTEM_COLUMN);
divColDef->setDivisionColumnFlag(TRUE);
divColDef->setDivisionColumnSequenceNumber(d);
// add this new divisioning column to the end of the row
// and also to the key, right after any existing salt and divisioning columns
colArray.insert(divColDef);
keyArray.insertAt(numSaltCols+numDivCols, edcrs);
numSysCols++;
numDivCols++;
}
}
} // iterate 1 or 2 times to get all columns, including divisioning columns
if (hbaseSerialization)
{
ActiveSchemaDB()->getDefaults().validateAndInsert
("hbase_serialization", hbVal, FALSE);
}
Int32 keyLength = 0;
for(CollIndex i = 0; i < keyArray.entries(); i++)
{
const NAString &colName = keyArray[i]->getColumnName();
Lng32 colIx = colArray.getColumnIndex(colName);
if (colIx < 0)
{
*CmpCommon::diags() << DgSqlCode(-1009)
<< DgColumnName(colName);
deallocEHI(ehi);
processReturn();
return -1;
}
NAType *colType = colArray[colIx]->getColumnDataType();
if (colType->getFSDatatype() == REC_BLOB || colType->getFSDatatype() == REC_CLOB)
//Cannot allow LOB in primary or clustering key
{
*CmpCommon::diags() << DgSqlCode(-CAT_LOB_COL_CANNOT_BE_INDEX_OR_KEY)
<< DgColumnName(colName);
deallocEHI(ehi);
processReturn();
return -1;
}
keyLength += colType->getEncodedKeyLength();
}
//check the key length
if(keyLength > MAX_HBASE_ROWKEY_LEN )
{
*CmpCommon::diags() << DgSqlCode(-CAT_ROWKEY_LEN_TOO_LARGE)
<< DgInt0(keyLength)
<< DgInt1(MAX_HBASE_ROWKEY_LEN);
deallocEHI(ehi);
processReturn();
return -1;
}
if (hbaseMapFormat)
{
for(CollIndex i = 0; i < colArray.entries(); i++)
{
const NAString colName = colInfoArray[i].colName;
Lng32 colIx = keyArray.getColumnIndex(colName);
if (colIx < 0) // not a key col
{
if (colInfoArray[i].defaultClass != COM_NULL_DEFAULT)
{
*CmpCommon::diags() << DgSqlCode(-3242)
<< DgString0("Non-key columns of an HBase mapped table must be nullable with default value of NULL.");
deallocEHI(ehi);
processReturn();
return -1;
}
// must have a default value if not nullable
if (! colInfoArray[i].nullable)
{
if (colInfoArray[i].defaultClass == COM_NO_DEFAULT)
{
*CmpCommon::diags() << DgSqlCode(-3242)
<< DgString0("Non-key non-nullable columns of an HBase mapped table must have a default value.");
deallocEHI(ehi);
processReturn();
return -1;
}
}
}
} // for
}
char ** encodedKeysBuffer = NULL;
if (numSplits > 0) {
TrafDesc * colDescs =
convertVirtTableColumnInfoArrayToDescStructs(&tableName,
colInfoArray,
numCols) ;
TrafDesc * keyDescs =
convertVirtTableKeyInfoArrayToDescStructs(keyInfoArray,
colInfoArray,
numKeys) ;
if (createEncodedKeysBuffer(encodedKeysBuffer/*out*/,
numSplits /*out*/,
colDescs, keyDescs,
numSaltPartns,
numSplits,
NULL,
numKeys,
keyLength, FALSE))
{
processReturn();
return -1;
}
}
ComTdbVirtTableTableInfo * tableInfo = new(STMTHEAP) ComTdbVirtTableTableInfo[1];
tableInfo->tableName = NULL;
tableInfo->createTime = 0;
tableInfo->redefTime = 0;
tableInfo->objUID = 0;
tableInfo->isAudited = (fileAttribs.getIsAudit() ? 1 : 0);
tableInfo->validDef = 1;
tableInfo->hbaseCreateOptions = NULL;
tableInfo->objectFlags = 0;
tableInfo->tablesFlags = 0;
if (fileAttribs.isOwnerSpecified())
{
// Fixed bug: if BY CLAUSE specified an unregistered user, then the object
// owner is set to 0 in metadata. Once 0, the table could not be dropped.
NAString owner = fileAttribs.getOwner();
Int16 retcode = (ComUser::getUserIDFromUserName(owner.data(),objectOwnerID));
if (retcode == FENOTFOUND)
{
*CmpCommon::diags() << DgSqlCode(-CAT_AUTHID_DOES_NOT_EXIST_ERROR)
<< DgString0(owner.data());
processReturn();
return -1;
}
else if (retcode != FEOK)
{
*CmpCommon::diags() << DgSqlCode (-CAT_INTERNAL_EXCEPTION_ERROR)
<< DgString0(__FILE__)
<< DgInt0(__LINE__)
<< DgString1("verifying grantee");
processReturn();
return -1;
}
if (schemaClass == COM_SCHEMA_CLASS_PRIVATE &&
objectOwnerID != schemaOwnerID)
{
*CmpCommon::diags() << DgSqlCode(-CAT_BY_CLAUSE_IN_PRIVATE_SCHEMA);
deallocEHI(ehi);
processReturn();
return -1;
}
}
tableInfo->objOwnerID = objectOwnerID;
tableInfo->schemaOwnerID = schemaOwnerID;
tableInfo->numSaltPartns = (numSplits > 0 ? numSplits+1 : 0);
if (hbaseMapFormat && hbaseMappedDataFormatIsString)
tableInfo->rowFormat = COM_HBASE_STR_FORMAT_TYPE;
else if (alignedFormat)
tableInfo->rowFormat = COM_ALIGNED_FORMAT_TYPE;
else
tableInfo->rowFormat = COM_HBASE_FORMAT_TYPE;
NAList<HbaseCreateOption*> hbaseCreateOptions(STMTHEAP);
NAString hco;
short retVal = setupHbaseOptions(createTableNode->getHbaseOptionsClause(),
numSplits, extTableName,
hbaseCreateOptions, hco);
if (retVal)
{
deallocEHI(ehi);
processReturn();
return -1;
}
if (alignedFormat)
{
hco += "ROW_FORMAT=>ALIGNED ";
}
tableInfo->hbaseCreateOptions = (hco.isNull() ? NULL : hco.data());
tableInfo->defaultColFam = NULL;
tableInfo->allColFams = NULL;
Int64 objUID = -1;
if (Get_SqlParser_Flags(INTERNAL_QUERY_FROM_EXEUTIL))
{
const char* v = ActiveSchemaDB()->getDefaults().
getValue(TRAF_CREATE_TABLE_WITH_UID);
if ((v) and (strlen(v) > 0))
{
objUID = str_atoi(v, strlen(v));
}
}
if (updateSeabaseMDTable(&cliInterface,
catalogNamePart, schemaNamePart, objectNamePart,
COM_BASE_TABLE_OBJECT,
COM_NO_LIT,
tableInfo,
numCols,
colInfoArray,
numKeys,
keyInfoArray,
0, NULL,
objUID))
{
*CmpCommon::diags()
<< DgSqlCode(-CAT_UNABLE_TO_CREATE_OBJECT)
<< DgTableName(extTableName);
deallocEHI(ehi);
processReturn();
return -1;
}
outObjUID = objUID;
// update TEXT table with column families.
// Column families are stored separated by a blank space character.
NAString allColFams;
NABoolean addToTextTab = FALSE;
if (defaultColFam != SEABASE_DEFAULT_COL_FAMILY)
addToTextTab = TRUE;
else if (userColFamVec.size() > 1)
addToTextTab = TRUE;
else if ((userColFamVec.size() == 1) && (userColFamVec[0] != SEABASE_DEFAULT_COL_FAMILY))
addToTextTab = TRUE;
if (addToTextTab)
{
allColFams = defaultColFam + " ";
for (int i = 0; i < userColFamVec.size(); i++)
{
allColFams += userColFamVec[i];
allColFams += " ";
}
cliRC = updateTextTable(&cliInterface, objUID,
COM_HBASE_COL_FAMILY_TEXT, 0,
allColFams);
if (cliRC < 0)
{
*CmpCommon::diags()
<< DgSqlCode(-CAT_UNABLE_TO_CREATE_OBJECT)
<< DgTableName(extTableName);
deallocEHI(ehi);
processReturn();
return -1;
}
}
if (createTableNode->getAddConstraintPK())
{
if (updatePKeyInfo(createTableNode->getAddConstraintPK(),
catalogNamePart, schemaNamePart, objectNamePart,
objectOwnerID,
schemaOwnerID,
keyArray.entries(),
NULL,
NULL,
keyInfoArray,
&cliInterface))
{
return -1;
}
}
if (identityColPos >= 0)
{
ElemDDLColDef *colDef = colArray[identityColPos];
NAString seqName;
SequenceGeneratorAttributes::genSequenceName
(catalogNamePart, schemaNamePart, objectNamePart, colDef->getColumnName(),
seqName);
if (colDef->getSGOptions())
{
colDef->getSGOptions()->setFSDataType((ComFSDataType)colDef->getColumnDataType()->getFSDatatype());
if (colDef->getSGOptions()->validate(2/*identity*/))
{
deallocEHI(ehi);
processReturn();
return -1;
}
}
SequenceGeneratorAttributes sga;
colDef->getSGOptions()->genSGA(sga);
NAString idOptions;
sga.display(NULL, &idOptions, TRUE);
char buf[4000];
str_sprintf(buf, "create internal sequence %s.\"%s\".\"%s\" %s",
catalogNamePart.data(), schemaNamePart.data(), seqName.data(),
idOptions.data());
cliRC = cliInterface.executeImmediate(buf);
if (cliRC < 0)
{
cliInterface.retrieveSQLDiagnostics(CmpCommon::diags());
deallocEHI(ehi);
processReturn();
return -1;
}
CorrName cn(objectNamePart, STMTHEAP, schemaNamePart, catalogNamePart);
ActiveSchemaDB()->getNATableDB()->removeNATable
(cn,
ComQiScope::REMOVE_MINE_ONLY, COM_BASE_TABLE_OBJECT,
createTableNode->ddlXns(), FALSE);
// update datatype for this sequence
str_sprintf(buf, "update %s.\"%s\".%s set fs_data_type = %d where seq_type = '%s' and seq_uid = (select object_uid from %s.\"%s\".\"%s\" where catalog_name = '%s' and schema_name = '%s' and object_name = '%s' and object_type = '%s') ",
getSystemCatalog(), SEABASE_MD_SCHEMA, SEABASE_SEQ_GEN,
colDef->getColumnDataType()->getFSDatatype(),
COM_INTERNAL_SG_LIT,
getSystemCatalog(), SEABASE_MD_SCHEMA, SEABASE_OBJECTS,
catalogNamePart.data(), schemaNamePart.data(), seqName.data(),
COM_SEQUENCE_GENERATOR_OBJECT_LIT);
Int64 rowsAffected = 0;
cliRC = cliInterface.executeImmediate(buf, NULL, NULL, FALSE, &rowsAffected);
if (cliRC < 0)
{
cliInterface.retrieveSQLDiagnostics(CmpCommon::diags());
deallocEHI(ehi);
processReturn();
return -1;
}
}
NABoolean ddlXns = createTableNode->ddlXns();
if ((NOT extNameForHbase.isNull()) &&
(CmpCommon::getDefault(TRAF_NO_HBASE_DROP_CREATE) == DF_OFF))
{
HbaseStr hbaseTable;
hbaseTable.val = (char*)extNameForHbase.data();
hbaseTable.len = extNameForHbase.length();
if (createHbaseTable(ehi, &hbaseTable, trafColFamVec,
&hbaseCreateOptions,
numSplits, keyLength,
encodedKeysBuffer,
FALSE, ddlXns
) == -1)
{
deallocEHI(ehi);
processReturn();
return -2;
}
}
// if this table has lob columns, create the lob files
short *lobNumList = new (STMTHEAP) short[numCols];
short *lobTypList = new (STMTHEAP) short[numCols];
char **lobLocList = new (STMTHEAP) char*[numCols];
char **lobColNameList = new (STMTHEAP) char*[numCols];
Lng32 j = 0;
Int64 lobMaxSize = CmpCommon::getDefaultNumeric(LOB_MAX_SIZE)*1024*1024;
for (Int32 i = 0; i < colArray.entries(); i++)
{
ElemDDLColDef *column = colArray[i];
Lng32 datatype = column->getColumnDataType()->getFSDatatype();
if ((datatype == REC_BLOB) ||
(datatype == REC_CLOB))
{
lobNumList[j] = i; //column->getColumnNumber();
lobTypList[j] = (short)(column->getLobStorage());
char * loc = new (STMTHEAP) char[1024];
const char* f = ActiveSchemaDB()->getDefaults().
getValue(LOB_STORAGE_FILE_DIR);
strcpy(loc, f);
lobLocList[j] = loc;
char *colname = new (STMTHEAP) char[256];
strcpy(colname,column->getColumnName());
lobColNameList[j] = colname;
j++;
}
}
char lobHdfsServer[256] ; // max length determined by dfs.namenode.fs-limits.max-component-length(255)
memset(lobHdfsServer,0,256);
strncpy(lobHdfsServer,CmpCommon::getDefaultString(LOB_HDFS_SERVER),sizeof(lobHdfsServer)-1);
Int32 lobHdfsPort = (Lng32)CmpCommon::getDefaultNumeric(LOB_HDFS_PORT);
if (j > 0)
{
Int32 rc = sendAllControls(FALSE, FALSE, TRUE);
//if the table is a volatile table return an error
if (createTableNode->isVolatile())
{
*CmpCommon::diags()
<< DgSqlCode(-CAT_LOB_COLUMN_IN_VOLATILE_TABLE)
<< DgTableName(extTableName);
deallocEHI(ehi);
processReturn();
return -1;
}
Int64 objUID = getObjectUID(&cliInterface,
catalogNamePart.data(), schemaNamePart.data(),
objectNamePart.data(),
COM_BASE_TABLE_OBJECT_LIT);
ComString newSchName = "\"";
newSchName += catalogNamePart;
newSchName.append("\".\"");
newSchName.append(schemaNamePart);
newSchName += "\"";
NABoolean lobTrace=FALSE;
if (getenv("TRACE_LOB_ACTIONS"))
lobTrace=TRUE;
rc = SQL_EXEC_LOBddlInterface((char*)newSchName.data(),
newSchName.length(),
objUID,
j,
LOB_CLI_CREATE,
lobNumList,
lobTypList,
lobLocList,
lobColNameList,
lobHdfsServer,
lobHdfsPort,
lobMaxSize,
lobTrace);
if (rc < 0)
{
// retrieve the cli diags here.
CmpCommon::diags()->mergeAfter(*(GetCliGlobals()->currContext()->getDiagsArea()));
*CmpCommon::diags() << DgSqlCode(-CAT_CREATE_OBJECT_ERROR)
<< DgTableName(extTableName);
deallocEHI(ehi);
processReturn();
return -2;
}
}
// if not a compound create, update valid def to true.
if (NOT ((createTableNode->getAddConstraintUniqueArray().entries() > 0) ||
(createTableNode->getAddConstraintRIArray().entries() > 0) ||
(createTableNode->getAddConstraintCheckArray().entries() > 0)))
{
cliRC = updateObjectValidDef(&cliInterface,
catalogNamePart, schemaNamePart, objectNamePart,
COM_BASE_TABLE_OBJECT_LIT, COM_YES_LIT);
if (cliRC < 0)
{
*CmpCommon::diags()
<< DgSqlCode(-CAT_UNABLE_TO_CREATE_OBJECT)
<< DgTableName(extTableName);
deallocEHI(ehi);
processReturn();
return -2;
}
}
if (NOT isCompound)
{
CorrName cn(objectNamePart, STMTHEAP, schemaNamePart, catalogNamePart);
ActiveSchemaDB()->getNATableDB()->removeNATable
(cn,
ComQiScope::REMOVE_MINE_ONLY,
COM_BASE_TABLE_OBJECT,
createTableNode->ddlXns(), FALSE);
}
processReturn();
return 0;
label_error:
if (hbaseSerialization)
{
ActiveSchemaDB()->getDefaults().validateAndInsert
("hbase_serialization", hbVal, FALSE);
}
return -1;
} // createSeabaseTable2
void CmpSeabaseDDL::createSeabaseTable(
StmtDDLCreateTable * createTableNode,
NAString &currCatName, NAString &currSchName,
NABoolean isCompound,
Int64 *retObjUID)
{
NABoolean xnWasStartedHere = FALSE;
ExeCliInterface cliInterface(STMTHEAP, 0, NULL,
CmpCommon::context()->sqlSession()->getParentQid());
ComObjectName tableName(createTableNode->getTableName());
ComAnsiNamePart currCatAnsiName(currCatName);
ComAnsiNamePart currSchAnsiName(currSchName);
tableName.applyDefaults(currCatAnsiName, currSchAnsiName);
const NAString catalogNamePart = tableName.getCatalogNamePartAsAnsiString();
const NAString schemaNamePart = tableName.getSchemaNamePartAsAnsiString(TRUE);
const NAString objectNamePart = tableName.getObjectNamePartAsAnsiString(TRUE);
if (beginXnIfNotInProgress(&cliInterface, xnWasStartedHere))
return;
Int64 objUID = 0;
short rc =
createSeabaseTable2(cliInterface, createTableNode, currCatName, currSchName,
isCompound, objUID);
if ((CmpCommon::diags()->getNumber(DgSqlCode::ERROR_)) &&
(rc < 0))
{
endXnIfStartedHere(&cliInterface, xnWasStartedHere, -1);
if (rc == -2) // cleanup before returning error..
{
cleanupObjectAfterError(cliInterface,
catalogNamePart, schemaNamePart, objectNamePart,
COM_BASE_TABLE_OBJECT,
createTableNode->ddlXns());
}
return;
}
if (retObjUID)
*retObjUID = objUID;
if (NOT isCompound)
{
if (updateObjectRedefTime(&cliInterface,
catalogNamePart, schemaNamePart, objectNamePart,
COM_BASE_TABLE_OBJECT_LIT, -1, objUID))
{
endXnIfStartedHere(&cliInterface, xnWasStartedHere, -1);
processReturn();
return;
}
}
endXnIfStartedHere(&cliInterface, xnWasStartedHere, 0);
return;
}
void CmpSeabaseDDL::addConstraints(
ComObjectName &tableName,
ComAnsiNamePart &currCatAnsiName,
ComAnsiNamePart &currSchAnsiName,
StmtDDLNode * ddlNode,
StmtDDLAddConstraintPK * pkConstr,
StmtDDLAddConstraintUniqueArray &uniqueConstrArr,
StmtDDLAddConstraintRIArray &riConstrArr,
StmtDDLAddConstraintCheckArray &checkConstrArr,
NABoolean isCompound)
{
Lng32 cliRC = 0;
const NAString catalogNamePart = tableName.getCatalogNamePartAsAnsiString();
const NAString schemaNamePart = tableName.getSchemaNamePartAsAnsiString(TRUE);
const NAString objectNamePart = tableName.getObjectNamePartAsAnsiString(TRUE);
const NAString extTableName = tableName.getExternalName(TRUE);
ExeCliInterface cliInterface(STMTHEAP, 0, NULL,
CmpCommon::context()->sqlSession()->getParentQid());
char buf[5000];
if (pkConstr)
{
NAString uniqueName;
genUniqueName(pkConstr, uniqueName);
ComObjectName constrName(uniqueName);
constrName.applyDefaults(currCatAnsiName, currSchAnsiName);
const NAString constrCatalogNamePart = constrName.getCatalogNamePartAsAnsiString();
const NAString constrSchemaNamePart = constrName.getSchemaNamePartAsAnsiString(TRUE);
const NAString constrObjectNamePart = constrName.getObjectNamePartAsAnsiString(TRUE);
ElemDDLConstraintPK *constraintNode =
( pkConstr->getConstraint() )->castToElemDDLConstraintPK();
ElemDDLColRefArray &keyColumnArray = constraintNode->getKeyColumnArray();
NAString keyColNameStr;
for (CollIndex i = 0; i < keyColumnArray.entries(); i++)
{
keyColNameStr += "\"";
keyColNameStr += keyColumnArray[i]->getColumnName();
keyColNameStr += "\"";
if (keyColumnArray[i]->getColumnOrdering() == COM_DESCENDING_ORDER)
keyColNameStr += "DESC";
else
keyColNameStr += "ASC";
if (i+1 < keyColumnArray.entries())
keyColNameStr += ", ";
}
str_sprintf(buf, "alter table \"%s\".\"%s\".\"%s\" add constraint \"%s\".\"%s\".\"%s\" primary key %s (%s)",
catalogNamePart.data(), schemaNamePart.data(), objectNamePart.data(),
constrCatalogNamePart.data(), constrSchemaNamePart.data(), constrObjectNamePart.data(),
(constraintNode->isNullableSpecified() ? " nullable " : ""),
keyColNameStr.data());
cliRC = cliInterface.executeImmediate(buf);
if (cliRC < 0)
{
cliInterface.retrieveSQLDiagnostics(CmpCommon::diags());
processReturn();
goto label_return;
}
}
if (uniqueConstrArr.entries() > 0)
{
for (Lng32 i = 0; i < uniqueConstrArr.entries(); i++)
{
StmtDDLAddConstraintUnique *uniqConstr =
uniqueConstrArr[i];
NAString uniqueName;
genUniqueName(uniqConstr, uniqueName);
ComObjectName constrName(uniqueName);
constrName.applyDefaults(currCatAnsiName, currSchAnsiName);
const NAString constrCatalogNamePart = constrName.getCatalogNamePartAsAnsiString();
const NAString constrSchemaNamePart = constrName.getSchemaNamePartAsAnsiString(TRUE);
const NAString constrObjectNamePart = constrName.getObjectNamePartAsAnsiString(TRUE);
ElemDDLConstraintUnique *constraintNode =
( uniqConstr->getConstraint() )->castToElemDDLConstraintUnique();
ElemDDLColRefArray &keyColumnArray = constraintNode->getKeyColumnArray();
NAString keyColNameStr;
for (CollIndex i = 0; i < keyColumnArray.entries(); i++)
{
keyColNameStr += "\"";
keyColNameStr += keyColumnArray[i]->getColumnName();
keyColNameStr += "\"";
if (keyColumnArray[i]->getColumnOrdering() == COM_DESCENDING_ORDER)
keyColNameStr += "DESC";
else
keyColNameStr += "ASC";
if (i+1 < keyColumnArray.entries())
keyColNameStr += ", ";
}
str_sprintf(buf, "alter table \"%s\".\"%s\".\"%s\" add constraint \"%s\".\"%s\".\"%s\" unique (%s)",
catalogNamePart.data(), schemaNamePart.data(), objectNamePart.data(),
constrCatalogNamePart.data(), constrSchemaNamePart.data(), constrObjectNamePart.data(),
keyColNameStr.data());
cliRC = cliInterface.executeImmediate(buf);
if (cliRC < 0)
{
cliInterface.retrieveSQLDiagnostics(CmpCommon::diags());
processReturn();
goto label_return;
}
} // for
} // if
if (riConstrArr.entries() > 0)
{
for (Lng32 i = 0; i < riConstrArr.entries(); i++)
{
StmtDDLAddConstraintRI *refConstr = riConstrArr[i];
ComObjectName refdTableName(refConstr->getReferencedTableName(), COM_TABLE_NAME);
refdTableName.applyDefaults(currCatAnsiName, currSchAnsiName);
const NAString refdCatNamePart = refdTableName.getCatalogNamePartAsAnsiString();
const NAString refdSchNamePart = refdTableName.getSchemaNamePartAsAnsiString(TRUE);
const NAString refdObjNamePart = refdTableName.getObjectNamePartAsAnsiString(TRUE);
NAString uniqueName;
genUniqueName(refConstr, uniqueName);
ComObjectName constrName(uniqueName);
constrName.applyDefaults(currCatAnsiName, currSchAnsiName);
const NAString constrCatalogNamePart = constrName.getCatalogNamePartAsAnsiString();
const NAString constrSchemaNamePart = constrName.getSchemaNamePartAsAnsiString(TRUE);
const NAString constrObjectNamePart = constrName.getObjectNamePartAsAnsiString(TRUE);
const NAString &addConstrName = constrName.getExternalName();
ElemDDLConstraintRI *constraintNode =
( refConstr->getConstraint() )->castToElemDDLConstraintRI();
ElemDDLColNameArray &ringColumnArray = constraintNode->getReferencingColumns();
NAString ringColNameStr;
for (CollIndex i = 0; i < ringColumnArray.entries(); i++)
{
ringColNameStr += "\"";
ringColNameStr += ringColumnArray[i]->getColumnName();
ringColNameStr += "\"";
if (i+1 < ringColumnArray.entries())
ringColNameStr += ", ";
}
ElemDDLColNameArray &refdColumnArray = constraintNode->getReferencedColumns();
NAString refdColNameStr;
if (refdColumnArray.entries() > 0)
refdColNameStr = "(";
for (CollIndex i = 0; i < refdColumnArray.entries(); i++)
{
refdColNameStr += "\"";
refdColNameStr += refdColumnArray[i]->getColumnName();
refdColNameStr += "\"";
if (i+1 < refdColumnArray.entries())
refdColNameStr += ", ";
}
if (refdColumnArray.entries() > 0)
refdColNameStr += ")";
str_sprintf(buf, "alter table \"%s\".\"%s\".\"%s\" add constraint \"%s\".\"%s\".\"%s\" foreign key (%s) references \"%s\".\"%s\".\"%s\" %s %s",
catalogNamePart.data(), schemaNamePart.data(), objectNamePart.data(),
constrCatalogNamePart.data(), constrSchemaNamePart.data(), constrObjectNamePart.data(),
ringColNameStr.data(),
refdCatNamePart.data(), refdSchNamePart.data(), refdObjNamePart.data(),
(refdColumnArray.entries() > 0 ? refdColNameStr.data() : " "),
(NOT constraintNode->isEnforced() ? " not enforced " : ""));
cliRC = cliInterface.executeImmediate(buf);
if (cliRC < 0)
{
cliInterface.retrieveSQLDiagnostics(CmpCommon::diags());
processReturn();
}
if (NOT isCompound)
{
CorrName cn2(refdObjNamePart.data(),
STMTHEAP,
refdSchNamePart.data(),
refdCatNamePart.data());
// remove natable for the table being referenced
ActiveSchemaDB()->getNATableDB()->removeNATable
(cn2,
ComQiScope::REMOVE_FROM_ALL_USERS,
COM_BASE_TABLE_OBJECT,
ddlNode->ddlXns(), FALSE);
}
if (cliRC < 0)
goto label_return;
if (NOT constraintNode->isEnforced())
{
*CmpCommon::diags()
<< DgSqlCode(1313)
<< DgString0(addConstrName);
}
} // for
} // if
if (checkConstrArr.entries() > 0)
{
for (Lng32 i = 0; i < checkConstrArr.entries(); i++)
{
StmtDDLAddConstraintCheck *checkConstr = checkConstrArr[i];
NAString uniqueName;
genUniqueName(checkConstr, uniqueName);
ComObjectName constrName(uniqueName);
constrName.applyDefaults(currCatAnsiName, currSchAnsiName);
const NAString constrCatalogNamePart = constrName.getCatalogNamePartAsAnsiString();
const NAString constrSchemaNamePart = constrName.getSchemaNamePartAsAnsiString(TRUE);
const NAString constrObjectNamePart = constrName.getObjectNamePartAsAnsiString(TRUE);
NAString constrText;
getCheckConstraintText(checkConstr, constrText);
str_sprintf(buf, "alter table \"%s\".\"%s\".\"%s\" add constraint \"%s\".\"%s\".\"%s\" check %s",
catalogNamePart.data(), schemaNamePart.data(), objectNamePart.data(),
constrCatalogNamePart.data(), constrSchemaNamePart.data(), constrObjectNamePart.data(),
constrText.data()
);
cliRC = cliInterface.executeImmediate(buf);
if (cliRC < 0)
{
cliInterface.retrieveSQLDiagnostics(CmpCommon::diags());
processReturn();
goto label_return;
}
}
}
label_return:
if (NOT isCompound)
{
// remove NATable cache entries for this table
CorrName cn(objectNamePart.data(),
STMTHEAP,
schemaNamePart.data(),
catalogNamePart.data());
// remove NATable for this table
ActiveSchemaDB()->getNATableDB()->removeNATable
(cn,
ComQiScope::REMOVE_FROM_ALL_USERS,
COM_BASE_TABLE_OBJECT,
ddlNode->ddlXns(), FALSE);
}
return;
}
void CmpSeabaseDDL::createSeabaseTableCompound(
StmtDDLCreateTable * createTableNode,
NAString &currCatName, NAString &currSchName)
{
Lng32 cliRC = 0;
Lng32 retcode = 0;
ExeCliInterface cliInterface(STMTHEAP, 0, NULL,
CmpCommon::context()->sqlSession()->getParentQid());
ComObjectName tableName(createTableNode->getTableName());
ComAnsiNamePart currCatAnsiName(currCatName);
ComAnsiNamePart currSchAnsiName(currSchName);
tableName.applyDefaults(currCatAnsiName, currSchAnsiName);
const NAString catalogNamePart = tableName.getCatalogNamePartAsAnsiString();
const NAString schemaNamePart = tableName.getSchemaNamePartAsAnsiString(TRUE);
const NAString objectNamePart = tableName.getObjectNamePartAsAnsiString(TRUE);
const NAString extTableName = tableName.getExternalName(TRUE);
NABoolean xnWasStartedHere = FALSE;
Int64 objUID = 0;
if ((createTableNode->isVolatile()) &&
((createTableNode->getAddConstraintUniqueArray().entries() > 0) ||
(createTableNode->getAddConstraintRIArray().entries() > 0) ||
(createTableNode->getAddConstraintCheckArray().entries() > 0)))
{
*CmpCommon::diags() << DgSqlCode(-1283);
processReturn();
goto label_error;
}
createSeabaseTable(createTableNode, currCatName, currSchName, TRUE, &objUID);
if (CmpCommon::diags()->getNumber(DgSqlCode::ERROR_))
{
return;
}
cliRC = cliInterface.holdAndSetCQD("TRAF_NO_CONSTR_VALIDATION", "ON");
if (cliRC < 0)
{
cliInterface.retrieveSQLDiagnostics(CmpCommon::diags());
processReturn();
goto label_error;
}
addConstraints(tableName, currCatAnsiName, currSchAnsiName,
createTableNode,
NULL,
createTableNode->getAddConstraintUniqueArray(),
createTableNode->getAddConstraintRIArray(),
createTableNode->getAddConstraintCheckArray(),
TRUE);
if (CmpCommon::diags()->getNumber(DgSqlCode::ERROR_))
{
if (cliInterface.statusXn() == 0) // xn in progress
{
rollbackXn(&cliInterface);
}
*CmpCommon::diags() << DgSqlCode(-1029)
<< DgTableName(extTableName);
processReturn();
goto label_error;
}
cliRC = cliInterface.restoreCQD("traf_no_constr_validation");
if (beginXnIfNotInProgress(&cliInterface, xnWasStartedHere))
goto label_error;
cliRC = updateObjectValidDef(&cliInterface,
catalogNamePart, schemaNamePart, objectNamePart,
COM_BASE_TABLE_OBJECT_LIT, COM_YES_LIT);
if (cliRC < 0)
{
*CmpCommon::diags()
<< DgSqlCode(-CAT_UNABLE_TO_CREATE_OBJECT)
<< DgTableName(extTableName);
endXnIfStartedHere(&cliInterface, xnWasStartedHere, cliRC);
goto label_error;
}
if (updateObjectRedefTime(&cliInterface,
catalogNamePart, schemaNamePart, objectNamePart,
COM_BASE_TABLE_OBJECT_LIT, -1, objUID))
{
endXnIfStartedHere(&cliInterface, xnWasStartedHere, -1);
goto label_error;
}
endXnIfStartedHere(&cliInterface, xnWasStartedHere, cliRC);
{
CorrName cn(objectNamePart, STMTHEAP, schemaNamePart, catalogNamePart);
ActiveSchemaDB()->getNATableDB()->removeNATable
(cn,
ComQiScope::REMOVE_FROM_ALL_USERS,
COM_BASE_TABLE_OBJECT,
createTableNode->ddlXns(), FALSE);
}
return;
label_error:
cliRC = cliInterface.restoreCQD("traf_no_constr_validation");
if (NOT createTableNode->isVolatile())
{
cleanupObjectAfterError(cliInterface,
catalogNamePart, schemaNamePart, objectNamePart,
COM_BASE_TABLE_OBJECT,
createTableNode->ddlXns());
return;
}
}
// return: 0, does not exist. 1, exists. -1, error.
short CmpSeabaseDDL::lookForTableInMD(
ExeCliInterface *cliInterface,
NAString &catNamePart, NAString &schNamePart, NAString &objNamePart,
NABoolean schNameSpecified, NABoolean hbaseMapSpecified,
ComObjectName &tableName, NAString &tabName, NAString &extTableName,
const ComObjectType objectType)
{
short retcode = 0;
if ((schNamePart == HBASE_EXT_MAP_SCHEMA) &&
(! Get_SqlParser_Flags(INTERNAL_QUERY_FROM_EXEUTIL)))
{
*CmpCommon::diags() << DgSqlCode(-4261)
<< DgSchemaName(schNamePart);
return -1;
}
if (NOT hbaseMapSpecified)
retcode = existsInSeabaseMDTable
(cliInterface,
catNamePart, schNamePart, objNamePart,
objectType, //COM_BASE_TABLE_OBJECT,
(Get_SqlParser_Flags(INTERNAL_QUERY_FROM_EXEUTIL)
? FALSE : TRUE),
TRUE, TRUE);
if (retcode < 0)
{
return -1; // error
}
if (retcode == 1)
return 1; // exists
if ((retcode == 0) && // does not exist
(NOT schNameSpecified))
{
// if explicit schema name was not specified,
// check to see if this is an hbase mapped table.
retcode = existsInSeabaseMDTable
(cliInterface,
catNamePart, HBASE_EXT_MAP_SCHEMA, objNamePart,
objectType, //COM_BASE_TABLE_OBJECT,
(Get_SqlParser_Flags(INTERNAL_QUERY_FROM_EXEUTIL)
? FALSE : TRUE),
TRUE, TRUE);
if (retcode < 0)
{
return -1; // error
}
if (retcode != 0) // exists
{
schNamePart = HBASE_EXT_MAP_SCHEMA;
ComAnsiNamePart mapSchAnsiName
(schNamePart, ComAnsiNamePart::INTERNAL_FORMAT);
tableName.setSchemaNamePart(mapSchAnsiName);
extTableName = tableName.getExternalName(TRUE);
tabName = tableName.getExternalName();
return 1; // exists
}
}
return 0; // does not exist
}
// RETURN: -1, no need to cleanup. -2, caller need to call cleanup
// 0, all ok.
short CmpSeabaseDDL::dropSeabaseTable2(
ExeCliInterface *cliInterface,
StmtDDLDropTable * dropTableNode,
NAString &currCatName, NAString &currSchName)
{
Lng32 cliRC = 0;
Lng32 retcode = 0;
NAString tabName = (NAString&)dropTableNode->getTableName();
ComObjectName tableName(tabName, COM_TABLE_NAME);
ComObjectName volTabName;
ComAnsiNamePart currCatAnsiName(currCatName);
ComAnsiNamePart currSchAnsiName(currSchName);
NABoolean schNameSpecified =
(NOT dropTableNode->getOrigTableNameAsQualifiedName().getSchemaName().isNull());
tableName.applyDefaults(currCatAnsiName, currSchAnsiName);
if (dropTableNode->isExternal())
{
// Convert the native name to its Trafodion form
tabName = ComConvertNativeNameToTrafName
(tableName.getCatalogNamePartAsAnsiString(),
tableName.getSchemaNamePartAsAnsiString(),
tableName.getObjectNamePartAsAnsiString());
ComObjectName adjustedName(tabName, COM_TABLE_NAME);
tableName = adjustedName;
}
NAString catalogNamePart = tableName.getCatalogNamePartAsAnsiString();
NAString schemaNamePart = tableName.getSchemaNamePartAsAnsiString(TRUE);
NAString objectNamePart = tableName.getObjectNamePartAsAnsiString(TRUE);
NAString extTableName = tableName.getExternalName(TRUE);
const NAString extNameForHbase = catalogNamePart + "." + schemaNamePart + "." + objectNamePart;
// allowExternalTables: true to allow an NATable entry to be created for an external table
BindWA bindWA(ActiveSchemaDB(), CmpCommon::context(), FALSE/*inDDL*/);
ExpHbaseInterface * ehi = allocEHI();
if (ehi == NULL)
{
processReturn();
return -1;
}
if ((isSeabaseReservedSchema(tableName)) &&
(!Get_SqlParser_Flags(INTERNAL_QUERY_FROM_EXEUTIL)))
{
*CmpCommon::diags() << DgSqlCode(-CAT_USER_CANNOT_DROP_SMD_TABLE)
<< DgTableName(extTableName);
deallocEHI(ehi);
processReturn();
return -1;
}
NABoolean isVolatile = FALSE;
if ((dropTableNode->isVolatile()) &&
(CmpCommon::context()->sqlSession()->volatileSchemaInUse()))
{
volTabName = tableName;
isVolatile = TRUE;
}
if ((NOT dropTableNode->isVolatile()) &&
(CmpCommon::context()->sqlSession()->volatileSchemaInUse()))
{
// updateVolatileQualifiedName qualifies the object name with a
// volatile catalog and schema name (if a volatile schema exists)
QualifiedName *qn =
CmpCommon::context()->sqlSession()->
updateVolatileQualifiedName
(dropTableNode->getOrigTableNameAsQualifiedName().getObjectName());
// don't believe it is possible to get a null pointer returned
if (qn == NULL)
{
*CmpCommon::diags()
<< DgSqlCode(-CAT_UNABLE_TO_DROP_OBJECT)
<< DgTableName(dropTableNode->getOrigTableNameAsQualifiedName().
getQualifiedNameAsAnsiString(TRUE));
deallocEHI(ehi);
processReturn();
return -1;
}
volTabName = qn->getQualifiedNameAsAnsiString();
volTabName.applyDefaults(currCatAnsiName, currSchAnsiName);
NAString vtCatNamePart = volTabName.getCatalogNamePartAsAnsiString();
NAString vtSchNamePart = volTabName.getSchemaNamePartAsAnsiString(TRUE);
NAString vtObjNamePart = volTabName.getObjectNamePartAsAnsiString(TRUE);
retcode = existsInSeabaseMDTable(cliInterface,
vtCatNamePart, vtSchNamePart, vtObjNamePart,
COM_BASE_TABLE_OBJECT);
if (retcode < 0)
{
deallocEHI(ehi);
processReturn();
return -1;
}
if (retcode == 1)
{
// table found in volatile schema
// Validate volatile table name.
if (CmpCommon::context()->sqlSession()->
validateVolatileQualifiedName
(dropTableNode->getOrigTableNameAsQualifiedName()))
{
// Valid volatile table. Drop it.
tabName = volTabName.getExternalName(TRUE);
catalogNamePart = vtCatNamePart;
schemaNamePart = vtSchNamePart;
objectNamePart = vtObjNamePart;
isVolatile = TRUE;
}
else
{
// volatile table found but the name is not a valid
// volatile name. Look for the input name in the regular
// schema.
// But first clear the diags area.
CmpCommon::diags()->clear();
}
}
else
{
CmpCommon::diags()->clear();
}
}
retcode = lookForTableInMD(cliInterface,
catalogNamePart, schemaNamePart, objectNamePart,
schNameSpecified,
(dropTableNode->isExternal() &&
(schemaNamePart == HBASE_EXT_MAP_SCHEMA)),
tableName, tabName, extTableName);
if (retcode < 0)
{
deallocEHI(ehi);
processReturn();
return -1;
}
if (retcode == 0) // does not exist
{
if (NOT dropTableNode->dropIfExists())
{
CmpCommon::diags()->clear();
if (isVolatile)
*CmpCommon::diags() << DgSqlCode(-CAT_OBJECT_DOES_NOT_EXIST_IN_TRAFODION)
<< DgString0(objectNamePart);
else
*CmpCommon::diags() << DgSqlCode(-CAT_OBJECT_DOES_NOT_EXIST_IN_TRAFODION)
<< DgString0(extTableName);
}
deallocEHI(ehi);
processReturn();
return -1;
}
// if this table does not exist in hbase but exists in metadata, return error.
// This is an internal inconsistency which needs to be fixed by running cleanup.
// If this is an external (native HIVE or HBASE) table, then skip
if (!isSeabaseExternalSchema(catalogNamePart, schemaNamePart))
{
HbaseStr hbaseTable;
hbaseTable.val = (char*)extNameForHbase.data();
hbaseTable.len = extNameForHbase.length();
if ((NOT isVolatile)&& (ehi->exists(hbaseTable) == 0)) // does not exist in hbase
{
*CmpCommon::diags() << DgSqlCode(-4254)
<< DgString0(extTableName);
deallocEHI(ehi);
processReturn();
return -1;
}
}
// Check to see if the user has the authority to drop the table
ComObjectName verifyName;
if (isVolatile)
verifyName = volTabName;
else
verifyName = tableName;
if (CmpCommon::getDefault(TRAF_RELOAD_NATABLE_CACHE) == DF_OFF)
ActiveSchemaDB()->getNATableDB()->useCache();
// save the current parserflags setting
ULng32 savedParserFlags = Get_SqlParser_Flags (0xFFFFFFFF);
Set_SqlParser_Flags(ALLOW_VOLATILE_SCHEMA_IN_TABLE_NAME);
CorrName cn(objectNamePart,
STMTHEAP,
schemaNamePart,
catalogNamePart);
if (dropTableNode->isExternal())
bindWA.setExternalTableDrop(TRUE);
NATable *naTable = bindWA.getNATableInternal(cn, TRUE, NULL, TRUE);
bindWA.setExternalTableDrop(FALSE);
const NAColumnArray &nacolArr = naTable->getNAColumnArray();
// Restore parser flags settings to what they originally were
Set_SqlParser_Flags (savedParserFlags);
if (naTable == NULL || bindWA.errStatus())
{
if (NOT dropTableNode->dropIfExists())
{
if (isVolatile)
*CmpCommon::diags() << DgSqlCode(-CAT_OBJECT_DOES_NOT_EXIST_IN_TRAFODION)
<< DgString0(objectNamePart);
else
*CmpCommon::diags() << DgSqlCode(-CAT_OBJECT_DOES_NOT_EXIST_IN_TRAFODION)
<< DgString0(extTableName);
}
else
CmpCommon::diags()->clear();
deallocEHI(ehi);
processReturn();
return -1;
}
if ((dropTableNode->isVolatile()) &&
(NOT CmpCommon::context()->sqlSession()->isValidVolatileSchemaName(schemaNamePart)))
{
*CmpCommon::diags() << DgSqlCode(-1279);
deallocEHI(ehi);
processReturn();
return -1;
}
Int64 objUID = naTable->objectUid().castToInt64();
// Make sure user has necessary privileges to perform drop
if (!isDDLOperationAuthorized(SQLOperation::DROP_TABLE,
naTable->getOwner(),
naTable->getSchemaOwner()))
{
*CmpCommon::diags() << DgSqlCode(-CAT_NOT_AUTHORIZED);
deallocEHI(ehi);
processReturn ();
return -1;
}
Queue * usingViewsQueue = NULL;
if (dropTableNode->getDropBehavior() == COM_RESTRICT_DROP_BEHAVIOR)
{
NAString usingObjName;
cliRC = getUsingObject(cliInterface, objUID, usingObjName);
if (cliRC < 0)
{
deallocEHI(ehi);
processReturn();
return -1;
}
if (cliRC != 100) // found an object
{
*CmpCommon::diags() << DgSqlCode(-CAT_DEPENDENT_VIEW_EXISTS)
<< DgTableName(usingObjName);
deallocEHI(ehi);
processReturn();
return -1;
}
}
else if (dropTableNode->getDropBehavior() == COM_CASCADE_DROP_BEHAVIOR)
{
cliRC = getAllUsingViews(cliInterface,
catalogNamePart, schemaNamePart, objectNamePart,
usingViewsQueue);
if (cliRC < 0)
{
deallocEHI(ehi);
processReturn();
return -1;
}
}
const AbstractRIConstraintList &uniqueList = naTable->getUniqueConstraints();
// return error if cascade is not specified and a referential constraint exists on
// any of the unique constraints.
if (dropTableNode->getDropBehavior() == COM_RESTRICT_DROP_BEHAVIOR)
{
for (Int32 i = 0; i < uniqueList.entries(); i++)
{
AbstractRIConstraint *ariConstr = uniqueList[i];
if (ariConstr->getOperatorType() != ITM_UNIQUE_CONSTRAINT)
continue;
UniqueConstraint * uniqConstr = (UniqueConstraint*)ariConstr;
if (uniqConstr->hasRefConstraintsReferencingMe())
{
const ComplementaryRIConstraint * rc = uniqConstr->getRefConstraintReferencingMe(0);
if (rc->getTableName() != naTable->getTableName())
{
const NAString &constrName =
(rc ? rc->getConstraintName().getObjectName() : " ");
*CmpCommon::diags() << DgSqlCode(-1059)
<< DgConstraintName(constrName);
deallocEHI(ehi);
processReturn();
return -1;
}
}
}
}
// Drop referencing objects
char query[4000];
// drop the views.
// usingViewsQueue contain them in ascending order of their create
// time. Drop them from last to first.
if (usingViewsQueue)
{
for (int idx = usingViewsQueue->numEntries()-1; idx >= 0; idx--)
{
OutputInfo * vi = (OutputInfo*)usingViewsQueue->get(idx);
char * viewName = vi->get(0);
if (dropOneTableorView(*cliInterface,viewName,COM_VIEW_OBJECT,false))
{
deallocEHI(ehi);
processReturn();
return -1;
}
}
}
// drop all referential constraints referencing me.
for (Int32 i = 0; i < uniqueList.entries(); i++)
{
AbstractRIConstraint *ariConstr = uniqueList[i];
if (ariConstr->getOperatorType() != ITM_UNIQUE_CONSTRAINT)
continue;
UniqueConstraint * uniqConstr = (UniqueConstraint*)ariConstr;
// We will only reach here is cascade option is specified.
// drop all constraints referencing me.
if (uniqConstr->hasRefConstraintsReferencingMe())
{
for (Lng32 j = 0; j < uniqConstr->getNumRefConstraintsReferencingMe(); j++)
{
const ComplementaryRIConstraint * rc =
uniqConstr->getRefConstraintReferencingMe(j);
str_sprintf(query, "alter table \"%s\".\"%s\".\"%s\" drop constraint \"%s\".\"%s\".\"%s\"",
rc->getTableName().getCatalogName().data(),
rc->getTableName().getSchemaName().data(),
rc->getTableName().getObjectName().data(),
rc->getConstraintName().getCatalogName().data(),
rc->getConstraintName().getSchemaName().data(),
rc->getConstraintName().getObjectName().data());
cliRC = cliInterface->executeImmediate(query);
if (cliRC < 0)
{
cliInterface->retrieveSQLDiagnostics(CmpCommon::diags());
deallocEHI(ehi);
processReturn();
return -2;
}
} // for
} // if
} // for
for (Int32 i = 0; i < uniqueList.entries(); i++)
{
AbstractRIConstraint *ariConstr = uniqueList[i];
if (ariConstr->getOperatorType() != ITM_UNIQUE_CONSTRAINT)
continue;
UniqueConstraint * uniqConstr = (UniqueConstraint*)ariConstr;
const NAString& constrCatName =
uniqConstr->getConstraintName().getCatalogName();
const NAString& constrSchName =
uniqConstr->getConstraintName().getSchemaName();
NAString constrObjName =
(NAString) uniqConstr->getConstraintName().getObjectName();
// Get the constraint UID
Int64 constrUID = -1;
// If the table being dropped is from a metadata schema, setup
// an UniqueConstraint entry for the table being dropped describing its
// primary key. This is temporary until metadata is changed to create
// primary keys with a known name.
if (isSeabasePrivMgrMD(catalogNamePart, schemaNamePart) ||
isSeabaseMD(catalogNamePart, schemaNamePart, objectNamePart))
{
assert (uniqueList.entries() == 1);
assert (uniqueList[0]->getOperatorType() == ITM_UNIQUE_CONSTRAINT);
UniqueConstraint * uniqConstr = (UniqueConstraint*)uniqueList[0];
assert (uniqConstr->isPrimaryKeyConstraint());
NAString adjustedConstrName;
if (getPKeyInfoForTable (catalogNamePart.data(),
schemaNamePart.data(),
objectNamePart.data(),
cliInterface,
constrObjName,
constrUID) == -1)
{
deallocEHI(ehi);
processReturn();
return -1;
}
}
// Read the metadata to get the constraint UID
else
{
constrUID = getObjectUID(cliInterface,
constrCatName.data(), constrSchName.data(), constrObjName.data(),
(uniqConstr->isPrimaryKeyConstraint() ?
COM_PRIMARY_KEY_CONSTRAINT_OBJECT_LIT :
COM_UNIQUE_CONSTRAINT_OBJECT_LIT));
if (constrUID == -1)
{
deallocEHI(ehi);
processReturn();
return -1;
}
}
if (deleteConstraintInfoFromSeabaseMDTables(cliInterface,
naTable->objectUid().castToInt64(),
0,
constrUID,
0,
constrCatName,
constrSchName,
constrObjName,
(uniqConstr->isPrimaryKeyConstraint() ?
COM_PRIMARY_KEY_CONSTRAINT_OBJECT :
COM_UNIQUE_CONSTRAINT_OBJECT)))
{
deallocEHI(ehi);
processReturn();
return -1;
}
}
// drop all referential constraints from metadata
const AbstractRIConstraintList &refList = naTable->getRefConstraints();
for (Int32 i = 0; i < refList.entries(); i++)
{
AbstractRIConstraint *ariConstr = refList[i];
if (ariConstr->getOperatorType() != ITM_REF_CONSTRAINT)
continue;
RefConstraint * refConstr = (RefConstraint*)ariConstr;
// if self referencing constraint, then it was already dropped as part of
// dropping 'ri constraints referencing me' earlier.
if (refConstr->selfRef())
continue;
const NAString& constrCatName =
refConstr->getConstraintName().getCatalogName();
const NAString& constrSchName =
refConstr->getConstraintName().getSchemaName();
const NAString& constrObjName =
refConstr->getConstraintName().getObjectName();
Int64 constrUID = getObjectUID(cliInterface,
constrCatName.data(), constrSchName.data(), constrObjName.data(),
COM_REFERENTIAL_CONSTRAINT_OBJECT_LIT);
if (constrUID < 0)
{
deallocEHI(ehi);
processReturn();
return -1;
}
NATable *otherNaTable = NULL;
CorrName otherCN(refConstr->getUniqueConstraintReferencedByMe().getTableName());
otherNaTable = bindWA.getNATable(otherCN);
if (otherNaTable == NULL || bindWA.errStatus())
{
deallocEHI(ehi);
processReturn();
return -1;
}
AbstractRIConstraint * otherConstr =
refConstr->findConstraint(&bindWA, refConstr->getUniqueConstraintReferencedByMe());
const NAString& otherSchName =
otherConstr->getConstraintName().getSchemaName();
const NAString& otherConstrName =
otherConstr->getConstraintName().getObjectName();
Int64 otherConstrUID = getObjectUID(cliInterface,
constrCatName.data(), otherSchName.data(), otherConstrName.data(),
COM_UNIQUE_CONSTRAINT_OBJECT_LIT );
if (otherConstrUID < 0)
{
CmpCommon::diags()->clear();
otherConstrUID = getObjectUID(cliInterface,
constrCatName.data(), otherSchName.data(), otherConstrName.data(),
COM_PRIMARY_KEY_CONSTRAINT_OBJECT_LIT );
if (otherConstrUID < 0)
{
deallocEHI(ehi);
processReturn();
return -1;
}
}
if (deleteConstraintInfoFromSeabaseMDTables(cliInterface,
naTable->objectUid().castToInt64(),
otherNaTable->objectUid().castToInt64(),
constrUID,
otherConstrUID,
constrCatName,
constrSchName,
constrObjName,
COM_REFERENTIAL_CONSTRAINT_OBJECT))
{
deallocEHI(ehi);
processReturn();
return -1;
}
if (updateObjectRedefTime
(cliInterface,
otherNaTable->getTableName().getCatalogName(),
otherNaTable->getTableName().getSchemaName(),
otherNaTable->getTableName().getObjectName(),
COM_BASE_TABLE_OBJECT_LIT, -1,
otherNaTable->objectUid().castToInt64()))
{
processReturn();
deallocEHI(ehi);
return -1;
}
}
// drop all check constraints from metadata if 'no check' is not specified.
if (NOT (dropTableNode->getDropBehavior() == COM_NO_CHECK_DROP_BEHAVIOR))
{
const CheckConstraintList &checkList = naTable->getCheckConstraints();
for (Int32 i = 0; i < checkList.entries(); i++)
{
CheckConstraint *checkConstr = checkList[i];
const NAString& constrCatName =
checkConstr->getConstraintName().getCatalogName();
const NAString& constrSchName =
checkConstr->getConstraintName().getSchemaName();
const NAString& constrObjName =
checkConstr->getConstraintName().getObjectName();
Int64 constrUID = getObjectUID(cliInterface,
constrCatName.data(), constrSchName.data(), constrObjName.data(),
COM_CHECK_CONSTRAINT_OBJECT_LIT);
if (constrUID < 0)
{
deallocEHI(ehi);
processReturn();
return -1;
}
if (deleteConstraintInfoFromSeabaseMDTables(cliInterface,
naTable->objectUid().castToInt64(),
0,
constrUID,
0,
constrCatName,
constrSchName,
constrObjName,
COM_CHECK_CONSTRAINT_OBJECT))
{
deallocEHI(ehi);
processReturn();
return -1;
}
}
}
const NAFileSetList &indexList = naTable->getIndexList();
// first drop all index objects from metadata.
Queue * indexInfoQueue = NULL;
if (getAllIndexes(cliInterface, objUID, TRUE, indexInfoQueue))
{
deallocEHI(ehi);
processReturn();
return -1;
}
SQL_QIKEY *qiKeys = new (STMTHEAP) SQL_QIKEY[indexInfoQueue->numEntries()];
indexInfoQueue->position();
for (int idx = 0; idx < indexInfoQueue->numEntries(); idx++)
{
OutputInfo * vi = (OutputInfo*)indexInfoQueue->getNext();
NAString idxCatName = (char*)vi->get(0);
NAString idxSchName = (char*)vi->get(1);
NAString idxObjName = (char*)vi->get(2);
// set up a qiKey for this index, later we will removed the
// index cache entry from concurrent processes
Int64 objUID = *(Int64*)vi->get(3);
qiKeys[idx].ddlObjectUID = objUID;
qiKeys[idx].operation[0] = 'O';
qiKeys[idx].operation[1] = 'R';
NAString qCatName = "\"" + idxCatName + "\"";
NAString qSchName = "\"" + idxSchName + "\"";
NAString qObjName = "\"" + idxObjName + "\"";
ComObjectName coName(qCatName, qSchName, qObjName);
NAString ansiName = coName.getExternalName(TRUE);
if (dropSeabaseObject(ehi, ansiName,
idxCatName, idxSchName, COM_INDEX_OBJECT,
dropTableNode->ddlXns(),
TRUE, FALSE))
{
NADELETEBASIC (qiKeys, STMTHEAP);
deallocEHI(ehi);
processReturn();
return -1;
}
} // for
// Remove index entries from other processes cache
// Fix for bug 1396774 & bug 1396746
if (indexInfoQueue->numEntries() > 0)
SQL_EXEC_SetSecInvalidKeys(indexInfoQueue->numEntries(), qiKeys);
NADELETEBASIC (qiKeys, STMTHEAP);
// if there is an identity column, drop sequence corresponding to it.
NABoolean found = FALSE;
Lng32 idPos = 0;
NAColumn *col = NULL;
while ((NOT found) && (idPos < naTable->getColumnCount()))
{
col = naTable->getNAColumnArray()[idPos];
if (col->isIdentityColumn())
{
found = TRUE;
continue;
}
idPos++;
}
if (found)
{
NAString seqName;
SequenceGeneratorAttributes::genSequenceName
(catalogNamePart, schemaNamePart, objectNamePart, col->getColName(),
seqName);
char buf[4000];
str_sprintf(buf, "drop sequence %s.\"%s\".\"%s\"",
catalogNamePart.data(), schemaNamePart.data(), seqName.data());
cliRC = cliInterface->executeImmediate(buf);
if (cliRC < 0 && cliRC != -CAT_OBJECT_DOES_NOT_EXIST_IN_TRAFODION)
{
cliInterface->retrieveSQLDiagnostics(CmpCommon::diags());
deallocEHI(ehi);
processReturn();
return -1;
}
}
// drop SB_HISTOGRAMS and SB_HISTOGRAM_INTERVALS entries, if any
// if the table that we are dropping itself is not a SB_HISTOGRAMS
// or SB_HISTOGRAM_INTERVALS table or sampling tables
// TBD: need to change once we start updating statistics for external
// tables
if (! (tableName.isExternalHive() || tableName.isExternalHbase()) )
{
if (objectNamePart != "SB_HISTOGRAMS" &&
objectNamePart != "SB_HISTOGRAM_INTERVALS" &&
objectNamePart != "SB_PERSISTENT_SAMPLES" &&
strncmp(objectNamePart.data(),TRAF_SAMPLE_PREFIX,sizeof(TRAF_SAMPLE_PREFIX)) != 0)
{
if (dropSeabaseStats(cliInterface,
catalogNamePart.data(),
schemaNamePart.data(),
objUID))
{
deallocEHI(ehi);
processReturn();
return -1;
}
}
}
// if metadata drop succeeds, drop indexes from hbase.
indexInfoQueue->position();
for (int idx = 0; idx < indexInfoQueue->numEntries(); idx++)
{
OutputInfo * vi = (OutputInfo*)indexInfoQueue->getNext();
NAString idxCatName = (char*)vi->get(0);
NAString idxSchName = (char*)vi->get(1);
NAString idxObjName = (char*)vi->get(2);
NAString qCatName = "\"" + idxCatName + "\"";
NAString qSchName = "\"" + idxSchName + "\"";
NAString qObjName = "\"" + idxObjName + "\"";
ComObjectName coName(qCatName, qSchName, qObjName);
NAString ansiName = coName.getExternalName(TRUE);
if (dropSeabaseObject(ehi, ansiName,
idxCatName, idxSchName, COM_INDEX_OBJECT,
dropTableNode->ddlXns(),
FALSE, TRUE))
{
deallocEHI(ehi);
processReturn();
return -2;
}
CorrName cni(qObjName, STMTHEAP, qSchName, qCatName);
ActiveSchemaDB()->getNATableDB()->removeNATable
(cni,
ComQiScope::REMOVE_FROM_ALL_USERS, COM_INDEX_OBJECT,
dropTableNode->ddlXns(), FALSE);
cni.setSpecialType(ExtendedQualName::INDEX_TABLE);
ActiveSchemaDB()->getNATableDB()->removeNATable
(cni,
ComQiScope::REMOVE_MINE_ONLY, COM_INDEX_OBJECT,
dropTableNode->ddlXns(), FALSE);
} // for
// If blob/clob columns are present, drop all the dependent files.
Lng32 numCols = nacolArr.entries();
// if this table has lob columns, drop the lob files
short *lobNumList = new (STMTHEAP) short[numCols];
short *lobTypList = new (STMTHEAP) short[numCols];
char **lobLocList = new (STMTHEAP) char*[numCols];
char lobHdfsServer[256] ; // max length determined by dfs.namenode.fs-limits.max-component-length(255)
memset(lobHdfsServer,0,256);
strncpy(lobHdfsServer,CmpCommon::getDefaultString(LOB_HDFS_SERVER),sizeof(lobHdfsServer)-1);
Int32 lobHdfsPort = (Lng32)CmpCommon::getDefaultNumeric(LOB_HDFS_PORT);
Lng32 j = 0;
for (Int32 i = 0; i < nacolArr.entries(); i++)
{
NAColumn *naColumn = nacolArr[i];
Lng32 datatype = naColumn->getType()->getFSDatatype();
if ((datatype == REC_BLOB) ||
(datatype == REC_CLOB))
{
lobNumList[j] = i; //column->getColumnNumber();
lobTypList[j] =
(short)(naColumn->lobStorageType() == Lob_Invalid_Storage
? Lob_HDFS_File : naColumn->lobStorageType());
// lobTypList[j] = (short)
// CmpCommon::getDefaultNumeric(LOB_STORAGE_TYPE);
char * loc = new (STMTHEAP) char[1024];
const char* f = ActiveSchemaDB()->getDefaults().
getValue(LOB_STORAGE_FILE_DIR);
strcpy(loc, f);
lobLocList[j] = loc;
j++;
}
}
if (j > 0)
{
Int32 rc = sendAllControls(FALSE, FALSE, TRUE);
Int64 objUID = getObjectUID(cliInterface,
catalogNamePart.data(), schemaNamePart.data(),
objectNamePart.data(),
COM_BASE_TABLE_OBJECT_LIT);
ComString newSchName = "\"";
newSchName += catalogNamePart;
newSchName.append("\".\"");
newSchName.append(schemaNamePart);
newSchName += "\"";
NABoolean lobTrace = FALSE;
if (getenv("TRACE_LOB_ACTIONS"))
lobTrace=TRUE;
rc = SQL_EXEC_LOBddlInterface((char*)newSchName.data(),
newSchName.length(),
objUID,
j,
LOB_CLI_DROP,
lobNumList,
lobTypList,
lobLocList,NULL,lobHdfsServer, lobHdfsPort,0,lobTrace);
if (rc < 0)
{
// retrieve the cli diags here.
CmpCommon::diags()->mergeAfter( *(GetCliGlobals()->currContext()->getDiagsArea()));
*CmpCommon::diags() << DgSqlCode(-CAT_UNABLE_TO_DROP_OBJECT)
<< DgTableName(extTableName);
deallocEHI(ehi);
processReturn();
return -2;
}
}
//Finally drop the table
NABoolean dropFromMD = TRUE;
NABoolean dropFromHbase = (NOT tableName.isExternalHbase());
if (CmpCommon::getDefault(TRAF_NO_HBASE_DROP_CREATE) == DF_ON)
dropFromHbase = FALSE;
if (dropSeabaseObject(ehi, tabName,
currCatName, currSchName, COM_BASE_TABLE_OBJECT,
dropTableNode->ddlXns(),
dropFromMD, dropFromHbase))
{
deallocEHI(ehi);
processReturn();
return -2;
}
deallocEHI(ehi);
processReturn();
CorrName cn2(objectNamePart, STMTHEAP, schemaNamePart, catalogNamePart);
ActiveSchemaDB()->getNATableDB()->removeNATable
(cn2,
ComQiScope::REMOVE_FROM_ALL_USERS, COM_BASE_TABLE_OBJECT,
dropTableNode->ddlXns(), FALSE);
// if hive external table, remove hive entry from NATable cache as well
if ((dropTableNode->isExternal()) &&
(dropTableNode->getTableNameAsQualifiedName().isHive()))
{
CorrName hcn(dropTableNode->getTableNameAsQualifiedName());
ActiveSchemaDB()->getNATableDB()->removeNATable
(hcn,
ComQiScope::REMOVE_FROM_ALL_USERS, COM_BASE_TABLE_OBJECT,
dropTableNode->ddlXns(), FALSE);
}
for (Int32 i = 0; i < refList.entries(); i++)
{
AbstractRIConstraint *ariConstr = refList[i];
if (ariConstr->getOperatorType() != ITM_REF_CONSTRAINT)
continue;
RefConstraint * refConstr = (RefConstraint*)ariConstr;
CorrName otherCN(refConstr->getUniqueConstraintReferencedByMe().getTableName());
ActiveSchemaDB()->getNATableDB()->removeNATable
(otherCN,
ComQiScope::REMOVE_FROM_ALL_USERS, COM_BASE_TABLE_OBJECT,
dropTableNode->ddlXns(), FALSE);
}
for (Int32 i = 0; i < uniqueList.entries(); i++)
{
UniqueConstraint * uniqConstr = (UniqueConstraint*)uniqueList[i];
// We will only reach here is cascade option is specified.
// drop all constraints referencing me.
if (uniqConstr->hasRefConstraintsReferencingMe())
{
for (Lng32 j = 0; j < uniqConstr->getNumRefConstraintsReferencingMe(); j++)
{
const ComplementaryRIConstraint * rc =
uniqConstr->getRefConstraintReferencingMe(j);
// remove this ref constr entry from natable cache
CorrName cnr(rc->getTableName().getObjectName().data(), STMTHEAP,
rc->getTableName().getSchemaName().data(),
rc->getTableName().getCatalogName().data());
ActiveSchemaDB()->getNATableDB()->removeNATable
(cnr,
ComQiScope::REMOVE_FROM_ALL_USERS, COM_BASE_TABLE_OBJECT,
dropTableNode->ddlXns(), FALSE);
} // for
} // if
} // for
return 0;
}
void CmpSeabaseDDL::dropSeabaseTable(
StmtDDLDropTable * dropTableNode,
NAString &currCatName, NAString &currSchName)
{
NABoolean xnWasStartedHere = FALSE;
ExeCliInterface cliInterface(STMTHEAP, 0, NULL,
CmpCommon::context()->sqlSession()->getParentQid());
if (beginXnIfNotInProgress(&cliInterface, xnWasStartedHere))
return;
short rc =
dropSeabaseTable2(&cliInterface, dropTableNode, currCatName, currSchName);
if ((CmpCommon::diags()->getNumber(DgSqlCode::ERROR_)) &&
(rc < 0))
{
endXnIfStartedHere(&cliInterface, xnWasStartedHere, -1);
if (rc == -2) // cleanup before returning error..
{
ComObjectName tableName(dropTableNode->getTableName());
ComAnsiNamePart currCatAnsiName(currCatName);
ComAnsiNamePart currSchAnsiName(currSchName);
tableName.applyDefaults(currCatAnsiName, currSchAnsiName);
const NAString catalogNamePart = tableName.getCatalogNamePartAsAnsiString();
const NAString schemaNamePart = tableName.getSchemaNamePartAsAnsiString(TRUE);
const NAString objectNamePart = tableName.getObjectNamePartAsAnsiString(TRUE);
cleanupObjectAfterError(cliInterface,
catalogNamePart, schemaNamePart, objectNamePart,
COM_BASE_TABLE_OBJECT,
dropTableNode->ddlXns());
}
return;
}
endXnIfStartedHere(&cliInterface, xnWasStartedHere, 0);
return;
}
short CmpSeabaseDDL::invalidateStats(Int64 tableUID)
{
SQL_QIKEY qiKey;
strncpy(qiKey.operation,COM_QI_STATS_UPDATED_LIT,sizeof(qiKey.operation));
qiKey.ddlObjectUID = tableUID;
return SQL_EXEC_SetSecInvalidKeys(1, &qiKey);
}
void CmpSeabaseDDL::renameSeabaseTable(
StmtDDLAlterTableRename * renameTableNode,
NAString &currCatName, NAString &currSchName)
{
Lng32 retcode = 0;
Lng32 cliRC = 0;
// variables needed to find identity column (have to be declared before
// the first goto or C++ will moan because of the initializers)
NABoolean found = FALSE;
Lng32 idPos = 0;
NAColumn *col = NULL;
ExeCliInterface cliInterface(STMTHEAP, 0, NULL,
CmpCommon::context()->sqlSession()->getParentQid());
NAString tabName = renameTableNode->getTableName();
NAString catalogNamePart;
NAString schemaNamePart;
NAString objectNamePart;
NAString extTableName;
NAString extNameForHbase;
NATable * naTable = NULL;
CorrName cn;
retcode =
setupAndErrorChecks(tabName,
renameTableNode->getOrigTableNameAsQualifiedName(),
currCatName, currSchName,
catalogNamePart, schemaNamePart, objectNamePart,
extTableName, extNameForHbase, cn,
&naTable,
FALSE, FALSE,
&cliInterface);
if (retcode < 0)
{
processReturn();
return;
}
ComObjectName newTableName(renameTableNode->getNewNameAsAnsiString());
newTableName.applyDefaults(catalogNamePart, schemaNamePart);
const NAString newObjectNamePart = newTableName.getObjectNamePartAsAnsiString(TRUE);
const NAString newExtTableName = newTableName.getExternalName(TRUE);
const NAString newExtNameForHbase = catalogNamePart + "." + schemaNamePart + "." + newObjectNamePart;
CorrName newcn(newObjectNamePart,
STMTHEAP,
schemaNamePart,
catalogNamePart);
BindWA bindWA(ActiveSchemaDB(), CmpCommon::context(), FALSE/*inDDL*/);
NATable *newNaTable = bindWA.getNATable(newcn);
if (newNaTable != NULL && (NOT bindWA.errStatus()))
{
// an object already exists with the new name
*CmpCommon::diags() << DgSqlCode(-1390)
<< DgString0(newExtTableName);
processReturn();
return;
}
else if (newNaTable == NULL &&
bindWA.errStatus() &&
(!CmpCommon::diags()->contains(-4082) || CmpCommon::diags()->getNumber() > 1))
{
// there is some error other than the usual -4082, object
// does not exist
// If there is also -4082 error, remove that as it is misleading
// to the user. The user would see, "new name does not exist"
// and wonder, what is wrong with that?
for (CollIndex i = CmpCommon::diags()->returnIndex(-4082);
i != NULL_COLL_INDEX;
i = CmpCommon::diags()->returnIndex(-4082))
{
CmpCommon::diags()->deleteError(i);
}
if (CmpCommon::diags()->getNumber() > 0) // still anything there?
{
processReturn(); // error is already in the diags
return;
}
}
CmpCommon::diags()->clear();
// cannot rename a view
if (naTable->getViewText())
{
*CmpCommon::diags()
<< DgSqlCode(-1427)
<< DgString0("Reason: Operation not allowed on a view.");
processReturn();
return;
}
// cascade option not supported
if (renameTableNode->isCascade())
{
*CmpCommon::diags() << DgSqlCode(-1427)
<< DgString0("Reason: Cascade option not supported.");
processReturn();
return;
}
const CheckConstraintList &checkList = naTable->getCheckConstraints();
if (checkList.entries() > 0)
{
*CmpCommon::diags()
<< DgSqlCode(-1427)
<< DgString0("Reason: Operation not allowed if check constraints are present. Drop the constraints and recreate them after rename.");
processReturn();
return;
}
Int64 objUID = getObjectUID(&cliInterface,
catalogNamePart.data(), schemaNamePart.data(),
objectNamePart.data(),
COM_BASE_TABLE_OBJECT_LIT);
if (objUID < 0)
{
processReturn();
return;
}
if (!renameTableNode->skipViewCheck())
{
// cannot rename if views are using this table
Queue * usingViewsQueue = NULL;
cliRC = getUsingViews(&cliInterface, objUID, usingViewsQueue);
if (cliRC < 0)
{
processReturn();
return;
}
if (usingViewsQueue->numEntries() > 0)
{
*CmpCommon::diags() << DgSqlCode(-1427)
<< DgString0("Reason: Operation not allowed if dependent views exist. Drop the views and recreate them after rename.");
processReturn();
return;
}
}
// this operation cannot be done if a xn is already in progress.
if (xnInProgress(&cliInterface))
{
*CmpCommon::diags() << DgSqlCode(-20125)
<< DgString0("This ALTER");
processReturn();
return;
}
NABoolean ddlXns = renameTableNode->ddlXns();
HbaseStr hbaseTable;
hbaseTable.val = (char*)extNameForHbase.data();
hbaseTable.len = extNameForHbase.length();
HbaseStr newHbaseTable;
newHbaseTable.val = (char*)newExtNameForHbase.data();
newHbaseTable.len = newExtNameForHbase.length();
ExpHbaseInterface * ehi = allocEHI();
if (ehi == NULL)
{
processReturn();
return;
}
NABoolean xnWasStartedHere = FALSE;
if (beginXnIfNotInProgress(&cliInterface, xnWasStartedHere))
return;
cliRC = updateObjectName(&cliInterface,
objUID,
catalogNamePart.data(), schemaNamePart.data(),
newObjectNamePart.data());
if (cliRC < 0)
{
processReturn();
goto label_error_2;
}
// if there is an identity column, rename the sequence corresponding to it
found = FALSE;
while ((NOT found) && (idPos < naTable->getColumnCount()))
{
col = naTable->getNAColumnArray()[idPos];
if (col->isIdentityColumn())
{
found = TRUE;
continue;
}
idPos++;
}
if (found)
{
NAString oldSeqName;
SequenceGeneratorAttributes::genSequenceName
(catalogNamePart, schemaNamePart, objectNamePart, col->getColName(),
oldSeqName);
NAString newSeqName;
SequenceGeneratorAttributes::genSequenceName
(catalogNamePart, schemaNamePart, newObjectNamePart, col->getColName(),
newSeqName);
Int64 seqUID = getObjectUID(&cliInterface,
catalogNamePart.data(), schemaNamePart.data(),
oldSeqName.data(),
COM_SEQUENCE_GENERATOR_OBJECT_LIT);
if (seqUID < 0)
{
processReturn();
goto label_error_2;
}
cliRC = updateObjectName(&cliInterface,
seqUID,
catalogNamePart.data(), schemaNamePart.data(),
newSeqName.data());
if (cliRC < 0)
{
processReturn();
goto label_error_2;
}
}
// rename the underlying hbase object
retcode = ehi->copy(hbaseTable, newHbaseTable);
if (retcode < 0)
{
*CmpCommon::diags() << DgSqlCode(-8448)
<< DgString0((char*)"ExpHbaseInterface::copy()")
<< DgString1(getHbaseErrStr(-retcode))
<< DgInt0(-retcode)
<< DgString2((char*)GetCliGlobals()->getJniErrorStr());
processReturn();
cliRC = -1;
goto label_error;
}
retcode = dropHbaseTable(ehi, &hbaseTable, FALSE, ddlXns);
if (retcode < 0)
{
cliRC = -1;
goto label_error;
}
cliRC = updateObjectRedefTime(&cliInterface,
catalogNamePart, schemaNamePart, newObjectNamePart,
COM_BASE_TABLE_OBJECT_LIT, -1, objUID);
if (cliRC < 0)
{
processReturn();
goto label_error;
}
ActiveSchemaDB()->getNATableDB()->removeNATable
(cn,
ComQiScope::REMOVE_FROM_ALL_USERS, COM_BASE_TABLE_OBJECT,
renameTableNode->ddlXns(), FALSE);
deallocEHI(ehi);
endXnIfStartedHere(&cliInterface, xnWasStartedHere, 0);
return;
label_error: // come here after HBase copy
retcode = dropHbaseTable(ehi, &newHbaseTable, FALSE, FALSE);
label_error_2: // come here after beginXnIfNotInProgress but before HBase copy
endXnIfStartedHere(&cliInterface, xnWasStartedHere, cliRC);
deallocEHI(ehi);
return;
}
void CmpSeabaseDDL::alterSeabaseTableStoredDesc(
StmtDDLAlterTableStoredDesc * alterStoredDesc,
NAString &currCatName, NAString &currSchName)
{
Lng32 retcode = 0;
Lng32 cliRC = 0;
ComObjectName tableName(alterStoredDesc->getTableName());
ComAnsiNamePart currCatAnsiName(currCatName);
ComAnsiNamePart currSchAnsiName(currSchName);
tableName.applyDefaults(currCatAnsiName, currSchAnsiName);
const NAString catalogNamePart = tableName.getCatalogNamePartAsAnsiString();
const NAString schemaNamePart = tableName.getSchemaNamePartAsAnsiString(TRUE);
const NAString objectNamePart = tableName.getObjectNamePartAsAnsiString(TRUE);
const NAString extTableName = tableName.getExternalName(TRUE);
const NAString extNameForHbase = catalogNamePart + "." + schemaNamePart + "." + objectNamePart;
ExeCliInterface cliInterface(STMTHEAP, 0, NULL,
CmpCommon::context()->sqlSession()->getParentQid());
ExpHbaseInterface * ehi = allocEHI();
if (ehi == NULL)
{
processReturn();
return;
}
if ((isSeabaseReservedSchema(tableName)) &&
(!Get_SqlParser_Flags(INTERNAL_QUERY_FROM_EXEUTIL)))
{
*CmpCommon::diags() << DgSqlCode(-CAT_SMD_CANNOT_BE_ALTERED)
<< DgTableName(extTableName);
deallocEHI(ehi);
processReturn();
return;
}
if (CmpCommon::context()->sqlSession()->volatileSchemaInUse())
{
QualifiedName *qn =
CmpCommon::context()->sqlSession()->
updateVolatileQualifiedName
(alterStoredDesc->getTableNameAsQualifiedName().getObjectName());
if (qn == NULL)
{
*CmpCommon::diags()
<< DgSqlCode(-1427);
processReturn();
return;
}
ComObjectName volTabName (qn->getQualifiedNameAsAnsiString());
volTabName.applyDefaults(currCatAnsiName, currSchAnsiName);
NAString vtCatNamePart = volTabName.getCatalogNamePartAsAnsiString();
NAString vtSchNamePart = volTabName.getSchemaNamePartAsAnsiString(TRUE);
NAString vtObjNamePart = volTabName.getObjectNamePartAsAnsiString(TRUE);
retcode = existsInSeabaseMDTable(&cliInterface,
vtCatNamePart, vtSchNamePart, vtObjNamePart,
COM_BASE_TABLE_OBJECT);
if (retcode < 0)
{
processReturn();
return;
}
if (retcode == 1)
{
// table found in volatile schema. cannot alter it.
*CmpCommon::diags()
<< DgSqlCode(-3242)
<< DgString0("Operation not allowed on volatile tables.");
processReturn();
return;
}
}
BindWA bindWA(ActiveSchemaDB(), CmpCommon::context(), FALSE/*inDDL*/);
CorrName cn(objectNamePart,
STMTHEAP,
schemaNamePart,
catalogNamePart);
NATable *naTable = bindWA.getNATable(cn);
if (naTable == NULL || bindWA.errStatus())
{
CmpCommon::diags()->clear();
*CmpCommon::diags() << DgSqlCode(-CAT_OBJECT_DOES_NOT_EXIST_IN_TRAFODION)
<< DgString0(extTableName);
processReturn();
return;
}
// Make sure user has the privilege to perform the alter
if (alterStoredDesc->getType() != StmtDDLAlterTableStoredDesc::CHECK)
{
if (!isDDLOperationAuthorized(SQLOperation::ALTER_TABLE,
naTable->getOwner(),naTable->getSchemaOwner()))
{
*CmpCommon::diags() << DgSqlCode(-CAT_NOT_AUTHORIZED);
processReturn ();
return;
}
}
Int64 objUID = naTable->objectUid().castToInt64();
if (alterStoredDesc->getType() == StmtDDLAlterTableStoredDesc::GENERATE)
{
cliRC =
updateObjectRedefTime(&cliInterface,
catalogNamePart, schemaNamePart, objectNamePart,
COM_BASE_TABLE_OBJECT_LIT,
-1, objUID, TRUE);
if (cliRC < 0)
{
processReturn ();
return;
}
}
else if (alterStoredDesc->getType() == StmtDDLAlterTableStoredDesc::DELETE)
{
cliRC = deleteFromTextTable
(&cliInterface, objUID, COM_STORED_DESC_TEXT, 0);
if (cliRC < 0)
{
processReturn ();
return;
}
Int64 flags = MD_OBJECTS_STORED_DESC | MD_OBJECTS_DISABLE_STORED_DESC;
cliRC = updateObjectFlags(&cliInterface, objUID, flags, TRUE);
if (cliRC < 0)
{
processReturn ();
return;
}
}
else if (alterStoredDesc->getType() == StmtDDLAlterTableStoredDesc::ENABLE)
{
Int64 flags = MD_OBJECTS_DISABLE_STORED_DESC;
cliRC = updateObjectFlags(&cliInterface, objUID, flags, TRUE);
if (cliRC < 0)
{
processReturn ();
return;
}
}
else if (alterStoredDesc->getType() == StmtDDLAlterTableStoredDesc::DISABLE)
{
Int64 flags = MD_OBJECTS_DISABLE_STORED_DESC;
cliRC = updateObjectFlags(&cliInterface, objUID, flags, FALSE);
if (cliRC < 0)
{
processReturn ();
return;
}
}
else if (alterStoredDesc->getType() == StmtDDLAlterTableStoredDesc::CHECK)
{
checkAndGetStoredObjectDesc(&cliInterface, objUID, NULL);
processReturn();
return;
}
ActiveSchemaDB()->getNATableDB()->removeNATable
(cn,
ComQiScope::REMOVE_FROM_ALL_USERS, COM_BASE_TABLE_OBJECT,
alterStoredDesc->ddlXns(), FALSE);
return;
}
void CmpSeabaseDDL::alterSeabaseTableHBaseOptions(
StmtDDLAlterTableHBaseOptions * hbaseOptionsNode,
NAString &currCatName, NAString &currSchName)
{
Lng32 retcode = 0;
Lng32 cliRC = 0;
ExeCliInterface cliInterface(STMTHEAP, 0, NULL,
CmpCommon::context()->sqlSession()->getParentQid());
NAString tabName = hbaseOptionsNode->getTableName();
NAString catalogNamePart, schemaNamePart, objectNamePart;
NAString extTableName, extNameForHbase;
NATable * naTable = NULL;
CorrName cn;
retcode =
setupAndErrorChecks(tabName,
hbaseOptionsNode->getOrigTableNameAsQualifiedName(),
currCatName, currSchName,
catalogNamePart, schemaNamePart, objectNamePart,
extTableName, extNameForHbase, cn,
&naTable,
FALSE, FALSE,
&cliInterface);
if (retcode < 0)
{
processReturn();
return;
}
CmpCommon::diags()->clear();
// Get the object UID so we can update the metadata
Int64 objUID = getObjectUID(&cliInterface,
catalogNamePart.data(), schemaNamePart.data(),
objectNamePart.data(),
COM_BASE_TABLE_OBJECT_LIT);
if (objUID < 0)
{
processReturn();
return;
}
// update HBase options in the metadata
ElemDDLHbaseOptions * edhbo = hbaseOptionsNode->getHBaseOptions();
short result = updateHbaseOptionsInMetadata(&cliInterface,objUID,edhbo);
if (result < 0)
{
processReturn();
return;
}
// tell HBase to change the options
ExpHbaseInterface * ehi = allocEHI();
if (ehi == NULL)
{
processReturn();
return;
}
HbaseStr hbaseTable;
hbaseTable.val = (char*)extNameForHbase.data();
hbaseTable.len = extNameForHbase.length();
result = alterHbaseTable(ehi,
&hbaseTable,
naTable->allColFams(),
&(edhbo->getHbaseOptions()),
hbaseOptionsNode->ddlXns());
if (result < 0)
{
processReturn();
deallocEHI(ehi);
return;
}
cliRC = updateObjectRedefTime(&cliInterface,
catalogNamePart, schemaNamePart, objectNamePart,
COM_BASE_TABLE_OBJECT_LIT, -1, objUID);
if (cliRC < 0)
{
cliInterface.retrieveSQLDiagnostics(CmpCommon::diags());
deallocEHI(ehi);
processReturn();
return;
}
// invalidate cached NATable info on this table for all users
ActiveSchemaDB()->getNATableDB()->removeNATable
(cn,
ComQiScope::REMOVE_FROM_ALL_USERS, COM_BASE_TABLE_OBJECT,
hbaseOptionsNode->ddlXns(), FALSE);
deallocEHI(ehi);
return;
}
short CmpSeabaseDDL::createSeabaseTableLike2(
CorrName &cn,
const NAString &likeTableName,
NABoolean withPartns,
NABoolean withoutSalt,
NABoolean withoutDivision,
NABoolean withoutRowFormat)
{
Lng32 retcode = 0;
char * buf = NULL;
ULng32 buflen = 0;
retcode = CmpDescribeSeabaseTable(cn, 3/*createlike*/, buf, buflen, STMTHEAP,
NULL, NULL,
withPartns, withoutSalt, withoutDivision,
withoutRowFormat,
FALSE, // include LOB columns (if any)
UINT_MAX,
TRUE);
if (retcode)
return -1;
NAString query = "create table ";
query += likeTableName;
query += " ";
NABoolean done = FALSE;
Lng32 curPos = 0;
while (NOT done)
{
short len = *(short*)&buf[curPos];
NAString frag(&buf[curPos+sizeof(short)],
len - ((buf[curPos+len-1]== '\n') ? 1 : 0));
query += frag;
curPos += ((((len+sizeof(short))-1)/8)+1)*8;
if (curPos >= buflen)
done = TRUE;
}
query += ";";
// send any user CQDs down
Lng32 retCode = sendAllControls(FALSE, FALSE, TRUE);
ExeCliInterface cliInterface(STMTHEAP, 0, NULL,
CmpCommon::context()->sqlSession()->getParentQid());
Lng32 cliRC = 0;
cliRC = cliInterface.executeImmediate((char*)query.data());
if (cliRC < 0)
{
cliInterface.retrieveSQLDiagnostics(CmpCommon::diags());
return -1;
}
return 0;
}
short CmpSeabaseDDL::cloneHbaseTable(
const NAString &srcTable, const NAString &clonedTable,
ExpHbaseInterface * inEHI)
{
Lng32 retcode = 0;
HbaseStr hbaseTable;
hbaseTable.val = (char*)srcTable.data();
hbaseTable.len = srcTable.length();
HbaseStr clonedHbaseTable;
clonedHbaseTable.val = (char*)clonedTable.data();
clonedHbaseTable.len = clonedTable.length();
ExpHbaseInterface * ehi = (inEHI ? inEHI : allocEHI());
if (ehi == NULL) {
processReturn();
return -1;
}
// copy hbaseTable as clonedHbaseTable
if (retcode = ehi->copy(hbaseTable, clonedHbaseTable, TRUE))
{
*CmpCommon::diags()
<< DgSqlCode(-8448)
<< DgString0((char*)"ExpHbaseInterface::copy()")
<< DgString1(getHbaseErrStr(-retcode))
<< DgInt0(-retcode)
<< DgString2((char*)GetCliGlobals()->getJniErrorStr());
if (! inEHI)
deallocEHI(ehi);
processReturn();
return -1;
}
if (! inEHI)
deallocEHI(ehi);
return 0;
}
short CmpSeabaseDDL::cloneSeabaseTable(
const NAString &srcTableNameStr,
Int64 srcTableUID,
const NAString &clonedTableNameStr,
const NATable * naTable,
ExpHbaseInterface * inEHI,
ExeCliInterface * cliInterface,
NABoolean withCreate)
{
Lng32 cliRC = 0;
Lng32 retcode = 0;
ComObjectName srcTableName(srcTableNameStr, COM_TABLE_NAME);
const NAString srcCatNamePart = srcTableName.getCatalogNamePartAsAnsiString();
const NAString srcSchNamePart = srcTableName.getSchemaNamePartAsAnsiString(TRUE);
const NAString srcObjNamePart = srcTableName.getObjectNamePartAsAnsiString(TRUE);
CorrName srcCN(srcObjNamePart, STMTHEAP, srcSchNamePart, srcCatNamePart);
ComObjectName clonedTableName(clonedTableNameStr, COM_TABLE_NAME);
const NAString clonedCatNamePart = clonedTableName.getCatalogNamePartAsAnsiString();
const NAString clonedSchNamePart = clonedTableName.getSchemaNamePartAsAnsiString(TRUE);
const NAString clonedObjNamePart = clonedTableName.getObjectNamePartAsAnsiString(TRUE);
char buf[2000];
if (withCreate)
{
retcode = createSeabaseTableLike2(srcCN, clonedTableNameStr,
FALSE, TRUE, TRUE);
if (retcode)
return -1;
Int64 clonedTableUID =
getObjectUID
(cliInterface,
clonedCatNamePart.data(),
clonedSchNamePart.data(),
clonedObjNamePart.data(),
COM_BASE_TABLE_OBJECT_LIT);
// if there are added or altered columns in the source table, then cloned
// table metadata need to reflect that.
// Update metadata and set the cloned column class to be the same as source.
str_sprintf(buf, "merge into %s.\"%s\".%s using (select column_name, column_class from %s.\"%s\".%s where object_uid = %ld) x on (object_uid = %ld and column_name = x.column_name) when matched then update set column_class = x.column_class;",
getSystemCatalog(), SEABASE_MD_SCHEMA, SEABASE_COLUMNS,
getSystemCatalog(), SEABASE_MD_SCHEMA, SEABASE_COLUMNS,
srcTableUID,
clonedTableUID);
cliRC = cliInterface->executeImmediate(buf);
if (cliRC < 0)
{
cliInterface->retrieveSQLDiagnostics(CmpCommon::diags());
processReturn();
return -1;
}
}
if (NOT withCreate)
{
// truncate cloned(tgt) table before upsert
if (truncateHbaseTable(clonedCatNamePart,
clonedSchNamePart,
clonedObjNamePart,
naTable->hasSaltedColumn(), inEHI))
{
return -1;
}
}
NAString quotedSrcCatName;
ToQuotedString(quotedSrcCatName,
NAString(srcCN.getQualifiedNameObj().getCatalogName()), FALSE);
NAString quotedSrcSchName;
ToQuotedString(quotedSrcSchName,
NAString(srcCN.getQualifiedNameObj().getSchemaName()), FALSE);
NAString quotedSrcObjName;
ToQuotedString(quotedSrcObjName,
NAString(srcCN.getQualifiedNameObj().getObjectName()), FALSE);
str_sprintf(buf, "upsert using load into %s select * from %s.%s.%s",
clonedTableNameStr.data(),
quotedSrcCatName.data(),
quotedSrcSchName.data(),
quotedSrcObjName.data());
cliRC = cliInterface->executeImmediate(buf);
if (cliRC < 0)
{
cliInterface->retrieveSQLDiagnostics(CmpCommon::diags());
processReturn();
return -1;
}
return 0;
}
short CmpSeabaseDDL::cloneAndTruncateTable(
const NATable * naTable, // IN: source table
NAString &tempTable, // OUT: temp table
ExpHbaseInterface * ehi,
ExeCliInterface * cliInterface)
{
Lng32 cliRC = 0;
Lng32 cliRC2 = 0;
NABoolean identityGenAlways = FALSE;
char buf[4000];
const NAString &catalogNamePart = naTable->getTableName().getCatalogName();
const NAString &schemaNamePart = naTable->getTableName().getSchemaName();
const NAString &objectNamePart = naTable->getTableName().getObjectName();
ComUID comUID;
comUID.make_UID();
Int64 objUID = comUID.get_value();
char objUIDbuf[100];
tempTable = naTable->getTableName().getQualifiedNameAsAnsiString();
tempTable += "_";
tempTable += str_ltoa(objUID, objUIDbuf);
// identity 'generated always' columns do not permit inserting user specified
// values. Override it since we want to move original values to tgt.
const NAColumnArray &naColArr = naTable->getNAColumnArray();
for (Int32 c = 0; c < naColArr.entries(); c++)
{
const NAColumn * nac = naColArr[c];
if (nac->isIdentityColumnAlways())
{
identityGenAlways = TRUE;
break;
}
} // for
if (identityGenAlways)
{
cliRC = cliInterface->holdAndSetCQD("override_generated_identity_values", "ON");
if (cliRC < 0)
{
cliInterface->retrieveSQLDiagnostics(CmpCommon::diags());
goto label_restore;
}
}
// clone source naTable to target tempTable
if (cloneSeabaseTable(naTable->getTableName().getQualifiedNameAsAnsiString(),
naTable->objectUid().castToInt64(),
tempTable,
naTable,
ehi, cliInterface, TRUE))
{
cliRC = -1;
goto label_drop;
}
// truncate source naTable
if (truncateHbaseTable(catalogNamePart, schemaNamePart, objectNamePart,
naTable->hasSaltedColumn(), ehi))
{
cliRC = -1;
goto label_restore;
}
cliRC = 0;
goto label_return;
label_restore:
if (cloneSeabaseTable(tempTable, -1,
naTable->getTableName().getQualifiedNameAsAnsiString(),
naTable,
ehi, cliInterface, FALSE))
{
cliRC = -1;
goto label_drop;
}
label_drop:
str_sprintf(buf, "drop table %s", tempTable.data());
cliRC2 = cliInterface->executeImmediate(buf);
label_return:
if (identityGenAlways)
cliInterface->restoreCQD("override_generated_identity_values");
if (cliRC < 0)
tempTable.clear();
return (cliRC < 0 ? -1 : 0);
}
void CmpSeabaseDDL::alterSeabaseTableAddColumn(
StmtDDLAlterTableAddColumn * alterAddColNode,
NAString &currCatName, NAString &currSchName)
{
Lng32 cliRC = 0;
Lng32 retcode = 0;
ExeCliInterface cliInterface(STMTHEAP, 0, NULL,
CmpCommon::context()->sqlSession()->getParentQid());
NAString tabName = alterAddColNode->getTableName();
NAString catalogNamePart;
NAString schemaNamePart;
NAString objectNamePart;
NAString extTableName;
NAString extNameForHbase;
NATable * naTable = NULL;
CorrName cn;
retcode =
setupAndErrorChecks(tabName,
alterAddColNode->getOrigTableNameAsQualifiedName(),
currCatName, currSchName,
catalogNamePart, schemaNamePart, objectNamePart,
extTableName, extNameForHbase, cn,
&naTable,
FALSE, TRUE,
&cliInterface);
if (retcode < 0)
{
processReturn();
return;
}
ComObjectName tableName(tabName, COM_TABLE_NAME);
ComAnsiNamePart currCatAnsiName(currCatName);
ComAnsiNamePart currSchAnsiName(currSchName);
tableName.applyDefaults(currCatAnsiName, currSchAnsiName);
ExpHbaseInterface * ehi = allocEHI();
if (ehi == NULL)
{
processReturn();
return;
}
const NAColumnArray &nacolArr = naTable->getNAColumnArray();
ElemDDLColDefArray ColDefArray = alterAddColNode->getColDefArray();
ElemDDLColDef *pColDef = ColDefArray[0];
// Do not allow to using a NOT NULL constraint without a default
// clause. Do not allow DEFAULT NULL together with NOT NULL.
if (pColDef->getIsConstraintNotNullSpecified())
{
if (pColDef->getDefaultClauseStatus() != ElemDDLColDef::DEFAULT_CLAUSE_SPEC)
{
*CmpCommon::diags() << DgSqlCode(-CAT_DEFAULT_REQUIRED);
processReturn();
return;
}
ConstValue *pDefVal = (ConstValue *)pColDef->getDefaultValueExpr();
if ((pDefVal) &&
(pDefVal->origOpType() != ITM_CURRENT_USER) &&
(pDefVal->origOpType() != ITM_CURRENT_TIMESTAMP) &&
(pDefVal->origOpType() != ITM_UNIX_TIMESTAMP) &&
(pDefVal->origOpType() != ITM_UNIQUE_ID) &&
(pDefVal->origOpType() != ITM_CAST))
{
if (pDefVal->isNull())
{
*CmpCommon::diags() << DgSqlCode(-CAT_CANNOT_BE_DEFAULT_NULL_AND_NOT_NULL);
processReturn();
return;
}
}
}
//Do not allow NO DEFAULT
if (pColDef->getDefaultClauseStatus() == ElemDDLColDef::NO_DEFAULT_CLAUSE_SPEC)
{
*CmpCommon::diags() << DgSqlCode(-CAT_DEFAULT_REQUIRED);
processReturn();
return;
}
if (pColDef->getSGOptions())
{
*CmpCommon::diags() << DgSqlCode(-1514);
processReturn();
return;
}
char query[4000];
NAString colFamily;
NAString colName;
Lng32 datatype, length, precision, scale, dt_start, dt_end, nullable, upshifted;
ComColumnClass colClass;
ComColumnDefaultClass defaultClass;
NAString charset, defVal;
NAString heading;
ULng32 hbaseColFlags;
Int64 colFlags;
LobsStorage lobStorage;
// if hbase map format, turn off global serialization default to off.
NABoolean hbaseSerialization = FALSE;
NAString hbVal;
if (naTable->isHbaseMapTable())
{
if (CmpCommon::getDefault(HBASE_SERIALIZATION) == DF_ON)
{
NAString value("OFF");
hbVal = "ON";
ActiveSchemaDB()->getDefaults().validateAndInsert(
"hbase_serialization", value, FALSE);
hbaseSerialization = TRUE;
}
}
retcode = getColInfo(pColDef,
FALSE, // not a metadata, histogram or repository column
colFamily,
colName,
naTable->isSQLMXAlignedTable(),
datatype, length, precision, scale, dt_start, dt_end, upshifted, nullable,
charset, colClass, defaultClass, defVal, heading, lobStorage, hbaseColFlags, colFlags);
if (hbaseSerialization)
{
ActiveSchemaDB()->getDefaults().validateAndInsert
("hbase_serialization", hbVal, FALSE);
}
if (retcode)
return;
if ((CmpCommon::getDefault(TRAF_ALLOW_RESERVED_COLNAMES) == DF_OFF) &&
(ComTrafReservedColName(colName)))
{
*CmpCommon::diags() << DgSqlCode(-CAT_RESERVED_COLUMN_NAME)
<< DgString0(colName);
deallocEHI(ehi);
processReturn();
return;
}
if (colFamily.isNull())
{
colFamily = naTable->defaultColFam();
}
NABoolean addFam = FALSE;
NAString trafColFam;
if ((colFamily == SEABASE_DEFAULT_COL_FAMILY) ||
(naTable->isHbaseMapTable()))
trafColFam = colFamily;
else
{
CollIndex idx = naTable->allColFams().index(colFamily);
if (idx == NULL_COLL_INDEX) // doesnt exist, add it
{
idx = naTable->allColFams().entries();
addFam = TRUE;
}
genTrafColFam(idx, trafColFam);
}
const NAColumn * nacol = nacolArr.getColumn(colName);
if (nacol)
{
// column exists. Error or return, depending on 'if not exists' option.
if (NOT alterAddColNode->addIfNotExists())
{
*CmpCommon::diags() << DgSqlCode(-CAT_DUPLICATE_COLUMNS)
<< DgColumnName(colName);
}
processReturn();
return;
}
// If column is a LOB column , error
if ((datatype == REC_BLOB) || (datatype == REC_CLOB))
{
*CmpCommon::diags() << DgSqlCode(-CAT_LOB_COLUMN_ALTER)
<< DgColumnName(colName);
processReturn();
return;
}
char * col_name = new(STMTHEAP) char[colName.length() + 1];
strcpy(col_name, (char*)colName.data());
ULng32 maxColQual = nacolArr.getMaxTrafHbaseColQualifier();
NAString quotedHeading;
if (NOT heading.isNull())
{
ToQuotedString(quotedHeading, heading, FALSE);
}
NAString quotedDefVal;
if (NOT defVal.isNull())
{
ToQuotedString(quotedDefVal, defVal, FALSE);
}
Int64 objUID = naTable->objectUid().castToInt64();
Int32 newColNum = naTable->getColumnCount();
for (Int32 cc = nacolArr.entries()-1; cc >= 0; cc--)
{
const NAColumn *nac = nacolArr[cc];
if ((NOT naTable->isSQLMXAlignedTable()) &&
(nac->isComputedColumn()))
{
str_sprintf(query, "update %s.\"%s\".%s set column_number = column_number + 1 where object_uid = %ld and column_number = %d",
getSystemCatalog(), SEABASE_MD_SCHEMA, SEABASE_COLUMNS,
objUID,
nac->getPosition());
cliRC = cliInterface.executeImmediate(query);
if (cliRC < 0)
{
cliInterface.retrieveSQLDiagnostics(CmpCommon::diags());
return;
}
str_sprintf(query, "update %s.\"%s\".%s set column_number = column_number + 1 where object_uid = %ld and column_number = %d",
getSystemCatalog(), SEABASE_MD_SCHEMA, SEABASE_KEYS,
objUID,
nac->getPosition());
cliRC = cliInterface.executeImmediate(query);
if (cliRC < 0)
{
cliInterface.retrieveSQLDiagnostics(CmpCommon::diags());
return;
}
str_sprintf(query, "update %s.\"%s\".%s set sub_id = sub_id + 1 where text_uid = %ld and text_type = %d and sub_id = %d",
getSystemCatalog(), SEABASE_MD_SCHEMA, SEABASE_TEXT,
objUID,
COM_COMPUTED_COL_TEXT,
nac->getPosition());
cliRC = cliInterface.executeImmediate(query);
if (cliRC < 0)
{
cliInterface.retrieveSQLDiagnostics(CmpCommon::diags());
return;
}
// keys for indexes refer to base table column number.
// modify it so they now refer to new column numbers.
if (naTable->hasSecondaryIndexes())
{
const NAFileSetList &naFsList = naTable->getIndexList();
for (Lng32 i = 0; i < naFsList.entries(); i++)
{
const NAFileSet * naFS = naFsList[i];
// skip clustering index
if (naFS->getKeytag() == 0)
continue;
const QualifiedName &indexName = naFS->getFileSetName();
str_sprintf(query, "update %s.\"%s\".%s set column_number = column_number + 1 where column_number = %d and object_uid = (select object_uid from %s.\"%s\".%s where catalog_name = '%s' and schema_name = '%s' and object_name = '%s' and object_type = 'IX') ",
getSystemCatalog(), SEABASE_MD_SCHEMA, SEABASE_KEYS,
nac->getPosition(),
getSystemCatalog(), SEABASE_MD_SCHEMA, SEABASE_OBJECTS,
indexName.getCatalogName().data(),
indexName.getSchemaName().data(),
indexName.getObjectName().data());
cliRC = cliInterface.executeImmediate(query);
if (cliRC < 0)
{
cliInterface.retrieveSQLDiagnostics(CmpCommon::diags());
goto label_return;
}
} // for
} // secondary indexes present
newColNum--;
}
}
str_sprintf(query, "insert into %s.\"%s\".%s values (%ld, '%s', %d, '%s', %d, '%s', %d, %d, %d, %d, %d, '%s', %d, %d, '%s', %d, '%s', '%s', '%s', '%u', '%s', '%s', %ld )",
getSystemCatalog(), SEABASE_MD_SCHEMA, SEABASE_COLUMNS,
objUID,
col_name,
newColNum, //naTable->getColumnCount(),
COM_ADDED_USER_COLUMN_LIT,
datatype,
getAnsiTypeStrFromFSType(datatype),
length,
precision,
scale,
dt_start,
dt_end,
(upshifted ? "Y" : "N"),
hbaseColFlags,
nullable,
(char*)charset.data(),
(Lng32)defaultClass,
(quotedDefVal.isNull() ? "" : quotedDefVal.data()),
(quotedHeading.isNull() ? "" : quotedHeading.data()),
trafColFam.data(),
maxColQual+1,
COM_UNKNOWN_PARAM_DIRECTION_LIT,
"N",
colFlags);
cliRC = cliInterface.executeImmediate(query);
if (cliRC < 0)
{
cliInterface.retrieveSQLDiagnostics(CmpCommon::diags());
processReturn();
return;
}
// if column family of added col doesnt exist in the table, add it
if (addFam)
{
NAString currColFams;
if (getTextFromMD(&cliInterface, objUID, COM_HBASE_COL_FAMILY_TEXT,
0, currColFams))
{
deallocEHI(ehi);
processReturn();
return;
}
Lng32 cliRC = deleteFromTextTable(&cliInterface, objUID,
COM_HBASE_COL_FAMILY_TEXT, 0);
if (cliRC < 0)
{
deallocEHI(ehi);
processReturn();
return;
}
NAString allColFams = currColFams + " " + colFamily;
cliRC = updateTextTable(&cliInterface, objUID,
COM_HBASE_COL_FAMILY_TEXT, 0,
allColFams);
if (cliRC < 0)
{
*CmpCommon::diags()
<< DgSqlCode(-CAT_UNABLE_TO_CREATE_OBJECT)
<< DgTableName(extTableName);
deallocEHI(ehi);
processReturn();
return;
}
HbaseCreateOption hbco("NAME", trafColFam.data());
NAList<HbaseCreateOption*> hbcol(STMTHEAP);
hbcol.insert(&hbco);
ElemDDLHbaseOptions edhbo(&hbcol, STMTHEAP);
NAList<NAString> nal(STMTHEAP);
nal.insert(trafColFam);
HbaseStr hbaseTable;
hbaseTable.val = (char*)extNameForHbase.data();
hbaseTable.len = extNameForHbase.length();
cliRC = alterHbaseTable(ehi,
&hbaseTable,
nal,
&(edhbo.getHbaseOptions()),
alterAddColNode->ddlXns());
if (cliRC < 0)
{
deallocEHI(ehi);
processReturn();
return;
}
}
ActiveSchemaDB()->getNATableDB()->removeNATable
(cn,
ComQiScope::REMOVE_FROM_ALL_USERS, COM_BASE_TABLE_OBJECT,
alterAddColNode->ddlXns(), FALSE);
if (alterAddColNode->getAddConstraintPK())
{
// if table already has a primary key, return error.
if ((naTable->getClusteringIndex()) &&
(NOT naTable->getClusteringIndex()->hasOnlySyskey()))
{
*CmpCommon::diags()
<< DgSqlCode(-1256)
<< DgString0(extTableName);
processReturn();
return;
}
}
if ((alterAddColNode->getAddConstraintPK()) OR
(alterAddColNode->getAddConstraintCheckArray().entries() NEQ 0) OR
(alterAddColNode->getAddConstraintUniqueArray().entries() NEQ 0) OR
(alterAddColNode->getAddConstraintRIArray().entries() NEQ 0))
{
addConstraints(tableName, currCatAnsiName, currSchAnsiName,
alterAddColNode,
alterAddColNode->getAddConstraintPK(),
alterAddColNode->getAddConstraintUniqueArray(),
alterAddColNode->getAddConstraintRIArray(),
alterAddColNode->getAddConstraintCheckArray());
if (CmpCommon::diags()->getNumber(DgSqlCode::ERROR_))
return;
}
if (updateObjectRedefTime(&cliInterface,
catalogNamePart, schemaNamePart, objectNamePart,
COM_BASE_TABLE_OBJECT_LIT, -1, objUID))
{
processReturn();
return;
}
label_return:
processReturn();
return;
}
short CmpSeabaseDDL::updateMDforDropCol(ExeCliInterface &cliInterface,
const NATable * naTable,
Lng32 dropColNum)
{
Lng32 cliRC = 0;
Int64 objUID = naTable->objectUid().castToInt64();
char buf[4000];
str_sprintf(buf, "delete from %s.\"%s\".%s where object_uid = %ld and column_number = %d",
getSystemCatalog(), SEABASE_MD_SCHEMA, SEABASE_COLUMNS,
objUID,
dropColNum);
cliRC = cliInterface.executeImmediate(buf);
if (cliRC < 0)
{
cliInterface.retrieveSQLDiagnostics(CmpCommon::diags());
return -1;
}
str_sprintf(buf, "update %s.\"%s\".%s set column_number = column_number - 1 where object_uid = %ld and column_number >= %d",
getSystemCatalog(), SEABASE_MD_SCHEMA, SEABASE_COLUMNS,
objUID,
dropColNum);
cliRC = cliInterface.executeImmediate(buf);
if (cliRC < 0)
{
cliInterface.retrieveSQLDiagnostics(CmpCommon::diags());
return -1;
}
str_sprintf(buf, "update %s.\"%s\".%s set column_number = column_number - 1 where object_uid = %ld and column_number >= %d",
getSystemCatalog(), SEABASE_MD_SCHEMA, SEABASE_KEYS,
objUID,
dropColNum);
cliRC = cliInterface.executeImmediate(buf);
if (cliRC < 0)
{
cliInterface.retrieveSQLDiagnostics(CmpCommon::diags());
return -1;
}
//delete comment in TEXT table for column
str_sprintf(buf, "delete from %s.\"%s\".%s where text_uid = %ld and text_type = %d and sub_id = %d ",
getSystemCatalog(), SEABASE_MD_SCHEMA, SEABASE_TEXT,
objUID,
COM_COLUMN_COMMENT_TEXT,
dropColNum);
cliRC = cliInterface.executeImmediate(buf);
if (cliRC < 0)
{
cliInterface.retrieveSQLDiagnostics(CmpCommon::diags());
return -1;
}
str_sprintf(buf, "update %s.\"%s\".%s set sub_id = sub_id - 1 where text_uid = %ld and ( text_type = %d or text_type = %d ) and sub_id > %d",
getSystemCatalog(), SEABASE_MD_SCHEMA, SEABASE_TEXT,
objUID,
COM_COMPUTED_COL_TEXT,
COM_COLUMN_COMMENT_TEXT,
dropColNum);
cliRC = cliInterface.executeImmediate(buf);
if (cliRC < 0)
{
cliInterface.retrieveSQLDiagnostics(CmpCommon::diags());
return -1;
}
// keys for pkey constraint refer to base table column number.
// modify it so they now refer to new column numbers.
str_sprintf(buf, "update %s.\"%s\".%s K set column_number = column_number - 1 where K.column_number >= %d and K.object_uid = (select C.constraint_uid from %s.\"%s\".%s C where C.table_uid = %ld and C.constraint_type = 'P')",
getSystemCatalog(), SEABASE_MD_SCHEMA, SEABASE_KEYS,
dropColNum,
getSystemCatalog(), SEABASE_MD_SCHEMA, SEABASE_TABLE_CONSTRAINTS,
objUID);
cliRC = cliInterface.executeImmediate(buf);
if (cliRC < 0)
{
cliInterface.retrieveSQLDiagnostics(CmpCommon::diags());
return -1;
}
// keys for indexes refer to base table column number.
// modify it so they now refer to new column numbers.
if (naTable->hasSecondaryIndexes())
{
const NAFileSetList &naFsList = naTable->getIndexList();
for (Lng32 i = 0; i < naFsList.entries(); i++)
{
const NAFileSet * naFS = naFsList[i];
// skip clustering index
if (naFS->getKeytag() == 0)
continue;
const QualifiedName &indexName = naFS->getFileSetName();
str_sprintf(buf, "update %s.\"%s\".%s set column_number = column_number - 1 where column_number >= %d and object_uid = (select object_uid from %s.\"%s\".%s where catalog_name = '%s' and schema_name = '%s' and object_name = '%s' and object_type = 'IX') ",
getSystemCatalog(), SEABASE_MD_SCHEMA, SEABASE_KEYS,
dropColNum,
getSystemCatalog(), SEABASE_MD_SCHEMA, SEABASE_OBJECTS,
indexName.getCatalogName().data(),
indexName.getSchemaName().data(),
indexName.getObjectName().data());
cliRC = cliInterface.executeImmediate(buf);
if (cliRC < 0)
{
cliInterface.retrieveSQLDiagnostics(CmpCommon::diags());
return -1;
}
} // for
} // secondary indexes present
return 0;
}
///////////////////////////////////////////////////////////////////////
//
// An aligned table constains all columns in one hbase cell.
// To drop a column, we need to read each row, create a
// new row with the removed column and insert into the original table.
//
// Steps to drop a column from an aligned table:
//
// -- make a copy of the source aligned table using hbase copy
// -- truncate the source table
// -- Update metadata and remove the dropped column.
// -- bulk load data from copied table into the source table
// -- drop the copied temp table
//
// If an error happens after the source table has been truncated, then
// it will be restored from the copied table.
//
///////////////////////////////////////////////////////////////////////
short CmpSeabaseDDL::alignedFormatTableDropColumn
(
const NAString &catalogNamePart,
const NAString &schemaNamePart,
const NAString &objectNamePart,
const NATable * naTable,
const NAString &altColName,
ElemDDLColDef *pColDef,
NABoolean ddlXns,
NAList<NAString> &viewNameList,
NAList<NAString> &viewDefnList)
{
Lng32 cliRC = 0;
Lng32 cliRC2 = 0;
const NAFileSet * naf = naTable->getClusteringIndex();
CorrName cn(objectNamePart, STMTHEAP, schemaNamePart, catalogNamePart);
ExpHbaseInterface * ehi = allocEHI();
if (ehi == NULL)
return -1;
ExeCliInterface cliInterface
(STMTHEAP, 0, NULL,
CmpCommon::context()->sqlSession()->getParentQid());
const NAColumnArray &naColArr = naTable->getNAColumnArray();
const NAColumn * altNaCol = naColArr.getColumn(altColName);
Lng32 altColNum = altNaCol->getPosition();
NAString tgtCols;
NAString srcCols;
NABoolean xnWasStartedHere = FALSE;
char buf[4000];
// save data by cloning as a temp table and truncate source table
NAString clonedTable;
cliRC = cloneAndTruncateTable(naTable, clonedTable, ehi, &cliInterface);
if (cliRC < 0)
{
goto label_drop; // diags already populated by called method
}
if (beginXnIfNotInProgress(&cliInterface, xnWasStartedHere))
{
cliRC = -1;
goto label_restore;
}
if (updateMDforDropCol(cliInterface, naTable, altColNum))
{
cliRC = -1;
goto label_restore;
}
ActiveSchemaDB()->getNATableDB()->removeNATable
(cn,
ComQiScope::REMOVE_FROM_ALL_USERS,
COM_BASE_TABLE_OBJECT, ddlXns, FALSE);
for (Int32 c = 0; c < naColArr.entries(); c++)
{
const NAColumn * nac = naColArr[c];
if (nac->getColName() == altColName)
continue;
if (nac->isComputedColumn())
continue;
if (nac->isSystemColumn())
continue;
tgtCols += "\"" + nac->getColName() + "\"";
tgtCols += ",";
} // for
tgtCols = tgtCols.strip(NAString::trailing, ',');
if (tgtCols.isNull())
{
*CmpCommon::diags() << DgSqlCode(-1424)
<< DgColumnName(altColName);
cliRC = -1;
goto label_restore;
}
if (naTable->hasSecondaryIndexes()) // user indexes
{
cliRC = cliInterface.holdAndSetCQD("hide_indexes", "ALL");
if (cliRC < 0)
{
cliInterface.retrieveSQLDiagnostics(CmpCommon::diags());
goto label_restore;
}
}
cliRC = cliInterface.holdAndSetCQD("override_generated_identity_values", "ON");
if (cliRC < 0)
{
cliInterface.retrieveSQLDiagnostics(CmpCommon::diags());
goto label_restore;
}
str_sprintf(buf, "upsert using load into %s(%s) select %s from %s",
naTable->getTableName().getQualifiedNameAsAnsiString().data(),
tgtCols.data(),
tgtCols.data(),
clonedTable.data());
cliRC = cliInterface.executeImmediate(buf);
if (cliRC < 0)
{
cliInterface.retrieveSQLDiagnostics(CmpCommon::diags());
goto label_restore;
}
if ((cliRC = recreateUsingViews(&cliInterface, viewNameList, viewDefnList,
ddlXns)) < 0)
{
NAString reason = "Error occurred while recreating views due to dependency on older column definition. Drop dependent views before doing the alter.";
*CmpCommon::diags() << DgSqlCode(-1404)
<< DgColumnName(altColName)
<< DgString0(reason);
goto label_restore;
}
endXnIfStartedHere(&cliInterface, xnWasStartedHere, 0);
goto label_drop;
label_restore:
endXnIfStartedHere(&cliInterface, xnWasStartedHere, -1);
ActiveSchemaDB()->getNATableDB()->removeNATable
(cn,
ComQiScope::REMOVE_FROM_ALL_USERS,
COM_BASE_TABLE_OBJECT, FALSE, FALSE);
if ((cliRC < 0) &&
(NOT clonedTable.isNull()) &&
(cloneSeabaseTable(clonedTable, -1,
naTable->getTableName().getQualifiedNameAsAnsiString(),
naTable,
ehi, &cliInterface, FALSE)))
{
cliRC = -1;
goto label_drop;
}
label_drop:
if (NOT clonedTable.isNull())
{
str_sprintf(buf, "drop table %s", clonedTable.data());
cliRC2 = cliInterface.executeImmediate(buf);
}
cliInterface.restoreCQD("override_generated_identity_values");
cliInterface.restoreCQD("hide_indexes");
ActiveSchemaDB()->getNATableDB()->removeNATable
(cn,
ComQiScope::REMOVE_FROM_ALL_USERS,
COM_BASE_TABLE_OBJECT, ddlXns, FALSE);
deallocEHI(ehi);
return (cliRC < 0 ? -1 : 0);
}
short CmpSeabaseDDL::hbaseFormatTableDropColumn(
ExpHbaseInterface *ehi,
const NAString &catalogNamePart,
const NAString &schemaNamePart,
const NAString &objectNamePart,
const NATable * naTable,
const NAString &dropColName,
const NAColumn * nacol,
NABoolean ddlXns,
NAList<NAString> &viewNameList,
NAList<NAString> &viewDefnList)
{
Lng32 cliRC = 0;
const NAString extNameForHbase =
(naTable->isHbaseMapTable() ? objectNamePart :
(catalogNamePart + "." + schemaNamePart + "." + objectNamePart));
ExeCliInterface cliInterface(
STMTHEAP, 0, NULL,
CmpCommon::context()->sqlSession()->getParentQid());
Lng32 colNumber = nacol->getPosition();
NABoolean xnWasStartedHere = FALSE;
if (beginXnIfNotInProgress(&cliInterface, xnWasStartedHere))
{
cliRC = -1;
goto label_error;
}
if (updateMDforDropCol(cliInterface, naTable, colNumber))
{
cliRC = -1;
goto label_error;
}
// remove column from all rows of the base table
HbaseStr hbaseTable;
hbaseTable.val = (char*)extNameForHbase.data();
hbaseTable.len = extNameForHbase.length();
{
NAString column(nacol->getHbaseColFam(), heap_);
column.append(":");
if (naTable->isHbaseMapTable())
{
column.append(dropColName);
}
else
{
char * colQualPtr = (char*)nacol->getHbaseColQual().data();
Lng32 colQualLen = nacol->getHbaseColQual().length();
Int64 colQval = str_atoi(colQualPtr, colQualLen);
if (colQval <= UCHAR_MAX)
{
unsigned char c = (unsigned char)colQval;
column.append((char*)&c, 1);
}
else if (colQval <= USHRT_MAX)
{
unsigned short s = (unsigned short)colQval;
column.append((char*)&s, 2);
}
else if (colQval <= ULONG_MAX)
{
Lng32 l = (Lng32)colQval;
column.append((char*)&l, 4);
}
else
column.append((char*)&colQval, 8);
}
HbaseStr colNameStr;
char * col = (char *) heap_->allocateMemory(column.length() + 1, FALSE);
if (col)
{
memcpy(col, column.data(), column.length());
col[column.length()] = 0;
colNameStr.val = col;
colNameStr.len = column.length();
}
else
{
cliRC = -EXE_NO_MEM_TO_EXEC;
*CmpCommon::diags() << DgSqlCode(-EXE_NO_MEM_TO_EXEC); // error -8571
goto label_error;
}
cliRC = ehi->deleteColumns(hbaseTable, colNameStr);
if (cliRC < 0)
{
*CmpCommon::diags() << DgSqlCode(-8448)
<< DgString0((char*)"ExpHbaseInterface::deleteColumns()")
<< DgString1(getHbaseErrStr(-cliRC))
<< DgInt0(-cliRC)
<< DgString2((char*)GetCliGlobals()->getJniErrorStr());
goto label_error;
}
}
if ((cliRC = recreateUsingViews(&cliInterface, viewNameList, viewDefnList,
ddlXns)) < 0)
{
NAString reason = "Error occurred while recreating views due to dependency on older column definition. Drop dependent views before doing the alter.";
*CmpCommon::diags() << DgSqlCode(-1404)
<< DgColumnName(dropColName)
<< DgString0(reason);
goto label_error;
}
endXnIfStartedHere(&cliInterface, xnWasStartedHere, 0);
return 0;
label_error:
endXnIfStartedHere(&cliInterface, xnWasStartedHere, -1);
return -1;
}
void CmpSeabaseDDL::alterSeabaseTableDropColumn(
StmtDDLAlterTableDropColumn * alterDropColNode,
NAString &currCatName, NAString &currSchName)
{
Lng32 cliRC = 0;
Lng32 retcode = 0;
ExeCliInterface cliInterface(STMTHEAP, 0, NULL,
CmpCommon::context()->sqlSession()->getParentQid());
NAString tabName = alterDropColNode->getTableName();
NAString catalogNamePart, schemaNamePart, objectNamePart;
NAString extTableName, extNameForHbase;
NATable * naTable = NULL;
CorrName cn;
retcode =
setupAndErrorChecks(tabName,
alterDropColNode->getOrigTableNameAsQualifiedName(),
currCatName, currSchName,
catalogNamePart, schemaNamePart, objectNamePart,
extTableName, extNameForHbase, cn,
&naTable,
FALSE, TRUE,
&cliInterface);
if (retcode < 0)
{
processReturn();
return;
}
const NAColumnArray &nacolArr = naTable->getNAColumnArray();
const NAString &colName = alterDropColNode->getColName();
const NAColumn * nacol = nacolArr.getColumn(colName);
if (! nacol)
{
// column doesnt exist. Error or return, depending on 'if exists' option.
if (NOT alterDropColNode->dropIfExists())
{
*CmpCommon::diags() << DgSqlCode(-CAT_COLUMN_DOES_NOT_EXIST_ERROR)
<< DgColumnName(colName);
}
processReturn();
return;
}
// If column is a LOB column , error
Int32 datatype = nacol->getType()->getFSDatatype();
if ((datatype == REC_BLOB) || (datatype == REC_CLOB))
{
*CmpCommon::diags() << DgSqlCode(-CAT_LOB_COLUMN_ALTER)
<< DgColumnName(colName);
processReturn();
return;
}
const NAFileSet * naFS = naTable->getClusteringIndex();
const NAColumnArray &naKeyColArr = naFS->getIndexKeyColumns();
if (naKeyColArr.getColumn(colName))
{
// key column cannot be dropped
*CmpCommon::diags() << DgSqlCode(-1420)
<< DgColumnName(colName);
processReturn();
return;
}
if (naTable->hasSecondaryIndexes())
{
const NAFileSetList &naFsList = naTable->getIndexList();
for (Lng32 i = 0; i < naFsList.entries(); i++)
{
naFS = naFsList[i];
// skip clustering index
if (naFS->getKeytag() == 0)
continue;
const NAColumnArray &naIndexColArr = naFS->getAllColumns();
if (naIndexColArr.getColumn(colName))
{
// secondary index column cannot be dropped
*CmpCommon::diags() << DgSqlCode(-1421)
<< DgColumnName(colName)
<< DgTableName(naFS->getExtFileSetName());
processReturn();
return;
}
} // for
} // secondary indexes present
if ((naTable->getClusteringIndex()->hasSyskey()) &&
(nacolArr.entries() == 2))
{
// this table has one SYSKEY column and one other column.
// Dropping that column will leave the table with no user column.
// Return an error.
*CmpCommon::diags() << DgSqlCode(-1424)
<< DgColumnName(colName);
processReturn();
return;
}
// this operation cannot be done if a xn is already in progress.
if (xnInProgress(&cliInterface))
{
*CmpCommon::diags() << DgSqlCode(-20125)
<< DgString0("This ALTER");
processReturn();
return;
}
ExpHbaseInterface * ehi = NULL;
Int64 objUID = naTable->objectUid().castToInt64();
NAList<NAString> viewNameList(STMTHEAP);
NAList<NAString> viewDefnList(STMTHEAP);
if (saveAndDropUsingViews(objUID, &cliInterface, viewNameList, viewDefnList))
{
NAString reason = "Error occurred while saving views.";
*CmpCommon::diags() << DgSqlCode(-1404)
<< DgColumnName(colName)
<< DgString0(reason);
processReturn();
return;
}
NABoolean xnWasStartedHere = FALSE;
Lng32 colNumber = nacol->getPosition();
char *col = NULL;
if (naTable->isSQLMXAlignedTable())
{
if (alignedFormatTableDropColumn
(
catalogNamePart, schemaNamePart, objectNamePart,
naTable,
alterDropColNode->getColName(),
NULL, alterDropColNode->ddlXns(),
viewNameList, viewDefnList))
{
cliRC = -1;
goto label_error;
}
}
else
{
ehi = allocEHI();
if (hbaseFormatTableDropColumn
(
ehi,
catalogNamePart, schemaNamePart, objectNamePart,
naTable,
alterDropColNode->getColName(),
nacol, alterDropColNode->ddlXns(),
viewNameList, viewDefnList))
{
cliRC = -1;
goto label_error;
}
} // hbase format table
cliRC = updateObjectRedefTime(&cliInterface,
catalogNamePart, schemaNamePart, objectNamePart,
COM_BASE_TABLE_OBJECT_LIT, -1, objUID);
if (cliRC < 0)
{
goto label_error;
}
label_return:
endXnIfStartedHere(&cliInterface, xnWasStartedHere, cliRC);
ActiveSchemaDB()->getNATableDB()->removeNATable
(cn,
ComQiScope::REMOVE_FROM_ALL_USERS, COM_BASE_TABLE_OBJECT,
alterDropColNode->ddlXns(), FALSE);
return;
label_error:
endXnIfStartedHere(&cliInterface, xnWasStartedHere, cliRC);
if ((cliRC = recreateUsingViews(&cliInterface, viewNameList, viewDefnList,
alterDropColNode->ddlXns())) < 0)
{
NAString reason = "Error occurred while recreating views due to dependency on older column definition. Drop dependent views before doing the alter.";
*CmpCommon::diags() << DgSqlCode(-1404)
<< DgColumnName(colName)
<< DgString0(reason);
}
deallocEHI(ehi);
heap_->deallocateMemory(col);
ActiveSchemaDB()->getNATableDB()->removeNATable
(cn,
ComQiScope::REMOVE_FROM_ALL_USERS, COM_BASE_TABLE_OBJECT,
alterDropColNode->ddlXns(), FALSE);
processReturn();
return;
}
void CmpSeabaseDDL::alterSeabaseTableAlterIdentityColumn(
StmtDDLAlterTableAlterColumnSetSGOption * alterIdentityColNode,
NAString &currCatName, NAString &currSchName)
{
Lng32 cliRC = 0;
Lng32 retcode = 0;
ExeCliInterface cliInterface(STMTHEAP, 0, NULL,
CmpCommon::context()->sqlSession()->getParentQid());
NAString tabName = alterIdentityColNode->getTableName();
NAString catalogNamePart, schemaNamePart, objectNamePart;
NAString extTableName, extNameForHbase;
NATable * naTable = NULL;
CorrName cn;
retcode =
setupAndErrorChecks(tabName,
alterIdentityColNode->getOrigTableNameAsQualifiedName(),
currCatName, currSchName,
catalogNamePart, schemaNamePart, objectNamePart,
extTableName, extNameForHbase, cn,
&naTable,
FALSE, FALSE,
&cliInterface);
if (retcode < 0)
{
processReturn();
return;
}
const NAColumnArray &nacolArr = naTable->getNAColumnArray();
const NAString &colName = alterIdentityColNode->getColumnName();
const NAColumn * nacol = nacolArr.getColumn(colName);
if (! nacol)
{
*CmpCommon::diags() << DgSqlCode(-CAT_COLUMN_DOES_NOT_EXIST_ERROR)
<< DgColumnName(colName);
processReturn();
return;
}
if (! nacol->isIdentityColumn())
{
*CmpCommon::diags() << DgSqlCode(-1590)
<< DgColumnName(colName);
processReturn();
return;
}
NAString seqName;
SequenceGeneratorAttributes::genSequenceName
(catalogNamePart, schemaNamePart, objectNamePart,
alterIdentityColNode->getColumnName(),
seqName);
ElemDDLSGOptions * sgo = alterIdentityColNode->getSGOptions();
NAString options;
if (sgo)
{
char tmpBuf[1000];
if (sgo->isIncrementSpecified())
{
str_sprintf(tmpBuf, " increment by %ld", sgo->getIncrement());
options += tmpBuf;
}
if (sgo->isMaxValueSpecified())
{
if (sgo->isNoMaxValue())
strcpy(tmpBuf, " no maxvalue ");
else
str_sprintf(tmpBuf, " maxvalue %ld", sgo->getMaxValue());
options += tmpBuf;
}
if (sgo->isMinValueSpecified())
{
if (sgo->isNoMinValue())
strcpy(tmpBuf, " no maxvalue ");
else
str_sprintf(tmpBuf, " minvalue %ld", sgo->getMinValue());
options += tmpBuf;
}
if (sgo->isStartValueSpecified())
{
str_sprintf(tmpBuf, " start with %ld", sgo->getStartValue());
options += tmpBuf;
}
if (sgo->isCacheSpecified())
{
if (sgo->isNoCache())
str_sprintf(tmpBuf, " no cache ");
else
str_sprintf(tmpBuf, " cache %ld ", sgo->getCache());
options += tmpBuf;
}
if (sgo->isCycleSpecified())
{
if (sgo->isNoCycle())
str_sprintf(tmpBuf, " no cycle ");
else
str_sprintf(tmpBuf, " cycle ");
options += tmpBuf;
}
if (sgo->isResetSpecified())
{
str_sprintf(tmpBuf, " reset ");
options += tmpBuf;
}
char buf[4000];
str_sprintf(buf, "alter internal sequence %s.\"%s\".\"%s\" %s",
catalogNamePart.data(), schemaNamePart.data(), seqName.data(),
options.data());
cliRC = cliInterface.executeImmediate(buf);
if (cliRC < 0)
{
cliInterface.retrieveSQLDiagnostics(CmpCommon::diags());
processReturn();
return;
}
}
cliRC = updateObjectRedefTime(&cliInterface,
catalogNamePart, schemaNamePart, objectNamePart,
COM_BASE_TABLE_OBJECT_LIT, -1, naTable->objectUid().castToInt64());
if (cliRC < 0)
{
cliInterface.retrieveSQLDiagnostics(CmpCommon::diags());
processReturn();
return;
}
ActiveSchemaDB()->getNATableDB()->removeNATable
(cn,
ComQiScope::REMOVE_FROM_ALL_USERS, COM_BASE_TABLE_OBJECT,
alterIdentityColNode->ddlXns(), FALSE);
return;
}
short CmpSeabaseDDL::saveAndDropUsingViews(Int64 objUID,
ExeCliInterface *cliInterface,
NAList<NAString> &viewNameList,
NAList<NAString> &viewDefnList)
{
Lng32 cliRC = 0;
NAString catName, schName, objName;
cliRC = getObjectName(cliInterface, objUID,
catName, schName, objName);
if (cliRC < 0)
{
processReturn();
return -1;
}
Queue * usingViewsQueue = NULL;
cliRC = getAllUsingViews(cliInterface,
catName, schName, objName,
usingViewsQueue);
if (cliRC < 0)
{
processReturn();
return -1;
}
if (usingViewsQueue->numEntries() == 0)
return 0;
NABoolean xnWasStartedHere = FALSE;
if (beginXnIfNotInProgress(cliInterface, xnWasStartedHere))
return -1;
// find out any views on this table.
// save their definition and drop them.
// they will be recreated before return.
usingViewsQueue->position();
for (int idx = 0; idx < usingViewsQueue->numEntries(); idx++)
{
OutputInfo * vi = (OutputInfo*)usingViewsQueue->getNext();
char * viewName = vi->get(0);
viewNameList.insert(viewName);
ComObjectName viewCO(viewName, COM_TABLE_NAME);
const NAString catName = viewCO.getCatalogNamePartAsAnsiString();
const NAString schName = viewCO.getSchemaNamePartAsAnsiString(TRUE);
const NAString objName = viewCO.getObjectNamePartAsAnsiString(TRUE);
Int64 viewUID = getObjectUID(cliInterface,
catName.data(), schName.data(), objName.data(),
COM_VIEW_OBJECT_LIT);
if (viewUID < 0 )
{
endXnIfStartedHere(cliInterface, xnWasStartedHere, -1);
return -1;
}
NAString viewText;
if (getTextFromMD(cliInterface, viewUID, COM_VIEW_TEXT, 0, viewText))
{
endXnIfStartedHere(cliInterface, xnWasStartedHere, -1);
return -1;
}
viewDefnList.insert(viewText);
}
// drop the views.
// usingViewsQueue contain them in ascending order of their create
// time. Drop them from last to first.
for (int idx = usingViewsQueue->numEntries()-1; idx >= 0; idx--)
{
OutputInfo * vi = (OutputInfo*)usingViewsQueue->get(idx);
char * viewName = vi->get(0);
if (dropOneTableorView(*cliInterface,viewName,COM_VIEW_OBJECT,false))
{
endXnIfStartedHere(cliInterface, xnWasStartedHere, -1);
processReturn();
return -1;
}
}
endXnIfStartedHere(cliInterface, xnWasStartedHere, 0);
return 0;
}
short CmpSeabaseDDL::recreateUsingViews(ExeCliInterface *cliInterface,
NAList<NAString> &viewNameList,
NAList<NAString> &viewDefnList,
NABoolean ddlXns)
{
Lng32 cliRC = 0;
if (viewDefnList.entries() == 0)
return 0;
NABoolean xnWasStartedHere = FALSE;
if (beginXnIfNotInProgress(cliInterface, xnWasStartedHere))
return -1;
for (Lng32 i = 0; i < viewDefnList.entries(); i++)
{
cliRC = cliInterface->executeImmediate(viewDefnList[i]);
if (cliRC < 0)
{
cliInterface->retrieveSQLDiagnostics(CmpCommon::diags());
cliRC = -1;
goto label_return;
}
}
cliRC = 0;
label_return:
for (Lng32 i = 0; i < viewDefnList.entries(); i++)
{
ComObjectName tableName(viewNameList[i], COM_TABLE_NAME);
const NAString catalogNamePart =
tableName.getCatalogNamePartAsAnsiString();
const NAString schemaNamePart =
tableName.getSchemaNamePartAsAnsiString(TRUE);
const NAString objectNamePart =
tableName.getObjectNamePartAsAnsiString(TRUE);
CorrName cn(objectNamePart, STMTHEAP, schemaNamePart, catalogNamePart);
ActiveSchemaDB()->getNATableDB()->removeNATable
(cn,
ComQiScope::REMOVE_MINE_ONLY, COM_VIEW_OBJECT,
ddlXns, FALSE);
}
endXnIfStartedHere(cliInterface, xnWasStartedHere, cliRC);
return cliRC;
}
///////////////////////////////////////////////////////////////////////
//
// An aligned table constains all columns in one hbase cell.
// To alter a column, we need to read each row, create a
// new row with the altered column and insert into the original table.
//
// Validation that altered col datatype is compatible with the
// original datatype has already been done before this method
// is called.
//
// Steps to alter a column from an aligned table:
//
// -- make a copy of the source aligned table using hbase copy
// -- truncate the source table
// -- Update metadata column definition with the new definition
// -- bulk load data from copied table into the source table
// -- recreate views, if existed, based on the new definition
// -- drop the copied temp table
//
// If an error happens after the source table has been truncated, then
// it will be restored from the copied table.
//
///////////////////////////////////////////////////////////////////////
short CmpSeabaseDDL::alignedFormatTableAlterColumnAttr
(
const NAString &catalogNamePart,
const NAString &schemaNamePart,
const NAString &objectNamePart,
const NATable * naTable,
const NAString &altColName,
ElemDDLColDef *pColDef,
NABoolean ddlXns,
NAList<NAString> &viewNameList,
NAList<NAString> &viewDefnList)
{
Lng32 cliRC = 0;
Lng32 cliRC2 = 0;
const NAFileSet * naf = naTable->getClusteringIndex();
CorrName cn(objectNamePart, STMTHEAP, schemaNamePart, catalogNamePart);
ExpHbaseInterface * ehi = allocEHI();
if (ehi == NULL)
return -1;
ExeCliInterface cliInterface
(STMTHEAP, 0, NULL,
CmpCommon::context()->sqlSession()->getParentQid());
const NAColumnArray &naColArr = naTable->getNAColumnArray();
const NAColumn * altNaCol = naColArr.getColumn(altColName);
Lng32 altColNum = altNaCol->getPosition();
NAString colFamily;
NAString colName;
Lng32 datatype, length, precision, scale, dt_start, dt_end,
nullable, upshifted;
ComColumnClass colClass;
ComColumnDefaultClass defaultClass;
NAString charset, defVal;
NAString heading;
ULng32 hbaseColFlags;
Int64 colFlags;
LobsStorage lobStorage;
NAString quotedDefVal;
NABoolean xnWasStartedHere = FALSE;
char buf[4000];
// save data by cloning as a temp table and truncate source table
NAString clonedTable;
cliRC = cloneAndTruncateTable(naTable, clonedTable, ehi, &cliInterface);
if (cliRC < 0)
{
goto label_drop; // diags already populated by called method
}
if (beginXnIfNotInProgress(&cliInterface, xnWasStartedHere))
{
cliRC = -1;
goto label_restore;
}
if (getColInfo(pColDef,
FALSE, // not a metadata, histogram or repository column
colFamily,
colName,
naTable->isSQLMXAlignedTable(),
datatype, length, precision, scale, dt_start, dt_end,
upshifted, nullable,
charset, colClass, defaultClass, defVal, heading, lobStorage,
hbaseColFlags, colFlags))
{
cliRC = -1;
processReturn();
goto label_restore;
}
if (NOT defVal.isNull())
{
ToQuotedString(quotedDefVal, defVal, FALSE);
}
str_sprintf(buf, "update %s.\"%s\".%s set (column_class, fs_data_type, sql_data_type, column_size, column_precision, column_scale, datetime_start_field, datetime_end_field, is_upshifted, nullable, character_set, default_class, default_value) = ('%s', %d, '%s', %d, %d, %d, %d, %d, '%s', %d, '%s', %d, '%s') where object_uid = %ld and column_number = %d",
getSystemCatalog(), SEABASE_MD_SCHEMA, SEABASE_COLUMNS,
COM_ALTERED_USER_COLUMN_LIT,
datatype,
getAnsiTypeStrFromFSType(datatype),
length,
precision,
scale,
dt_start,
dt_end,
(upshifted ? "Y" : "N"),
nullable,
(char*)charset.data(),
(Lng32)defaultClass,
(quotedDefVal.isNull() ? "" : quotedDefVal.data()),
naTable->objectUid().castToInt64(),
altColNum);
cliRC = cliInterface.executeImmediate(buf);
if (cliRC < 0)
{
cliInterface.retrieveSQLDiagnostics(CmpCommon::diags());
goto label_restore;
}
ActiveSchemaDB()->getNATableDB()->removeNATable
(cn,
ComQiScope::REMOVE_FROM_ALL_USERS,
COM_BASE_TABLE_OBJECT, ddlXns, FALSE);
str_sprintf(buf, "upsert using load into %s select * from %s",
naTable->getTableName().getQualifiedNameAsAnsiString().data(),
clonedTable.data());
cliRC = cliInterface.executeImmediate(buf);
if (cliRC < 0)
{
cliInterface.retrieveSQLDiagnostics(CmpCommon::diags());
NAString reason;
reason = "Old data could not be updated using the altered column definition.";
// column cannot be altered
*CmpCommon::diags() << DgSqlCode(-1404)
<< DgColumnName(altColName)
<< DgString0(reason);
goto label_restore;
}
if ((cliRC = recreateUsingViews(&cliInterface, viewNameList, viewDefnList,
ddlXns)) < 0)
{
NAString reason = "Error occurred while recreating views due to dependency on older column definition. Drop dependent views before doing the alter.";
*CmpCommon::diags() << DgSqlCode(-1404)
<< DgColumnName(altColName)
<< DgString0(reason);
goto label_restore;
}
endXnIfStartedHere(&cliInterface, xnWasStartedHere, 0);
goto label_drop;
label_restore:
endXnIfStartedHere(&cliInterface, xnWasStartedHere, -1);
ActiveSchemaDB()->getNATableDB()->removeNATable
(cn,
ComQiScope::REMOVE_FROM_ALL_USERS,
COM_BASE_TABLE_OBJECT, FALSE, FALSE);
if ((cliRC < 0) &&
(NOT clonedTable.isNull()) &&
(cloneSeabaseTable(clonedTable, -1,
naTable->getTableName().getQualifiedNameAsAnsiString(),
naTable,
ehi, &cliInterface, FALSE)))
{
cliRC = -1;
goto label_drop;
}
label_drop:
if (NOT clonedTable.isNull())
{
str_sprintf(buf, "drop table %s", clonedTable.data());
cliRC2 = cliInterface.executeImmediate(buf);
}
cliInterface.restoreCQD("override_generated_identity_values");
cliInterface.restoreCQD("hide_indexes");
ActiveSchemaDB()->getNATableDB()->removeNATable
(cn,
ComQiScope::REMOVE_FROM_ALL_USERS,
COM_BASE_TABLE_OBJECT, ddlXns, FALSE);
deallocEHI(ehi);
return (cliRC < 0 ? -1 : 0);
}
/////////////////////////////////////////////////////////////////////
// this method is called if alter could be done by metadata changes
// only and without affecting table data.
/////////////////////////////////////////////////////////////////////
short CmpSeabaseDDL::mdOnlyAlterColumnAttr(
const NAString &catalogNamePart, const NAString &schemaNamePart,
const NAString &objectNamePart,
const NATable * naTable, const NAColumn * naCol, NAType * newType,
StmtDDLAlterTableAlterColumnDatatype * alterColNode,
NAList<NAString> &viewNameList,
NAList<NAString> &viewDefnList)
{
Lng32 cliRC = 0;
ExeCliInterface cliInterface
(STMTHEAP, 0, NULL,
CmpCommon::context()->sqlSession()->getParentQid());
Int64 objUID = naTable->objectUid().castToInt64();
Lng32 colNumber = naCol->getPosition();
NABoolean xnWasStartedHere = FALSE;
if (beginXnIfNotInProgress(&cliInterface, xnWasStartedHere))
return -1;
char buf[4000];
str_sprintf(buf, "update %s.\"%s\".%s set column_size = %d, column_class = '%s' where object_uid = %ld and column_number = %d",
getSystemCatalog(), SEABASE_MD_SCHEMA, SEABASE_COLUMNS,
newType->getNominalSize(),
COM_ALTERED_USER_COLUMN_LIT,
objUID,
colNumber);
cliRC = cliInterface.executeImmediate(buf);
if (cliRC < 0)
{
cliInterface.retrieveSQLDiagnostics(CmpCommon::diags());
goto label_error;
}
cliRC = recreateUsingViews(&cliInterface, viewNameList, viewDefnList,
alterColNode->ddlXns());
if (cliRC < 0)
{
NAString reason = "Error occurred while recreating views due to dependency on older column definition. Drop dependent views before doing the alter.";
*CmpCommon::diags() << DgSqlCode(-1404)
<< DgColumnName(naCol->getColName().data())
<< DgString0(reason);
goto label_error;
}
endXnIfStartedHere(&cliInterface, xnWasStartedHere, cliRC);
return 0;
label_error:
endXnIfStartedHere(&cliInterface, xnWasStartedHere, cliRC);
return -1;
}
///////////////////////////////////////////////////////////////////////
//
// Steps to alter a column from an hbase format table:
//
// Validation that altered col datatype is compatible with the
// original datatype has already been done before this method
// is called.
//
// -- add a temp column based on the altered datatype
// -- update temp col with data from the original col
// -- update metadata column definition with the new col definition
// -- update original col with data from temp col
// -- recreate views, if existed, based on the new definition
// -- drop the temp col. Dependent views will be recreated during drop.
//
// If an error happens after the source table has been truncated, then
// it will be restored from the copied table.
//
///////////////////////////////////////////////////////////////////////
short CmpSeabaseDDL::hbaseFormatTableAlterColumnAttr(
const NAString &catalogNamePart, const NAString &schemaNamePart,
const NAString &objectNamePart,
const NATable * naTable, const NAColumn * naCol, NAType * newType,
StmtDDLAlterTableAlterColumnDatatype * alterColNode)
{
ExeCliInterface cliInterface
(STMTHEAP, 0, NULL,
CmpCommon::context()->sqlSession()->getParentQid());
CorrName cn(objectNamePart, STMTHEAP, schemaNamePart,catalogNamePart);
Lng32 cliRC = 0;
Lng32 retcode = 0;
ComUID comUID;
comUID.make_UID();
Int64 objUID = comUID.get_value();
char objUIDbuf[100];
NAString tempCol(naCol->getColName());
tempCol += "_";
tempCol += str_ltoa(objUID, objUIDbuf);
char dispBuf[1000];
Lng32 ii = 0;
NABoolean identityCol;
ElemDDLColDef *pColDef = alterColNode->getColToAlter()->castToElemDDLColDef();
NAColumn *nac = NULL;
if (getNAColumnFromColDef(pColDef, nac))
return -1;
dispBuf[0] = 0;
if (cmpDisplayColumn(nac, (char*)tempCol.data(), newType, 3, NULL, dispBuf,
ii, FALSE, identityCol,
FALSE, FALSE, UINT_MAX, NULL))
return -1;
Int64 tableUID = naTable->objectUid().castToInt64();
const NAColumnArray &nacolArr = naTable->getNAColumnArray();
const NAString &altColName = naCol->getColName();
const NAColumn * altNaCol = nacolArr.getColumn(altColName);
Lng32 altColNum = altNaCol->getPosition();
char buf[4000];
str_sprintf(buf, "alter table %s add column %s",
naTable->getTableName().getQualifiedNameAsAnsiString().data(),
dispBuf);
cliRC = cliInterface.executeImmediate(buf);
if (cliRC < 0)
{
cliInterface.retrieveSQLDiagnostics(CmpCommon::diags());
processReturn();
return -1;
}
ActiveSchemaDB()->getNATableDB()->removeNATable
(cn,
ComQiScope::REMOVE_FROM_ALL_USERS,
COM_BASE_TABLE_OBJECT,
alterColNode->ddlXns(), FALSE);
str_sprintf(buf, "update %s set %s = %s",
naTable->getTableName().getQualifiedNameAsAnsiString().data(),
tempCol.data(),
naCol->getColName().data());
cliRC = cliInterface.executeImmediate(buf);
if (cliRC < 0)
{
cliInterface.retrieveSQLDiagnostics(CmpCommon::diags());
goto label_error1;
}
str_sprintf(buf, "delete from %s.\"%s\".%s where object_uid = %ld and column_number = %d",
getSystemCatalog(), SEABASE_MD_SCHEMA, SEABASE_COLUMNS,
tableUID,
altColNum);
cliRC = cliInterface.executeImmediate(buf);
if (cliRC < 0)
{
cliInterface.retrieveSQLDiagnostics(CmpCommon::diags());
goto label_error1;
}
str_sprintf(buf, "insert into %s.\"%s\".%s select object_uid, '%s', %d, '%s', fs_data_type, sql_data_type, column_size, column_precision, column_scale, datetime_start_field, datetime_end_field, is_upshifted, column_flags, nullable, character_set, default_class, default_value, column_heading, '%s', '%s', direction, is_optional, flags from %s.\"%s\".%s where object_uid = %ld and column_number = (select column_number from %s.\"%s\".%s where object_uid = %ld and column_name = '%s')",
getSystemCatalog(), SEABASE_MD_SCHEMA, SEABASE_COLUMNS,
naCol->getColName().data(),
altColNum,
COM_ALTERED_USER_COLUMN_LIT,
altNaCol->getHbaseColFam().data(),
altNaCol->getHbaseColQual().data(),
getSystemCatalog(), SEABASE_MD_SCHEMA, SEABASE_COLUMNS,
tableUID,
getSystemCatalog(), SEABASE_MD_SCHEMA, SEABASE_COLUMNS,
tableUID,
tempCol.data());
cliRC = cliInterface.executeImmediate(buf);
if (cliRC < 0)
{
cliInterface.retrieveSQLDiagnostics(CmpCommon::diags());
goto label_error1;
}
ActiveSchemaDB()->getNATableDB()->removeNATable
(cn,
ComQiScope::REMOVE_FROM_ALL_USERS,
COM_BASE_TABLE_OBJECT,
alterColNode->ddlXns(), FALSE);
str_sprintf(buf, "update %s set %s = %s",
naTable->getTableName().getQualifiedNameAsAnsiString().data(),
naCol->getColName().data(),
tempCol.data());
cliRC = cliInterface.executeImmediate(buf);
if (cliRC < 0)
{
cliInterface.retrieveSQLDiagnostics(CmpCommon::diags());
NAString reason;
reason = "Old data could not be updated into the new column definition.";
// column cannot be altered
*CmpCommon::diags() << DgSqlCode(-1404)
<< DgColumnName(naCol->getColName())
<< DgString0(reason);
processReturn();
goto label_error1;
}
str_sprintf(buf, "alter table %s drop column %s",
naTable->getTableName().getQualifiedNameAsAnsiString().data(),
tempCol.data());
cliRC = cliInterface.executeImmediate(buf);
if (cliRC < 0)
{
cliInterface.retrieveSQLDiagnostics(CmpCommon::diags());
processReturn();
return -1;
}
return 0;
label_error1:
str_sprintf(buf, "alter table %s drop column %s",
naTable->getTableName().getQualifiedNameAsAnsiString().data(),
tempCol.data());
cliRC = cliInterface.executeImmediate(buf);
if (cliRC < 0)
{
processReturn();
return -1;
}
return -1;
}
void CmpSeabaseDDL::alterSeabaseTableAlterColumnDatatype(
StmtDDLAlterTableAlterColumnDatatype * alterColNode,
NAString &currCatName, NAString &currSchName)
{
Lng32 cliRC = 0;
Lng32 retcode = 0;
ExeCliInterface cliInterface(STMTHEAP, 0, NULL,
CmpCommon::context()->sqlSession()->getParentQid());
NAString tabName = alterColNode->getTableName();
NAString catalogNamePart, schemaNamePart, objectNamePart;
NAString extTableName, extNameForHbase;
NATable * naTable = NULL;
CorrName cn;
retcode =
setupAndErrorChecks(tabName,
alterColNode->getOrigTableNameAsQualifiedName(),
currCatName, currSchName,
catalogNamePart, schemaNamePart, objectNamePart,
extTableName, extNameForHbase, cn,
&naTable,
FALSE, FALSE,
&cliInterface);
if (retcode < 0)
{
processReturn();
return;
}
ElemDDLColDef *pColDef = alterColNode->getColToAlter()->castToElemDDLColDef();
const NAColumnArray &nacolArr = naTable->getNAColumnArray();
const NAString &colName = pColDef->getColumnName();
const NAColumn * nacol = nacolArr.getColumn(colName);
if (! nacol)
{
// column doesnt exist. Error.
*CmpCommon::diags() << DgSqlCode(-CAT_COLUMN_DOES_NOT_EXIST_ERROR)
<< DgColumnName(colName);
processReturn();
return;
}
const NAType * currType = nacol->getType();
NAType * newType = pColDef->getColumnDataType();
// If column is a LOB column , error
if ((currType->getFSDatatype() == REC_BLOB) || (currType->getFSDatatype() == REC_CLOB))
{
*CmpCommon::diags() << DgSqlCode(-CAT_LOB_COLUMN_ALTER)
<< DgColumnName(colName);
processReturn();
return;
}
const NAFileSet * naFS = naTable->getClusteringIndex();
const NAColumnArray &naKeyColArr = naFS->getIndexKeyColumns();
if (naKeyColArr.getColumn(colName))
{
// key column cannot be altered
*CmpCommon::diags() << DgSqlCode(-1420)
<< DgColumnName(colName);
processReturn();
return;
}
if (naTable->hasSecondaryIndexes())
{
const NAFileSetList &naFsList = naTable->getIndexList();
for (Lng32 i = 0; i < naFsList.entries(); i++)
{
naFS = naFsList[i];
// skip clustering index
if (naFS->getKeytag() == 0)
continue;
const NAColumnArray &naIndexColArr = naFS->getAllColumns();
if (naIndexColArr.getColumn(colName))
{
// secondary index column cannot be altered
*CmpCommon::diags() << DgSqlCode(-1421)
<< DgColumnName(colName)
<< DgTableName(naFS->getExtFileSetName());
processReturn();
return;
}
} // for
} // secondary indexes present
if ((NOT currType->isCompatible(*newType)) &&
(NOT ((currType->getTypeQualifier() == NA_CHARACTER_TYPE) &&
(newType->getTypeQualifier() == NA_CHARACTER_TYPE))))
{
NAString reason = "Old and New datatypes must be compatible.";
// column cannot be altered
*CmpCommon::diags() << DgSqlCode(-1404)
<< DgColumnName(colName)
<< DgString0(reason);
processReturn();
return;
}
// Column that can be altered by updating metadata only
// must meet these conditions:
// -- old and new column datatype must be VARCHAR
// -- old and new datatype must have the same nullable attr
// -- new col length must be greater than or equal to old length
// -- old and new character sets must be the same
NABoolean mdAlterOnly = FALSE;
if ((DFS2REC::isSQLVarChar(currType->getFSDatatype())) &&
(DFS2REC::isSQLVarChar(newType->getFSDatatype())) &&
(currType->getFSDatatype() == newType->getFSDatatype()) &&
(currType->supportsSQLnull() == newType->supportsSQLnull()) &&
(currType->getNominalSize() <= newType->getNominalSize()) &&
(((CharType*)currType)->getCharSet() == ((CharType*)newType)->getCharSet()))
mdAlterOnly = TRUE;
if ((NOT mdAlterOnly) &&
(CmpCommon::getDefault(TRAF_ALTER_COL_ATTRS) == DF_OFF))
{
NAString reason;
if (NOT ((DFS2REC::isSQLVarChar(currType->getFSDatatype())) &&
(DFS2REC::isSQLVarChar(newType->getFSDatatype()))))
reason = "Old and New datatypes must be VARCHAR.";
else if (currType->getFSDatatype() != newType->getFSDatatype())
reason = "Old and New datatypes must be the same.";
else if (((CharType*)currType)->getCharSet() != ((CharType*)newType)->getCharSet())
reason = "Old and New character sets must be the same.";
else if (currType->getNominalSize() > newType->getNominalSize())
reason = "New length must be greater than or equal to old length.";
else if (currType->supportsSQLnull() != newType->supportsSQLnull())
reason = "Old and New nullability must be the same.";
// column cannot be altered
*CmpCommon::diags() << DgSqlCode(-1404)
<< DgColumnName(colName)
<< DgString0(reason);
processReturn();
return;
}
// this operation cannot be done if a xn is already in progress.
if ((NOT mdAlterOnly) && (xnInProgress(&cliInterface)))
{
*CmpCommon::diags() << DgSqlCode(-20125)
<< DgString0("This ALTER");
processReturn();
return;
}
Int64 objUID = naTable->objectUid().castToInt64();
// if there are views on the table, save the definition and drop
// the views.
// At the end of alter, views will be recreated. If an error happens
// during view recreation, alter will fail.
NAList<NAString> viewNameList(STMTHEAP);
NAList<NAString> viewDefnList(STMTHEAP);
if (saveAndDropUsingViews(objUID, &cliInterface, viewNameList, viewDefnList))
{
NAString reason = "Error occurred while saving views.";
*CmpCommon::diags() << DgSqlCode(-1404)
<< DgColumnName(colName)
<< DgString0(reason);
processReturn();
return;
}
if (mdAlterOnly)
{
if (mdOnlyAlterColumnAttr
(catalogNamePart, schemaNamePart, objectNamePart,
naTable, nacol, newType, alterColNode,
viewNameList, viewDefnList))
{
cliRC = -1;
goto label_error;
}
}
else if (naTable->isSQLMXAlignedTable())
{
ElemDDLColDef *pColDef =
alterColNode->getColToAlter()->castToElemDDLColDef();
if (alignedFormatTableAlterColumnAttr
(catalogNamePart, schemaNamePart, objectNamePart,
naTable,
colName,
pColDef,
alterColNode->ddlXns(),
viewNameList, viewDefnList))
{
cliRC = -1;
goto label_error;
}
}
else if (hbaseFormatTableAlterColumnAttr
(catalogNamePart, schemaNamePart, objectNamePart,
naTable, nacol, newType, alterColNode))
{
cliRC = -1;
goto label_error;
}
cliRC = updateObjectRedefTime(&cliInterface,
catalogNamePart, schemaNamePart, objectNamePart,
COM_BASE_TABLE_OBJECT_LIT, -1, objUID);
if (cliRC < 0)
{
goto label_error;
}
label_return:
ActiveSchemaDB()->getNATableDB()->removeNATable
(cn,
ComQiScope::REMOVE_FROM_ALL_USERS, COM_BASE_TABLE_OBJECT,
alterColNode->ddlXns(), FALSE);
processReturn();
return;
label_error:
if ((cliRC = recreateUsingViews(&cliInterface, viewNameList, viewDefnList,
alterColNode->ddlXns())) < 0)
{
NAString reason = "Error occurred while recreating views due to dependency on older column definition. Drop dependent views before doing the alter.";
*CmpCommon::diags() << DgSqlCode(-1404)
<< DgColumnName(colName)
<< DgString0(reason);
}
ActiveSchemaDB()->getNATableDB()->removeNATable
(cn,
ComQiScope::REMOVE_FROM_ALL_USERS, COM_BASE_TABLE_OBJECT,
alterColNode->ddlXns(), FALSE);
processReturn();
return;
}
/////////////////////////////////////////////////////////////////////
// this method renames an existing column to the specified new name.
//
// A column cannot be renamed if it is a system, salt, division by,
// computed or a lob column.
//
// If any index exists on the renamed column, then the index column
// is also renamed.
//
// If views exist on the table, they are dropped and recreated after
// rename. If recreation runs into an error, then alter fails.
//
///////////////////////////////////////////////////////////////////
void CmpSeabaseDDL::alterSeabaseTableAlterColumnRename(
StmtDDLAlterTableAlterColumnRename * alterColNode,
NAString &currCatName, NAString &currSchName)
{
Lng32 cliRC = 0;
Lng32 retcode = 0;
const NAString &tabName = alterColNode->getTableName();
ComObjectName tableName(tabName, COM_TABLE_NAME);
ComAnsiNamePart currCatAnsiName(currCatName);
ComAnsiNamePart currSchAnsiName(currSchName);
tableName.applyDefaults(currCatAnsiName, currSchAnsiName);
const NAString catalogNamePart = tableName.getCatalogNamePartAsAnsiString();
const NAString schemaNamePart = tableName.getSchemaNamePartAsAnsiString(TRUE);
const NAString objectNamePart = tableName.getObjectNamePartAsAnsiString(TRUE);
const NAString extTableName = tableName.getExternalName(TRUE);
const NAString extNameForHbase = catalogNamePart + "." + schemaNamePart + "." + objectNamePart;
ExeCliInterface cliInterface(STMTHEAP, 0, NULL,
CmpCommon::context()->sqlSession()->getParentQid());
if ((isSeabaseReservedSchema(tableName)) &&
(!Get_SqlParser_Flags(INTERNAL_QUERY_FROM_EXEUTIL)))
{
*CmpCommon::diags() << DgSqlCode(-CAT_CANNOT_ALTER_DEFINITION_METADATA_SCHEMA);
processReturn();
return;
}
retcode = existsInSeabaseMDTable(&cliInterface,
catalogNamePart, schemaNamePart, objectNamePart,
COM_BASE_TABLE_OBJECT,
(Get_SqlParser_Flags(INTERNAL_QUERY_FROM_EXEUTIL)
? FALSE : TRUE),
TRUE, TRUE);
if (retcode < 0)
{
processReturn();
return;
}
if (retcode == 0) // does not exist
{
*CmpCommon::diags() << DgSqlCode(-CAT_CANNOT_ALTER_WRONG_TYPE)
<< DgString0(extTableName);
processReturn();
return;
}
ActiveSchemaDB()->getNATableDB()->useCache();
BindWA bindWA(ActiveSchemaDB(), CmpCommon::context(), FALSE/*inDDL*/);
CorrName cn(tableName.getObjectNamePart().getInternalName(),
STMTHEAP,
tableName.getSchemaNamePart().getInternalName(),
tableName.getCatalogNamePart().getInternalName());
NATable *naTable = bindWA.getNATable(cn);
if (naTable == NULL || bindWA.errStatus())
{
*CmpCommon::diags()
<< DgSqlCode(-4082)
<< DgTableName(cn.getExposedNameAsAnsiString());
processReturn();
return;
}
// Make sure user has the privilege to perform the alter column
if (!isDDLOperationAuthorized(SQLOperation::ALTER_TABLE,
naTable->getOwner(),naTable->getSchemaOwner()))
{
*CmpCommon::diags() << DgSqlCode(-CAT_NOT_AUTHORIZED);
processReturn ();
return;
}
// return an error if trying to alter a column from a volatile table
if (naTable->isVolatileTable())
{
*CmpCommon::diags() << DgSqlCode(-CAT_REGULAR_OPERATION_ON_VOLATILE_OBJECT);
processReturn ();
return;
}
const NAColumnArray &nacolArr = naTable->getNAColumnArray();
const NAString &colName = alterColNode->getColumnName();
const NAString &renamedColName = alterColNode->getRenamedColumnName();
const NAColumn * nacol = nacolArr.getColumn(colName);
if (! nacol)
{
// column doesnt exist. Error.
*CmpCommon::diags() << DgSqlCode(-CAT_COLUMN_DOES_NOT_EXIST_ERROR)
<< DgColumnName(colName);
processReturn();
return;
}
if ((CmpCommon::getDefault(TRAF_ALLOW_RESERVED_COLNAMES) == DF_OFF) &&
(ComTrafReservedColName(renamedColName)))
{
NAString reason = "Renamed column " + renamedColName + " is reserved for internal system usage.";
*CmpCommon::diags() << DgSqlCode(-1404)
<< DgColumnName(colName)
<< DgString0(reason);
processReturn();
return;
}
if (nacol->isComputedColumn() || nacol->isSystemColumn())
{
NAString reason = "Cannot rename system or computed column.";
*CmpCommon::diags() << DgSqlCode(-1404)
<< DgColumnName(colName)
<< DgString0(reason);
processReturn();
return;
}
const NAColumn * renNacol = nacolArr.getColumn(renamedColName);
if (renNacol)
{
// column already exist. Error.
NAString reason = "Renamed column " + renamedColName + " already exist in the table.";
*CmpCommon::diags() << DgSqlCode(-1404)
<< DgColumnName(colName)
<< DgString0(reason);
processReturn();
return;
}
const NAType * currType = nacol->getType();
// If column is a LOB column , error
if ((currType->getFSDatatype() == REC_BLOB) || (currType->getFSDatatype() == REC_CLOB))
{
*CmpCommon::diags() << DgSqlCode(-CAT_LOB_COLUMN_ALTER)
<< DgColumnName(colName);
processReturn();
return;
}
const NAFileSet * naFS = naTable->getClusteringIndex();
const NAColumnArray &naKeyColArr = naFS->getIndexKeyColumns();
NABoolean isPkeyCol = FALSE;
if (naKeyColArr.getColumn(colName))
{
isPkeyCol = TRUE;
}
Int64 objUID = naTable->objectUid().castToInt64();
NAList<NAString> viewNameList(STMTHEAP);
NAList<NAString> viewDefnList(STMTHEAP);
if (saveAndDropUsingViews(objUID, &cliInterface, viewNameList, viewDefnList))
{
NAString reason = "Error occurred while saving dependent views.";
*CmpCommon::diags() << DgSqlCode(-1404)
<< DgColumnName(colName)
<< DgString0(reason);
processReturn();
return;
}
Lng32 colNumber = nacol->getPosition();
char buf[4000];
str_sprintf(buf, "update %s.\"%s\".%s set column_name = '%s', column_class = '%s' where object_uid = %ld and column_number = %d",
getSystemCatalog(), SEABASE_MD_SCHEMA, SEABASE_COLUMNS,
renamedColName.data(),
COM_ALTERED_USER_COLUMN_LIT,
objUID,
colNumber);
cliRC = cliInterface.executeImmediate(buf);
if (cliRC < 0)
{
cliInterface.retrieveSQLDiagnostics(CmpCommon::diags());
processReturn();
return;
}
if (isPkeyCol)
{
Lng32 divColPos = -1;
if ((naTable->hasDivisioningColumn(&divColPos)))
{
NAString reason = "Not supported with DIVISION BY clause.";
*CmpCommon::diags() << DgSqlCode(-1404)
<< DgColumnName(colName)
<< DgString0(reason);
processReturn();
return;
}
Lng32 saltColPos = -1;
if ((naTable->hasSaltedColumn(&saltColPos)))
{
NAString saltText;
cliRC = getTextFromMD(&cliInterface, objUID, COM_COMPUTED_COL_TEXT,
saltColPos, saltText);
if (cliRC < 0)
{
processReturn();
return;
}
// replace col reference with renamed col
NAString quotedColName = "\"" + colName + "\"";
NAString renamedQuotedColName = "\"" + renamedColName + "\"";
saltText = replaceAll(saltText, quotedColName, renamedQuotedColName);
cliRC = updateTextTable(&cliInterface, objUID, COM_COMPUTED_COL_TEXT,
saltColPos, saltText, NULL, -1, TRUE);
if (cliRC < 0)
{
processReturn();
return;
}
} // saltCol
} // pkeyCol being renamed
if (naTable->hasSecondaryIndexes())
{
const NAFileSetList &naFsList = naTable->getIndexList();
for (Lng32 i = 0; i < naFsList.entries(); i++)
{
naFS = naFsList[i];
// skip clustering index
if (naFS->getKeytag() == 0)
continue;
str_sprintf(buf, "update %s.\"%s\".%s set column_name = '%s' || '@' where object_uid = %ld and column_name = '%s' || '@'",
getSystemCatalog(), SEABASE_MD_SCHEMA, SEABASE_COLUMNS,
renamedColName.data(),
naFS->getIndexUID(),
colName.data());
cliRC = cliInterface.executeImmediate(buf);
if (cliRC < 0)
{
cliInterface.retrieveSQLDiagnostics(CmpCommon::diags());
processReturn();
return;
}
str_sprintf(buf, "update %s.\"%s\".%s set column_name = '%s' where object_uid = %ld and column_name = '%s'",
getSystemCatalog(), SEABASE_MD_SCHEMA, SEABASE_COLUMNS,
renamedColName.data(),
naFS->getIndexUID(),
colName.data());
cliRC = cliInterface.executeImmediate(buf);
if (cliRC < 0)
{
cliInterface.retrieveSQLDiagnostics(CmpCommon::diags());
processReturn();
return;
}
} // for
} // secondary indexes present
cliRC = recreateUsingViews(&cliInterface, viewNameList, viewDefnList,
alterColNode->ddlXns());
if (cliRC < 0)
{
NAString reason = "Error occurred while recreating views due to dependency on older column definition. Drop dependent views before doing the alter.";
*CmpCommon::diags() << DgSqlCode(-1404)
<< DgColumnName(colName)
<< DgString0(reason);
processReturn();
return;
}
cliRC = updateObjectRedefTime(&cliInterface,
catalogNamePart, schemaNamePart, objectNamePart,
COM_BASE_TABLE_OBJECT_LIT, -1, objUID);
if (cliRC < 0)
{
return;
}
ActiveSchemaDB()->getNATableDB()->removeNATable
(cn,
ComQiScope::REMOVE_FROM_ALL_USERS,
COM_BASE_TABLE_OBJECT,
alterColNode->ddlXns(), FALSE);
processReturn();
return;
}
void CmpSeabaseDDL::alterSeabaseTableAddPKeyConstraint(
StmtDDLAddConstraint * alterAddConstraint,
NAString &currCatName, NAString &currSchName)
{
Lng32 cliRC = 0;
Lng32 cliRC2 = 0;
Lng32 retcode = 0;
ExeCliInterface cliInterface(STMTHEAP, 0, NULL,
CmpCommon::context()->sqlSession()->getParentQid());
ExpHbaseInterface * ehi = allocEHI();
if (ehi == NULL)
{
processReturn();
return;
}
NAString tabName = alterAddConstraint->getTableName();
NAString catalogNamePart, schemaNamePart, objectNamePart;
NAString extTableName, extNameForHbase;
NATable * naTable = NULL;
CorrName cn;
retcode =
setupAndErrorChecks(tabName,
alterAddConstraint->getOrigTableNameAsQualifiedName(),
currCatName, currSchName,
catalogNamePart, schemaNamePart, objectNamePart,
extTableName, extNameForHbase, cn,
&naTable,
FALSE, FALSE,
&cliInterface);
if (retcode < 0)
{
processReturn();
return;
}
// if table already has a clustering or primary key, return error.
if ((naTable->getClusteringIndex()) &&
(NOT naTable->getClusteringIndex()->hasOnlySyskey()))
{
*CmpCommon::diags()
<< DgSqlCode(-1256)
<< DgString0(extTableName);
processReturn();
return;
}
ElemDDLColRefArray &keyColumnArray = alterAddConstraint->getConstraint()->castToElemDDLConstraintPK()->getKeyColumnArray();
NAList<NAString> keyColList(HEAP, keyColumnArray.entries());
NAString pkeyColsStr;
if (alterAddConstraint->getConstraint()->castToElemDDLConstraintPK()->isNullableSpecified())
pkeyColsStr += " NULLABLE ";
pkeyColsStr += "(";
for (Int32 j = 0; j < keyColumnArray.entries(); j++)
{
const NAString &colName = keyColumnArray[j]->getColumnName();
keyColList.insert(colName);
pkeyColsStr += colName;
if (keyColumnArray[j]->getColumnOrdering() == COM_DESCENDING_ORDER)
pkeyColsStr += " DESC";
else
pkeyColsStr += " ASC";
if (j < (keyColumnArray.entries() - 1))
pkeyColsStr += ", ";
}
pkeyColsStr += ")";
if (constraintErrorChecks(&cliInterface,
alterAddConstraint->castToStmtDDLAddConstraintPK(),
naTable,
COM_UNIQUE_CONSTRAINT, //TRUE,
keyColList))
{
return;
}
// update unique key constraint info
NAString uniqueStr;
if (genUniqueName(alterAddConstraint, uniqueStr))
{
return;
}
// find out if this table has dependent objects (views, user indexes,
// unique constraints, referential constraints)
NABoolean dependentObjects = FALSE;
Queue * usingViewsQueue = NULL;
cliRC = getUsingViews(&cliInterface, naTable->objectUid().castToInt64(),
usingViewsQueue);
if (cliRC < 0)
{
processReturn();
return;
}
if ((naTable->hasSecondaryIndexes()) || // user indexes
(naTable->getUniqueConstraints().entries() > 0) || // unique constraints
(naTable->getRefConstraints().entries() > 0) || // ref constraints
(usingViewsQueue->entries() > 0))
{
dependentObjects = TRUE;
}
// If cqd is set to create pkey as a unique constraint, then do that.
// otherwise if table has dependent objects, return error.
// Users need to drop them before adding primary key
if (CmpCommon::getDefault(TRAF_ALTER_ADD_PKEY_AS_UNIQUE_CONSTRAINT) == DF_ON)
{
// either dependent objects or cqd set to create unique constraint.
// cannot create clustered primary key constraint.
// create a unique constraint instead.
NAString cliQuery;
cliQuery = "alter table " + extTableName + " add constraint " + uniqueStr
+ " unique " + pkeyColsStr + ";";
cliRC = cliInterface.executeImmediate((char*)cliQuery.data());
if (cliRC < 0)
{
cliInterface.retrieveSQLDiagnostics(CmpCommon::diags());
}
if (!Get_SqlParser_Flags(INTERNAL_QUERY_FROM_EXEUTIL))
{
// remove NATable for this table
ActiveSchemaDB()->getNATableDB()->removeNATable
(cn,
ComQiScope::REMOVE_FROM_ALL_USERS,
COM_BASE_TABLE_OBJECT,
alterAddConstraint->ddlXns(), FALSE);
}
return;
}
else if (dependentObjects)
{
// error
*CmpCommon::diags() << DgSqlCode(-3242)
<< DgString0("Cannot alter/add primary key constraint on a table with dependencies. Drop all dependent objects (views, indexes, unique and referential constraints) on the specified table and recreate them after adding the primary key.");
return;
}
// create a true primary key by drop/create/populate of table.
NABoolean isEmpty = FALSE;
HbaseStr hbaseTable;
hbaseTable.val = (char*)extNameForHbase.data();
hbaseTable.len = extNameForHbase.length();
retcode = ehi->isEmpty(hbaseTable);
if (retcode < 0)
{
*CmpCommon::diags()
<< DgSqlCode(-8448)
<< DgString0((char*)"ExpHbaseInterface::isEmpty()")
<< DgString1(getHbaseErrStr(-retcode))
<< DgInt0(-retcode)
<< DgString2((char*)GetCliGlobals()->getJniErrorStr());
deallocEHI(ehi);
processReturn();
return;
}
isEmpty = (retcode == 1);
Int64 tableUID =
getObjectUID(&cliInterface,
catalogNamePart.data(), schemaNamePart.data(), objectNamePart.data(),
COM_BASE_TABLE_OBJECT_LIT);
NAString clonedTable;
if (NOT isEmpty) // non-empty table
{
// clone as a temp table and truncate source table
cliRC = cloneAndTruncateTable(naTable, clonedTable, ehi, &cliInterface);
if (cliRC < 0)
{
return; // diags already populated by called method
}
}
// Drop and recreate it with the new primary key.
NAString pkeyName;
if (NOT alterAddConstraint->getConstraintName().isNull())
{
pkeyName = alterAddConstraint->getConstraintName();
}
char * buf = NULL;
ULng32 buflen = 0;
retcode = CmpDescribeSeabaseTable(cn, 3/*createlike*/, buf, buflen, STMTHEAP,
pkeyName.data(), pkeyColsStr.data(), TRUE);
if (retcode)
return;
NABoolean done = FALSE;
Lng32 curPos = 0;
NAString cliQuery;
char cqdbuf[200];
NABoolean xnWasStartedHere = FALSE;
str_sprintf(cqdbuf, "cqd traf_no_hbase_drop_create 'ON';");
cliRC = cliInterface.executeImmediate(cqdbuf);
if (cliRC < 0)
{
cliInterface.retrieveSQLDiagnostics(CmpCommon::diags());
goto label_return;
}
if (beginXnIfNotInProgress(&cliInterface, xnWasStartedHere))
goto label_return;
// drop this table from metadata.
cliQuery = "drop table ";
cliQuery += extTableName;
cliQuery += " no check;";
cliRC = cliInterface.executeImmediate((char*)cliQuery.data());
if (cliRC < 0)
{
cliInterface.retrieveSQLDiagnostics(CmpCommon::diags());
goto label_return;
}
str_sprintf(cqdbuf, "cqd traf_create_table_with_uid '%ld';",
tableUID);
cliRC = cliInterface.executeImmediate(cqdbuf);
if (cliRC < 0)
{
cliInterface.retrieveSQLDiagnostics(CmpCommon::diags());
goto label_return;
}
// and recreate it with the new primary key.
cliQuery = "create table ";
cliQuery += extTableName;
cliQuery += " ";
while (NOT done)
{
short len = *(short*)&buf[curPos];
NAString frag(&buf[curPos+sizeof(short)],
len - ((buf[curPos+len-1]== '\n') ? 1 : 0));
cliQuery += frag;
curPos += ((((len+sizeof(short))-1)/8)+1)*8;
if (curPos >= buflen)
done = TRUE;
}
cliRC = cliInterface.executeImmediate((char*)cliQuery.data());
if (cliRC < 0)
{
cliInterface.retrieveSQLDiagnostics(CmpCommon::diags());
goto label_return;
}
str_sprintf(cqdbuf, "cqd traf_create_table_with_uid '' ;");
cliInterface.executeImmediate(cqdbuf);
str_sprintf(cqdbuf, "cqd traf_no_hbase_drop_create 'OFF';");
cliInterface.executeImmediate(cqdbuf);
if (NOT isEmpty) // non-empty table
{
// remove NATable so current definition could be loaded
ActiveSchemaDB()->getNATableDB()->removeNATable
(cn,
ComQiScope::REMOVE_FROM_ALL_USERS,
COM_BASE_TABLE_OBJECT,
alterAddConstraint->ddlXns(), FALSE);
// copy tempTable data into newly created table
str_sprintf(buf, "insert with no rollback into %s select * from %s",
naTable->getTableName().getQualifiedNameAsAnsiString().data(),
clonedTable.data());
cliRC = cliInterface.executeImmediate(buf);
if (cliRC < 0)
{
cliInterface.retrieveSQLDiagnostics(CmpCommon::diags());
goto label_restore;
}
}
if (updateObjectRedefTime(&cliInterface,
catalogNamePart, schemaNamePart, objectNamePart,
COM_BASE_TABLE_OBJECT_LIT, -1, tableUID))
{
processReturn();
goto label_return;
}
endXnIfStartedHere(&cliInterface, xnWasStartedHere, 0);
if (!Get_SqlParser_Flags(INTERNAL_QUERY_FROM_EXEUTIL))
{
// remove NATable for this table
ActiveSchemaDB()->getNATableDB()->removeNATable
(cn,
ComQiScope::REMOVE_FROM_ALL_USERS,
COM_BASE_TABLE_OBJECT,
alterAddConstraint->ddlXns(), FALSE);
}
if (NOT clonedTable.isNull())
{
str_sprintf(buf, "drop table %s", clonedTable.data());
cliRC = cliInterface.executeImmediate(buf);
if (cliRC < 0)
{
cliInterface.retrieveSQLDiagnostics(CmpCommon::diags());
goto label_restore;
}
}
cliRC = 0;
// normal return
label_restore:
endXnIfStartedHere(&cliInterface, xnWasStartedHere, -1);
ActiveSchemaDB()->getNATableDB()->removeNATable
(cn,
ComQiScope::REMOVE_FROM_ALL_USERS,
COM_BASE_TABLE_OBJECT, FALSE, FALSE);
if ((cliRC < 0) &&
(NOT clonedTable.isNull()) &&
(cloneSeabaseTable(clonedTable, -1,
naTable->getTableName().getQualifiedNameAsAnsiString(),
naTable,
ehi, &cliInterface, FALSE)))
{
cliRC = -1;
goto label_drop;
}
label_drop:
endXnIfStartedHere(&cliInterface, xnWasStartedHere, -1);
if ((cliRC < 0) &&
(NOT clonedTable.isNull()))
{
str_sprintf(buf, "drop table %s", clonedTable.data());
cliRC2 = cliInterface.executeImmediate(buf);
}
deallocEHI(ehi);
label_return:
endXnIfStartedHere(&cliInterface, xnWasStartedHere, -1);
str_sprintf(cqdbuf, "cqd traf_create_table_with_uid '' ;");
cliInterface.executeImmediate(cqdbuf);
str_sprintf(cqdbuf, "cqd traf_no_hbase_drop_create 'OFF';");
cliInterface.executeImmediate(cqdbuf);
return;
}
void CmpSeabaseDDL::alterSeabaseTableAddUniqueConstraint(
StmtDDLAddConstraint * alterAddConstraint,
NAString &currCatName, NAString &currSchName)
{
Lng32 cliRC = 0;
Lng32 retcode = 0;
ExeCliInterface cliInterface(STMTHEAP, 0, NULL,
CmpCommon::context()->sqlSession()->getParentQid());
ExpHbaseInterface * ehi = allocEHI();
if (ehi == NULL)
{
processReturn();
return;
}
NAString tabName = alterAddConstraint->getTableName();
NAString catalogNamePart, schemaNamePart, objectNamePart;
NAString extTableName, extNameForHbase;
NATable * naTable = NULL;
CorrName cn;
retcode =
setupAndErrorChecks(tabName,
alterAddConstraint->getOrigTableNameAsQualifiedName(),
currCatName, currSchName,
catalogNamePart, schemaNamePart, objectNamePart,
extTableName, extNameForHbase, cn,
&naTable,
FALSE, FALSE,
&cliInterface);
if (retcode < 0)
{
processReturn();
return;
}
ElemDDLColRefArray &keyColumnArray = alterAddConstraint->getConstraint()->castToElemDDLConstraintUnique()->getKeyColumnArray();
NAList<NAString> keyColList(HEAP, keyColumnArray.entries());
NAList<NAString> keyColOrderList(HEAP, keyColumnArray.entries());
for (Int32 j = 0; j < keyColumnArray.entries(); j++)
{
const NAString &colName = keyColumnArray[j]->getColumnName();
keyColList.insert(colName);
if (keyColumnArray[j]->getColumnOrdering() == COM_DESCENDING_ORDER)
keyColOrderList.insert("DESC");
else
keyColOrderList.insert("ASC");
}
if (constraintErrorChecks(
&cliInterface,
alterAddConstraint->castToStmtDDLAddConstraintUnique(),
naTable,
COM_UNIQUE_CONSTRAINT,
keyColList))
{
return;
}
// update unique key constraint info
NAString uniqueStr;
if (genUniqueName(alterAddConstraint, uniqueStr))
{
return;
}
Int64 tableUID =
getObjectUID(&cliInterface,
catalogNamePart.data(), schemaNamePart.data(), objectNamePart.data(),
COM_BASE_TABLE_OBJECT_LIT);
ComUID comUID;
comUID.make_UID();
Int64 uniqueUID = comUID.get_value();
if (updateConstraintMD(keyColList, keyColOrderList, uniqueStr, tableUID, uniqueUID,
naTable, COM_UNIQUE_CONSTRAINT, TRUE, &cliInterface))
{
*CmpCommon::diags()
<< DgSqlCode(-1043)
<< DgTableName(uniqueStr);
return;
}
NAList<NAString> emptyKeyColList(STMTHEAP);
if (updateIndexInfo(keyColList,
keyColOrderList,
emptyKeyColList,
uniqueStr,
uniqueUID,
catalogNamePart, schemaNamePart, objectNamePart,
naTable,
TRUE,
(CmpCommon::getDefault(TRAF_NO_CONSTR_VALIDATION) == DF_ON),
TRUE,
FALSE,
&cliInterface))
{
*CmpCommon::diags()
<< DgSqlCode(-1029)
<< DgTableName(uniqueStr);
return;
}
if (updateObjectRedefTime(&cliInterface,
catalogNamePart, schemaNamePart, objectNamePart,
COM_BASE_TABLE_OBJECT_LIT, -1, tableUID))
{
processReturn();
return;
}
if (!Get_SqlParser_Flags(INTERNAL_QUERY_FROM_EXEUTIL))
{
// remove NATable for this table
ActiveSchemaDB()->getNATableDB()->removeNATable
(cn,
ComQiScope::REMOVE_FROM_ALL_USERS,
COM_BASE_TABLE_OBJECT,
alterAddConstraint->ddlXns(), FALSE);
}
return;
}
// returns 1 if referenced table refdTable has a dependency on the
// original referencing table origRingTable.
// return 0, if it does not.
// return -1, if error.
short CmpSeabaseDDL::isCircularDependent(CorrName &ringTable,
CorrName &refdTable,
CorrName &origRingTable,
BindWA *bindWA)
{
// get natable for the referenced table.
NATable *naTable = bindWA->getNATable(refdTable);
if (naTable == NULL || bindWA->errStatus())
{
*CmpCommon::diags() << DgSqlCode(-CAT_OBJECT_DOES_NOT_EXIST_IN_TRAFODION)
<< DgString0(naTable->getTableName().getQualifiedNameAsString());
processReturn();
return -1;
}
// find all the tables the refdTable depends on.
const AbstractRIConstraintList &refList = naTable->getRefConstraints();
for (Int32 i = 0; i < refList.entries(); i++)
{
AbstractRIConstraint *ariConstr = refList[i];
if (ariConstr->getOperatorType() != ITM_REF_CONSTRAINT)
continue;
RefConstraint * refConstr = (RefConstraint*)ariConstr;
if (refConstr->selfRef())
continue;
CorrName cn(refConstr->getUniqueConstraintReferencedByMe().getTableName());
if (cn == origRingTable)
{
return 1; // dependency exists
}
short rc = isCircularDependent(cn, cn,
origRingTable, bindWA);
if (rc)
return rc;
} // for
return 0;
}
void CmpSeabaseDDL::alterSeabaseTableAddRIConstraint(
StmtDDLAddConstraint * alterAddConstraint,
NAString &currCatName, NAString &currSchName)
{
Lng32 cliRC = 0;
Lng32 retcode = 0;
const NAString &tabName = alterAddConstraint->getTableName();
ComObjectName referencingTableName(tabName, COM_TABLE_NAME);
ComAnsiNamePart currCatAnsiName(currCatName);
ComAnsiNamePart currSchAnsiName(currSchName);
referencingTableName.applyDefaults(currCatAnsiName, currSchAnsiName);
const NAString catalogNamePart = referencingTableName.getCatalogNamePartAsAnsiString();
const NAString schemaNamePart = referencingTableName.getSchemaNamePartAsAnsiString(TRUE);
const NAString objectNamePart = referencingTableName.getObjectNamePartAsAnsiString(TRUE);
const NAString extTableName = referencingTableName.getExternalName(TRUE);
const NAString extNameForHbase = catalogNamePart + "." + schemaNamePart + "." + objectNamePart;
if ((isSeabaseReservedSchema(referencingTableName)) &&
(!Get_SqlParser_Flags(INTERNAL_QUERY_FROM_EXEUTIL)))
{
*CmpCommon::diags() << DgSqlCode(-CAT_CANNOT_ALTER_DEFINITION_METADATA_SCHEMA);
processReturn();
return;
}
ExeCliInterface cliInterface(STMTHEAP, 0, NULL,
CmpCommon::context()->sqlSession()->getParentQid());
ExpHbaseInterface * ehi = allocEHI();
if (ehi == NULL)
{
processReturn();
return;
}
retcode = existsInSeabaseMDTable(&cliInterface,
catalogNamePart, schemaNamePart, objectNamePart,
COM_BASE_TABLE_OBJECT,
(Get_SqlParser_Flags(INTERNAL_QUERY_FROM_EXEUTIL)
? FALSE : TRUE),
TRUE, TRUE);
if (retcode < 0)
{
processReturn();
return;
}
BindWA bindWA(ActiveSchemaDB(), CmpCommon::context(), FALSE/*inDDL*/);
CorrName cn(referencingTableName.getObjectNamePart().getInternalName(),
STMTHEAP,
referencingTableName.getSchemaNamePart().getInternalName(),
referencingTableName.getCatalogNamePart().getInternalName());
NATable *ringNaTable = bindWA.getNATable(cn);
if (ringNaTable == NULL || bindWA.errStatus())
{
*CmpCommon::diags()
<< DgSqlCode(-4082)
<< DgTableName(cn.getExposedNameAsAnsiString());
deallocEHI(ehi);
processReturn();
return;
}
// Make sure user has the privilege to perform the add RI constraint
if (!isDDLOperationAuthorized(SQLOperation::ALTER_TABLE,
ringNaTable->getOwner(),ringNaTable->getSchemaOwner()))
{
*CmpCommon::diags() << DgSqlCode(-CAT_NOT_AUTHORIZED);
deallocEHI(ehi);
processReturn ();
return;
}
if (ringNaTable->isHbaseMapTable())
{
// not supported
*CmpCommon::diags() << DgSqlCode(-3242)
<< DgString0("This alter option cannot be used for an HBase mapped table.");
deallocEHI(ehi);
processReturn();
return;
}
const ElemDDLConstraintRI *constraintNode =
alterAddConstraint->getConstraint()->castToElemDDLConstraintRI();
ComObjectName referencedTableName( constraintNode->getReferencedTableName()
, COM_TABLE_NAME);
referencedTableName.applyDefaults(currCatAnsiName, currSchAnsiName);
if ((isSeabaseReservedSchema(referencedTableName)) &&
(!Get_SqlParser_Flags(INTERNAL_QUERY_FROM_EXEUTIL)))
{
*CmpCommon::diags() << DgSqlCode(-CAT_CANNOT_ALTER_DEFINITION_METADATA_SCHEMA);
processReturn();
return;
}
retcode = existsInSeabaseMDTable(&cliInterface,
referencedTableName.getCatalogNamePart().getInternalName(),
referencedTableName.getSchemaNamePart().getInternalName(),
referencedTableName.getObjectNamePart().getInternalName(),
COM_BASE_TABLE_OBJECT,
TRUE);
if (retcode < 0)
{
processReturn();
return;
}
CorrName cn2(referencedTableName.getObjectNamePart().getInternalName(),
STMTHEAP,
referencedTableName.getSchemaNamePart().getInternalName(),
referencedTableName.getCatalogNamePart().getInternalName());
NATable *refdNaTable = bindWA.getNATable(cn2);
if (refdNaTable == NULL || bindWA.errStatus())
{
*CmpCommon::diags()
<< DgSqlCode(-4082)
<< DgTableName(cn2.getExposedNameAsAnsiString());
deallocEHI(ehi);
processReturn();
return;
}
if (refdNaTable->getViewText())
{
*CmpCommon::diags()
<< DgSqlCode(-1127)
<< DgTableName(cn2.getExposedNameAsAnsiString());
deallocEHI(ehi);
processReturn();
return;
}
if (refdNaTable->isHbaseMapTable())
{
// not supported
*CmpCommon::diags() << DgSqlCode(-3242)
<< DgString0("This alter option cannot be used for an HBase mapped table.");
deallocEHI(ehi);
processReturn();
return;
}
// If the referenced and referencing tables are the same,
// reject the request. At this time, we do not allow self
// referencing constraints.
if ((CmpCommon::getDefault(TRAF_ALLOW_SELF_REF_CONSTR) == DF_OFF) &&
(referencingTableName == referencedTableName))
{
*CmpCommon::diags() << DgSqlCode(-CAT_SELF_REFERENCING_CONSTRAINT);
processReturn();
return;
}
// User must have REFERENCES privilege on the referenced table
// First check for REFERENCES at the object level (column checks happen
// later)
NABoolean noObjPriv = FALSE;
if (isAuthorizationEnabled())
{
PrivMgrUserPrivs* privs = refdNaTable->getPrivInfo();
if (privs == NULL)
{
*CmpCommon::diags() << DgSqlCode(-CAT_UNABLE_TO_RETRIEVE_PRIVS);
deallocEHI(ehi);
processReturn();
return;
}
if (!ComUser::isRootUserID() && !privs->hasReferencePriv())
noObjPriv = TRUE;
}
ElemDDLColNameArray &ringCols = alterAddConstraint->getConstraint()->castToElemDDLConstraintRI()->getReferencingColumns();
NAList<NAString> ringKeyColList(HEAP, ringCols.entries());
NAList<NAString> ringKeyColOrderList(HEAP, ringCols.entries());
NAString ringColListForValidation;
NAString ringNullList;
for (Int32 j = 0; j < ringCols.entries(); j++)
{
const NAString &colName = ringCols[j]->getColumnName();
ringKeyColList.insert(colName);
ringKeyColOrderList.insert("ASC");
ringColListForValidation += "\"";
ringColListForValidation += colName;
ringColListForValidation += "\"";
if (j < (ringCols.entries() - 1))
ringColListForValidation += ", ";
ringNullList += "and ";
ringNullList += "\"";
ringNullList += colName;
ringNullList += "\"";
ringNullList += " is not null ";
}
if (constraintErrorChecks(&cliInterface,
alterAddConstraint->castToStmtDDLAddConstraintRI(),
ringNaTable,
COM_FOREIGN_KEY_CONSTRAINT, //FALSE, // referencing constr
ringKeyColList))
{
return;
}
const NAString &addConstrName = alterAddConstraint->
getConstraintNameAsQualifiedName().getQualifiedNameAsAnsiString();
// Compare the referenced column list against the primary and unique
// constraint defined for the referenced table. The referenced
// column list must match one of these constraints. Note that if there
// was no referenced column list specified, the primary key is used
// and a match has automatically been found.
const ElemDDLColNameArray &referencedColNode =
constraintNode->getReferencedColumns();
NAList<NAString> refdKeyColList(HEAP, referencedColNode.entries());
NAString refdColListForValidation;
for (Int32 j = 0; j < referencedColNode.entries(); j++)
{
const NAString &colName = referencedColNode[j]->getColumnName();
refdKeyColList.insert(colName);
refdColListForValidation += "\"";
refdColListForValidation += colName;
refdColListForValidation += "\"";
if (j < (referencedColNode.entries() - 1))
refdColListForValidation += ", ";
}
if (referencedColNode.entries() == 0)
{
NAFileSet * naf = refdNaTable->getClusteringIndex();
for (Lng32 i = 0; i < naf->getIndexKeyColumns().entries(); i++)
{
NAColumn * nac = naf->getIndexKeyColumns()[i];
if (nac->isComputedColumnAlways() &&
nac->isSystemColumn())
// always computed system columns in the key are redundant,
// don't include them (also don't include them in the DDL)
continue;
const NAString &colName = nac->getColName();
refdKeyColList.insert(colName);
refdColListForValidation += "\"";
refdColListForValidation += nac->getColName();
refdColListForValidation += "\"";
if (i < (naf->getIndexKeyColumns().entries() - 1))
refdColListForValidation += ", ";
}
}
if (ringKeyColList.entries() != refdKeyColList.entries())
{
*CmpCommon::diags()
<< DgSqlCode(-1046)
<< DgConstraintName(addConstrName);
processReturn();
return;
}
const NAColumnArray &ringNACarr = ringNaTable->getNAColumnArray();
const NAColumnArray &refdNACarr = refdNaTable->getNAColumnArray();
for (Int32 i = 0; i < ringKeyColList.entries(); i++)
{
const NAString &ringColName = ringKeyColList[i];
const NAString &refdColName = refdKeyColList[i];
const NAColumn * ringNAC = ringNACarr.getColumn(ringColName);
const NAColumn * refdNAC = refdNACarr.getColumn(refdColName);
if (! refdNAC)
{
*CmpCommon::diags() << DgSqlCode(-1009)
<< DgColumnName(refdColName);
processReturn();
return;
}
if (NOT (ringNAC->getType()->equalIgnoreNull(*refdNAC->getType())))
{
*CmpCommon::diags()
<< DgSqlCode(-1046)
<< DgConstraintName(addConstrName);
processReturn();
return;
}
// If the user/role does not have REFERENCES privilege at the object
// level, check to see if the user/role has been granted the privilege
// on all affected columns
if (noObjPriv)
{
PrivMgrUserPrivs* privs = refdNaTable->getPrivInfo();
if (!privs->hasColReferencePriv(refdNAC->getPosition()))
{
*CmpCommon::diags() << DgSqlCode(-4481)
<< DgString0("REFERENCES")
<< DgString1(referencedTableName.getObjectNamePart().getExternalName().data());
processReturn();
return;
}
}
}
// method getCorrespondingConstraint expects an empty input list if there are no
// user specified columns. Clear the refdKeyColList before calling it.
if (referencedColNode.entries() == 0)
{
refdKeyColList.clear();
}
NAString constrName;
NABoolean isPkey = FALSE;
NAList<int> reorderList(HEAP);
// Find a uniqueness constraint on the referenced table that matches
// the referenced column list (not necessarily in the original order
// of columns). Also find out how to reorder the column lists to
// match the found uniqueness constraint. This is the order in
// which we'll add the columns to the metadata (KEYS table). Note
// that SHOWDDL may therefore show the foreign key columns in a
// different order. This is a limitation of the current way we
// store RI constraints in the metadata.
if (NOT refdNaTable->getCorrespondingConstraint(refdKeyColList,
TRUE, // unique constraint
&constrName,
&isPkey,
&reorderList))
{
*CmpCommon::diags() << DgSqlCode(-CAT_REFERENCED_CONSTRAINT_DOES_NOT_EXIST)
<< DgConstraintName(addConstrName);
return;
}
if (reorderList.entries() > 0)
{
CollIndex numEntries = ringKeyColList.entries();
CMPASSERT(ringKeyColOrderList.entries() == numEntries &&
refdKeyColList.entries() == numEntries &&
reorderList.entries() == numEntries);
// re-order referencing and referenced key column lists to match
// the order of the uniqueness constraint in the referenced table
NAArray<NAString> ringTempKeyColArray(HEAP, numEntries);
NAArray<NAString> ringTempKeyColOrderArray(HEAP, numEntries);
NAArray<NAString> refdTempKeyColArray(HEAP, numEntries);
// copy the lists into temp arrays in the correct order
for (CollIndex i=0; i<numEntries; i++)
{
CollIndex newEntry = static_cast<CollIndex>(reorderList[i]);
ringTempKeyColArray.insertAt(newEntry, ringKeyColList[i]);
ringTempKeyColOrderArray.insertAt(newEntry, ringKeyColOrderList[i]);
refdTempKeyColArray.insertAt(newEntry, refdKeyColList[i]);
}
// copy back into the lists (this will assert if we have any holes in the array)
for (CollIndex j=0; j<numEntries; j++)
{
ringKeyColList[j] = ringTempKeyColArray[j];
ringKeyColOrderList[j] = ringTempKeyColOrderArray[j];
refdKeyColList[j] = refdTempKeyColArray[j];
}
} // reorder the lists if needed
// check for circular RI dependencies.
// check if referenced table cn2 refers back to the referencing table cn.
retcode = isCircularDependent(cn, cn2, cn, &bindWA);
if (retcode == 1) // dependency exists
{
*CmpCommon::diags() << DgSqlCode(-CAT_RI_CIRCULAR_DEPENDENCY)
<< DgConstraintName(addConstrName)
<< DgTableName(cn.getExposedNameAsAnsiString());
return;
}
else if (retcode < 0)
{
// error. Diags area has been populated
return;
}
if ((CmpCommon::getDefault(TRAF_NO_CONSTR_VALIDATION) == DF_OFF) &&
(constraintNode->isEnforced()))
{
// validate data for RI constraint.
// generate a "select" statement to validate the constraint. For example:
// SELECT count(*) FROM T1
// WHERE NOT ((T1C1,T1C2) IN (SELECT T2C1,T2C2 FROM T2))
// OR T1C1 IS NULL OR T1C2 IS NULL;
// This statement returns > 0 if there exist data violating the constraint.
char * validQry =
new(STMTHEAP) char[ringColListForValidation.length() +
refdColListForValidation.length() +
ringNullList.length() +
2000];
str_sprintf(validQry, "select count(*) from \"%s\".\"%s\".\"%s\" where not ((%s) in (select %s from \"%s\".\"%s\".\"%s\")) %s;",
referencingTableName.getCatalogNamePart().getInternalName().data(),
referencingTableName.getSchemaNamePart().getInternalName().data(),
referencingTableName.getObjectNamePart().getInternalName().data(),
ringColListForValidation.data(),
refdColListForValidation.data(),
referencedTableName.getCatalogNamePart().getInternalName().data(),
referencedTableName.getSchemaNamePart().getInternalName().data(),
referencedTableName.getObjectNamePart().getInternalName().data(),
ringNullList.data());
Lng32 len = 0;
Int64 rowCount = 0;
cliRC = cliInterface.executeImmediate(validQry, (char*)&rowCount, &len, FALSE);
if (cliRC < 0)
{
cliInterface.retrieveSQLDiagnostics(CmpCommon::diags());
return;
}
if (rowCount > 0)
{
*CmpCommon::diags() << DgSqlCode(-1143)
<< DgConstraintName(addConstrName)
<< DgTableName(referencingTableName.getObjectNamePart().getInternalName().data())
<< DgString0(referencedTableName.getObjectNamePart().getInternalName().data())
<< DgString1(validQry);
return;
}
}
ComObjectName refdConstrName(constrName);
refdConstrName.applyDefaults(currCatAnsiName, currSchAnsiName);
const NAString refdCatName = refdConstrName.getCatalogNamePartAsAnsiString();
const NAString refdSchName = refdConstrName.getSchemaNamePartAsAnsiString(TRUE);
const NAString refdObjName = refdConstrName.getObjectNamePartAsAnsiString(TRUE);
Int64 refdConstrUID =
getObjectUID(&cliInterface,
refdCatName.data(), refdSchName.data(), refdObjName.data(),
(isPkey ? COM_PRIMARY_KEY_CONSTRAINT_OBJECT_LIT :
COM_UNIQUE_CONSTRAINT_OBJECT_LIT));
NAString uniqueStr;
if (genUniqueName(alterAddConstraint, uniqueStr))
{
return;
}
Int64 tableUID =
getObjectUID(&cliInterface,
catalogNamePart.data(), schemaNamePart.data(), objectNamePart.data(),
COM_BASE_TABLE_OBJECT_LIT);
ComUID comUID;
comUID.make_UID();
Int64 ringConstrUID = comUID.get_value();
if (updateConstraintMD(ringKeyColList, ringKeyColOrderList, uniqueStr, tableUID, ringConstrUID,
ringNaTable, COM_FOREIGN_KEY_CONSTRAINT,
constraintNode->isEnforced(), &cliInterface))
{
*CmpCommon::diags()
<< DgSqlCode(-1029)
<< DgTableName(uniqueStr);
return;
}
if (updateRIConstraintMD(ringConstrUID, refdConstrUID,
&cliInterface))
{
*CmpCommon::diags()
<< DgSqlCode(-1029)
<< DgTableName(uniqueStr);
return;
}
if (updateIndexInfo(ringKeyColList,
ringKeyColOrderList,
refdKeyColList,
uniqueStr,
ringConstrUID,
catalogNamePart, schemaNamePart, objectNamePart,
ringNaTable,
FALSE,
(CmpCommon::getDefault(TRAF_NO_CONSTR_VALIDATION) == DF_ON),
constraintNode->isEnforced(),
TRUE, // because of the way the data is recorded in the
// metadata, the indexes of referencing and referenced
// tables need to have their columns in the same
// sequence (differences in ASC/DESC are ok)
&cliInterface))
{
*CmpCommon::diags()
<< DgSqlCode(-1029)
<< DgTableName(uniqueStr);
return;
}
if (NOT constraintNode->isEnforced())
{
*CmpCommon::diags()
<< DgSqlCode(1313)
<< DgString0(addConstrName);
}
if (updateObjectRedefTime(&cliInterface,
catalogNamePart, schemaNamePart, objectNamePart,
COM_BASE_TABLE_OBJECT_LIT, -1, tableUID))
{
processReturn();
deallocEHI(ehi);
return;
}
if (!Get_SqlParser_Flags(INTERNAL_QUERY_FROM_EXEUTIL))
{
// remove NATable for this table
ActiveSchemaDB()->getNATableDB()->removeNATable
(cn,
ComQiScope::REMOVE_FROM_ALL_USERS,
COM_BASE_TABLE_OBJECT,
alterAddConstraint->ddlXns(), FALSE);
}
// remove natable for the table being referenced
ActiveSchemaDB()->getNATableDB()->removeNATable
(cn2,
ComQiScope::REMOVE_FROM_ALL_USERS,
COM_BASE_TABLE_OBJECT,
alterAddConstraint->ddlXns(), FALSE);
// regenerate and store packed descriptor in metadata for referenced table.
if (updateObjectRedefTime
(&cliInterface,
referencedTableName.getCatalogNamePart().getInternalName(),
referencedTableName.getSchemaNamePart().getInternalName(),
referencedTableName.getObjectNamePart().getInternalName(),
COM_BASE_TABLE_OBJECT_LIT, -1,
refdNaTable->objectUid().castToInt64()))
{
processReturn();
deallocEHI(ehi);
return;
}
return;
}
short CmpSeabaseDDL::getCheckConstraintText(StmtDDLAddConstraintCheck *addCheckNode,
NAString &qualifiedText)
{
// ComString qualifiedText;
const ParNameLocList &nameLocList = addCheckNode->getNameLocList();
const ParNameLoc *pNameLoc = NULL;
const char *pInputStr = nameLocList.getInputStringPtr();
StringPos inputStrPos = addCheckNode->getStartPosition();
// CharInfo::CharSet mapCS = (CharInfo::CharSet) SqlParser_ISO_MAPPING;
for (size_t x = 0; x < nameLocList.entries(); x++)
{
pNameLoc = &nameLocList[x];
const NAString &nameExpanded = pNameLoc->getExpandedName(FALSE/*no assert*/);
size_t nameAsIs = 0;
size_t nameLenInBytes = 0;
//
// When the character set of the input string is a variable-length/width
// multi-byte characters set, the value returned by getNameLength()
// may not be numerically equal to the number of bytes in the original
// input string that we need to skip. So, we get the character
// conversion routines to tell us how many bytes we need to skip.
//
enum cnv_charset eCnvCS = convertCharsetEnum(nameLocList.getInputStringCharSet());
const char *str_to_test = (const char *) &pInputStr[pNameLoc->getNamePosition()];
const int max_bytes2cnv = addCheckNode->getEndPosition()
- pNameLoc->getNamePosition() + 1;
const char *tmp_out_bufr = new (STMTHEAP) char[max_bytes2cnv * 4 + 10 /* Ensure big enough! */ ];
char * p1stUnstranslatedChar = NULL;
int cnvErrStatus = LocaleToUTF16(
cnv_version1 // in - const enum cnv_version version
, str_to_test // in - const char *in_bufr
, max_bytes2cnv // in - const int in_len
, tmp_out_bufr // out - const char *out_bufr
, max_bytes2cnv * 4 // in - const int out_len
, eCnvCS // in - enum cnv_charset charset
, p1stUnstranslatedChar // out - char * & first_untranslated_char
, NULL // out - unsigned int *output_data_len_p
, 0 // in - const int cnv_flags
, (int)FALSE // in - const int addNullAtEnd_flag
, NULL // out - unsigned int * translated_char_cnt_p
, pNameLoc->getNameLength() // in - unsigned int max_chars_to_convert
);
// NOTE: No errors should be possible -- string has been converted before.
NADELETEBASIC (tmp_out_bufr, STMTHEAP);
nameLenInBytes = p1stUnstranslatedChar - str_to_test;
// If name not expanded, then use the original name as is
if (nameExpanded.isNull())
nameAsIs = nameLenInBytes;
// Copy from (last position in) input string up to current name
qualifiedText += ComString(&pInputStr[inputStrPos],
pNameLoc->getNamePosition() - inputStrPos +
nameAsIs);
if (NOT nameAsIs) // original name to be replaced with expanded
{
size_t namePos = pNameLoc->getNamePosition();
size_t nameLen = pNameLoc->getNameLength();
// Solution 10-080506-3000
// For description and explanation of the fix, please read the
// comments in method CatExecCreateView::buildViewText() in
// module CatExecCreateView.cpp
// Example: CREATE TABLE T ("c1" INT NOT NULL PRIMARY KEY,
// C2 INT CHECK (C2 BETWEEN 0 AND"c1")) NO PARTITION;
if ( pInputStr[namePos] EQU '"'
AND nameExpanded.data()[0] NEQ '"'
AND namePos > 1
AND ( pInputStr[namePos - 1] EQU '_' OR
isAlNumIsoMapCS((unsigned char)pInputStr[namePos - 1]) )
)
{
// insert a blank separator to avoid syntax error
// WITHOUT FIX - Example:
// ... ALTER TABLE CAT.SCH.T ADD CONSTRAINT CAT.SCH.T_788388997_8627
// CHECK (CAT.SCH.T.C2 BETWEEN 0 ANDCAT.SCH.T."c1") DROPPABLE ;
// ... ^^^^^^
qualifiedText += " "; // the FIX
// WITH FIX - Example:
// ... ALTER TABLE CAT.SCH.T ADD CONSTRAINT CAT.SCH.T_788388997_8627
// CHECK (CAT.SCH.T.C2 BETWEEN 0 AND CAT.SCH.T."c1") DROPPABLE ;
// ... ^^^
}
qualifiedText += nameExpanded;
// Problem reported in solution 10-080506-3000
// Example: CREATE TABLE T (C1 INT NOT NULL PRIMARY KEY,
// C2 INT CHECK ("C2"IN(1,2,3))) NO PARTITION;
if ( pInputStr[namePos + nameLen - 1] EQU '"'
AND nameExpanded.data()[nameExpanded.length() - 1] NEQ '"'
AND pInputStr[namePos + nameLen] NEQ '\0'
AND ( pInputStr[namePos + nameLen] EQU '_' OR
isAlNumIsoMapCS((unsigned char)pInputStr[namePos + nameLen]) )
)
{
// insert a blank separator to avoid syntax error
// WITHOUT FIX - Example:
// ... ALTER TABLE CAT.SCH.T ADD CONSTRAINT CAT.SCH.T_654532688_9627
// CHECK (CAT.SCH.T.C2IN (1, 2, 3)) DROPPABLE ;
// ... ^^^^
qualifiedText += " "; // the FIX
// WITH FIX - Example:
// ... ALTER TABLE CAT.SCH.T ADD CONSTRAINT CAT.SCH.T_654532688_9627
// CHECK (CAT.SCH.T.C2 IN (1, 2, 3)) DROPPABLE ;
// ... ^^^
}
} // if (NOT nameAsIs)
inputStrPos = pNameLoc->getNamePosition() + nameLenInBytes;
} // for
// CAT_ASSERT(addCheckNode->getEndPosition() >= inputStrPos);
qualifiedText += ComString(&pInputStr[inputStrPos],
addCheckNode->getEndPosition() - inputStrPos + 1);
PrettifySqlText(qualifiedText, NULL);
return 0;
}
// nonstatic method, calling two member functions
short CmpSeabaseDDL::getTextFromMD(
ExeCliInterface * cliInterface,
Int64 textUID,
ComTextType textType,
Lng32 textSubID,
NAString &outText,
NABoolean binaryData)
{
short retcode = getTextFromMD(getSystemCatalog(),
cliInterface,
textUID,
textType,
textSubID,
outText,
binaryData);
if (retcode)
processReturn();
return retcode;
}
// static version of this method
short CmpSeabaseDDL::getTextFromMD(const char * catalogName,
ExeCliInterface * cliInterface,
Int64 textUID,
ComTextType textType,
Lng32 textSubID,
NAString &outText,
NABoolean binaryData)
{
Lng32 cliRC;
char query[1000];
str_sprintf(query, "select octet_length(text), text from %s.\"%s\".%s where text_uid = %ld and text_type = %d and sub_id = %d for read committed access order by seq_num",
catalogName, SEABASE_MD_SCHEMA, SEABASE_TEXT,
textUID, static_cast<int>(textType), textSubID);
Queue * textQueue = NULL;
cliRC = cliInterface->fetchAllRows(textQueue, query, 0, FALSE, FALSE, TRUE);
if (cliRC < 0)
{
cliInterface->retrieveSQLDiagnostics(CmpCommon::diags());
return -1;
}
// glue text together
NAString binaryText;
for (Lng32 idx = 0; idx < textQueue->numEntries(); idx++)
{
OutputInfo * vi = (OutputInfo*)textQueue->getNext();
Lng32 len = *(Lng32*)vi->get(0);
char * text = (char*)vi->get(1);
if (binaryData)
binaryText.append(text, len);
else
outText.append(text, len);
}
// if binary data, decode it and then return
if (binaryData)
{
Lng32 decodedMaxLen = str_decoded_len(binaryText.length());
char * decodedData = new(STMTHEAP) char[decodedMaxLen];
Lng32 decodedLen =
str_decode(decodedData, decodedMaxLen,
binaryText.data(), binaryText.length());
if (decodedLen < 0)
return -1;
outText.append(decodedData, decodedLen);
}
return 0;
}
void CmpSeabaseDDL::alterSeabaseTableAddCheckConstraint(
StmtDDLAddConstraint * alterAddConstraint,
NAString &currCatName, NAString &currSchName)
{
StmtDDLAddConstraintCheck *alterAddCheckNode = alterAddConstraint
->castToStmtDDLAddConstraintCheck();
Lng32 cliRC = 0;
Lng32 retcode = 0;
ExeCliInterface cliInterface(STMTHEAP, 0, NULL,
CmpCommon::context()->sqlSession()->getParentQid());
NAString tabName = alterAddConstraint->getTableName();
NAString catalogNamePart, schemaNamePart, objectNamePart;
NAString extTableName, extNameForHbase;
NATable * naTable = NULL;
CorrName cn;
retcode =
setupAndErrorChecks(tabName,
alterAddConstraint->getOrigTableNameAsQualifiedName(),
currCatName, currSchName,
catalogNamePart, schemaNamePart, objectNamePart,
extTableName, extNameForHbase, cn,
&naTable,
FALSE, FALSE,
&cliInterface);
if (retcode < 0)
{
processReturn();
return;
}
const ParCheckConstraintColUsageList &colList =
alterAddCheckNode->getColumnUsageList();
for (CollIndex cols = 0; cols < colList.entries(); cols++)
{
const ParCheckConstraintColUsage &ckColUsg = colList[cols];
const ComString &colName = ckColUsg.getColumnName();
if ((colName EQU "SYSKEY") &&
(naTable->getClusteringIndex()->hasSyskey()))
{
*CmpCommon::diags() << DgSqlCode(-CAT_SYSKEY_COL_NOT_ALLOWED_IN_CK_CNSTRNT)
<< DgColumnName( "SYSKEY")
<< DgTableName(extTableName);
processReturn();
return;
}
}
NAList<NAString> keyColList(STMTHEAP);
if (constraintErrorChecks(&cliInterface,
alterAddConstraint->castToStmtDDLAddConstraintCheck(),
naTable,
COM_CHECK_CONSTRAINT,
keyColList))
{
return;
}
// update check constraint info
NAString uniqueStr;
if (genUniqueName(alterAddConstraint, uniqueStr))
{
return;
}
// get check text
NAString checkConstrText;
if (getCheckConstraintText(alterAddCheckNode, checkConstrText))
{
return;
}
if (CmpCommon::getDefault(TRAF_NO_CONSTR_VALIDATION) == DF_OFF)
{
// validate data for check constraint.
// generate a "select" statement to validate the constraint. For example:
// SELECT count(*) FROM T1 where not checkConstrText;
// This statement returns > 0 if there exist data violating the constraint.
char * validQry = new(STMTHEAP) char[checkConstrText.length() + 2000];
str_sprintf(validQry, "select count(*) from \"%s\".\"%s\".\"%s\" where not %s",
catalogNamePart.data(),
schemaNamePart.data(),
objectNamePart.data(),
checkConstrText.data());
Lng32 len = 0;
Int64 rowCount = 0;
cliRC = cliInterface.executeImmediate(validQry, (char*)&rowCount, &len, FALSE);
if (cliRC < 0)
{
cliInterface.retrieveSQLDiagnostics(CmpCommon::diags());
return;
}
if (rowCount > 0)
{
*CmpCommon::diags() << DgSqlCode(-1083)
<< DgConstraintName(uniqueStr);
return;
}
}
Int64 tableUID =
getObjectUID(&cliInterface,
catalogNamePart.data(), schemaNamePart.data(), objectNamePart.data(),
COM_BASE_TABLE_OBJECT_LIT);
ComUID comUID;
comUID.make_UID();
Int64 checkUID = comUID.get_value();
NAList<NAString> emptyList(STMTHEAP);
if (updateConstraintMD(keyColList, emptyList, uniqueStr, tableUID, checkUID,
naTable, COM_CHECK_CONSTRAINT, TRUE, &cliInterface))
{
*CmpCommon::diags()
<< DgSqlCode(-1029)
<< DgTableName(uniqueStr);
return;
}
if (updateTextTable(&cliInterface, checkUID, COM_CHECK_CONSTR_TEXT, 0,
checkConstrText))
{
processReturn();
return;
}
if (updateObjectRedefTime(&cliInterface,
catalogNamePart, schemaNamePart, objectNamePart,
COM_BASE_TABLE_OBJECT_LIT, -1, tableUID))
{
processReturn();
return;
}
if (!Get_SqlParser_Flags(INTERNAL_QUERY_FROM_EXEUTIL))
{
// remove NATable for this table
ActiveSchemaDB()->getNATableDB()->removeNATable
(cn,
ComQiScope::REMOVE_FROM_ALL_USERS,
COM_BASE_TABLE_OBJECT,
alterAddConstraint->ddlXns(), FALSE);
}
return;
}
void CmpSeabaseDDL::alterSeabaseTableDropConstraint(
StmtDDLDropConstraint * alterDropConstraint,
NAString &currCatName, NAString &currSchName)
{
Lng32 cliRC = 0;
Lng32 retcode = 0;
ExeCliInterface cliInterface(STMTHEAP, 0, NULL,
CmpCommon::context()->sqlSession()->getParentQid());
NAString tabName = alterDropConstraint->getTableName();
NAString catalogNamePart, schemaNamePart, objectNamePart;
NAString extTableName, extNameForHbase;
NATable * naTable = NULL;
CorrName cn;
retcode =
setupAndErrorChecks(tabName,
alterDropConstraint->getOrigTableNameAsQualifiedName(),
currCatName, currSchName,
catalogNamePart, schemaNamePart, objectNamePart,
extTableName, extNameForHbase, cn,
&naTable,
FALSE, FALSE,
&cliInterface);
if (retcode < 0)
{
processReturn();
return;
}
const NAString &dropConstrName = alterDropConstraint->
getConstraintNameAsQualifiedName().getQualifiedNameAsAnsiString();
const NAString &constrCatName = alterDropConstraint->
getConstraintNameAsQualifiedName().getCatalogName();
const NAString &constrSchName = alterDropConstraint->
getConstraintNameAsQualifiedName().getSchemaName();
const NAString &constrObjName = alterDropConstraint->
getConstraintNameAsQualifiedName().getObjectName();
char outObjType[10];
Int64 constrUID = getObjectUID(&cliInterface,
constrCatName.data(), constrSchName.data(), constrObjName.data(),
NULL,
"object_type = '" COM_PRIMARY_KEY_CONSTRAINT_OBJECT_LIT"' or object_type = '" COM_UNIQUE_CONSTRAINT_OBJECT_LIT"' or object_type = '" COM_REFERENTIAL_CONSTRAINT_OBJECT_LIT"' or object_type = '" COM_CHECK_CONSTRAINT_OBJECT_LIT"' ",
outObjType);
if (constrUID < 0)
{
*CmpCommon::diags()
<< DgSqlCode(-1005)
<< DgConstraintName(dropConstrName);
processReturn();
return;
}
NABoolean isUniqConstr =
((strcmp(outObjType, COM_UNIQUE_CONSTRAINT_OBJECT_LIT) == 0) ||
(strcmp(outObjType, COM_PRIMARY_KEY_CONSTRAINT_OBJECT_LIT) == 0));
NABoolean isRefConstr =
(strcmp(outObjType, COM_REFERENTIAL_CONSTRAINT_OBJECT_LIT) == 0);
NABoolean isPkeyConstr =
(strcmp(outObjType, COM_PRIMARY_KEY_CONSTRAINT_OBJECT_LIT) == 0);
NABoolean isCheckConstr =
(strcmp(outObjType, COM_CHECK_CONSTRAINT_OBJECT_LIT) == 0);
NABoolean constrFound = FALSE;
if (isUniqConstr)
{
constrFound = FALSE;
const AbstractRIConstraintList &ariList = naTable->getUniqueConstraints();
for (Int32 i = 0; i < ariList.entries(); i++)
{
AbstractRIConstraint *ariConstr = ariList[i];
UniqueConstraint * uniqueConstr = (UniqueConstraint*)ariList[i];
const NAString &tableConstrName =
uniqueConstr->getConstraintName().getQualifiedNameAsAnsiString();
if (dropConstrName == tableConstrName)
{
constrFound = TRUE;
if (uniqueConstr->hasRefConstraintsReferencingMe())
{
*CmpCommon::diags()
<< DgSqlCode(-1050);
processReturn();
return;
}
}
} // for
if (NOT constrFound)
{
*CmpCommon::diags() << DgSqlCode(-1052);
processReturn();
return;
}
if (isPkeyConstr)
{
*CmpCommon::diags() << DgSqlCode(-1255)
<< DgString0(dropConstrName)
<< DgString1(extTableName);
processReturn();
return;
}
}
NATable *otherNaTable = NULL;
Int64 otherConstrUID = 0;
if (isRefConstr)
{
constrFound = FALSE;
RefConstraint * refConstr = NULL;
const AbstractRIConstraintList &ariList = naTable->getRefConstraints();
for (Int32 i = 0; i < ariList.entries(); i++)
{
AbstractRIConstraint *ariConstr = ariList[i];
const NAString &tableConstrName =
ariConstr->getConstraintName().getQualifiedNameAsAnsiString();
if (dropConstrName == tableConstrName)
{
constrFound = TRUE;
refConstr = (RefConstraint*)ariConstr;
}
} // for
if (NOT constrFound)
{
*CmpCommon::diags() << DgSqlCode(-1052);
processReturn();
return;
}
CorrName otherCN(refConstr->getUniqueConstraintReferencedByMe().getTableName());
BindWA bindWA(ActiveSchemaDB(), CmpCommon::context(), FALSE/*inDDL*/);
otherNaTable = bindWA.getNATable(otherCN);
if (otherNaTable == NULL || bindWA.errStatus())
{
processReturn();
return;
}
AbstractRIConstraint * otherConstr =
refConstr->findConstraint(&bindWA, refConstr->getUniqueConstraintReferencedByMe());
const NAString& otherCatName =
otherConstr->getConstraintName().getCatalogName();
const NAString& otherSchName =
otherConstr->getConstraintName().getSchemaName();
const NAString& otherConstrName =
otherConstr->getConstraintName().getObjectName();
otherConstrUID = getObjectUID(&cliInterface,
otherCatName.data(), otherSchName.data(), otherConstrName.data(),
COM_UNIQUE_CONSTRAINT_OBJECT_LIT );
if (otherConstrUID < 0)
{
CmpCommon::diags()->clear();
otherConstrUID = getObjectUID(&cliInterface,
otherCatName.data(), otherSchName.data(), otherConstrName.data(),
COM_PRIMARY_KEY_CONSTRAINT_OBJECT_LIT );
if (otherConstrUID < 0)
{
processReturn();
return;
}
}
}
NABoolean indexFound = FALSE;
Lng32 isExplicit = 0;
Lng32 keytag = 0;
if ((isUniqConstr || isRefConstr) && (NOT isPkeyConstr))
{
// find the index that corresponds to this constraint
char query[1000];
// the cardinality hint should force a nested join with
// TABLE_CONSTRAINTS as the outer and INDEXES as the inner
str_sprintf(query, "select I.keytag, I.is_explicit from %s.\"%s\".%s T, %s.\"%s\".%s I /*+ cardinality 1e9 */ where T.table_uid = %ld and T.constraint_uid = %ld and T.table_uid = I.base_table_uid and T.index_uid = I.index_uid ",
getSystemCatalog(), SEABASE_MD_SCHEMA, SEABASE_TABLE_CONSTRAINTS,
getSystemCatalog(), SEABASE_MD_SCHEMA, SEABASE_INDEXES,
naTable->objectUid().castToInt64(),
constrUID);
Queue * indexQueue = NULL;
ExeCliInterface cliInterface(STMTHEAP, 0, NULL,
CmpCommon::context()->sqlSession()->getParentQid());
cliRC = cliInterface.fetchAllRows(indexQueue, query, 0, FALSE, FALSE, TRUE);
if (cliRC < 0)
{
cliInterface.retrieveSQLDiagnostics(CmpCommon::diags());
processReturn();
return;
}
if (indexQueue->numEntries() > 1)
{
*CmpCommon::diags()
<< DgSqlCode(-1005)
<< DgConstraintName(dropConstrName);
processReturn();
return;
}
if (indexQueue->numEntries() ==1)
{
indexFound = TRUE;
indexQueue->position();
OutputInfo * oi = (OutputInfo*)indexQueue->getCurr();
keytag = *(Lng32*)oi->get(0);
isExplicit = *(Lng32*)oi->get(1);
}
}
if (deleteConstraintInfoFromSeabaseMDTables(&cliInterface,
naTable->objectUid().castToInt64(),
(otherNaTable ? otherNaTable->objectUid().castToInt64() : 0),
constrUID,
otherConstrUID,
constrCatName,
constrSchName,
constrObjName,
(isPkeyConstr ? COM_PRIMARY_KEY_CONSTRAINT_OBJECT :
(isUniqConstr ? COM_UNIQUE_CONSTRAINT_OBJECT :
(isRefConstr ? COM_REFERENTIAL_CONSTRAINT_OBJECT :
COM_CHECK_CONSTRAINT_OBJECT)))))
{
processReturn();
return;
}
// if the index corresponding to this constraint is an implicit index and 'no check'
// option is not specified, drop it.
if (((indexFound) && (NOT isExplicit) && (keytag != 0)) &&
(alterDropConstraint->getDropBehavior() != COM_NO_CHECK_DROP_BEHAVIOR))
{
char buf[4000];
str_sprintf(buf, "drop index \"%s\".\"%s\".\"%s\" no check",
constrCatName.data(), constrSchName.data(), constrObjName.data());
cliRC = cliInterface.executeImmediate(buf);
if (cliRC < 0)
{
cliInterface.retrieveSQLDiagnostics(CmpCommon::diags());
return;
}
}
Int64 tableUID = naTable->objectUid().castToInt64();
if (updateObjectRedefTime(&cliInterface,
catalogNamePart, schemaNamePart, objectNamePart,
COM_BASE_TABLE_OBJECT_LIT, -1, tableUID))
{
processReturn();
return;
}
// remove NATable for this table
ActiveSchemaDB()->getNATableDB()->removeNATable
(cn,
ComQiScope::REMOVE_FROM_ALL_USERS, COM_BASE_TABLE_OBJECT,
alterDropConstraint->ddlXns(), FALSE);
if (isRefConstr && otherNaTable)
{
CorrName otherCn(
otherNaTable->getExtendedQualName().getQualifiedNameObj(), STMTHEAP);
if (updateObjectRedefTime
(&cliInterface,
otherCn.getQualifiedNameObj().getCatalogName(),
otherCn.getQualifiedNameObj().getSchemaName(),
otherCn.getQualifiedNameObj().getObjectName(),
COM_BASE_TABLE_OBJECT_LIT, -1,
otherNaTable->objectUid().castToInt64()))
{
processReturn();
return;
}
ActiveSchemaDB()->getNATableDB()->removeNATable
(otherCn,
ComQiScope::REMOVE_FROM_ALL_USERS, COM_BASE_TABLE_OBJECT,
alterDropConstraint->ddlXns(), FALSE);
}
return;
}
void CmpSeabaseDDL::seabaseGrantRevoke(
StmtDDLNode * stmtDDLNode,
NABoolean isGrant,
NAString &currCatName,
NAString &currSchName,
NABoolean internalCall)
{
Lng32 retcode = 0;
if (!isAuthorizationEnabled())
{
*CmpCommon::diags() << DgSqlCode(-CAT_AUTHORIZATION_NOT_ENABLED);
return;
}
StmtDDLGrant * grantNode = NULL;
StmtDDLRevoke * revokeNode = NULL;
NAString tabName;
NAString origTabName;
ComAnsiNameSpace nameSpace;
NAString grantedByName;
NABoolean isGrantedBySpecified = FALSE;
if (isGrant)
{
grantNode = stmtDDLNode->castToStmtDDLGrant();
tabName = grantNode->getTableName();
origTabName = grantNode->getOrigObjectName();
nameSpace = grantNode->getGrantNameAsQualifiedName().getObjectNameSpace();
isGrantedBySpecified = grantNode->isByGrantorOptionSpecified();
grantedByName =
isGrantedBySpecified ? grantNode->getByGrantor()->getAuthorizationIdentifier(): "";
}
else
{
revokeNode = stmtDDLNode->castToStmtDDLRevoke();
tabName = revokeNode->getTableName();
origTabName = revokeNode->getOrigObjectName();
nameSpace = revokeNode->getRevokeNameAsQualifiedName().getObjectNameSpace();
isGrantedBySpecified = revokeNode->isByGrantorOptionSpecified();
grantedByName =
isGrantedBySpecified ? revokeNode->getByGrantor()->getAuthorizationIdentifier(): "";
}
ComObjectName origTableName(origTabName, COM_TABLE_NAME);
ExeCliInterface cliInterface(STMTHEAP, 0, NULL,
CmpCommon::context()->sqlSession()->getParentQid());
BindWA bindWA(ActiveSchemaDB(), CmpCommon::context(), FALSE/*inDDL*/);
CorrName cn(origTableName.getObjectNamePart().getInternalName(),
STMTHEAP,
origTableName.getSchemaNamePart().getInternalName(),
origTableName.getCatalogNamePart().getInternalName());
// set up common information for all grantees
ComObjectType objectType = COM_BASE_TABLE_OBJECT;
switch (nameSpace)
{
case COM_LIBRARY_NAME:
objectType = COM_LIBRARY_OBJECT;
break;
case COM_UDF_NAME:
case COM_UDR_NAME:
objectType = COM_USER_DEFINED_ROUTINE_OBJECT;
break;
case COM_SEQUENCE_GENERATOR_NAME:
objectType = COM_SEQUENCE_GENERATOR_OBJECT;
break;
default:
objectType = COM_BASE_TABLE_OBJECT;
}
// get the objectUID and objectOwner
Int64 objectUID = 0;
Int32 objectOwnerID = 0;
Int32 schemaOwnerID = 0;
Int64 objectFlags = 0 ;
NATable *naTable = NULL;
ComObjectName tableName(tabName, COM_TABLE_NAME);
if (objectType == COM_BASE_TABLE_OBJECT)
{
naTable = bindWA.getNATable(cn);
if (naTable == NULL || bindWA.errStatus())
{
*CmpCommon::diags()
<< DgSqlCode(-4082)
<< DgTableName(cn.getExposedNameAsAnsiString());
processReturn();
return;
}
objectUID = (int64_t)naTable->objectUid().get_value();
objectOwnerID = (int32_t)naTable->getOwner();
schemaOwnerID = naTable->getSchemaOwner();
objectType = naTable->getObjectType();
if (naTable->isView())
objectType = COM_VIEW_OBJECT;
NAString tns = naTable->getTableName().getQualifiedNameAsAnsiString();
tableName = ComObjectName(tns);
}
ComAnsiNamePart currCatAnsiName(currCatName);
ComAnsiNamePart currSchAnsiName(currSchName);
tableName.applyDefaults(currCatAnsiName, currSchAnsiName);
const NAString catalogNamePart = tableName.getCatalogNamePartAsAnsiString();
const NAString schemaNamePart = tableName.getSchemaNamePartAsAnsiString(TRUE);
const NAString objectNamePart = tableName.getObjectNamePartAsAnsiString(TRUE);
const NAString extTableName = tableName.getExternalName(TRUE);
ElemDDLGranteeArray & pGranteeArray =
(isGrant ? grantNode->getGranteeArray() : revokeNode->getGranteeArray());
ElemDDLPrivActArray & privActsArray =
(isGrant ? grantNode->getPrivilegeActionArray() :
revokeNode->getPrivilegeActionArray());
NABoolean allPrivs =
(isGrant ? grantNode->isAllPrivilegesSpecified() :
revokeNode->isAllPrivilegesSpecified());
NABoolean isWGOSpecified =
(isGrant ? grantNode->isWithGrantOptionSpecified() :
revokeNode->isGrantOptionForSpecified());
std::vector<PrivType> objectPrivs;
std::vector<ColPrivSpec> colPrivs;
if (allPrivs)
objectPrivs.push_back(ALL_PRIVS);
else
if (!checkSpecifiedPrivs(privActsArray,extTableName.data(),objectType,
naTable,objectPrivs,colPrivs))
{
processReturn();
return;
}
// If column privs specified for non SELECT ops for Hive/HBase native tables,
// return an error
if (naTable &&
(naTable->getTableName().isHive() || naTable->getTableName().isHbase()) &&
(colPrivs.size() > 0))
{
if (hasValue(colPrivs, INSERT_PRIV) ||
hasValue(colPrivs, UPDATE_PRIV) ||
hasValue(colPrivs, REFERENCES_PRIV))
{
NAString text1("INSERT, UPDATE, REFERENCES");
NAString text2("Hive columns on");
*CmpCommon::diags() << DgSqlCode(-CAT_INVALID_PRIV_FOR_OBJECT)
<< DgString0(text1.data())
<< DgString1(text2.data())
<< DgTableName(extTableName);
processReturn();
return;
}
}
// Prepare to call privilege manager
NAString MDLoc;
CONCAT_CATSCH(MDLoc, getSystemCatalog(), SEABASE_MD_SCHEMA);
NAString privMgrMDLoc;
CONCAT_CATSCH(privMgrMDLoc, getSystemCatalog(), SEABASE_PRIVMGR_SCHEMA);
PrivMgrCommands command(std::string(MDLoc.data()),
std::string(privMgrMDLoc.data()),
CmpCommon::diags());
// If the object is a metadata table or a privilege manager table, don't
// allow the privilege to be grantable.
NABoolean isMDTable = (isSeabaseMD(tableName) ||
isSeabasePrivMgrMD(tableName));
if (isMDTable && isWGOSpecified)
{
*CmpCommon::diags() << DgSqlCode(-CAT_WGO_NOT_ALLOWED);
processReturn();
return;
}
// Grants/revokes of the select privilege on metadata tables are allowed
// Grants/revokes of other relevant privileges are allowed if parser flag
// INTERNAL_QUERY_FROM_EXEUTIL is set
// Revoke: allow ALL and ALL_DML to be specified
if (isMDTable && !Get_SqlParser_Flags(INTERNAL_QUERY_FROM_EXEUTIL) &&
!isMDGrantRevokeOK(objectPrivs,colPrivs,isGrant))
{
*CmpCommon::diags() << DgSqlCode(-CAT_SMD_PRIVS_CANNOT_BE_CHANGED);
processReturn();
return;
}
// Hive tables must be registered in traf metadata
if (objectUID == 0 &&
naTable && naTable->isHiveTable())
{
// Register this hive table in traf metadata
// Privilege checks performed by register code
char query[(ComMAX_ANSI_IDENTIFIER_EXTERNAL_LEN*4) + 100];
snprintf(query, sizeof(query),
"register internal hive %s if not exists %s.\"%s\".\"%s\"",
(naTable->isView() ? "view" : "table"),
catalogNamePart.data(),
schemaNamePart.data(),
objectNamePart.data());
Lng32 retcode = cliInterface.executeImmediate(query);
if (retcode < 0)
{
cliInterface.retrieveSQLDiagnostics(CmpCommon::diags());
return;
}
// reload NATable to get registered objectUID
naTable = bindWA.getNATable(cn);
if (naTable == NULL)
{
SEABASEDDL_INTERNAL_ERROR("Bad NATable pointer in seabaseGrantRevoke");
return;
}
objectUID = (int64_t)naTable->objectUid().get_value();
objectOwnerID = (int32_t)naTable->getOwner();
schemaOwnerID = naTable->getSchemaOwner();
objectType = naTable->getObjectType();
if (naTable->isView())
objectType = COM_VIEW_OBJECT;
}
// HBase tables must be registered in traf metadata
if (objectUID == 0 &&
naTable &&
((naTable->isHbaseCellTable()) || (naTable->isHbaseRowTable())))
{
// For native hbase tables, grantor must be DB__ROOT or belong
// to one of the admin roles: DB__ROOTROLE, DB__HIVEROLE
// In hive, you must be an admin, DB__ROOTROLE and DB__HIVEROLE
// is the equivalent of an admin.
if (!ComUser::isRootUserID() &&
!ComUser::currentUserHasRole(ROOT_ROLE_ID) &&
!ComUser::currentUserHasRole(HBASE_ROLE_ID))
{
*CmpCommon::diags() << DgSqlCode (-CAT_NOT_AUTHORIZED);
processReturn();
return;
}
// register this hive table in traf metadata
char query[(ComMAX_ANSI_IDENTIFIER_EXTERNAL_LEN*4) + 100];
snprintf(query, sizeof(query),
"register internal hbase table if not exists %s.\"%s\".\"%s\"",
catalogNamePart.data(),
schemaNamePart.data(),
objectNamePart.data());
Lng32 retcode = cliInterface.executeImmediate(query);
if (retcode < 0)
{
cliInterface.retrieveSQLDiagnostics(CmpCommon::diags());
return;
}
// reload NATable to get registered objectUID
naTable = bindWA.getNATable(cn);
if (naTable == NULL)
{
SEABASEDDL_INTERNAL_ERROR("Bad NATable pointer in seabaseGrantRevoke");
return;
}
objectUID = (int64_t)naTable->objectUid().get_value();
objectOwnerID = (int32_t)naTable->getOwner();
schemaOwnerID = naTable->getSchemaOwner();
objectType = naTable->getObjectType();
}
// for metadata tables, the objectUID is not initialized in the NATable
// structure
if (objectUID == 0)
{
ExeCliInterface cliInterface(STMTHEAP, 0, NULL,
CmpCommon::context()->sqlSession()->getParentQid());
objectUID = getObjectInfo(&cliInterface,
catalogNamePart.data(), schemaNamePart.data(),
objectNamePart.data(), objectType,
objectOwnerID,schemaOwnerID,objectFlags);
if (objectUID == -1 || objectOwnerID == 0)
{
if (CmpCommon::diags()->getNumber(DgSqlCode::ERROR_) == 0)
SEABASEDDL_INTERNAL_ERROR("getting object UID and object owner for grant/revoke request");
processReturn();
return;
}
}
// Determine effective grantor ID and grantor name based on GRANTED BY clause
// current user, and object owner
//
// NOTE: If the user can grant privilege based on a role, we may want the
// effective grantor to be the role instead of the current user.
Int32 effectiveGrantorID;
std::string effectiveGrantorName;
PrivStatus result = command.getGrantorDetailsForObject(
isGrantedBySpecified,
std::string(grantedByName.data()),
objectOwnerID,
effectiveGrantorID,
effectiveGrantorName);
if (result != STATUS_GOOD)
{
if (CmpCommon::diags()->getNumber(DgSqlCode::ERROR_) == 0)
SEABASEDDL_INTERNAL_ERROR("getting grantor ID and grantor name");
processReturn();
return;
}
std::string objectName (extTableName.data());
// Map hbase map table to external name
if (ComIsHBaseMappedIntFormat(catalogNamePart, schemaNamePart))
{
NAString newCatName;
NAString newSchName;
ComConvertHBaseMappedIntToExt(catalogNamePart, schemaNamePart,
newCatName, newSchName);
objectName = newCatName.data() + std::string(".\"");
objectName += newSchName.data() + std::string("\".");
objectName += tableName.getObjectNamePart().getExternalName();
}
else
objectName = extTableName.data();
// For now, only support one grantee per request
// TBD: support multiple grantees - a testing effort?
if (pGranteeArray.entries() > 1)
{
*CmpCommon::diags() << DgSqlCode (-CAT_ONLY_ONE_GRANTEE_ALLOWED);
processReturn();
return;
}
for (CollIndex j = 0; j < pGranteeArray.entries(); j++)
{
NAString authName(pGranteeArray[j]->getAuthorizationIdentifier());
Int32 grantee;
if (pGranteeArray[j]->isPublic())
{
// don't allow WGO for public auth ID
if (isWGOSpecified)
{
*CmpCommon::diags() << DgSqlCode(-CAT_WGO_NOT_ALLOWED);
processReturn();
return;
}
grantee = PUBLIC_USER;
authName = PUBLIC_AUTH_NAME;
}
else
{
Int16 retcode = ComUser::getAuthIDFromAuthName(authName.data(), grantee);
if (retcode == FENOTFOUND)
{
*CmpCommon::diags() << DgSqlCode(-CAT_AUTHID_DOES_NOT_EXIST_ERROR)
<< DgString0(authName.data());
processReturn();
return;
}
else if (retcode != FEOK)
{
*CmpCommon::diags() << DgSqlCode (-CAT_INTERNAL_EXCEPTION_ERROR)
<< DgString0(__FILE__)
<< DgInt0(__LINE__)
<< DgString1("verifying grantee");
processReturn();
return;
}
// Don't allow WGO for roles
if (CmpSeabaseDDLauth::isRoleID(grantee) && isWGOSpecified &&
CmpCommon::getDefault(ALLOW_WGO_FOR_ROLES) == DF_OFF)
{
// If grantee is system role, allow grant
Int32 numberRoles = sizeof(systemRoles)/sizeof(SystemAuthsStruct);
NABoolean isSystemRole = FALSE;
for (Int32 i = 0; i < numberRoles; i++)
{
const SystemAuthsStruct &roleDefinition = systemRoles[i];
NAString systemRole = roleDefinition.authName;
if (systemRole == authName)
{
isSystemRole = TRUE;
break;
}
}
if (!isSystemRole)
{
*CmpCommon::diags() << DgSqlCode(-CAT_WGO_NOT_ALLOWED);
processReturn();
return;
}
}
}
std::string granteeName (authName.data());
if (isGrant)
{
PrivStatus result = command.grantObjectPrivilege(objectUID,
objectName,
objectType,
grantee,
granteeName,
effectiveGrantorID,
effectiveGrantorName,
objectPrivs,
colPrivs,
allPrivs,
isWGOSpecified);
}
else
{
PrivStatus result = command.revokeObjectPrivilege(objectUID,
objectName,
objectType,
grantee,
granteeName,
effectiveGrantorID,
effectiveGrantorName,
objectPrivs,
colPrivs,
allPrivs,
isWGOSpecified);
}
}
if (result == STATUS_ERROR)
return;
if (isHbase(tableName))
hbaseGrantRevoke(stmtDDLNode, isGrant, currCatName, currSchName);
// Adjust the stored descriptor
char objectTypeLit[3] = {0};
strncpy(objectTypeLit,PrivMgr::ObjectEnumToLit(objectType),2);
updateObjectRedefTime(&cliInterface,
catalogNamePart, schemaNamePart, objectNamePart,
objectTypeLit, -1, objectUID);
return;
}
void CmpSeabaseDDL::hbaseGrantRevoke(
StmtDDLNode * stmtDDLNode,
NABoolean isGrant,
NAString &currCatName, NAString &currSchName)
{
Lng32 cliRC = 0;
Lng32 retcode = 0;
StmtDDLGrant * grantNode = NULL;
StmtDDLRevoke * revokeNode = NULL;
NAString tabName;
if (isGrant)
{
grantNode = stmtDDLNode->castToStmtDDLGrant();
tabName = grantNode->getTableName();
}
else
{
revokeNode = stmtDDLNode->castToStmtDDLRevoke();
tabName = revokeNode->getTableName();
}
ComObjectName tableName(tabName);
ComAnsiNamePart currCatAnsiName(currCatName);
ComAnsiNamePart currSchAnsiName(currSchName);
tableName.applyDefaults(currCatAnsiName, currSchAnsiName);
const NAString catalogNamePart = tableName.getCatalogNamePartAsAnsiString();
const NAString schemaNamePart = tableName.getSchemaNamePartAsAnsiString(TRUE);
const NAString objectNamePart = tableName.getObjectNamePartAsAnsiString(TRUE);
const NAString extTableName = tableName.getExternalName(TRUE);
const NAString extNameForHbase = catalogNamePart + "." + schemaNamePart + "." + objectNamePart;
ExeCliInterface cliInterface(STMTHEAP, 0, NULL,
CmpCommon::context()->sqlSession()->getParentQid());
if (isSeabaseReservedSchema(tableName))
{
*CmpCommon::diags() << DgSqlCode(-1118)
<< DgTableName(extTableName);
processReturn();
return;
}
ExpHbaseInterface * ehi = allocEHI();
if (ehi == NULL)
{
processReturn();
return;
}
BindWA bindWA(ActiveSchemaDB(), CmpCommon::context(), FALSE/*inDDL*/);
CorrName cn(tableName.getObjectNamePart().getInternalName(),
STMTHEAP,
tableName.getSchemaNamePart().getInternalName(),
tableName.getCatalogNamePart().getInternalName());
NATable *naTable = bindWA.getNATable(cn);
if (naTable == NULL || bindWA.errStatus())
{
*CmpCommon::diags()
<< DgSqlCode(-4082)
<< DgTableName(cn.getExposedNameAsAnsiString());
deallocEHI(ehi);
processReturn();
return;
}
ElemDDLGranteeArray & pGranteeArray =
(isGrant ? grantNode->getGranteeArray() : revokeNode->getGranteeArray());
ElemDDLPrivActArray & pPrivActsArray =
(isGrant ? grantNode->getPrivilegeActionArray() :
revokeNode->getPrivilegeActionArray());
NABoolean allPrivs =
(isGrant ? grantNode->isAllPrivilegesSpecified() :
revokeNode->isAllPrivilegesSpecified());
TextVec userPermissions;
if (allPrivs)
{
userPermissions.push_back("READ");
userPermissions.push_back("WRITE");
userPermissions.push_back("CREATE");
}
else
{
for (Lng32 i = 0; i < pPrivActsArray.entries(); i++)
{
switch (pPrivActsArray[i]->getOperatorType() )
{
case ELM_PRIV_ACT_SELECT_ELEM:
{
userPermissions.push_back("READ");
break;
}
case ELM_PRIV_ACT_INSERT_ELEM:
case ELM_PRIV_ACT_DELETE_ELEM:
case ELM_PRIV_ACT_UPDATE_ELEM:
{
userPermissions.push_back("WRITE");
break;
}
case ELM_PRIV_ACT_CREATE_ELEM:
{
userPermissions.push_back("CREATE");
break;
}
default:
{
NAString privType = "UNKNOWN";
*CmpCommon::diags() << DgSqlCode(-CAT_INVALID_PRIV_FOR_OBJECT)
<< DgString0(privType)
<< DgString1(extTableName);
deallocEHI(ehi);
processReturn();
return;
}
} // end switch
} // for
}
for (CollIndex j = 0; j < pGranteeArray.entries(); j++)
{
NAString authName(pGranteeArray[j]->getAuthorizationIdentifier());
if (isGrant)
retcode = ehi->grant(authName.data(), extNameForHbase.data(), userPermissions);
else
retcode = ehi->revoke(authName.data(), extNameForHbase.data(), userPermissions);
if (retcode < 0)
{
*CmpCommon::diags() << DgSqlCode(-8448)
<< (isGrant ? DgString0((char*)"ExpHbaseInterface::grant()") :
DgString0((char*)"ExpHbaseInterface::revoke()"))
<< DgString1(getHbaseErrStr(-retcode))
<< DgInt0(-retcode)
<< DgString2((char*)GetCliGlobals()->getJniErrorStr());
deallocEHI(ehi);
processReturn();
return;
}
}
retcode = ehi->close();
if (retcode < 0)
{
*CmpCommon::diags() << DgSqlCode(-8448)
<< DgString0((char*)"ExpHbaseInterface::close()")
<< DgString1(getHbaseErrStr(-retcode))
<< DgInt0(-retcode)
<< DgString2((char*)GetCliGlobals()->getJniErrorStr());
deallocEHI(ehi);
processReturn();
return;
}
deallocEHI(ehi);
processReturn();
return;
}
void CmpSeabaseDDL::createNativeHbaseTable(
ExeCliInterface *cliInterface,
StmtDDLCreateHbaseTable * createTableNode,
NAString &currCatName, NAString &currSchName)
{
Lng32 retcode = 0;
Lng32 cliRC = 0;
// Verify that user has privilege to create HBase tables - must be DB__ROOT
// or granted the DB__HBASEROLE
if (isAuthorizationEnabled() &&
!ComUser::isRootUserID() &&
!ComUser::currentUserHasRole(ROOT_ROLE_ID) &&
!ComUser::currentUserHasRole(HBASE_ROLE_ID))
{
*CmpCommon::diags() << DgSqlCode (-CAT_NOT_AUTHORIZED);
processReturn();
return;
}
ComObjectName tableName(createTableNode->getTableName());
const NAString catalogNamePart = tableName.getCatalogNamePartAsAnsiString();
const NAString schemaNamePart = tableName.getSchemaNamePartAsAnsiString(TRUE);
const NAString objectNamePart = tableName.getObjectNamePartAsAnsiString(TRUE);
ExpHbaseInterface * ehi = allocEHI();
if (ehi == NULL)
{
processReturn();
return;
}
// If table already exists, return
retcode = existsInHbase(objectNamePart, ehi);
if (retcode)
{
*CmpCommon::diags() << DgSqlCode(CAT_TABLE_ALREADY_EXISTS)
<< DgTableName(objectNamePart.data());
deallocEHI(ehi);
processReturn();
return;
}
std::vector<NAString> colFamVec;
for (Lng32 i = 0; i < createTableNode->csl()->entries(); i++)
{
const NAString * nas = (NAString*)(*createTableNode->csl())[i];
colFamVec.push_back(nas->data());
}
NAList<HbaseCreateOption*> hbaseCreateOptions(STMTHEAP);
NAString hco;
retcode = setupHbaseOptions(createTableNode->getHbaseOptionsClause(),
0, objectNamePart,
hbaseCreateOptions, hco);
if (retcode)
{
deallocEHI(ehi);
processReturn();
return;
}
HbaseStr hbaseTable;
hbaseTable.val = (char*)objectNamePart.data();
hbaseTable.len = objectNamePart.length();
if (createHbaseTable(ehi, &hbaseTable, colFamVec,
&hbaseCreateOptions) == -1)
{
deallocEHI(ehi);
processReturn();
return;
}
// Register the table
char query[(ComMAX_ANSI_IDENTIFIER_EXTERNAL_LEN) + 100];
snprintf(query, sizeof(query),
"register internal hbase table if not exists \"%s\"",
objectNamePart.data());
cliRC = cliInterface->executeImmediate(query);
if (cliRC < 0)
{
cliInterface->retrieveSQLDiagnostics(CmpCommon::diags());
return;
}
}
void CmpSeabaseDDL::dropNativeHbaseTable(
ExeCliInterface *cliInterface,
StmtDDLDropHbaseTable * dropTableNode,
NAString &currCatName, NAString &currSchName)
{
Lng32 retcode = 0;
Lng32 cliRC = 0;
// Verify that user has privilege to drop HBase tables - must be DB__ROOT
// or granted the DB__HBASEROLE
if (isAuthorizationEnabled() &&
!ComUser::isRootUserID() &&
!ComUser::currentUserHasRole(ROOT_ROLE_ID) &&
!ComUser::currentUserHasRole(HBASE_ROLE_ID))
{
*CmpCommon::diags() << DgSqlCode (-CAT_NOT_AUTHORIZED);
processReturn();
return;
}
ComObjectName tableName(dropTableNode->getTableName());
const NAString catalogNamePart = tableName.getCatalogNamePartAsAnsiString();
const NAString schemaNamePart = tableName.getSchemaNamePartAsAnsiString(TRUE);
const NAString objectNamePart = tableName.getObjectNamePartAsAnsiString(TRUE);
ExpHbaseInterface * ehi = allocEHI();
if (ehi == NULL)
{
processReturn();
return;
}
// If table does not exist, return
retcode = existsInHbase(objectNamePart, ehi);
if (retcode == 0)
{
*CmpCommon::diags() << DgSqlCode(CAT_TABLE_DOES_NOT_EXIST_ERROR)
<< DgTableName(objectNamePart.data());
deallocEHI(ehi);
processReturn();
return;
}
// Load definitions into cache
BindWA bindWA(ActiveSchemaDB(),CmpCommon::context(),FALSE/*inDDL*/);
CorrName cnCell(objectNamePart,STMTHEAP, HBASE_CELL_SCHEMA, HBASE_SYSTEM_CATALOG);
NATable *naCellTable = bindWA.getNATableInternal(cnCell);
CorrName cnRow(objectNamePart,STMTHEAP, HBASE_ROW_SCHEMA, HBASE_SYSTEM_CATALOG);
NATable *naRowTable = bindWA.getNATableInternal(cnRow);
// unregister tables
char query[(ComMAX_ANSI_IDENTIFIER_EXTERNAL_LEN*4) + 100];
snprintf(query, sizeof(query),
"unregister hbase table %s", tableName.getObjectNamePart().getExternalName().data());
cliRC = cliInterface->executeImmediate(query);
if (cliRC < 0 && cliRC != -CAT_REG_UNREG_OBJECTS && cliRC != -3251)
{
cliInterface->retrieveSQLDiagnostics(CmpCommon::diags());
deallocEHI(ehi);
processReturn();
return;
}
// Drop external mapping table
//ComObjectName externalName(objectNamePart);
snprintf(query, sizeof(query),
"drop external table if exists %s ",
tableName.getObjectNamePart().getExternalName().data());
cliRC = cliInterface->executeImmediate(query);
if (cliRC < 0)
{
cliInterface->retrieveSQLDiagnostics(CmpCommon::diags());
deallocEHI(ehi);
processReturn();
return;
}
// Remove cell and row tables from cache.
if (naCellTable)
{
ActiveSchemaDB()->getNATableDB()->removeNATable
(cnCell,
ComQiScope::REMOVE_FROM_ALL_USERS,
COM_BASE_TABLE_OBJECT,
dropTableNode->ddlXns(), FALSE);
}
if (naRowTable)
{
ActiveSchemaDB()->getNATableDB()->removeNATable
(cnRow,
ComQiScope::REMOVE_FROM_ALL_USERS,
COM_BASE_TABLE_OBJECT,
dropTableNode->ddlXns(), FALSE);
}
// Remove table from HBase
HbaseStr hbaseTable;
hbaseTable.val = (char*)objectNamePart.data();
hbaseTable.len = objectNamePart.length();
retcode = dropHbaseTable(ehi, &hbaseTable, FALSE, FALSE);
if (retcode < 0)
{
deallocEHI(ehi);
processReturn();
return;
}
}
short CmpSeabaseDDL::registerNativeTable
(
const NAString &catalogNamePart,
const NAString &schemaNamePart,
const NAString &objectNamePart,
Int32 objOwnerId,
Int32 schemaOwnerId,
ExeCliInterface &cliInterface,
NABoolean isRegister,
NABoolean isInternal
)
{
Lng32 retcode = 0;
ComObjectType objType = COM_BASE_TABLE_OBJECT;
Int64 flags = 0;
if (isRegister && isInternal)
flags = MD_OBJECTS_INTERNAL_REGISTER;
Int64 objUID = -1;
retcode =
updateSeabaseMDObjectsTable
(&cliInterface,
catalogNamePart.data(),
schemaNamePart.data(),
objectNamePart.data(),
objType,
NULL,
objOwnerId, schemaOwnerId,
flags, objUID);
if (retcode < 0)
return -1;
// Grant owner privileges
if (isAuthorizationEnabled())
{
NAString fullName (catalogNamePart);
fullName += ".";
fullName += schemaNamePart;
fullName += ".";
fullName += objectNamePart;
if (!insertPrivMgrInfo(objUID,
fullName,
objType,
objOwnerId,
schemaOwnerId,
ComUser::getCurrentUser()))
{
*CmpCommon::diags()
<< DgSqlCode(-CAT_UNABLE_TO_GRANT_PRIVILEGES)
<< DgTableName(objectNamePart);
return -1;
}
}
return 0;
}
short CmpSeabaseDDL::unregisterNativeTable
(
const NAString &catalogNamePart,
const NAString &schemaNamePart,
const NAString &objectNamePart,
ExeCliInterface &cliInterface,
ComObjectType objType
)
{
short retcode = 0;
Int64 objUID = getObjectUID(&cliInterface,
catalogNamePart.data(),
schemaNamePart.data(),
objectNamePart.data(),
comObjectTypeLit(objType));
// Revoke owner privileges
if (isAuthorizationEnabled())
{
NAString fullName (catalogNamePart);
fullName += ".";
fullName += schemaNamePart;
fullName += ".";
fullName += objectNamePart;
if (!deletePrivMgrInfo(fullName,
objUID,
objType))
{
*CmpCommon::diags()
<< DgSqlCode(-CAT_PRIVILEGE_NOT_REVOKED)
<< DgTableName(objectNamePart);
return -1;
}
}
// delete hist stats, if HIST tables exist
retcode = existsInSeabaseMDTable
(&cliInterface,
HIVE_STATS_CATALOG, HIVE_STATS_SCHEMA_NO_QUOTES, HBASE_HIST_NAME,
COM_BASE_TABLE_OBJECT);
if (retcode < 0)
return -1;
if (retcode == 1) // exists
{
if (dropSeabaseStats(&cliInterface,
HIVE_STATS_CATALOG,
HIVE_STATS_SCHEMA_NO_QUOTES,
objUID))
{
return -1;
}
}
// drop from metadata
retcode =
deleteFromSeabaseMDObjectsTable
(&cliInterface,
catalogNamePart.data(),
schemaNamePart.data(),
objectNamePart.data(),
objType
);
return 0;
}
short CmpSeabaseDDL::registerHiveView
(
const NAString &catalogNamePart,
const NAString &schemaNamePart,
const NAString &objectNamePart,
Int32 objOwnerId,
Int32 schemaOwnerId,
NATable *naTable,
ExeCliInterface &cliInterface,
NABoolean isInternal,
NABoolean cascade
)
{
Lng32 retcode = 0;
Int64 flags = 0;
if (isInternal)
flags = MD_OBJECTS_INTERNAL_REGISTER;
ComObjectType objType = COM_VIEW_OBJECT;
Int64 objUID = -1;
retcode =
updateSeabaseMDObjectsTable
(&cliInterface,
catalogNamePart.data(),
schemaNamePart.data(),
objectNamePart.data(),
objType,
NULL,
objOwnerId, schemaOwnerId,
flags, objUID);
if (retcode < 0)
return -1;
// Grant owner privileges
if (isAuthorizationEnabled())
{
NAString fullName (catalogNamePart);
fullName += ".";
fullName += schemaNamePart;
fullName += ".";
fullName += objectNamePart;
if (!insertPrivMgrInfo(objUID,
fullName,
objType,
objOwnerId,
schemaOwnerId,
ComUser::getCurrentUser()))
{
*CmpCommon::diags()
<< DgSqlCode(-CAT_UNABLE_TO_GRANT_PRIVILEGES)
<< DgTableName(objectNamePart);
return -1;
}
}
// if cascade option is specified, find out all objects that are part
// of this view. Register them in traf metadata and update view usage
// metadata table.
if (cascade)
{
BindWA bindWA(ActiveSchemaDB(), CmpCommon::context(), FALSE/*inDDL*/);
// temporarily change the default schema to
// that of viewName.
// This will make sure that all unqualified objects in view
// text are expanded in this schema.
SchemaName s(schemaNamePart, catalogNamePart);
bindWA.setDefaultSchema(s);
Parser parser(bindWA.currentCmpContext());
parser.hiveDDLInfo_->disableDDLcheck_ = TRUE;
ExprNode *viewTree = parser.parseDML(naTable->getViewText(),
naTable->getViewLen(),
naTable->getViewTextCharSet());
if (! viewTree)
{
return -1;
}
RelExpr *queryTree =
viewTree->castToStatementExpr()->getQueryExpression();
StmtDDLCreateView *createViewNode =
((DDLExpr *)(queryTree->getChild(0)))->
getDDLNode()->castToStmtDDLNode()->castToStmtDDLCreateView();
ExprNode * boundTree = createViewNode->bindNode(&bindWA);
if ((! boundTree) || (bindWA.errStatus()) ||
(CmpCommon::diags()->getNumber(DgSqlCode::ERROR_)))
{
return -1;
}
if (updateViewUsage(createViewNode, objUID, &cliInterface))
{
return -1;
}
}
return 0;
}
short CmpSeabaseDDL::unregisterHiveView
(
const NAString &catalogNamePart,
const NAString &schemaNamePart,
const NAString &objectNamePart,
NATable *naTable,
ExeCliInterface &cliInterface,
NABoolean cascade
)
{
Lng32 retcode = 0;
Int64 objUID = getObjectUID(&cliInterface,
catalogNamePart.data(),
schemaNamePart.data(),
objectNamePart.data(),
comObjectTypeLit(COM_VIEW_OBJECT));
// Revoke owner privileges
if (isAuthorizationEnabled())
{
NAString fullName (catalogNamePart);
fullName += ".";
fullName += schemaNamePart;
fullName += ".";
fullName += objectNamePart;
if (!deletePrivMgrInfo(fullName,
objUID,
COM_VIEW_OBJECT))
{
*CmpCommon::diags()
<< DgSqlCode(-CAT_PRIVILEGE_NOT_REVOKED)
<< DgTableName(objectNamePart);
return -1;
}
}
// delete hist stats, if HIST tables exist
retcode = existsInSeabaseMDTable
(&cliInterface,
HIVE_STATS_CATALOG, HIVE_STATS_SCHEMA_NO_QUOTES, HBASE_HIST_NAME,
COM_BASE_TABLE_OBJECT);
if (retcode < 0)
return -1;
if (retcode == 1) // exists
{
if (dropSeabaseStats(&cliInterface,
HIVE_STATS_CATALOG,
HIVE_STATS_SCHEMA_NO_QUOTES,
objUID))
{
return -1;
}
}
// drop from metadata
retcode =
deleteFromSeabaseMDTable
(&cliInterface,
catalogNamePart.data(),
schemaNamePart.data(),
objectNamePart.data(),
COM_VIEW_OBJECT
);
if (retcode < 0)
return -1;
// if cascade option is specified, find out all objects that are part
// of this view. Unregister them from traf metadata and update view usage
// metadata table.
if ((cascade) && (naTable))
{
BindWA bindWA(ActiveSchemaDB(), CmpCommon::context(), FALSE/*inDDL*/);
// temporarily change the default schema to
// that of viewName.
// This will make sure that all unqualified objects in view
// text are expanded in this schema.
SchemaName s(schemaNamePart, catalogNamePart);
bindWA.setDefaultSchema(s);
Parser parser(bindWA.currentCmpContext());
parser.hiveDDLInfo_->disableDDLcheck_ = TRUE;
ExprNode *viewTree = parser.parseDML(naTable->getViewText(),
naTable->getViewLen(),
naTable->getViewTextCharSet());
if (! viewTree)
{
return -1;
}
RelExpr *queryTree =
viewTree->castToStatementExpr()->getQueryExpression();
StmtDDLCreateView *createViewNode =
((DDLExpr *)(queryTree->getChild(0)))->
getDDLNode()->castToStmtDDLNode()->castToStmtDDLCreateView();
ExprNode * boundTree = createViewNode->bindNode(&bindWA);
if ((! boundTree) || (bindWA.errStatus()) ||
(CmpCommon::diags()->getNumber(DgSqlCode::ERROR_)))
{
return -1;
}
if (unregisterHiveViewUsage(createViewNode, objUID, &cliInterface))
{
return -1;
}
}
return 0;
}
short CmpSeabaseDDL::unregisterHiveViewUsage(StmtDDLCreateView * createViewParseNode,
Int64 viewUID,
ExeCliInterface * cliInterface)
{
const ParViewUsages &vu = createViewParseNode->getViewUsages();
const ParTableUsageList &vtul = vu.getViewTableUsageList();
char query[1000];
for (CollIndex i = 0; i < vtul.entries(); i++)
{
ComObjectName usedObjName(vtul[i].getQualifiedNameObj()
.getQualifiedNameAsAnsiString(),
vtul[i].getAnsiNameSpace());
const NAString catalogNamePart = usedObjName.getCatalogNamePartAsAnsiString();
const NAString schemaNamePart = usedObjName.getSchemaNamePartAsAnsiString(TRUE);
const NAString objectNamePart = usedObjName.getObjectNamePartAsAnsiString(TRUE);
const NAString extUsedObjName = usedObjName.getExternalName(TRUE);
Int64 usedObjUID = -1;
CorrName cn(objectNamePart,STMTHEAP, schemaNamePart,catalogNamePart);
BindWA bindWA(ActiveSchemaDB(),CmpCommon::context(),FALSE/*inDDL*/);
NATable *naTable = bindWA.getNATableInternal(cn);
if ((naTable == NULL) ||
(NOT naTable->isHiveTable()) ||
(NOT naTable->isRegistered()))
{
NAString reason;
if (naTable == NULL)
reason = NAString("naTable for ") + extUsedObjName + " is NULL.";
else if (NOT naTable->isHiveTable())
reason = extUsedObjName + " is not a Hive table.";
else
reason = extUsedObjName + " is not registered.";
*CmpCommon::diags() << DgSqlCode(-3242) <<
DgString0(reason);
return -1;
}
// unregister this hive object from traf metadata, if not already
str_sprintf(query, "unregister hive %s if exists %s.\"%s\".\"%s\" ",
(naTable->isView() ? "view" : "table"),
catalogNamePart.data(),
schemaNamePart.data(),
objectNamePart.data());
Lng32 cliRC = cliInterface->executeImmediate(query);
if (cliRC < 0)
{
cliInterface->retrieveSQLDiagnostics(CmpCommon::diags());
return -1;
}
// save the current parserflags setting
ULng32 savedCliParserFlags = 0;;
SQL_EXEC_GetParserFlagsForExSqlComp_Internal(savedCliParserFlags_);
SQL_EXEC_SetParserFlagsForExSqlComp_Internal(INTERNAL_QUERY_FROM_EXEUTIL);
usedObjUID = naTable->objectUid().get_value();
str_sprintf(query, "delete from %s.\"%s\".%s where using_view_uid = %ld and used_object_uid = %ld",
getSystemCatalog(), SEABASE_MD_SCHEMA, SEABASE_VIEWS_USAGE,
viewUID,
usedObjUID);
cliRC = cliInterface->executeImmediate(query);
SQL_EXEC_AssignParserFlagsForExSqlComp_Internal(savedCliParserFlags);
if (cliRC < 0)
{
cliInterface->retrieveSQLDiagnostics(CmpCommon::diags());
return -1;
}
} // for
return 0;
}
short CmpSeabaseDDL::unregisterHiveSchema
(
const NAString &catalogNamePart,
const NAString &schemaNamePart,
ExeCliInterface &cliInterface,
NABoolean cascade
)
{
Lng32 cliRC = 0;
short retcode = 0;
if (cascade)
{
// unregister all objects in this schema
Queue * objectsInfo = NULL;
char query[2000];
str_sprintf(query, "select object_type, object_name "
"from %s.\"%s\".%s "
"where catalog_name = '%s' and schema_name = '%s'"
"order by 1 for read committed access",
getSystemCatalog(), SEABASE_MD_SCHEMA, SEABASE_OBJECTS,
catalogNamePart.data(), schemaNamePart.data());
cliRC = cliInterface.fetchAllRows(objectsInfo, query, 0, FALSE, FALSE, TRUE);
if (cliRC < 0)
{
cliInterface.retrieveSQLDiagnostics(CmpCommon::diags());
return -1;
}
objectsInfo->position();
for (Lng32 i = 0; i < objectsInfo->numEntries(); i++)
{
OutputInfo * oi = (OutputInfo*)objectsInfo->getNext();
char * objType = (char*)oi->get(0);
char * objName = (char*)oi->get(1);
if (strcmp(objType, COM_BASE_TABLE_OBJECT_LIT) == 0)
{
retcode = unregisterNativeTable(
catalogNamePart, schemaNamePart, objName,
cliInterface,
COM_BASE_TABLE_OBJECT);
}
else if (strcmp(objType, COM_VIEW_OBJECT_LIT) == 0)
{
retcode = unregisterHiveView(
catalogNamePart, schemaNamePart, objName,
NULL,
cliInterface,
FALSE); // dont cascade
}
if (retcode < 0)
{
return -1;
}
} // for
}
retcode = unregisterNativeTable(
catalogNamePart, schemaNamePart, SEABASE_SCHEMA_OBJECTNAME,
cliInterface,
COM_SHARED_SCHEMA_OBJECT);
return retcode;
}
void CmpSeabaseDDL::regOrUnregNativeObject(
StmtDDLRegOrUnregObject * regOrUnregObject,
NAString &currCatName, NAString &currSchName)
{
Lng32 retcode = 0;
char errReason[400];
ExeCliInterface cliInterface(STMTHEAP, 0, NULL,
CmpCommon::context()->sqlSession()->getParentQid());
NAString catalogNamePart = regOrUnregObject->getObjNameAsQualifiedName().
getCatalogName();
NAString schemaNamePart = regOrUnregObject->getObjNameAsQualifiedName().
getSchemaName();
NAString objectNamePart = regOrUnregObject->getObjNameAsQualifiedName().
getObjectName();
ComObjectName tableName;
NAString tabName;
NAString extTableName;
NABoolean isHive = (catalogNamePart.index(HIVE_SYSTEM_CATALOG, 0, NAString::ignoreCase) == 0);
NABoolean isHBase = (catalogNamePart.index(HBASE_SYSTEM_CATALOG, 0, NAString::ignoreCase) == 0);
if (NOT (isHive || isHBase))
{
*CmpCommon::diags() << DgSqlCode(-3242) <<
DgString0("Register/Unregister statement must specify a hive or hbase object.");
processReturn();
return;
}
if (isHive)
{
if (NOT (schemaNamePart == HIVE_SYSTEM_SCHEMA))
schemaNamePart.toUpper();
objectNamePart.toUpper();
}
// make sure that underlying hive/hbase object exists
BindWA bindWA(ActiveSchemaDB(), CmpCommon::context(), FALSE/*inDDL*/);
CorrName cn(objectNamePart, STMTHEAP,
((isHBase && (schemaNamePart == HBASE_SYSTEM_SCHEMA))
? HBASE_CELL_SCHEMA : schemaNamePart),
catalogNamePart);
if (isHive && regOrUnregObject->objType() == COM_SHARED_SCHEMA_OBJECT)
cn.setSpecialType(ExtendedQualName::SCHEMA_TABLE);
NATable * naTable = bindWA.getNATable(cn);
if (((naTable == NULL) || (bindWA.errStatus())) &&
((regOrUnregObject->isRegister()) || // register
(NOT regOrUnregObject->cleanup()))) // unreg and not cleanup
{
CmpCommon::diags()->clear();
*CmpCommon::diags() << DgSqlCode(-3251)
<< (regOrUnregObject->isRegister() ? DgString0("REGISTER") :
DgString0("UNREGISTER"))
<< DgString1(NAString(" Reason: Specified object ") +
(regOrUnregObject->objType() == COM_SHARED_SCHEMA_OBJECT ?
schemaNamePart : objectNamePart) +
NAString(" does not exist."));
processReturn();
return;
}
// ignore errors for 'unregister cleanup'
CmpCommon::diags()->clear();
if (naTable)
{
if (regOrUnregObject->isRegister() &&
(naTable->isRegistered())) // already registered
{
if (NOT regOrUnregObject->registeredOption())
{
str_sprintf(errReason, " Reason: %s has already been registered.",
(regOrUnregObject->objType() == COM_SHARED_SCHEMA_OBJECT ?
schemaNamePart.data() :
regOrUnregObject->getObjNameAsQualifiedName().
getQualifiedNameAsString().data()));
*CmpCommon::diags() << DgSqlCode(-3251)
<< DgString0("REGISTER")
<< DgString1(errReason);
}
processReturn();
return;
}
else if ((NOT regOrUnregObject->isRegister()) && // unregister
(NOT naTable->isRegistered())) // not registered
{
if (NOT regOrUnregObject->registeredOption())
{
str_sprintf(errReason, " Reason: %s has not been registered.",
(regOrUnregObject->objType() == COM_SHARED_SCHEMA_OBJECT ?
schemaNamePart.data() :
regOrUnregObject->getObjNameAsQualifiedName().
getQualifiedNameAsString().data()));
*CmpCommon::diags() << DgSqlCode(-3251)
<< DgString0("UNREGISTER")
<< DgString1(errReason);
}
processReturn();
return;
}
}
// For native hive/hbase tables, grantor must be DB__ROOT or belong
// to one of the admin roles: DB__ROOTROLE, DB__HIVEROLE/DB__HBASEROLE.
// In hive/hbase, you must be an admin, DB__ROOTROLE,DB__HIVEROLE/HBASEROLE
// is the equivalent of an admin.
if (!Get_SqlParser_Flags(INTERNAL_QUERY_FROM_EXEUTIL) &&
!ComUser::isRootUserID() &&
!ComUser::currentUserHasRole(ROOT_ROLE_ID) &&
((isHive && !ComUser::currentUserHasRole(HIVE_ROLE_ID)) ||
(isHBase && !ComUser::currentUserHasRole(HBASE_ROLE_ID))))
{
*CmpCommon::diags() << DgSqlCode (-CAT_NOT_AUTHORIZED);
processReturn();
return;
}
Int32 objOwnerId = (isHive ? HIVE_ROLE_ID : HBASE_ROLE_ID);
Int32 schemaOwnerId = (isHive ? HIVE_ROLE_ID : HBASE_ROLE_ID);
Int64 objUID = -1;
Int64 flags = 0;
if ((regOrUnregObject->isRegister()) &&
(regOrUnregObject->objType() == COM_SHARED_SCHEMA_OBJECT))
{
retcode =
updateSeabaseMDObjectsTable
(&cliInterface,
catalogNamePart.data(),
schemaNamePart.data(),
SEABASE_SCHEMA_OBJECTNAME,
regOrUnregObject->objType(),
NULL,
objOwnerId, schemaOwnerId,
flags, objUID);
}
else if (regOrUnregObject->isRegister())
{
if (((regOrUnregObject->objType() == COM_BASE_TABLE_OBJECT) &&
(naTable && naTable->isView())) ||
((regOrUnregObject->objType() == COM_VIEW_OBJECT) &&
(naTable && (! naTable->isView()))))
{
// underlying object is a view but registered object type specified
// in the register statement is a table, or
// underlying object is a table but registered object type specified
// in the register statement is a view
str_sprintf(errReason, " Reason: Mismatch between specified(%s) and underlying(%s) type for %s.",
(regOrUnregObject->objType() == COM_BASE_TABLE_OBJECT ? "TABLE" : "VIEW"),
(naTable->isView() ? "VIEW" : "TABLE"),
regOrUnregObject->getObjNameAsQualifiedName().
getQualifiedNameAsString().data());
*CmpCommon::diags() << DgSqlCode(-3251)
<< DgString0("REGISTER")
<< DgString1(errReason);
processReturn();
return;
}
if (regOrUnregObject->objType() == COM_BASE_TABLE_OBJECT)
{
if (schemaNamePart == HBASE_SYSTEM_SCHEMA)
{
// register CELL and ROW formats of HBase table
retcode = registerNativeTable(
catalogNamePart, HBASE_CELL_SCHEMA, objectNamePart,
objOwnerId, schemaOwnerId,
cliInterface,
regOrUnregObject->isRegister(),
regOrUnregObject->isInternal());
retcode = registerNativeTable(
catalogNamePart, HBASE_ROW_SCHEMA, objectNamePart,
objOwnerId, schemaOwnerId,
cliInterface,
regOrUnregObject->isRegister(),
regOrUnregObject->isInternal());
}
else
{
retcode = registerNativeTable(
catalogNamePart, schemaNamePart, objectNamePart,
objOwnerId, schemaOwnerId,
cliInterface,
regOrUnregObject->isRegister(),
regOrUnregObject->isInternal());
}
}
else // COM_VIEW_OBJECT
{
retcode = registerHiveView(
catalogNamePart, schemaNamePart, objectNamePart,
objOwnerId, schemaOwnerId,
naTable,
cliInterface,
regOrUnregObject->isInternal(),
regOrUnregObject->cascade());
}
if (retcode < 0)
return;
}
else // unregister
{
if ((regOrUnregObject->objType() == COM_BASE_TABLE_OBJECT) ||
(regOrUnregObject->objType() == COM_SHARED_SCHEMA_OBJECT))
{
if (schemaNamePart == HBASE_SYSTEM_SCHEMA)
{
// unregister CELL and ROW formats of HBase table
retcode = unregisterNativeTable(
catalogNamePart, HBASE_CELL_SCHEMA, objectNamePart,
cliInterface);
retcode = unregisterNativeTable(
catalogNamePart, HBASE_ROW_SCHEMA, objectNamePart,
cliInterface);
}
else if ((regOrUnregObject->objType() == COM_SHARED_SCHEMA_OBJECT) &&
(catalogNamePart.index(HIVE_SYSTEM_CATALOG, 0, NAString::ignoreCase) == 0))
{
retcode = unregisterHiveSchema(
catalogNamePart, schemaNamePart,
cliInterface,
regOrUnregObject->cascade());
}
else
{
retcode = unregisterNativeTable(
catalogNamePart, schemaNamePart, objectNamePart,
cliInterface,
(regOrUnregObject->objType() == COM_SHARED_SCHEMA_OBJECT ?
COM_SHARED_SCHEMA_OBJECT : COM_BASE_TABLE_OBJECT));
}
}
else // view
{
retcode = unregisterHiveView(
catalogNamePart, schemaNamePart, objectNamePart,
naTable,
cliInterface,
regOrUnregObject->cascade());
}
} // unregister
if (retcode < 0)
return;
ActiveSchemaDB()->getNATableDB()->removeNATable
(cn,
ComQiScope::REMOVE_FROM_ALL_USERS, regOrUnregObject->objType(),
FALSE, FALSE);
if (isHBase)
{
CorrName cn(objectNamePart, STMTHEAP,
HBASE_ROW_SCHEMA,
catalogNamePart);
ActiveSchemaDB()->getNATableDB()->removeNATable
(cn,
ComQiScope::REMOVE_FROM_ALL_USERS, regOrUnregObject->objType(),
FALSE, FALSE);
}
return;
}
static void processPassthruHiveDDL(StmtDDLonHiveObjects * hddl)
{
NAString hiveQuery(hddl->getHiveDDL());
hiveQuery = hiveQuery.strip(NAString::leading, ' ');
if (NOT ((hiveQuery.index("CREATE ", 0, NAString::ignoreCase) == 0) ||
(hiveQuery.index("DROP ", 0, NAString::ignoreCase) == 0) ||
(hiveQuery.index("ALTER ", 0, NAString::ignoreCase) == 0) ||
(hiveQuery.index("TRUNCATE ", 0, NAString::ignoreCase) == 0) ||
(hiveQuery.index("GRANT ", 0, NAString::ignoreCase) == 0) ||
(hiveQuery.index("REVOKE ", 0, NAString::ignoreCase) == 0) ||
(hiveQuery.index("RELOAD ", 0, NAString::ignoreCase) == 0) ||
(hiveQuery.index("MSCK ", 0, NAString::ignoreCase) == 0)))
{
// error case
*CmpCommon::diags() << DgSqlCode(-3242) << DgString0("Specified DDL operation cannot be executed directly by hive.");
return;
}
if (HiveClient_JNI::executeHiveSQL(hddl->getHiveDDL().data()) != HVC_OK)
{
*CmpCommon::diags() << DgSqlCode(-1214)
<< DgString0(getSqlJniErrorStr())
<< DgString1(hddl->getHiveDDL());
return;
}
return;
} // passthru
void CmpSeabaseDDL::processDDLonHiveObjects(StmtDDLonHiveObjects * hddl,
NAString &currCatName,
NAString &currSchName)
{
Lng32 cliRC = 0;
// For hive ddl operations, grantor must be DB__ROOT or belong
// to one of the admin roles: DB__ROOTROLE or DB__HIVEROLE.
if (!Get_SqlParser_Flags(INTERNAL_QUERY_FROM_EXEUTIL) &&
!ComUser::isRootUserID() &&
!ComUser::currentUserHasRole(ROOT_ROLE_ID) &&
!ComUser::currentUserHasRole(HIVE_ROLE_ID))
{
*CmpCommon::diags() << DgSqlCode (-CAT_NOT_AUTHORIZED);
processReturn();
return;
}
// if passthru ddl specified via "process hive ddl" or "create hive table like"
// stmt, execute the specified string.
if (hddl->getOper() == StmtDDLonHiveObjects::PASSTHRU_DDL_)
{
// error diagnostics is set in CmpCommon::diags
processPassthruHiveDDL(hddl);
return;
}
// Start error checks
if (NOT ((hddl->getOper() == StmtDDLonHiveObjects::CREATE_) ||
(hddl->getOper() == StmtDDLonHiveObjects::DROP_) ||
(hddl->getOper() == StmtDDLonHiveObjects::ALTER_) ||
(hddl->getOper() == StmtDDLonHiveObjects::TRUNCATE_) ||
(hddl->getOper() == StmtDDLonHiveObjects::MSCK_)))
{
// error case
*CmpCommon::diags() << DgSqlCode(-3242) << DgString0("Only CREATE, DROP, ALTER or TRUNCATE DDL commands can be specified on hive objects. Use \"PROCESS HIVE DDL '<ddl-stmt>' \" to directly execute other statements through hive.");
return;
}
if ((hddl->getOper() == StmtDDLonHiveObjects::TRUNCATE_) &&
(hddl->getType() != StmtDDLonHiveObjects::TABLE_))
{
// error case
*CmpCommon::diags() << DgSqlCode(-3242) << DgString0("Only table can be truncated.");
return;
}
if (NOT ((hddl->getType() == StmtDDLonHiveObjects::TABLE_) ||
(hddl->getType() == StmtDDLonHiveObjects::SCHEMA_) ||
(hddl->getType() == StmtDDLonHiveObjects::VIEW_)))
{
// error case
*CmpCommon::diags() << DgSqlCode(-3242) << DgString0("Only TABLE, VIEW or SCHEMA object can be specified. Use \"PROCESS HIVE DDL '<ddl-stmt>' \" to directly execute other statements through hive.");
return;
}
// End error checks
ExeCliInterface cliInterface(STMTHEAP, NULL, NULL,
CmpCommon::context()->sqlSession()->getParentQid());
char buf[4000];
buf[0] = 0;
ComObjectName con(hddl->getName());
con.applyDefaults(currCatName, currSchName);
const NAString &catName = con.getCatalogNamePartAsAnsiString(TRUE);
NAString schName =
((con.getSchemaNamePartAsAnsiString(TRUE).compareTo(HIVE_DEFAULT_SCHEMA_EXE, NAString::ignoreCase) == 0) ?
HIVE_SYSTEM_SCHEMA : con.getSchemaNamePartAsAnsiString(TRUE));
NAString objName = con.getObjectNamePartAsAnsiString(TRUE);
NAString extObjectName;
if (con.getSchemaNamePartAsAnsiString(TRUE).compareTo(HIVE_DEFAULT_SCHEMA_EXE, NAString::ignoreCase) == 0)
extObjectName = HIVE_DEFAULT_SCHEMA_EXE;
else if (schName != HIVE_SYSTEM_SCHEMA)
extObjectName = schName;
if (NOT (hddl->getType() == StmtDDLonHiveObjects::SCHEMA_))
{
if (NOT extObjectName.isNull())
extObjectName += NAString(".");
extObjectName += objName;
}
extObjectName.toLower();
if (NOT (schName.compareTo(HIVE_SYSTEM_SCHEMA, NAString::ignoreCase) == 0))
schName.toUpper();
if (NOT (objName == SEABASE_SCHEMA_OBJECTNAME))
objName.toUpper();
CorrName cnTgt(objName, STMTHEAP, schName, catName);
ComObjectType objType;
NAString objStr;
if (hddl->getType() == StmtDDLonHiveObjects::TABLE_)
{
objType = COM_BASE_TABLE_OBJECT;
objStr = "Table";
}
else if (hddl->getType() == StmtDDLonHiveObjects::SCHEMA_)
{
objType = COM_SHARED_SCHEMA_OBJECT;
cnTgt.setSpecialType(ExtendedQualName::SCHEMA_TABLE);
objStr = "Schema";
}
else
{
objType = COM_VIEW_OBJECT;
objStr = "View";
}
BindWA bindWA(ActiveSchemaDB(), CmpCommon::context(), FALSE/*inDDL*/);
NATable *naTable = bindWA.getNATable(cnTgt);
NABoolean objExists = FALSE;
if (naTable == NULL || bindWA.errStatus())
objExists = FALSE;
else
objExists = TRUE;
NABoolean isRegistered = FALSE;
if (naTable && naTable->isRegistered())
isRegistered = TRUE;
NABoolean hasExternalTable = FALSE;
if (naTable && naTable->hasExternalTable())
hasExternalTable = TRUE;
NABoolean tableWasAltered = FALSE;
NAString alterStmt;
CmpCommon::diags()->clear();
if ((hddl->getOper() == StmtDDLonHiveObjects::DROP_) ||
(hddl->getOper() == StmtDDLonHiveObjects::TRUNCATE_))
{
if (NOT objExists)
{
// return error if 'if exists' option is not specified.
// otherwise just return.
if (NOT hddl->getIfExistsOrNotExists())
{
*CmpCommon::diags() << DgSqlCode(-1388)
<< DgString0(objStr)
<< DgString1(extObjectName);
}
return;
}
}
if (hddl->getOper() == StmtDDLonHiveObjects::CREATE_)
{
if (objExists)
{
// return error if 'if not exists' option is not specified.
// Otherwise just return.
if (NOT hddl->getIfExistsOrNotExists())
{
*CmpCommon::diags() << DgSqlCode(-1387)
<< DgString0(objStr)
<< DgString1(extObjectName);
}
return;
}
}
NABoolean xnWasStartedHere = FALSE;
if (beginXnIfNotInProgress(&cliInterface, xnWasStartedHere))
return;
if ((objExists) &&
(hddl->getOper() == StmtDDLonHiveObjects::DROP_))
{
cliRC = 0;
// drop any external table, if exists
if ((objType == COM_BASE_TABLE_OBJECT) &&
(hasExternalTable))
{
str_sprintf(buf, "drop external table if exists %s.\"%s\".\"%s\" ",
catName.data(), schName.data(), objName.data());
cliRC = cliInterface.executeImmediate(buf);
if (cliRC < 0)
{
cliInterface.retrieveSQLDiagnostics(CmpCommon::diags());
goto label_error;
}
}
if (isRegistered)
{
if (objType == COM_BASE_TABLE_OBJECT)
{
cliRC = unregisterNativeTable(
catName, schName, objName,
cliInterface,
objType);
}
else if (objType == COM_SHARED_SCHEMA_OBJECT)
{
cliRC = unregisterHiveSchema(
catName, schName,
cliInterface,
TRUE /*cascade*/);
}
else if (objType == COM_VIEW_OBJECT)
{
cliRC = unregisterHiveView(
catName, schName, objName,
NULL,
cliInterface,
FALSE); // dont cascade
}
} // isRegistered
if (cliRC < 0)
{
goto label_error;
}
} // drop
if ((CmpCommon::getDefault(HIVE_NO_REGISTER_OBJECTS) == DF_OFF) &&
((hddl->getOper() == StmtDDLonHiveObjects::CREATE_) ||
(hddl->getOper() == StmtDDLonHiveObjects::ALTER_)) &&
(NOT isRegistered))
{
cliRC = 0;
if (objType == COM_SHARED_SCHEMA_OBJECT)
{
Int64 objUID = -1;
Int64 flags = 0;
cliRC =
updateSeabaseMDObjectsTable
(&cliInterface,
catName, schName,
SEABASE_SCHEMA_OBJECTNAME,
objType,
NULL,
HIVE_ROLE_ID, HIVE_ROLE_ID,
flags, objUID);
}
else if (objType == COM_BASE_TABLE_OBJECT)
{
cliRC = registerNativeTable(
catName, schName, objName,
HIVE_ROLE_ID, HIVE_ROLE_ID,
cliInterface,
TRUE, // register
TRUE ); // internal
}
else if (objType == COM_VIEW_OBJECT)
{
cliRC = registerHiveView(
catName, schName, objName,
HIVE_ROLE_ID, HIVE_ROLE_ID,
NULL,
cliInterface,
TRUE, // register
FALSE); // no cascade
}
if (cliRC < 0)
{
goto label_error;
}
} // register this object
// execute the hive DDL statement.
if (HiveClient_JNI::executeHiveSQL(hddl->getHiveDDL().data()) != HVC_OK)
{
*CmpCommon::diags() << DgSqlCode(-1214)
<< DgString0(getSqlJniErrorStr())
<< DgString1(hddl->getHiveDDL());
goto label_error;
}
endXnIfStartedHere(&cliInterface, xnWasStartedHere, 0);
// this ALTER may be a RENAME command.
// If the table being renamed is registered in Traf MD, unregister it.
if (hddl->getOper() == StmtDDLonHiveObjects::ALTER_)
{
// set cqd so NATable is recreated instead of returning cached one.
NABoolean cqdChanged = FALSE;
if (CmpCommon::getDefault(TRAF_RELOAD_NATABLE_CACHE) == DF_OFF)
{
NAString value("ON");
ActiveSchemaDB()->getDefaults().validateAndInsert(
"traf_reload_natable_cache", value, FALSE);
cqdChanged = TRUE;
}
NATable *naTable = bindWA.getNATable(cnTgt);
if (cqdChanged)
{
NAString value("OFF");
ActiveSchemaDB()->getDefaults().validateAndInsert(
"traf_reload_natable_cache", value, FALSE);
}
NABoolean objExists = FALSE;
if (naTable == NULL || bindWA.errStatus())
objExists = FALSE;
else
objExists = TRUE;
if (NOT objExists)
{
CmpCommon::diags()->clear();
cliRC = unregisterNativeTable(
catName, schName, objName,
cliInterface,
objType);
}
}
ActiveSchemaDB()->getNATableDB()->removeNATable
(cnTgt,
ComQiScope::REMOVE_FROM_ALL_USERS,
COM_BASE_TABLE_OBJECT,
FALSE, FALSE);
return;
label_error:
endXnIfStartedHere(&cliInterface, xnWasStartedHere, -1);
return;
}
// ------------------------------------------------------------------------
// setupQueryTreeForHiveDDL
//
// This method is called if a hive ddl statement is seen during parsing.
// When that is detected, information is set in HiveDDLInfo
// and parsing phase errors out.
// This is needed to avoid enhancing the parser with hive ddl syntax.
//
// For example:
// create table hive.hive.t (a int) stored as sequencefile;
// Traf parser does not undertand 'stored as sequencefile' syntax.
// As soon as 'hive.hive.t' is detected, all relevant information is
// stored in HiveDDLInfo class and parsing phase is terminated.
// This method then creates the needed structures so the create stmt could
// be passed on to hive api layer.
//
// Return: 'node' contains the generated tree.
// TRUE, if all ok.
// FALSE, if error.
// -------------------------------------------------------------------------
NABoolean CmpSeabaseDDL::setupQueryTreeForHiveDDL(
Parser::HiveDDLInfo * hiveDDLInfo,
char * inputStr,
CharInfo::CharSet inputStrCharSet,
NAString currCatName,
NAString currSchName,
ExprNode** node)
{
// extract hive ddl info from global SqlParser_CurrentParser. These fields
// are set during parsing.
// ddl operation and type of object.
StmtDDLonHiveObjects::Operation oper =
(StmtDDLonHiveObjects::Operation)hiveDDLInfo->ddlOperation_;
StmtDDLonHiveObjects::ObjectType type =
(StmtDDLonHiveObjects::ObjectType)hiveDDLInfo->ddlObjectType_;
// position and length of the object name specified in the query.
Lng32 hiveNamePos = hiveDDLInfo->ddlNamePos_;
Lng32 hiveNameLen = hiveDDLInfo->ddlNameLen_;
NABoolean ifExistsOrNotExists = hiveDDLInfo->ifExistsOrNotExists_;
NAString &origHiveDDL = hiveDDLInfo->userSpecifiedStmt_;
NAString hiveDDL = origHiveDDL;
NAString hiveNameStr;
if (hiveNameLen > 0)
hiveNameStr = NAString(&origHiveDDL.data()[hiveNamePos], hiveNameLen);
ComObjectName con;
if (hiveNameStr.isNull())
con = NAString("");
else
{
con = hiveNameStr +
((type == StmtDDLonHiveObjects::SCHEMA_) ?
(NAString(".") + "\"" + SEABASE_SCHEMA_OBJECTNAME + "\"") : "");
con.applyDefaults(ComAnsiNamePart(CmpCommon::getDefaultString(CATALOG)),
ComAnsiNamePart(CmpCommon::getDefaultString(SCHEMA)));
}
NAString newHiveName;
newHiveName = ComConvertTrafHiveNameToNativeHiveName
(con.getCatalogNamePartAsAnsiString(TRUE),
con.getSchemaNamePartAsAnsiString(TRUE),
(type != StmtDDLonHiveObjects::SCHEMA_ ?
con.getObjectNamePartAsAnsiString(TRUE) : NAString("")));
if (newHiveName.isNull())
{
PARSERASSERT(1);
}
// remove original name at hiveNamePos/hiveNameLen and replace with the
// newly constructed name.
if ((hiveDDL.length() > 0) && (hiveNameLen > 0))
{
hiveDDL.remove(hiveNamePos, hiveNameLen);
hiveDDL.insert(hiveNamePos, newHiveName);
}
// remove trailing semicolon
if ((hiveDDL.length() > 0) &&
(hiveDDL[hiveDDL.length()-1] == ';'))
hiveDDL.remove(hiveDDL.length()-1);
CmpCommon::diags()->clear();
if (oper == StmtDDLonHiveObjects::MSCK_)
{
// this may be set through 'msck repair table <tablename>' or
// 'alter table <tablename> repair partitions'.
// Underlying Hive may not support the 'alter repair' syntax on
// all platforms.
// Create 'msck' version which is supported.
NAString newHiveDDL("MSCK REPAIR TABLE ");
newHiveDDL += newHiveName;
hiveDDL.clear();
hiveDDL = newHiveDDL;
}
DDLExpr * ddlExpr = NULL;
RelExpr * ddlExprRoot = NULL;
if (oper == StmtDDLonHiveObjects::TRUNCATE_)
{
NAString newHiveDDL("TRUNCATE TABLE ");
newHiveDDL += hiveDDL(hiveNamePos, hiveDDL.length() - hiveNamePos);
hiveDDL.clear();
hiveDDL = newHiveDDL;
CorrName cn(con.getObjectNamePartAsAnsiString(),
PARSERHEAP(),
con.getSchemaNamePartAsAnsiString(),
con.getCatalogNamePartAsAnsiString());
ExeUtilHiveTruncate * ht =
new (PARSERHEAP()) ExeUtilHiveTruncate
(cn, newHiveName, hiveDDL, PARSERHEAP());
if (ifExistsOrNotExists)
ht->setIfExists(TRUE);
ddlExprRoot = new(CmpCommon::statementHeap()) RelRoot(ht);
}
// Construct DDL expr tree for regular query or query
// explain/showplan/showshape/display.
//
// Regular DDL query:
// StmtQuery => RelRoot => DDLExpr => StmtDDLonHiveObjects
//
// explain query:
// StmtQuery => RelRoot => ExeUtilDisplayExplain => RelRoot
// => DDLExpr => StmtDDLonHiveObjects
//
// showplan/showshape:
// StmtQuery => RelRoot => Describe
//
// display:
// same as regular query with displayTree flag set in RelRoot
//
else if (NOT ((hiveDDLInfo->essd_ == Parser::HiveDDLInfo::SHOWPLAN_) ||
(hiveDDLInfo->essd_ == Parser::HiveDDLInfo::SHOWSHAPE_)))
{
// get the hive schema name if set in the session.
BindWA bindWA(ActiveSchemaDB(), CmpCommon::context(), FALSE/*inDDL*/);
NAString hiveDB = ComConvertTrafHiveNameToNativeHiveName
(bindWA.getDefaultSchema().getCatalogName(),
bindWA.getDefaultSchema().getSchemaName(),
NAString(""));
hiveDB.toLower();
StmtDDLonHiveObjects * sdho =
new (PARSERHEAP()) StmtDDLonHiveObjects(oper, type,
ifExistsOrNotExists,
con.getExternalName(),
hiveDDL, hiveDB,
PARSERHEAP());
DDLExpr * ddlExpr = new(CmpCommon::statementHeap())
DDLExpr(sdho, inputStr, inputStrCharSet,
CmpCommon::statementHeap());
ddlExprRoot = new(CmpCommon::statementHeap()) RelRoot(ddlExpr);
}
RelExpr *root = ddlExprRoot;
if (hiveDDLInfo->essd_ == Parser::HiveDDLInfo::EXPLAIN_)
{
ExeUtilDisplayExplain * eue =
new (PARSERHEAP ()) ExeUtilDisplayExplain
(ExeUtilExpr::DISPLAY_EXPLAIN_,
&inputStr[hiveDDLInfo->essdQueryStartPos_],
inputStrCharSet,
NULL, NULL,
(hiveDDLInfo->essdOptions_.isNull() ? NULL :
(char*)hiveDDLInfo->essdOptions_.data()),
ddlExprRoot,
PARSERHEAP());
root = new(CmpCommon::statementHeap()) RelRoot(eue);
}
else if ((hiveDDLInfo->essd_ == Parser::HiveDDLInfo::SHOWPLAN_) ||
(hiveDDLInfo->essd_ == Parser::HiveDDLInfo::SHOWSHAPE_))
{
CorrName c;
Describe * des = NULL;
if (hiveDDLInfo->essd_ == Parser::HiveDDLInfo::SHOWPLAN_)
{
des = new (PARSERHEAP ()) Describe
(inputStr, c, Describe::PLAN_, COM_TABLE_NAME, 0);
}
else
{
des = new (PARSERHEAP ()) Describe
(inputStr, c, Describe::SHAPE_);
}
root = new(CmpCommon::statementHeap())
RelRoot(des, REL_ROOT,
new (PARSERHEAP())
ColReference(new (PARSERHEAP()) ColRefName(TRUE, PARSERHEAP())));
}
// indicate that this is the root for the entire query
if (root)
{
((RelRoot *) root)->setRootFlag(TRUE);
if (hiveDDLInfo->essd_ == Parser::HiveDDLInfo::DISPLAY_)
((RelRoot*)root)->setDisplayTree(TRUE);
}
StmtQuery* query = new(PARSERHEAP()) StmtQuery(root);
*node = query;
return TRUE;
}
/////////////////////////////////////////////////////////////////////////
// This method generates and returns tableInfo struct for internal special
// tables (like metadata, histograms). These tables have hardcoded definitions
// but need objectUID to be returned. ObjectUID is stored in metadata
// and is read from there.
// This is done only if we are not in bootstrap mode, for example, when initializing
// metadata. At that time, there is no metadata available so it cannot be read
// to return objectUID.
// A NULL tableInfo is returned if in bootstrap mode.
//
// RETURN: -1, if error. 0, if all ok.
//////////////////////////////////////////////////////////////////////////
short CmpSeabaseDDL::getSpecialTableInfo
(
NAMemory * heap,
const NAString &catName,
const NAString &schName,
const NAString &objName,
const NAString &extTableName,
const ComObjectType &objType,
ComTdbVirtTableTableInfo* &tableInfo)
{
Lng32 cliRC = 0;
tableInfo = NULL;
NABoolean switched = FALSE;
Int32 objectOwner = NA_UserIdDefault;
Int32 schemaOwner = NA_UserIdDefault;
Int64 objUID = 1; // dummy value
Int64 objectFlags = 0 ;
NABoolean createTableInfo = FALSE;
NABoolean isUninit = FALSE;
if (CmpCommon::context()->isUninitializedSeabase())
{
isUninit = TRUE;
createTableInfo = TRUE;
}
NABoolean getUID = TRUE;
if (isUninit)
getUID = FALSE;
else if (CmpCommon::context()->isMxcmp())
getUID = FALSE;
else if (CmpCommon::getDefault(TRAF_BOOTSTRAP_MD_MODE) == DF_ON)
getUID = FALSE;
if (getUID)
{
ExeCliInterface cliInterface(STMTHEAP, NULL, NULL,
CmpCommon::context()->sqlSession()->getParentQid());
if (switchCompiler(CmpContextInfo::CMPCONTEXT_TYPE_META))
return -1;
cliRC = cliInterface.holdAndSetCQD("traf_bootstrap_md_mode", "ON");
if (cliRC < 0)
{
goto label_error_return;
}
objUID = getObjectInfo(&cliInterface,
catName.data(), schName.data(), objName.data(),
objType, objectOwner, schemaOwner,objectFlags);
cliRC = cliInterface.restoreCQD("traf_bootstrap_md_mode");
if (objUID <= 0)
goto label_error_return;
switchBackCompiler();
createTableInfo = TRUE;
}
if (createTableInfo)
{
tableInfo = new(heap) ComTdbVirtTableTableInfo[1];
tableInfo->tableName = new(heap) char[extTableName.length() + 1];
strcpy((char*)tableInfo->tableName, (char*)extTableName.data());
tableInfo->createTime = 0;
tableInfo->redefTime = 0;
tableInfo->objUID = objUID;
tableInfo->isAudited = 1;
tableInfo->validDef = 1;
tableInfo->objOwnerID = objectOwner;
tableInfo->schemaOwnerID = schemaOwner;
tableInfo->hbaseCreateOptions = NULL;
tableInfo->objectFlags = objectFlags;
tableInfo->tablesFlags = 0;
tableInfo->rowFormat = COM_UNKNOWN_FORMAT_TYPE;
}
return 0;
label_error_return:
switchBackCompiler();
return -1;
}
TrafDesc * CmpSeabaseDDL::getSeabaseMDTableDesc(
const NAString &catName,
const NAString &schName,
const NAString &objName,
const ComObjectType objType)
{
Lng32 cliRC = 0;
TrafDesc * tableDesc = NULL;
NAString schNameL = "\"";
schNameL += schName;
schNameL += "\"";
ComObjectName coName(catName, schNameL, objName);
NAString extTableName = coName.getExternalName(TRUE);
ComTdbVirtTableTableInfo * tableInfo = NULL;
Lng32 colInfoSize = 0;
const ComTdbVirtTableColumnInfo * colInfo = NULL;
Lng32 keyInfoSize = 0;
const ComTdbVirtTableKeyInfo * keyInfo = NULL;
Lng32 uniqueInfoSize = 0;
ComTdbVirtTableConstraintInfo * constrInfo = NULL;
Lng32 indexInfoSize = 0;
const ComTdbVirtTableIndexInfo * indexInfo = NULL;
if (NOT CmpSeabaseMDupgrade::getMDtableInfo(coName,
tableInfo,
colInfoSize, colInfo,
keyInfoSize, keyInfo,
indexInfoSize, indexInfo,
objType))
return NULL;
// Setup the primary key information as a unique constraint
uniqueInfoSize = 1;
constrInfo = new(STMTHEAP) ComTdbVirtTableConstraintInfo[uniqueInfoSize];
constrInfo->baseTableName = (char*)extTableName.data();
// The primary key constraint name is the name of the object appended
// with "_PK";
NAString constrName = extTableName;
constrName += "_PK";
constrInfo->constrName = (char*)constrName.data();
constrInfo->constrType = 3; // pkey_constr
constrInfo->colCount = keyInfoSize;
constrInfo->keyInfoArray = (ComTdbVirtTableKeyInfo *)keyInfo;
constrInfo->numRingConstr = 0;
constrInfo->ringConstrArray = NULL;
constrInfo->numRefdConstr = 0;
constrInfo->refdConstrArray = NULL;
constrInfo->checkConstrLen = 0;
constrInfo->checkConstrText = NULL;
tableDesc =
Generator::createVirtualTableDesc
((char*)extTableName.data(),
NULL, // let it decide what heap to use
colInfoSize,
(ComTdbVirtTableColumnInfo*)colInfo,
keyInfoSize,
(ComTdbVirtTableKeyInfo*)keyInfo,
uniqueInfoSize, constrInfo,
indexInfoSize,
(ComTdbVirtTableIndexInfo *)indexInfo,
0, NULL,
tableInfo);
return tableDesc;
}
TrafDesc * CmpSeabaseDDL::getSeabaseHistTableDesc(const NAString &catName,
const NAString &schName,
const NAString &objName)
{
Lng32 cliRC = 0;
TrafDesc * tableDesc = NULL;
NAString schNameL = "\"";
schNameL += schName;
schNameL += "\""; // transforms internal format schName to external format
ComObjectName coName(catName, schNameL, objName);
NAString extTableName = coName.getExternalName(TRUE);
Lng32 numCols = 0;
ComTdbVirtTableColumnInfo * colInfo = NULL;
Lng32 numKeys;
ComTdbVirtTableKeyInfo * keyInfo;
ComTdbVirtTableIndexInfo * indexInfo;
Parser parser(CmpCommon::context());
parser.hiveDDLInfo_->disableDDLcheck_ = TRUE;
ComTdbVirtTableConstraintInfo * constrInfo =
new(STMTHEAP) ComTdbVirtTableConstraintInfo[1];
NAString constrName;
if (objName == HBASE_HIST_NAME)
{
if (processDDLandCreateDescs(parser,
seabaseHistogramsDDL, sizeof(seabaseHistogramsDDL),
FALSE,
0, NULL, 0, NULL,
numCols, colInfo,
numKeys, keyInfo,
indexInfo))
return NULL;
constrName = HBASE_HIST_PK;
}
else if (objName == HBASE_HISTINT_NAME)
{
if (processDDLandCreateDescs(parser,
seabaseHistogramIntervalsDDL, sizeof(seabaseHistogramIntervalsDDL),
FALSE,
0, NULL, 0, NULL,
numCols, colInfo,
numKeys, keyInfo,
indexInfo))
return NULL;
constrName = HBASE_HISTINT_PK;
}
else
return NULL;
ComObjectName coConstrName(catName, schNameL, constrName);
NAString * extConstrName =
new(STMTHEAP) NAString(coConstrName.getExternalName(TRUE));
constrInfo->baseTableName = (char*)extTableName.data();
constrInfo->constrName = (char*)extConstrName->data();
constrInfo->constrType = 3; // pkey_constr
constrInfo->colCount = numKeys;
constrInfo->keyInfoArray = keyInfo;
constrInfo->numRingConstr = 0;
constrInfo->ringConstrArray = NULL;
constrInfo->numRefdConstr = 0;
constrInfo->refdConstrArray = NULL;
constrInfo->checkConstrLen = 0;
constrInfo->checkConstrText = NULL;
ComTdbVirtTableTableInfo * tableInfo = NULL;
if (getSpecialTableInfo(STMTHEAP, catName, schName, objName,
extTableName, COM_BASE_TABLE_OBJECT, tableInfo))
return NULL;
tableDesc =
Generator::createVirtualTableDesc
((char*)extTableName.data(),
NULL, // let it decide what heap to use
numCols,
colInfo,
numKeys,
keyInfo,
1, constrInfo,
0, NULL,
0, NULL,
tableInfo);
return tableDesc;
}
Lng32 CmpSeabaseDDL::getSeabaseColumnInfo(ExeCliInterface *cliInterface,
Int64 objUID,
const NAString &catName,
const NAString &schName,
const NAString &objName,
char *direction,
NABoolean *isTableSalted,
Lng32 *identityColPos,
Lng32 *numCols,
ComTdbVirtTableColumnInfo **outColInfoArray)
{
char query[3000];
Lng32 cliRC;
if (identityColPos)
*identityColPos = -1;
Queue * tableColInfo = NULL;
str_sprintf(query, "select column_name, column_number, column_class, "
"fs_data_type, column_size, column_precision, column_scale, "
"datetime_start_field, datetime_end_field, trim(is_upshifted), column_flags, "
"nullable, trim(character_set), default_class, default_value, "
"trim(column_heading), hbase_col_family, hbase_col_qualifier, direction, "
"is_optional, flags from %s.\"%s\".%s "
"where object_uid = %ld and direction in (%s)"
"order by 2 for read committed access",
getSystemCatalog(), SEABASE_MD_SCHEMA, SEABASE_COLUMNS,
objUID,
direction);
cliRC = cliInterface->fetchAllRows(tableColInfo, query, 0, FALSE, FALSE, TRUE);
if (cliRC < 0)
{
cliInterface->retrieveSQLDiagnostics(CmpCommon::diags());
return -1;
}
*numCols = tableColInfo->numEntries();
ComTdbVirtTableColumnInfo *colInfoArray =
new(STMTHEAP) ComTdbVirtTableColumnInfo[*numCols];
NABoolean tableIsSalted = FALSE;
tableColInfo->position();
for (Lng32 idx = 0; idx < *numCols; idx++)
{
OutputInfo * oi = (OutputInfo*)tableColInfo->getNext();
ComTdbVirtTableColumnInfo &colInfo = colInfoArray[idx];
char * data = NULL;
Lng32 len = 0;
// get the column name
oi->get(0, data, len);
colInfo.colName = new(STMTHEAP) char[len + 1];
strcpy((char*)colInfo.colName, data);
colInfo.colNumber = *(Lng32*)oi->get(1);
char *colClass = (char*)oi->get(2);
if (strcmp(colClass,COM_USER_COLUMN_LIT) == 0)
colInfo.columnClass = COM_USER_COLUMN;
else if (strcmp(colClass,COM_SYSTEM_COLUMN_LIT) == 0)
colInfo.columnClass = COM_SYSTEM_COLUMN;
else if (strcmp(colClass,COM_ADDED_USER_COLUMN_LIT) == 0)
colInfo.columnClass = COM_ADDED_USER_COLUMN;
else if (strcmp(colClass,COM_ALTERED_USER_COLUMN_LIT) == 0)
colInfo.columnClass = COM_ALTERED_USER_COLUMN;
else if (strcmp(colClass,COM_MV_SYSTEM_ADDED_COLUMN_LIT) == 0)
colInfo.columnClass = COM_MV_SYSTEM_ADDED_COLUMN;
else
CMPASSERT(0);
colInfo.datatype = *(Lng32*)oi->get(3);
colInfo.length = *(Lng32*)oi->get(4);
colInfo.precision = *(Lng32*)oi->get(5);
colInfo.scale = *(Lng32*)oi->get(6);
colInfo.dtStart = *(Lng32 *)oi->get(7);
colInfo.dtEnd = *(Lng32 *)oi->get(8);
if (strcmp((char*)oi->get(9), "Y") == 0)
colInfo.upshifted = -1;
else
colInfo.upshifted = 0;
colInfo.hbaseColFlags = *(ULng32 *)oi->get(10);
colInfo.nullable = *(Lng32 *)oi->get(11);
colInfo.charset =
(SQLCHARSET_CODE)CharInfo::getCharSetEnum((char*)oi->get(12));
colInfo.defaultClass = (ComColumnDefaultClass)*(Lng32 *)oi->get(13);
NAString tempDefVal;
data = NULL;
if (colInfo.defaultClass == COM_USER_DEFINED_DEFAULT ||
colInfo.defaultClass == COM_ALWAYS_COMPUTE_COMPUTED_COLUMN_DEFAULT ||
colInfo.defaultClass == COM_ALWAYS_DEFAULT_COMPUTED_COLUMN_DEFAULT)
{
oi->get(14, data, len);
if (colInfo.defaultClass != COM_USER_DEFINED_DEFAULT)
{
// get computed column definition from text table, but note
// that for older tables the definition may be stored in
// COLUMNS.DEFAULT_VALUE instead (that's returned in "data")
cliRC = getTextFromMD(cliInterface,
objUID,
COM_COMPUTED_COL_TEXT,
colInfo.colNumber,
tempDefVal);
if (cliRC < 0)
{
cliInterface->retrieveSQLDiagnostics(CmpCommon::diags());
return -1;
}
if (strcmp(colInfo.colName,
ElemDDLSaltOptionsClause::getSaltSysColName()) == 0)
tableIsSalted = TRUE;
}
}
else if (colInfo.defaultClass == COM_FUNCTION_DEFINED_DEFAULT)
{
oi->get(14, data, len);
tempDefVal = data ;
}
else if (colInfo.defaultClass == COM_NULL_DEFAULT)
{
tempDefVal = "NULL";
}
else if (colInfo.defaultClass == COM_USER_FUNCTION_DEFAULT)
{
tempDefVal = "USER";
}
else if (colInfo.defaultClass == COM_CURRENT_DEFAULT)
{
tempDefVal = "CURRENT_TIMESTAMP";
}
else if (colInfo.defaultClass == COM_CURRENT_UT_DEFAULT)
{
tempDefVal = "UNIX_TIMESTAMP()";
}
else if (colInfo.defaultClass == COM_UUID_DEFAULT)
{
tempDefVal = "UUID()";
}
else if ((colInfo.defaultClass == COM_IDENTITY_GENERATED_BY_DEFAULT) ||
(colInfo.defaultClass == COM_IDENTITY_GENERATED_ALWAYS))
{
NAString userFunc("SEQNUM(");
NAString seqName;
SequenceGeneratorAttributes::genSequenceName
(catName, schName, objName, colInfo.colName,
seqName);
NAString fullyQSeq = catName + "." + schName + "." + "\"" + seqName + "\"";
tempDefVal = userFunc + fullyQSeq + ")";
if (identityColPos)
*identityColPos = idx;
}
if (! tempDefVal.isNull())
{
data = (char*)tempDefVal.data();
len = tempDefVal.length();
}
if (colInfo.defaultClass != COM_NO_DEFAULT)
{
colInfo.defVal = new(STMTHEAP) char[len + 2];
str_cpy_all((char*)colInfo.defVal, data, len);
char * c = (char*)colInfo.defVal;
c[len] = 0;
c[len+1] = 0;
}
else
colInfo.defVal = NULL;
oi->get(15, data, len);
if (len > 0)
{
colInfo.colHeading = new(STMTHEAP) char[len + 1];
strcpy((char*)colInfo.colHeading, data);
}
else
colInfo.colHeading = NULL;
oi->get(16, data, len);
colInfo.hbaseColFam = new(STMTHEAP) char[len + 1];
strcpy((char*)colInfo.hbaseColFam, data);
oi->get(17, data, len);
colInfo.hbaseColQual = new(STMTHEAP) char[len + 1];
strcpy((char*)colInfo.hbaseColQual, data);
strcpy(colInfo.paramDirection, (char*)oi->get(18));
if (*((char*)oi->get(19)) == 'Y')
colInfo.isOptional = 1;
else
colInfo.isOptional = 0;
colInfo.colFlags = *(Int64 *)oi->get(20);
// temporary code, until we have updated flags to have the salt
// flag set for all tables, even those created before end of November
// 2014, when the flag was added during Trafodion R1.0 development
if (colInfo.defaultClass == COM_ALWAYS_COMPUTE_COMPUTED_COLUMN_DEFAULT &&
strcmp(colInfo.colName,
ElemDDLSaltOptionsClause::getSaltSysColName()) == 0)
colInfo.colFlags |= SEABASE_COLUMN_IS_SALT;
}
if (isTableSalted != NULL)
*isTableSalted = tableIsSalted;
*outColInfoArray = colInfoArray;
return *numCols;
}
ComTdbVirtTableSequenceInfo * CmpSeabaseDDL::getSeabaseSequenceInfo(
const NAString &catName,
const NAString &schName,
const NAString &seqName,
NAString &extSeqName,
Int32 & objectOwner,
Int32 & schemaOwner,
Int64 & seqUID)
{
Lng32 retcode = 0;
Lng32 cliRC = 0;
NAString schNameL = "\"";
schNameL += schName;
schNameL += "\"";
NAString seqNameL = "\"";
seqNameL += seqName;
seqNameL += "\"";
ComObjectName coName(catName, schNameL, seqNameL);
extSeqName = coName.getExternalName(TRUE);
ExeCliInterface cliInterface(STMTHEAP, 0, NULL,
CmpCommon::context()->sqlSession()->getParentQid());
objectOwner = NA_UserIdDefault;
seqUID = -1;
schemaOwner = NA_UserIdDefault;
Int64 objectFlags = 0 ;
seqUID = getObjectInfo(&cliInterface,
catName.data(), schName.data(), seqName.data(),
COM_SEQUENCE_GENERATOR_OBJECT,
objectOwner,schemaOwner,objectFlags,TRUE/*report error*/);
if (seqUID == -1 || objectOwner == 0)
{
// There may not be an error in the diags area, if not, add an error
if (CmpCommon::diags()->getNumber(DgSqlCode::ERROR_) == 0)
SEABASEDDL_INTERNAL_ERROR("getting object UID and owners for get sequence command");
return NULL;
}
char buf[4000];
str_sprintf(buf, "select fs_data_type, start_value, increment, max_value, min_value, cycle_option, cache_size, next_value, seq_type, redef_ts from %s.\"%s\".%s where seq_uid = %ld",
getSystemCatalog(), SEABASE_MD_SCHEMA, SEABASE_SEQ_GEN,
seqUID);
Queue * seqQueue = NULL;
cliRC = cliInterface.fetchAllRows(seqQueue, buf, 0, FALSE, FALSE, TRUE);
if (cliRC < 0)
{
cliInterface.retrieveSQLDiagnostics(CmpCommon::diags());
return NULL;
}
if ((seqQueue->numEntries() == 0) ||
(seqQueue->numEntries() > 1))
{
*CmpCommon::diags() << DgSqlCode(-4082)
<< DgTableName(extSeqName);
return NULL;
}
ComTdbVirtTableSequenceInfo *seqInfo =
new (STMTHEAP) ComTdbVirtTableSequenceInfo();
seqQueue->position();
OutputInfo * vi = (OutputInfo*)seqQueue->getNext();
seqInfo->datatype = *(Lng32*)vi->get(0);
seqInfo->startValue = *(Int64*)vi->get(1);
seqInfo->increment = *(Int64*)vi->get(2);
seqInfo->maxValue = *(Int64*)vi->get(3);
seqInfo->minValue = *(Int64*)vi->get(4);
seqInfo->cycleOption = (memcmp(vi->get(5), COM_YES_LIT, 1) == 0 ? 1 : 0);
seqInfo->cache = *(Int64*)vi->get(6);
seqInfo->nextValue = *(Int64*)vi->get(7);
seqInfo->seqType = (memcmp(vi->get(8), "E", 1) == 0 ? COM_EXTERNAL_SG : COM_INTERNAL_SG);
seqInfo->seqUID = seqUID;
seqInfo->redefTime = *(Int64*)vi->get(9);
return seqInfo;
}
// ****************************************************************************
// Method: getSeabasePrivInfo
//
// This method retrieves the list of privilege descriptors for each user that
// has been granted an object or column level privilege on the object.
// ****************************************************************************
ComTdbVirtTablePrivInfo * CmpSeabaseDDL::getSeabasePrivInfo(
const Int64 objUID,
const ComObjectType objType)
{
if (!isAuthorizationEnabled())
return NULL;
// Prepare to call privilege manager
NAString MDLoc;
CONCAT_CATSCH(MDLoc, getSystemCatalog(), SEABASE_MD_SCHEMA);
NAString privMgrMDLoc;
CONCAT_CATSCH(privMgrMDLoc, getSystemCatalog(), SEABASE_PRIVMGR_SCHEMA);
// Summarize privileges for object
PrivStatus privStatus = STATUS_GOOD;
std::vector<PrivMgrDesc> privDescs;
PrivMgrCommands command(std::string(MDLoc.data()),
std::string(privMgrMDLoc.data()),
CmpCommon::diags());
if (command.getPrivileges(objUID, objType, privDescs) != STATUS_GOOD)
{
*CmpCommon::diags() << DgSqlCode(-CAT_UNABLE_TO_RETRIEVE_PRIVS);
return NULL;
}
ComTdbVirtTablePrivInfo *privInfo = new (STMTHEAP) ComTdbVirtTablePrivInfo();
// PrivMgrDesc operator= is a deep copy
privInfo->privmgr_desc_list = new (STMTHEAP) NAList<PrivMgrDesc>(STMTHEAP);
for (size_t i = 0; i < privDescs.size(); i++)
privInfo->privmgr_desc_list->insert(privDescs[i]);
return privInfo;
}
TrafDesc * CmpSeabaseDDL::getSeabaseLibraryDesc(
const NAString &catName,
const NAString &schName,
const NAString &libraryName)
{
TrafDesc * tableDesc = NULL;
NAString extLibName;
Int32 objectOwner = 0;
Int32 schemaOwner = 0;
Int64 objectFlags = 0 ;
char query[4000];
char buf[4000];
ExeCliInterface cliInterface(STMTHEAP, 0, NULL,
CmpCommon::context()->sqlSession()->getParentQid());
if (switchCompiler(CmpContextInfo::CMPCONTEXT_TYPE_META))
return NULL;
Int64 libUID = getObjectInfo(&cliInterface,
catName.data(), schName.data(),
libraryName.data(),
COM_LIBRARY_OBJECT,
objectOwner, schemaOwner,objectFlags);
if (libUID == -1)
{
switchBackCompiler();
return NULL;
}
str_sprintf(buf, "SELECT library_filename, version "
"FROM %s.\"%s\".%s "
"WHERE library_uid = %ld "
"FOR READ COMMITTED ACCESS",
getSystemCatalog(),SEABASE_MD_SCHEMA,SEABASE_LIBRARIES,libUID);
Int32 cliRC = cliInterface.fetchRowsPrologue(buf, TRUE/*no exec*/);
if (cliRC < 0)
{
cliInterface.retrieveSQLDiagnostics(CmpCommon::diags());
switchBackCompiler();
return NULL;
}
cliRC = cliInterface.clearExecFetchClose(NULL, 0);
if (cliRC < 0)
{
cliInterface.retrieveSQLDiagnostics(CmpCommon::diags());
switchBackCompiler();
return NULL;
}
if (cliRC == 100) // did not find the row
{
*CmpCommon::diags() << DgSqlCode(-CAT_OBJECT_DOES_NOT_EXIST_IN_TRAFODION)
<< DgString0(libraryName);
switchBackCompiler();
return NULL;
}
switchBackCompiler();
char * ptr = NULL;
Lng32 len = 0;
ComTdbVirtTableLibraryInfo *libraryInfo = new (STMTHEAP) ComTdbVirtTableLibraryInfo();
if (libraryInfo == NULL)
return NULL;
libraryInfo->library_name = libraryName.data();
cliInterface.getPtrAndLen(1, ptr, len);
libraryInfo->library_filename = new (STMTHEAP) char[len + 1];
str_cpy_and_null((char *)libraryInfo->library_filename, ptr, len, '\0', ' ', TRUE);
cliInterface.getPtrAndLen(2, ptr, len);
libraryInfo->library_version = *(Int32 *)ptr;
libraryInfo->object_owner_id = objectOwner;
libraryInfo->schema_owner_id = schemaOwner;
libraryInfo->library_UID = libUID;
TrafDesc *library_desc = Generator::createVirtualLibraryDesc(
libraryName.data(),
libraryInfo, NULL);
processReturn();
return library_desc;
}
TrafDesc * CmpSeabaseDDL::getSeabaseSequenceDesc(const NAString &catName,
const NAString &schName,
const NAString &seqName)
{
TrafDesc * tableDesc = NULL;
NAString extSeqName;
Int32 objectOwner = 0;
Int32 schemaOwner = 0;
Int64 seqUID = -1;
ComTdbVirtTableSequenceInfo * seqInfo =
getSeabaseSequenceInfo(catName, schName, seqName, extSeqName,
objectOwner, schemaOwner, seqUID);
if (! seqInfo)
{
return NULL;
}
ComTdbVirtTablePrivInfo * privInfo =
getSeabasePrivInfo(seqUID, COM_SEQUENCE_GENERATOR_OBJECT);
ComTdbVirtTableTableInfo * tableInfo =
new(STMTHEAP) ComTdbVirtTableTableInfo[1];
tableInfo->tableName = extSeqName.data();
tableInfo->createTime = 0;
tableInfo->redefTime = 0;
tableInfo->objUID = seqUID;
tableInfo->isAudited = 0;
tableInfo->validDef = 1;
tableInfo->objOwnerID = objectOwner;
tableInfo->schemaOwnerID = schemaOwner;
tableInfo->hbaseCreateOptions = NULL;
tableInfo->objectFlags = 0;
tableInfo->tablesFlags = 0;
tableDesc =
Generator::createVirtualTableDesc
((char*)extSeqName.data(),
NULL, // let it decide what heap to use
0, NULL, // colInfo
0, NULL, // keyInfo
0, NULL,
0, NULL, //indexInfo
0, NULL, // viewInfo
tableInfo,
seqInfo,
NULL, NULL, // endKeyArray, snapshotName
FALSE, NULL, FALSE, // genPackedDesc, packedDescLen, isUserTable
privInfo);
return tableDesc;
}
short CmpSeabaseDDL::genHbaseRegionDescs(TrafDesc * desc,
const NAString &catName,
const NAString &schName,
const NAString &objName)
{
if (! desc)
return -1;
ExpHbaseInterface* ehi = allocEHI();
if (ehi == NULL)
return -1;
NAString extNameForHbase;
if ((catName != HBASE_SYSTEM_CATALOG) ||
((schName != HBASE_ROW_SCHEMA) && (schName != HBASE_CELL_SCHEMA)))
extNameForHbase = genHBaseObjName(catName, schName, objName);
else
// for HBASE._ROW_.objName or HBASE._CELL_.objName, just pass objName
extNameForHbase = objName;
NAArray<HbaseStr>* endKeyArray =
ehi->getRegionEndKeys(extNameForHbase);
TrafDesc * regionKeyDesc =
Generator::assembleDescs(endKeyArray, heap_);
deallocEHI(ehi);
TrafTableDesc* tDesc = desc->tableDesc();
if (tDesc)
tDesc->hbase_regionkey_desc = regionKeyDesc;
else {
TrafIndexesDesc* iDesc = desc->indexesDesc();
if (iDesc)
iDesc->hbase_regionkey_desc = regionKeyDesc;
else
return -1;
}
return 0;
}
TrafDesc * CmpSeabaseDDL::getSeabaseUserTableDesc(const NAString &catName,
const NAString &schName,
const NAString &objName,
const ComObjectType objType,
NABoolean includeInvalidDefs,
Int32 ctlFlags,
Int32 &packedDescLen)
{
Lng32 retcode = 0;
Lng32 cliRC = 0;
char query[4000];
ExeCliInterface cliInterface(STMTHEAP, 0, NULL,
CmpCommon::context()->sqlSession()->getParentQid());
TrafDesc * tableDesc = NULL;
Int32 objectOwner = 0 ;
Int32 schemaOwner = 0 ;
Int64 objUID = -1 ;
Int64 objectFlags = 0 ;
//
// For performance reasons, whenever possible, we want to issue only one
// "select" to the OBJECTS metadata table to determine both the existence
// of the specified table and the objUID for the table. Since it is more
// likely that a user query refers to tables (directly or indirectly) that
// are already in existence, this optimization can save the cost of the
// existence check for all such user objects. In the less likely case that
// an object does not exist we must drop back and re-issue the metadata
// query for the existence check in order to ensure we get the proper error
// reported.
//
NABoolean checkForValidDef = TRUE;
if ((includeInvalidDefs) ||
(Get_SqlParser_Flags(INTERNAL_QUERY_FROM_EXEUTIL)) ||
(objType == COM_INDEX_OBJECT))
checkForValidDef = FALSE;
if ( objType ) // Must have objType
{
objUID = getObjectInfo(&cliInterface,
catName.data(), schName.data(), objName.data(),
objType, objectOwner, schemaOwner,objectFlags, FALSE /*no error now */,
checkForValidDef);
}
// If we didn't call getObjectInfo() above OR if it gave an error, then:
if ( objUID < 0 )
{
cliRC = existsInSeabaseMDTable(&cliInterface,
catName.data(), schName.data(), objName.data(),
COM_UNKNOWN_OBJECT,
checkForValidDef,
TRUE, TRUE);
if (cliRC < 0)
{
processReturn();
return NULL;
}
if (cliRC == 0) // doesn't exist
{
processReturn();
return NULL;
}
}
if (objUID < 0)
{
if (objType != COM_BASE_TABLE_OBJECT)
{
processReturn();
return NULL;
}
else
{
// object type passed in was for a table. Could not find it but.
// this could be a view. Look for that.
CmpCommon::diags()->clear();
objUID = getObjectInfo(&cliInterface,
catName.data(), schName.data(), objName.data(), COM_VIEW_OBJECT,
objectOwner,schemaOwner,objectFlags);
if (objUID < 0)
{
processReturn();
return NULL;
}
}
}
if ((ctlFlags & READ_OBJECT_DESC) && // read stored descriptor
((objectFlags & MD_OBJECTS_STORED_DESC) != 0) && // stored desc available
((objectFlags & MD_OBJECTS_DISABLE_STORED_DESC) == 0)) // not disabled
{
TrafDesc * desc = NULL;
// if good stored desc was retrieved, return it.
// Otherwise, continue and generate descriptor the old fashioned way.
if (! checkAndGetStoredObjectDesc(&cliInterface, objUID, &desc))
{
CmpCommon::diags()->clear();
return desc;
}
// clear diags and continue
CmpCommon::diags()->clear();
}
str_sprintf(query, "select is_audited, num_salt_partns, row_format, flags from %s.\"%s\".%s where table_uid = %ld for read committed access",
getSystemCatalog(), SEABASE_MD_SCHEMA, SEABASE_TABLES,
objUID);
Queue * tableAttrQueue = NULL;
cliRC = cliInterface.fetchAllRows(tableAttrQueue, query, 0, FALSE, FALSE, TRUE);
if (cliRC < 0)
{
cliInterface.retrieveSQLDiagnostics(CmpCommon::diags());
processReturn();
return NULL;
}
Int64 tablesFlags = 0;
NABoolean isAudited = TRUE;
Lng32 numSaltPartns = 0;
NABoolean alignedFormat = FALSE;
NABoolean hbaseStrDataFormat = FALSE;
NAString * hbaseCreateOptions = new(STMTHEAP) NAString();
NAString colFamStr;
if (cliRC == 0) // read some rows
{
if (tableAttrQueue->entries() != 1) // only one row should be returned
{
processReturn();
return NULL;
}
tableAttrQueue->position();
OutputInfo * vi = (OutputInfo*)tableAttrQueue->getNext();
char * audit = vi->get(0);
isAudited = (memcmp(audit, COM_YES_LIT, 1) == 0);
numSaltPartns = *(Lng32*)vi->get(1);
char * format = vi->get(2);
alignedFormat = (memcmp(format, COM_ALIGNED_FORMAT_LIT, 2) == 0);
hbaseStrDataFormat = (memcmp(format, COM_HBASE_STR_FORMAT_LIT, 2) == 0);
tablesFlags = *(Int64*)vi->get(3);
if (getTextFromMD(&cliInterface, objUID, COM_HBASE_OPTIONS_TEXT, 0,
*hbaseCreateOptions))
{
processReturn();
return NULL;
}
if (getTextFromMD(&cliInterface, objUID, COM_HBASE_COL_FAMILY_TEXT, 0,
colFamStr))
{
processReturn();
return NULL;
}
}
Lng32 numCols;
ComTdbVirtTableColumnInfo * colInfoArray;
NABoolean tableIsSalted = FALSE;
char direction[20];
str_sprintf(direction, "'%s'", COM_UNKNOWN_PARAM_DIRECTION_LIT);
Lng32 identityColPos = -1;
if (getSeabaseColumnInfo(&cliInterface,
objUID,
catName, schName, objName,
(char *)direction,
&tableIsSalted,
&identityColPos,
&numCols,
&colInfoArray) <= 0)
{
processReturn();
return NULL;
}
if (objType == COM_INDEX_OBJECT)
{
str_sprintf(query, "select k.column_name, c.column_number, k.keyseq_number, ordering, cast(0 as int not null) from %s.\"%s\".%s k, %s.\"%s\".%s c where k.column_name = c.column_name and k.object_uid = c.object_uid and k.object_uid = %ld and k.nonkeycol = 0 for read committed access order by keyseq_number",
getSystemCatalog(), SEABASE_MD_SCHEMA, SEABASE_KEYS,
getSystemCatalog(), SEABASE_MD_SCHEMA, SEABASE_COLUMNS,
objUID);
}
else
{
str_sprintf(query, "select column_name, column_number, keyseq_number, ordering, cast(0 as int not null) from %s.\"%s\".%s where object_uid = %ld and nonkeycol = 0 for read committed access order by keyseq_number",
getSystemCatalog(), SEABASE_MD_SCHEMA, SEABASE_KEYS,
objUID);
}
Queue * tableKeyInfo = NULL;
cliRC = cliInterface.fetchAllRows(tableKeyInfo, query, 0, FALSE, FALSE, TRUE);
if (cliRC < 0)
{
cliInterface.retrieveSQLDiagnostics(CmpCommon::diags());
processReturn();
return NULL;
}
ComTdbVirtTableKeyInfo * keyInfoArray = NULL;
if (tableKeyInfo->numEntries() > 0)
{
keyInfoArray =
new(STMTHEAP) ComTdbVirtTableKeyInfo[tableKeyInfo->numEntries()];
}
tableKeyInfo->position();
for (int idx = 0; idx < tableKeyInfo->numEntries(); idx++)
{
OutputInfo * vi = (OutputInfo*)tableKeyInfo->getNext();
populateKeyInfo(keyInfoArray[idx], vi);
}
str_sprintf(query, "select O.catalog_name, O.schema_name, O.object_name, I.keytag, I.is_unique, I.is_explicit, I.key_colcount, I.nonkey_colcount, T.num_salt_partns, T.row_format, I.index_uid from %s.\"%s\".%s I, %s.\"%s\".%s O , %s.\"%s\".%s T where I.base_table_uid = %ld and I.index_uid = O.object_uid %s and I.index_uid = T.table_uid for read committed access order by 1,2,3",
getSystemCatalog(), SEABASE_MD_SCHEMA, SEABASE_INDEXES,
getSystemCatalog(), SEABASE_MD_SCHEMA, SEABASE_OBJECTS,
getSystemCatalog(), SEABASE_MD_SCHEMA, SEABASE_TABLES,
objUID,
(includeInvalidDefs ? " " : " and O.valid_def = 'Y' "));
//Turn off CQDs MERGE_JOINS and HASH_JOINS to avoid a full table scan of
//SEABASE_OBJECTS table. Full table scan of SEABASE_OBJECTS table causes
//simultaneous DDL operations to run into conflict.
//Make sure to restore the CQDs after this query including error paths.
cliInterface.holdAndSetCQD("MERGE_JOINS", "OFF");
cliInterface.holdAndSetCQD("HASH_JOINS", "OFF");
Queue * indexInfoQueue = NULL;
cliRC = cliInterface.fetchAllRows(indexInfoQueue, query, 0, FALSE, FALSE, TRUE);
if (cliRC < 0)
{
cliInterface.retrieveSQLDiagnostics(CmpCommon::diags());
processReturn();
}
//restore CQDs.
cliInterface.restoreCQD("MERGE_JOINS");
cliInterface.restoreCQD("HASH_JOINS");
if (cliRC < 0)
return NULL;
ComTdbVirtTableIndexInfo * indexInfoArray = NULL;
if (indexInfoQueue->numEntries() > 0)
{
indexInfoArray =
new(STMTHEAP) ComTdbVirtTableIndexInfo[indexInfoQueue->numEntries()];
}
NAString qCatName = "\"";
qCatName += catName;
qCatName += "\"";
NAString qSchName = "\"";
qSchName += schName;
qSchName += "\"";
NAString qObjName = "\"";
qObjName += objName;
qObjName += "\"";
ComObjectName coName(qCatName, qSchName, qObjName);
NAString * extTableName =
new(STMTHEAP) NAString(coName.getExternalName(TRUE));
const NAString extNameForHbase = catName + "." + schName + "." + objName;
indexInfoQueue->position();
for (int idx = 0; idx < indexInfoQueue->numEntries(); idx++)
{
OutputInfo * vi = (OutputInfo*)indexInfoQueue->getNext();
char * idxCatName = (char*)vi->get(0);
char * idxSchName = (char*)vi->get(1);
char * idxObjName = (char*)vi->get(2);
Lng32 keyTag = *(Lng32*)vi->get(3);
Lng32 isUnique = *(Lng32*)vi->get(4);
Lng32 isExplicit = *(Lng32*)vi->get(5);
Lng32 keyColCount = *(Lng32*)vi->get(6);
Lng32 nonKeyColCount = *(Lng32*)vi->get(7);
Lng32 idxNumSaltPartns = *(Lng32*)vi->get(8);
char * format = vi->get(9);
Int64 indexUID = *(Int64*)vi->get(10);
ComRowFormat idxRowFormat;
if (memcmp(format, COM_ALIGNED_FORMAT_LIT, 2) == 0)
idxRowFormat = COM_ALIGNED_FORMAT_TYPE;
else
if (memcmp(format, COM_HBASE_FORMAT_LIT, 2) == 0)
idxRowFormat = COM_HBASE_FORMAT_TYPE;
else
idxRowFormat = COM_UNKNOWN_FORMAT_TYPE;
Int64 idxUID = getObjectUID(&cliInterface,
idxCatName, idxSchName, idxObjName,
COM_INDEX_OBJECT_LIT);
if (idxUID < 0)
{
processReturn();
return NULL;
}
NAString * idxHbaseCreateOptions = new(STMTHEAP) NAString();
if (getTextFromMD(&cliInterface, idxUID, COM_HBASE_OPTIONS_TEXT, 0,
*idxHbaseCreateOptions))
{
processReturn();
return NULL;
}
indexInfoArray[idx].baseTableName = (char*)extTableName->data();
NAString qIdxCatName = "\"";
qIdxCatName += idxCatName;
qIdxCatName += "\"";
NAString qIdxSchName = "\"";
qIdxSchName += idxSchName;
qIdxSchName += "\"";
NAString qIdxObjName = "\"";
qIdxObjName += idxObjName;
qIdxObjName += "\"";
ComObjectName coIdxName(qIdxCatName, qIdxSchName, qIdxObjName);
NAString * extIndexName =
new(STMTHEAP) NAString(coIdxName.getExternalName(TRUE));
indexInfoArray[idx].indexName = (char*)extIndexName->data();
indexInfoArray[idx].indexUID = indexUID;
indexInfoArray[idx].keytag = keyTag;
indexInfoArray[idx].isUnique = isUnique;
indexInfoArray[idx].isExplicit = isExplicit;
indexInfoArray[idx].keyColCount = keyColCount;
indexInfoArray[idx].nonKeyColCount = nonKeyColCount;
indexInfoArray[idx].hbaseCreateOptions =
(idxHbaseCreateOptions->isNull() ? NULL : idxHbaseCreateOptions->data());
indexInfoArray[idx].numSaltPartns = idxNumSaltPartns;
indexInfoArray[idx].rowFormat = idxRowFormat;
Queue * keyInfoQueue = NULL;
str_sprintf(query, "select column_name, column_number, keyseq_number, ordering, nonkeycol from %s.\"%s\".%s where object_uid = %ld for read committed access order by keyseq_number",
getSystemCatalog(), SEABASE_MD_SCHEMA, SEABASE_KEYS,
idxUID);
cliRC = cliInterface.initializeInfoList(keyInfoQueue, TRUE);
if (cliRC < 0)
{
cliInterface.retrieveSQLDiagnostics(CmpCommon::diags());
processReturn();
return NULL;
}
cliRC = cliInterface.fetchAllRows(keyInfoQueue, query);
if (cliRC < 0)
{
cliInterface.retrieveSQLDiagnostics(CmpCommon::diags());
processReturn();
return NULL;
}
if (keyInfoQueue->numEntries() == 0)
{
*CmpCommon::diags() << DgSqlCode(-4400);
processReturn();
return NULL;
}
ComTdbVirtTableKeyInfo * keyInfoArray =
new(STMTHEAP) ComTdbVirtTableKeyInfo[keyColCount];
ComTdbVirtTableKeyInfo * nonKeyInfoArray = NULL;
if (nonKeyColCount > 0)
{
nonKeyInfoArray =
new(STMTHEAP) ComTdbVirtTableKeyInfo[nonKeyColCount];
}
keyInfoQueue->position();
Lng32 jk = 0;
Lng32 jnk = 0;
for (Lng32 j = 0; j < keyInfoQueue->numEntries(); j++)
{
OutputInfo * vi = (OutputInfo*)keyInfoQueue->getNext();
Lng32 nonKeyCol = *(Lng32*)vi->get(4);
if (nonKeyCol == 0)
{
populateKeyInfo(keyInfoArray[jk], vi, TRUE);
jk++;
}
else
{
if (nonKeyInfoArray)
{
populateKeyInfo(nonKeyInfoArray[jnk], vi, TRUE);
jnk++;
}
}
}
indexInfoArray[idx].keyInfoArray = keyInfoArray;
indexInfoArray[idx].nonKeyInfoArray = nonKeyInfoArray;
} // for
// get constraint info
str_sprintf(query, "select O.object_name, C.constraint_type, C.col_count, C.constraint_uid, C.enforced, C.flags from %s.\"%s\".%s O, %s.\"%s\".%s C where O.catalog_name = '%s' and O.schema_name = '%s' and C.table_uid = %ld and O.object_uid = C.constraint_uid order by 1",
getSystemCatalog(), SEABASE_MD_SCHEMA, SEABASE_OBJECTS,
getSystemCatalog(), SEABASE_MD_SCHEMA, SEABASE_TABLE_CONSTRAINTS,
catName.data(), schName.data(),
objUID);
Queue * constrInfoQueue = NULL;
cliRC = cliInterface.fetchAllRows(constrInfoQueue, query, 0, FALSE, FALSE, TRUE);
if (cliRC < 0)
{
cliInterface.retrieveSQLDiagnostics(CmpCommon::diags());
processReturn();
return NULL;
}
ComTdbVirtTableConstraintInfo * constrInfoArray = NULL;
if (constrInfoQueue->numEntries() > 0)
{
constrInfoArray =
new(STMTHEAP) ComTdbVirtTableConstraintInfo[constrInfoQueue->numEntries()];
}
NAString tableCatName = "\"";
tableCatName += catName;
tableCatName += "\"";
NAString tableSchName = "\"";
tableSchName += schName;
tableSchName += "\"";
NAString tableObjName = "\"";
tableObjName += objName;
tableObjName += "\"";
ComObjectName coTableName(tableCatName, tableSchName, tableObjName);
extTableName =
new(STMTHEAP) NAString(coTableName.getExternalName(TRUE));
NABoolean pkeyNotSerialized = FALSE;
constrInfoQueue->position();
for (int idx = 0; idx < constrInfoQueue->numEntries(); idx++)
{
OutputInfo * vi = (OutputInfo*)constrInfoQueue->getNext();
char * constrName = (char*)vi->get(0);
char * constrType = (char*)vi->get(1);
Lng32 colCount = *(Lng32*)vi->get(2);
Int64 constrUID = *(Int64*)vi->get(3);
char * enforced = (char*)vi->get(4);
Int64 flags = *(Int64*)vi->get(5);
constrInfoArray[idx].baseTableName = (char*)extTableName->data();
NAString cnNas = "\"";
cnNas += constrName;
cnNas += "\"";
ComObjectName coConstrName(tableCatName, tableSchName, cnNas);
NAString * extConstrName =
new(STMTHEAP) NAString(coConstrName.getExternalName(TRUE));
constrInfoArray[idx].constrName = (char*)extConstrName->data();
constrInfoArray[idx].colCount = colCount;
if (strcmp(constrType, COM_UNIQUE_CONSTRAINT_LIT) == 0)
constrInfoArray[idx].constrType = 0; // unique_constr
else if (strcmp(constrType, COM_FOREIGN_KEY_CONSTRAINT_LIT) == 0)
constrInfoArray[idx].constrType = 1; // ref_constr
else if (strcmp(constrType, COM_CHECK_CONSTRAINT_LIT) == 0)
constrInfoArray[idx].constrType = 2; // check_constr
else if (strcmp(constrType, COM_PRIMARY_KEY_CONSTRAINT_LIT) == 0)
constrInfoArray[idx].constrType = 3; // pkey_constr
if ((constrInfoArray[idx].constrType == 3) && // pkey. TBD: Add Enum
(CmpSeabaseDDL::isMDflagsSet(flags, CmpSeabaseDDL::MD_TABLE_CONSTRAINTS_PKEY_NOT_SERIALIZED_FLG)))
constrInfoArray[idx].notSerialized = 1;
else
constrInfoArray[idx].notSerialized = 0;
if (strcmp(enforced, COM_YES_LIT) == 0)
constrInfoArray[idx].isEnforced = 1;
else
constrInfoArray[idx].isEnforced = 0;
Queue * keyInfoQueue = NULL;
str_sprintf(query, "select column_name, column_number, keyseq_number, ordering , cast(0 as int not null) from %s.\"%s\".%s where object_uid = %ld for read committed access order by keyseq_number",
getSystemCatalog(), SEABASE_MD_SCHEMA, SEABASE_KEYS,
constrUID);
cliRC = cliInterface.initializeInfoList(keyInfoQueue, TRUE);
if (cliRC < 0)
{
cliInterface.retrieveSQLDiagnostics(CmpCommon::diags());
processReturn();
return NULL;
}
cliRC = cliInterface.fetchAllRows(keyInfoQueue, query);
if (cliRC < 0)
{
cliInterface.retrieveSQLDiagnostics(CmpCommon::diags());
processReturn();
return NULL;
}
ComTdbVirtTableKeyInfo * keyInfoArray = NULL;
if (colCount > 0)
{
keyInfoArray =
new(STMTHEAP) ComTdbVirtTableKeyInfo[colCount];
keyInfoQueue->position();
Lng32 jk = 0;
for (Lng32 j = 0; j < keyInfoQueue->numEntries(); j++)
{
OutputInfo * vi = (OutputInfo*)keyInfoQueue->getNext();
populateKeyInfo(keyInfoArray[jk], vi, TRUE);
jk++;
}
}
constrInfoArray[idx].keyInfoArray = keyInfoArray;
constrInfoArray[idx].numRingConstr = 0;
constrInfoArray[idx].ringConstrArray = NULL;
constrInfoArray[idx].numRefdConstr = 0;
constrInfoArray[idx].refdConstrArray = NULL;
constrInfoArray[idx].checkConstrLen = 0;
constrInfoArray[idx].checkConstrText = NULL;
// attach all the referencing constraints
if ((strcmp(constrType, COM_UNIQUE_CONSTRAINT_LIT) == 0) ||
(strcmp(constrType, COM_PRIMARY_KEY_CONSTRAINT_LIT) == 0))
{
// force the query plan; without this we tend to do full scans of
// TABLE_CONSTRAINTS which reduces DDL concurrency
str_sprintf(query,"control query shape sort(nested_join(nested_join(nested_join(scan('U'),scan('O')), scan('T','TRAFODION.\"_MD_\".TABLE_CONSTRAINTS_IDX')),cut))");
cliRC = cliInterface.setCQS(query);
if (cliRC < 0)
{
cliInterface.retrieveSQLDiagnostics(CmpCommon::diags());
processReturn();
return NULL;
}
str_sprintf(query, "select trim(O.catalog_name || '.' || '\"' || O.schema_name || '\"' || '.' || '\"' || O.object_name || '\"' ) constr_name, trim(O2.catalog_name || '.' || '\"' || O2.schema_name || '\"' || '.' || '\"' || O2.object_name || '\"' ) table_name from %s.\"%s\".%s U, %s.\"%s\".%s O, %s.\"%s\".%s O2, %s.\"%s\".%s T where O.object_uid = U.foreign_constraint_uid and O2.object_uid = T.table_uid and T.constraint_uid = U.foreign_constraint_uid and U.unique_constraint_uid = %ld order by 2, 1",
getSystemCatalog(), SEABASE_MD_SCHEMA, SEABASE_UNIQUE_REF_CONSTR_USAGE,
getSystemCatalog(), SEABASE_MD_SCHEMA, SEABASE_OBJECTS,
getSystemCatalog(), SEABASE_MD_SCHEMA, SEABASE_OBJECTS,
getSystemCatalog(), SEABASE_MD_SCHEMA, SEABASE_TABLE_CONSTRAINTS,
constrUID
);
Queue * ringInfoQueue = NULL;
cliRC = cliInterface.fetchAllRows(ringInfoQueue, query, 0, FALSE, FALSE, TRUE);
if (cliRC < 0)
{
cliInterface.retrieveSQLDiagnostics(CmpCommon::diags());
processReturn();
cliInterface.resetCQS();
return NULL;
}
cliInterface.resetCQS();
ComTdbVirtTableRefConstraints * ringInfoArray = NULL;
if (ringInfoQueue->numEntries() > 0)
{
ringInfoArray =
new(STMTHEAP) ComTdbVirtTableRefConstraints[ringInfoQueue->numEntries()];
}
ringInfoQueue->position();
for (Lng32 i = 0; i < ringInfoQueue->numEntries(); i++)
{
OutputInfo * vi = (OutputInfo*)ringInfoQueue->getNext();
ringInfoArray[i].constrName = (char*)vi->get(0);
ringInfoArray[i].baseTableName = (char*)vi->get(1);
}
constrInfoArray[idx].numRingConstr = ringInfoQueue->numEntries();
constrInfoArray[idx].ringConstrArray = ringInfoArray;
}
// attach all the referencing constraints
if (strcmp(constrType, COM_FOREIGN_KEY_CONSTRAINT_LIT) == 0)
{
str_sprintf(query, "select trim(O.catalog_name || '.' || '\"' || O.schema_name || '\"' || '.' || '\"' || O.object_name || '\"' ) constr_name, trim(O2.catalog_name || '.' || '\"' || O2.schema_name || '\"' || '.' || '\"' || O2.object_name || '\"' ) table_name from %s.\"%s\".%s R, %s.\"%s\".%s O, %s.\"%s\".%s O2, %s.\"%s\".%s T where O.object_uid = R.unique_constraint_uid and O2.object_uid = T.table_uid and T.constraint_uid = R.unique_constraint_uid and R.ref_constraint_uid = %ld order by 2,1",
getSystemCatalog(), SEABASE_MD_SCHEMA, SEABASE_REF_CONSTRAINTS,
getSystemCatalog(), SEABASE_MD_SCHEMA, SEABASE_OBJECTS,
getSystemCatalog(), SEABASE_MD_SCHEMA, SEABASE_OBJECTS,
getSystemCatalog(), SEABASE_MD_SCHEMA, SEABASE_TABLE_CONSTRAINTS,
constrUID
);
Queue * refdInfoQueue = NULL;
cliRC = cliInterface.fetchAllRows(refdInfoQueue, query, 0, FALSE, FALSE, TRUE);
if (cliRC < 0)
{
cliInterface.retrieveSQLDiagnostics(CmpCommon::diags());
processReturn();
return NULL;
}
ComTdbVirtTableRefConstraints * refdInfoArray = NULL;
if (refdInfoQueue->numEntries() > 0)
{
refdInfoArray =
new(STMTHEAP) ComTdbVirtTableRefConstraints[refdInfoQueue->numEntries()];
}
refdInfoQueue->position();
for (Lng32 i = 0; i < refdInfoQueue->numEntries(); i++)
{
OutputInfo * vi = (OutputInfo*)refdInfoQueue->getNext();
refdInfoArray[i].constrName = (char*)vi->get(0);
refdInfoArray[i].baseTableName = (char*)vi->get(1);
}
constrInfoArray[idx].numRefdConstr = refdInfoQueue->numEntries();
constrInfoArray[idx].refdConstrArray = refdInfoArray;
}
if (strcmp(constrType, COM_CHECK_CONSTRAINT_LIT) == 0)
{
NAString constrText;
if (getTextFromMD(&cliInterface, constrUID, COM_CHECK_CONSTR_TEXT, 0,
constrText))
{
processReturn();
return NULL;
}
char * ct = new(STMTHEAP) char[constrText.length()+1];
memcpy(ct, constrText.data(), constrText.length());
ct[constrText.length()] = 0;
constrInfoArray[idx].checkConstrLen = constrText.length();
constrInfoArray[idx].checkConstrText = ct;
}
} // for
str_sprintf(query, "select check_option, is_updatable, is_insertable from %s.\"%s\".%s where view_uid = %ld for read committed access ",
getSystemCatalog(), SEABASE_MD_SCHEMA, SEABASE_VIEWS,
objUID);
Queue * viewInfoQueue = NULL;
cliRC = cliInterface.fetchAllRows(viewInfoQueue, query, 0, FALSE, FALSE, TRUE);
if (cliRC < 0)
{
cliInterface.retrieveSQLDiagnostics(CmpCommon::diags());
processReturn();
return NULL;
}
ComTdbVirtTableViewInfo * viewInfoArray = NULL;
if (viewInfoQueue->numEntries() > 0)
{
// must have only one entry
if (viewInfoQueue->numEntries() > 1)
{
processReturn();
return NULL;
}
viewInfoArray = new(STMTHEAP) ComTdbVirtTableViewInfo[1];
viewInfoQueue->position();
OutputInfo * vi = (OutputInfo*)viewInfoQueue->getNext();
char * checkOption = (char*)vi->get(0);
Lng32 isUpdatable = *(Lng32*)vi->get(1);
Lng32 isInsertable = *(Lng32*)vi->get(2);
viewInfoArray[0].viewName = (char*)extTableName->data();
if (NAString(checkOption) != COM_NONE_CHECK_OPTION_LIT)
{
viewInfoArray[0].viewCheckText = new(STMTHEAP) char[strlen(checkOption) + 1];
strcpy(viewInfoArray[0].viewCheckText, checkOption);
}
else
viewInfoArray[0].viewCheckText = NULL;
viewInfoArray[0].isUpdatable = isUpdatable;
viewInfoArray[0].isInsertable = isInsertable;
// get view text from TEXT table
NAString viewText;
if (getTextFromMD(&cliInterface, objUID, COM_VIEW_TEXT, 0, viewText))
{
processReturn();
return NULL;
}
viewInfoArray[0].viewText = new(STMTHEAP) char[viewText.length() + 1];
strcpy(viewInfoArray[0].viewText, viewText.data());
// get view col usages from TEXT table
NAString viewColUsages;
if (getTextFromMD(&cliInterface, objUID, COM_VIEW_REF_COLS_TEXT, 0, viewColUsages))
{
processReturn();
return NULL;
}
viewInfoArray[0].viewColUsages = new(STMTHEAP) char[viewColUsages.length() + 1];
strcpy(viewInfoArray[0].viewColUsages, viewColUsages.data());
}
ComTdbVirtTableSequenceInfo * seqInfo = NULL;
if (identityColPos >= 0)
{
NAString seqName;
SequenceGeneratorAttributes::genSequenceName
(catName, schName, objName, colInfoArray[identityColPos].colName,
seqName);
NAString extSeqName;
Int32 objectOwner;
Int64 seqUID;
seqInfo = getSeabaseSequenceInfo(catName, schName, seqName,
extSeqName, objectOwner, schemaOwner, seqUID);
}
ComTdbVirtTablePrivInfo * privInfo = getSeabasePrivInfo(objUID, objType);
ComTdbVirtTableTableInfo * tableInfo = new(STMTHEAP) ComTdbVirtTableTableInfo[1];
tableInfo->tableName = extTableName->data();
tableInfo->createTime = 0;
tableInfo->redefTime = 0;
tableInfo->objUID = objUID;
tableInfo->isAudited = (isAudited ? -1 : 0);
tableInfo->validDef = 1;
tableInfo->objOwnerID = objectOwner;
tableInfo->schemaOwnerID = schemaOwner;
tableInfo->numSaltPartns = numSaltPartns;
tableInfo->hbaseCreateOptions =
(hbaseCreateOptions->isNull() ? NULL : hbaseCreateOptions->data());
if (alignedFormat)
tableInfo->rowFormat = COM_ALIGNED_FORMAT_TYPE;
else if (hbaseStrDataFormat)
tableInfo->rowFormat = COM_HBASE_STR_FORMAT_TYPE;
else
tableInfo->rowFormat = COM_HBASE_FORMAT_TYPE;
if (NOT colFamStr.isNull())
{
char colFamBuf[1000];
char * colFamBufPtr = colFamBuf;
strcpy(colFamBufPtr, colFamStr.data());
strsep(&colFamBufPtr, " ");
tableInfo->defaultColFam = new(STMTHEAP) char[strlen(colFamBuf)+1];
strcpy((char*)tableInfo->defaultColFam, colFamBuf);
tableInfo->allColFams = new(STMTHEAP) char[strlen(colFamBufPtr)+1];
strcpy((char*)tableInfo->allColFams, colFamBufPtr);
}
else
{
tableInfo->defaultColFam = new(STMTHEAP) char[strlen(SEABASE_DEFAULT_COL_FAMILY)+1];
strcpy((char*)tableInfo->defaultColFam, SEABASE_DEFAULT_COL_FAMILY);
tableInfo->allColFams = NULL;
}
tableInfo->objectFlags = objectFlags;
tableInfo->tablesFlags = tablesFlags;
// request the default
ExpHbaseInterface* ehi = CmpSeabaseDDL::allocEHI();
if (ehi == NULL)
return NULL;
NAArray<HbaseStr>* endKeyArray = ehi->getRegionEndKeys(extNameForHbase);
char * snapshotName = NULL;
if (ctlFlags & GET_SNAPSHOTS)
{
Lng32 retcode =
ehi->getLatestSnapshot(extNameForHbase.data(), snapshotName, STMTHEAP);
if (retcode < 0)
{
*CmpCommon::diags()
<< DgSqlCode(-8448)
<< DgString0((char*)"ExpHbaseInterface::getLatestSnapshot()")
<< DgString1(getHbaseErrStr(-retcode))
<< DgInt0(-retcode)
<< DgString2((char*)GetCliGlobals()->getJniErrorStr());
delete ehi;
}
}
tableDesc =
Generator::createVirtualTableDesc
(
extTableName->data(), //objName,
NULL, // let it decide what heap to use
numCols,
colInfoArray,
tableKeyInfo->numEntries(), //keyIndex,
keyInfoArray,
constrInfoQueue->numEntries(),
constrInfoArray,
indexInfoQueue->numEntries(),
indexInfoArray,
viewInfoQueue->numEntries(),
viewInfoArray,
tableInfo,
seqInfo,
endKeyArray,
snapshotName,
((ctlFlags & GEN_PACKED_DESC) != 0),
&packedDescLen,
TRUE /*user table*/,
privInfo);
deleteNAArray(heap_, endKeyArray);
if ( tableDesc ) {
// if this is base table or index and hbase object doesn't exist,
// then this object is corrupted.
if (!objectFlags & SEABASE_OBJECT_IS_EXTERNAL_HIVE &&
!objectFlags & SEABASE_OBJECT_IS_EXTERNAL_HBASE)
{
if ((tableDesc->tableDesc()->objectType() == COM_BASE_TABLE_OBJECT) &&
(existsInHbase(extNameForHbase, ehi) == 0))
{
*CmpCommon::diags() << DgSqlCode(-4254)
<< DgString0(*extTableName);
tableDesc = NULL;
return NULL;
}
}
}
CmpSeabaseDDL::deallocEHI(ehi);
if (! tableDesc)
processReturn();
return tableDesc;
}
TrafDesc * CmpSeabaseDDL::getSeabaseTableDesc(const NAString &catName,
const NAString &schName,
const NAString &objName,
const ComObjectType objType,
NABoolean includeInvalidDefs)
{
Lng32 retcode = 0;
Lng32 cliRC = 0;
if ((CmpCommon::context()->isUninitializedSeabase()) &&
(!Get_SqlParser_Flags(INTERNAL_QUERY_FROM_EXEUTIL)))
{
if (CmpCommon::context()->uninitializedSeabaseErrNum() == -TRAF_HBASE_ACCESS_ERROR)
*CmpCommon::diags() << DgSqlCode(CmpCommon::context()->uninitializedSeabaseErrNum())
<< DgInt0(CmpCommon::context()->hbaseErrNum())
<< DgString0(CmpCommon::context()->hbaseErrStr());
else
*CmpCommon::diags() << DgSqlCode(CmpCommon::context()->uninitializedSeabaseErrNum());
return NULL;
}
TrafDesc *tDesc = NULL;
NABoolean isMDTable = (isSeabaseMD(catName, schName, objName) ||
isSeabasePrivMgrMD(catName, schName));
if (isMDTable)
{
if (! CmpCommon::context()->getTrafMDDescsInfo())
{
*CmpCommon::diags() << DgSqlCode(-1428);
return NULL;
}
tDesc = getSeabaseMDTableDesc(catName, schName, objName, objType);
// Could not find this metadata object in the static predefined structs.
// It could be a metadata view or other objects created in MD schema.
// Look for it as a regular object.
}
else if ((objName == HBASE_HIST_NAME) ||
(objName == HBASE_HISTINT_NAME))
{
NAString tabName = catName;
tabName += ".";
tabName += schName;
tabName += ".";
tabName += objName;
if (existsInHbase(tabName))
{
tDesc = getSeabaseHistTableDesc(catName, schName, objName);
}
return tDesc;
}
if (! tDesc)
{
if ((CmpCommon::context()->isUninitializedSeabase()) &&
(!Get_SqlParser_Flags(INTERNAL_QUERY_FROM_EXEUTIL)))
{
if (CmpCommon::context()->uninitializedSeabaseErrNum() == -TRAF_HBASE_ACCESS_ERROR)
*CmpCommon::diags() << DgSqlCode(CmpCommon::context()->uninitializedSeabaseErrNum())
<< DgInt0(CmpCommon::context()->hbaseErrNum())
<< DgString0(CmpCommon::context()->hbaseErrStr());
else
*CmpCommon::diags() << DgSqlCode(CmpCommon::context()->uninitializedSeabaseErrNum());
}
else
{
Int32 ctlFlags = 0;
if (CmpCommon::getDefault(TRAF_TABLE_SNAPSHOT_SCAN) != DF_NONE)
ctlFlags = GET_SNAPSHOTS; // get snapshot
if ((CmpCommon::getDefault(TRAF_READ_OBJECT_DESC) == DF_ON) &&
(!Get_SqlParser_Flags(INTERNAL_QUERY_FROM_EXEUTIL)) &&
(NOT includeInvalidDefs))
ctlFlags |= READ_OBJECT_DESC;
if (switchCompiler(CmpContextInfo::CMPCONTEXT_TYPE_META))
return NULL;
switch (objType)
{
case COM_SEQUENCE_GENERATOR_OBJECT:
tDesc = getSeabaseSequenceDesc(catName, schName, objName);
break;
case COM_LIBRARY_OBJECT:
tDesc = getSeabaseLibraryDesc(catName, schName, objName);
break;
default:
Int32 packedDescLen = 0;
tDesc = getSeabaseUserTableDesc(catName, schName, objName,
objType, includeInvalidDefs,
ctlFlags, packedDescLen);
break;
}
switchBackCompiler();
}
}
return tDesc;
}
// a wrapper method to getSeabaseRoutineDescInternal so
// CmpContext context switching can take place.
// getSeabaseRoutineDescInternal prepares and executes
// several queries on metadata tables
TrafDesc *CmpSeabaseDDL::getSeabaseRoutineDesc(const NAString &catName,
const NAString &schName,
const NAString &objName)
{
TrafDesc *result = NULL;
if (switchCompiler(CmpContextInfo::CMPCONTEXT_TYPE_META))
return NULL;
result = getSeabaseRoutineDescInternal(catName, schName, objName);
switchBackCompiler();
return result;
}
TrafDesc *CmpSeabaseDDL::getSeabaseRoutineDescInternal(const NAString &catName,
const NAString &schName,
const NAString &objName)
{
Lng32 retcode = 0;
Lng32 cliRC = 0;
TrafDesc *result;
char query[4000];
char buf[4000];
ExeCliInterface cliInterface(STMTHEAP, 0, NULL,
CmpCommon::context()->sqlSession()->getParentQid());
Int64 objectUID = 0;
Int32 objectOwnerID = 0;
Int32 schemaOwnerID = 0;
Int64 objectFlags = 0 ;
ComObjectType objectType = COM_USER_DEFINED_ROUTINE_OBJECT;
objectUID = getObjectInfo(&cliInterface,
catName.data(), schName.data(),
objName.data(), objectType,
objectOwnerID,schemaOwnerID,objectFlags);
if (objectUID == -1 || objectOwnerID == 0)
{
if (CmpCommon::diags()->getNumber(DgSqlCode::ERROR_) == 0)
SEABASEDDL_INTERNAL_ERROR("getting object UID and owners for routine desc request");
processReturn();
return NULL;
}
str_sprintf(buf, "select udr_type, language_type, deterministic_bool,"
" sql_access, call_on_null, isolate_bool, param_style,"
" transaction_attributes, max_results, state_area_size, external_name,"
" parallelism, user_version, external_security, execution_mode,"
" library_filename, version, signature, catalog_name, schema_name,"
" object_name"
" from %s.\"%s\".%s r, %s.\"%s\".%s l, %s.\"%s\".%s o "
" where r.udr_uid = %ld and r.library_uid = l.library_uid "
" and l.library_uid = o.object_uid for read committed access",
getSystemCatalog(), SEABASE_MD_SCHEMA, SEABASE_ROUTINES,
getSystemCatalog(), SEABASE_MD_SCHEMA, SEABASE_LIBRARIES,
getSystemCatalog(), SEABASE_MD_SCHEMA, SEABASE_OBJECTS,
objectUID);
cliRC = cliInterface.fetchRowsPrologue(buf, TRUE/*no exec*/);
if (cliRC < 0)
{
cliInterface.retrieveSQLDiagnostics(CmpCommon::diags());
return NULL;
}
cliRC = cliInterface.clearExecFetchClose(NULL, 0);
if (cliRC < 0)
{
cliInterface.retrieveSQLDiagnostics(CmpCommon::diags());
return NULL;
}
if (cliRC == 100) // did not find the row
{
*CmpCommon::diags() << DgSqlCode(-CAT_OBJECT_DOES_NOT_EXIST_IN_TRAFODION)
<< DgString0(objName);
return NULL;
}
char * ptr = NULL;
Lng32 len = 0;
ComTdbVirtTableRoutineInfo *routineInfo = new (STMTHEAP) ComTdbVirtTableRoutineInfo();
routineInfo->object_uid = objectUID;
routineInfo->object_owner_id = objectOwnerID;
routineInfo->schema_owner_id = schemaOwnerID;
routineInfo->routine_name = objName.data();
cliInterface.getPtrAndLen(1, ptr, len);
str_cpy_all(routineInfo->UDR_type, ptr, len);
routineInfo->UDR_type[len] = '\0';
cliInterface.getPtrAndLen(2, ptr, len);
str_cpy_all(routineInfo->language_type, ptr, len);
routineInfo->language_type[len] = '\0';
cliInterface.getPtrAndLen(3, ptr, len);
if (*ptr == 'Y')
routineInfo->deterministic = 1;
else
routineInfo->deterministic = 0;
cliInterface.getPtrAndLen(4, ptr, len);
str_cpy_all(routineInfo->sql_access, ptr, len);
routineInfo->sql_access[len] = '\0';
cliInterface.getPtrAndLen(5, ptr, len);
if (*ptr == 'Y')
routineInfo->call_on_null = 1;
else
routineInfo->call_on_null = 0;
cliInterface.getPtrAndLen(6, ptr, len);
if (*ptr == 'Y')
routineInfo->isolate = 1;
else
routineInfo->isolate = 0;
cliInterface.getPtrAndLen(7, ptr, len);
str_cpy_all(routineInfo->param_style, ptr, len);
routineInfo->param_style[len] = '\0';
cliInterface.getPtrAndLen(8, ptr, len);
str_cpy_all(routineInfo->transaction_attributes, ptr, len);
routineInfo->transaction_attributes[len] = '\0';
cliInterface.getPtrAndLen(9, ptr, len);
routineInfo->max_results = *(Int32 *)ptr;
cliInterface.getPtrAndLen(10, ptr, len);
routineInfo->state_area_size = *(Int32 *)ptr;
cliInterface.getPtrAndLen(11, ptr, len);
routineInfo->external_name = new (STMTHEAP) char[len+1];
str_cpy_and_null((char *)routineInfo->external_name, ptr, len, '\0', ' ', TRUE);
cliInterface.getPtrAndLen(12, ptr, len);
str_cpy_all(routineInfo->parallelism, ptr, len);
routineInfo->parallelism[len] = '\0';
cliInterface.getPtrAndLen(13, ptr, len);
str_cpy_all(routineInfo->user_version, ptr, len);
routineInfo->user_version[len] = '\0';
cliInterface.getPtrAndLen(14, ptr, len);
str_cpy_all(routineInfo->external_security, ptr, len);
routineInfo->external_security[len] = '\0';
cliInterface.getPtrAndLen(15, ptr, len);
str_cpy_all(routineInfo->execution_mode, ptr, len);
routineInfo->execution_mode[len] = '\0';
cliInterface.getPtrAndLen(16, ptr, len);
routineInfo->library_filename = new (STMTHEAP) char[len+1];
str_cpy_and_null((char *)routineInfo->library_filename, ptr, len, '\0', ' ', TRUE);
cliInterface.getPtrAndLen(17, ptr, len);
routineInfo->library_version = *(Int32 *)ptr;
cliInterface.getPtrAndLen(18, ptr, len);
routineInfo->signature = new (STMTHEAP) char[len+1];
str_cpy_and_null((char *)routineInfo->signature, ptr, len, '\0', ' ', TRUE);
// library SQL name, in three parts
cliInterface.getPtrAndLen(19, ptr, len);
char *libCat = new (STMTHEAP) char[len+1];
str_cpy_and_null(libCat, ptr, len, '\0', ' ', TRUE);
cliInterface.getPtrAndLen(20, ptr, len);
char *libSch = new (STMTHEAP) char[len+1];
str_cpy_and_null(libSch, ptr, len, '\0', ' ', TRUE);
cliInterface.getPtrAndLen(21, ptr, len);
char *libObj = new (STMTHEAP) char[len+1];
str_cpy_and_null(libObj, ptr, len, '\0', ' ', TRUE);
ComObjectName libSQLName(libCat, libSch, libObj,
COM_UNKNOWN_NAME,
ComAnsiNamePart::INTERNAL_FORMAT,
STMTHEAP);
NAString libSQLExtName = libSQLName.getExternalName();
routineInfo->library_sqlname = new (STMTHEAP) char[libSQLExtName.length()+1];
str_cpy_and_null((char *)routineInfo->library_sqlname,
libSQLExtName.data(),
libSQLExtName.length(),
'\0', ' ', TRUE);
ComTdbVirtTableColumnInfo *paramsArray;
Lng32 numParams;
char direction[50];
str_sprintf(direction, "'%s', '%s', '%s'",
COM_INPUT_PARAM_LIT, COM_OUTPUT_PARAM_LIT,
COM_INOUT_PARAM_LIT);
// Params
if (getSeabaseColumnInfo(&cliInterface,
objectUID,
catName, schName, objName,
(char *)direction,
NULL,
NULL,
&numParams,
&paramsArray) < 0)
{
processReturn();
return NULL;
}
ComTdbVirtTablePrivInfo * privInfo = getSeabasePrivInfo(objectUID, objectType);
TrafDesc *routine_desc = NULL;
routine_desc = Generator::createVirtualRoutineDesc(
objName.data(),
routineInfo,
numParams,
paramsArray,
privInfo,
NULL);
if (routine_desc == NULL)
processReturn();
return routine_desc;
}
// *****************************************************************************
// * *
// * Function: checkSpecifiedPrivs *
// * *
// * Processes the privilege specification and returns the lists of object *
// * and column privileges. *
// * *
// *****************************************************************************
// * *
// * Parameters: *
// * *
// * <privActsArray> ElemDDLPrivActArray & In *
// * is a reference to the parsed list of privileges to be granted or *
// * revoked. *
// * *
// * <externalObjectName> const char * In *
// * is the fully qualified name of the object that privileges are being *
// * granted or revoked on. *
// * *
// * <objectType> ComObjectType In *
// * is the type of the object that privileges are being granted or *
// * revoked on. *
// * *
// * <naTable> NATable * In *
// * if the object type is a table or view, the cache for the metadata *
// * related to the object, otherwise NULL. *
// * *
// * <objectPrivs> std::vector<PrivType> & Out *
// * passes back a list of the object privileges to be granted or revoked. *
// * *
// * <colPrivs> std::vector<ColPrivSpec> & Out *
// * passes back a list of the column privileges and the specific columns *
// * on which the privileges are to be granted or revoked. *
// * *
// *****************************************************************************
// * *
// * Returns: bool *
// * *
// * true: Privileges processed successfully. Lists of object and column *
// * privileges were returned. *
// * false: Error processing privileges. The error is in the diags area. *
// * *
// *****************************************************************************
static bool checkSpecifiedPrivs(
ElemDDLPrivActArray & privActsArray,
const char * externalObjectName,
ComObjectType objectType,
NATable * naTable,
std::vector<PrivType> & objectPrivs,
std::vector<ColPrivSpec> & colPrivs)
{
for (Lng32 i = 0; i < privActsArray.entries(); i++)
{
// Currently only DML privileges are supported.
PrivType privType;
if (!ElmPrivToPrivType(privActsArray[i]->getOperatorType(),privType) ||
!isDMLPrivType(privType))
{
*CmpCommon::diags() << DgSqlCode(-CAT_INVALID_PRIV_FOR_OBJECT)
<< DgString0(PrivMgrUserPrivs::convertPrivTypeToLiteral(privType).c_str())
<< DgString1(externalObjectName);
return false;
}
//
// The same privilege cannot be specified twice in one grant or revoke
// statement. This includes granting or revoking the same privilege at
// the object-level and the column-level.
if (hasValue(objectPrivs,privType) || hasValue(colPrivs,privType))
{
*CmpCommon::diags() << DgSqlCode(-CAT_DUPLICATE_PRIVILEGES);
return false;
}
if (!isValidPrivTypeForObject(objectType,privType) && privType != PrivType::ALL_DML)
{
*CmpCommon::diags() << DgSqlCode(-CAT_PRIVILEGE_NOT_ALLOWED_FOR_THIS_OBJECT_TYPE)
<< DgString0(PrivMgrUserPrivs::convertPrivTypeToLiteral(privType).c_str());
return false;
}
// For some DML privileges the user may be granting either column
// or object privileges. If it is not a privilege that can be granted
// at the column level, it is an object-level privilege.
if (!isColumnPrivType(privType))
{
objectPrivs.push_back(privType);
continue;
}
ElemDDLPrivActWithColumns * privActWithColumns = dynamic_cast<ElemDDLPrivActWithColumns *>(privActsArray[i]);
ElemDDLColNameArray colNameArray = privActWithColumns->getColumnNameArray();
// If no columns were specified, this is an object-level privilege.
if (colNameArray.entries() == 0)
{
objectPrivs.push_back(privType);
continue;
}
// Column-level privileges can only be specified for tables and views.
if (objectType != COM_BASE_TABLE_OBJECT && objectType != COM_VIEW_OBJECT)
{
*CmpCommon::diags() << DgSqlCode(-CAT_INCORRECT_OBJECT_TYPE)
<< DgTableName(externalObjectName);
return false;
}
// It's a table or view, validate the column. Get the list of
// columns and verify the list contains the specified column(s).
const NAColumnArray &nacolArr = naTable->getNAColumnArray();
for (size_t c = 0; c < colNameArray.entries(); c++)
{
const NAColumn * naCol = nacolArr.getColumn(colNameArray[c]->getColumnName());
if (naCol == NULL)
{
*CmpCommon::diags() << DgSqlCode(-CAT_COLUMN_DOES_NOT_EXIST_ERROR)
<< DgColumnName(colNameArray[c]->getColumnName());
return false;
}
// Specified column was found.
ColPrivSpec colPrivEntry;
colPrivEntry.privType = privType;
colPrivEntry.columnOrdinal = naCol->getPosition();
colPrivs.push_back(colPrivEntry);
}
}
return true;
}
//************************ End of checkSpecifiedPrivs **************************
// *****************************************************************************
// * *
// * Function: ElmPrivToPrivType *
// * *
// * This function maps a parser privilege enum (ELM_PRIV_ACT) to a Privilege *
// * Manager PrivType. *
// * *
// *****************************************************************************
// * *
// * Parameters: *
// * *
// * <elmPriv> OperatorTypeEnum In *
// * is a parser privilege enum. *
// * *
// * <privType> PrivType & Out *
// * passes back the CatPrivBitmap privilege enum. *
// * *
// * <forRevoke> bool [In] *
// * is true if this is part of a revoke command, otherwise false. Default *
// * to true. Currently unused, placeholder for schema and DDL privileges. *
// * *
// *****************************************************************************
// * *
// * Returns: bool *
// * *
// * true: Privilege converted *
// * false: Privilege not recognized. *
// * *
// *****************************************************************************
static bool ElmPrivToPrivType(
OperatorTypeEnum elmPriv,
PrivType & privType,
bool forRevoke)
{
switch (elmPriv)
{
case ELM_PRIV_ACT_DELETE_ELEM:
privType = PrivType::DELETE_PRIV;
break;
case ELM_PRIV_ACT_EXECUTE_ELEM:
privType = PrivType::EXECUTE_PRIV;
break;
case ELM_PRIV_ACT_INSERT_ELEM:
privType = PrivType::INSERT_PRIV;
break;
case ELM_PRIV_ACT_REFERENCES_ELEM:
privType = PrivType::REFERENCES_PRIV;
break;
case ELM_PRIV_ACT_SELECT_ELEM:
privType = PrivType::SELECT_PRIV;
break;
case ELM_PRIV_ACT_UPDATE_ELEM:
privType = PrivType::UPDATE_PRIV;
break;
case ELM_PRIV_ACT_USAGE_ELEM:
privType = PrivType::USAGE_PRIV;
break;
case ELM_PRIV_ACT_ALTER_ELEM:
// if (forRevoke)
// privType = PrivType::ALL_ALTER;
// else
privType = PrivType::ALTER_PRIV;
break;
case ELM_PRIV_ACT_CREATE_ELEM:
// if (forRevoke)
// privType = PrivType::ALL_CREATE;
// else
privType = PrivType::CREATE_PRIV;
break;
case ELM_PRIV_ACT_DROP_ELEM:
// if (forRevoke)
// privType = PrivType::ALL_DROP;
// else
privType = PrivType::DROP_PRIV;
break;
case ELM_PRIV_ACT_ALL_DDL_ELEM:
privType = PrivType::ALL_DDL;
break;
case ELM_PRIV_ACT_ALL_DML_ELEM:
privType = PrivType::ALL_DML;
break;
case ELM_PRIV_ACT_ALL_OTHER_ELEM:
privType = PrivType::ALL_PRIVS;
break;
default:
return false;
}
return true;
}
//************************* End of ElmPrivToPrivType ***************************
// *****************************************************************************
// * *
// * Function: hasValue *
// * *
// * This function determines if a ColPrivSpec vector contains a PrivType *
// * value. *
// * *
// *****************************************************************************
// * *
// * Parameters: *
// * *
// * <container> std::vector<ColPrivSpec> In *
// * is the vector of ColPrivSpec values. *
// * *
// * <value> PrivType In *
// * is the value to be compared against existing values in the vector. *
// * *
// *****************************************************************************
// * *
// * Returns: bool *
// * *
// * true: Vector contains the value. *
// * false: Vector does not contain the value. *
// * *
// *****************************************************************************
static bool hasValue(
const std::vector<ColPrivSpec> & container,
PrivType value)
{
for (size_t index = 0; index < container.size(); index++)
if (container[index].privType == value)
return true;
return false;
}
//***************************** End of hasValue ********************************
// *****************************************************************************
// * *
// * Function: hasValue *
// * *
// * This function determines if a PrivType vector contains a PrivType value.*
// * *
// *****************************************************************************
// * *
// * Parameters: *
// * *
// * <container> std::vector<PrivType> In *
// * is the vector of 32-bit values. *
// * *
// * <value> PrivType In *
// * is the value to be compared against existing values in the vector. *
// * *
// *****************************************************************************
// * *
// * Returns: bool *
// * *
// * true: Vector contains the value. *
// * false: Vector does not contain the value. *
// * *
// *****************************************************************************
static bool hasValue(
const std::vector<PrivType> & container,
PrivType value)
{
for (size_t index = 0; index < container.size(); index++)
if (container[index] == value)
return true;
return false;
}
//***************************** End of hasValue ********************************
// *****************************************************************************
// * *
// * Function: isMDGrantRevokeOK *
// * *
// * This function determines if a grant or revoke a privilege to/from a *
// * metadata table should be allowed. *
// * *
// *****************************************************************************
// * *
// * Parameters: *
// * *
// * <objectPrivs> const std::vector<PrivType> & In *
// * is a vector of object-level privileges. *
// * *
// * <colPrivs> const std::vector<ColPrivSpec> & In *
// * is a vector of column-level privileges. *
// * *
// * <isGrant> bool In *
// * is a true if this is a grant operation, false if revoke. *
// * *
// *****************************************************************************
// * *
// * Returns: bool *
// * *
// * true: Grant/revoke is OK. *
// * false: Grant/revoke should be rejected. *
// * *
// *****************************************************************************
static bool isMDGrantRevokeOK(
const std::vector<PrivType> & objectPrivs,
const std::vector<ColPrivSpec> & colPrivs,
bool isGrant)
{
// Can only grant or revoke privileges on MD tables if only granting select,
// or only revoking all privileges. Only valid combination is no object
// privileges and 1 or more column privileges (all SELECT), or no column
// privilege and exactly one object privilege. In the latter case, the
// privilege must either be SELECT, or if a REVOKE operation, either
// ALL_PRIVS or ALL_DML.
// First check if no column privileges.
if (colPrivs.size() == 0)
{
// Should never get this far with both vectors being empty, but check
// just in case.
if (objectPrivs.size() == 0)
return false;
if (objectPrivs.size() > 1)
return false;
if (objectPrivs[0] == SELECT_PRIV)
return true;
if (isGrant)
return false;
if (objectPrivs[0] == ALL_PRIVS || objectPrivs[0] == ALL_DML)
return true;
return false;
}
// Have column privs
if (objectPrivs.size() > 0)
return false;
for (size_t i = 0; i < colPrivs.size(); i++)
if (colPrivs[i].privType != SELECT_PRIV)
return false;
return true;
}
//************************* End of isMDGrantRevokeOK ***************************
// *****************************************************************************
// * *
// * Function: isValidPrivTypeForObject *
// * *
// * This function determines if a priv type is valid for an object. *
// * *
// *****************************************************************************
// * *
// * Parameters: *
// * *
// * <objectType> ComObjectType In *
// * is the type of the object. *
// * *
// * <privType> PrivType In *
// * is the type of the privilege. *
// * *
// *****************************************************************************
// * *
// * Returns: bool *
// * *
// * true: Priv type is valid for object. *
// * false: Priv type is not valid for object. *
// * *
// *****************************************************************************
static bool isValidPrivTypeForObject(
ComObjectType objectType,
PrivType privType)
{
switch (objectType)
{
case COM_LIBRARY_OBJECT:
return isLibraryPrivType(privType);
case COM_STORED_PROCEDURE_OBJECT:
case COM_USER_DEFINED_ROUTINE_OBJECT:
return isUDRPrivType(privType);
case COM_SEQUENCE_GENERATOR_OBJECT:
return isSequenceGeneratorPrivType(privType);
case COM_BASE_TABLE_OBJECT:
case COM_VIEW_OBJECT:
return isTablePrivType(privType);
default:
return false;
}
return false;
}
//********************* End of isValidPrivTypeForObject ************************