blob: 62ed05d8a8a7e54a34b7f44827a20cfd0ee9a4bb [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: hs_la.C
* Description: Function to retrieve lable info.
* Created: 03/25/96
* Language: C++
*
*
*
*
*****************************************************************************
*/
#define HS_FILE "hs_la"
#include "hs_la.h"
#define SQLPARSERGLOBALS_FLAGS
#include "SqlParserGlobalsCmn.h"
#include "CmpCommon.h" //heap usage
#include "CompException.h"
#include "hs_log.h"
#include "sql_id.h"
#include "ComMPLoc.h"
#include "EHException.h"
#include "hs_cli.h"
#include "SchemaDB.h"
#include "hs_globals.h"
#include "hs_util.h"
#include "OptimizerSimulator.h"
#include "ComSizeDefs.h"
#include "hiveHook.h"
#include "ComSmallDefs.h"
#include "BindWA.h"
#include "RelScan.h"
#include "NATable.h"
HSTableDef* HSTableDef::create(CollHeap* heap,
const ComObjectName &tableName,
const hs_table_type tableType,
const ComAnsiNameSpace nameSpace)
{
if (HSGlobalsClass::isHbaseCat(tableName.getCatalogNamePart().getInternalName()))
return new(heap) HSHbaseTableDef(tableName, tableType, nameSpace);
else if (HSGlobalsClass::isHiveCat(tableName.getCatalogNamePart().getInternalName()))
return new(heap) HSHiveTableDef(tableName, tableType, nameSpace);
else
return new(heap) HSSqTableDef(tableName, tableType, nameSpace);
}
HSTableDef::HSTableDef(const ComObjectName &tableName, const hs_table_type tableType, const ComAnsiNameSpace nameSpace)
:tableName_(new(STMTHEAP) NAString(STMTHEAP)),
ansiName_(new(STMTHEAP) NAString(STMTHEAP)),
naTbl_(NULL),
catalog_(new(STMTHEAP) NAString(tableName.getCatalogNamePart().getInternalName(), STMTHEAP)),
schema_(new(STMTHEAP) NAString(tableName.getSchemaNamePart().getInternalName(), STMTHEAP)),
object_(new(STMTHEAP) NAString(tableName.getObjectNamePart().getInternalName(), STMTHEAP)),
objectUID_(0),
objActualFormat_(UNKNOWN),
objFormat_(tableType),
numCols_(0),
colInfo_(NULL),
retcode_(0),
isVolatile_(FALSE),
guardianName_(new(STMTHEAP) NAString(STMTHEAP)),
nameSpace_(nameSpace),
labelAccessed_(FALSE),
objectType_(COM_UNKNOWN_OBJECT),
isMetadataObject_(FALSE),
hasSyskey_(FALSE)
{
// Set volatile schema flag based on schema name.
if (!strncmp(schema_->data(),
COM_VOLATILE_SCHEMA_PREFIX,
strlen(COM_VOLATILE_SCHEMA_PREFIX)))
isVolatile_ = TRUE;
}
HSTableDef::~HSTableDef()
{
if (colInfo_ != NULL)
{
delete [] colInfo_;
colInfo_ = NULL;
}
}
NABoolean HSSqTableDef::objExists(NABoolean createExternalTable)
{
setNATable();
if (!naTbl_)
return FALSE;
return TRUE;
}
void HSTableDef::setNATable()
{
BindWA bindWA(ActiveSchemaDB(), CmpCommon::context(), FALSE,
HSGlobalsClass::isNativeCat(*catalog_));
CorrName corrName(*object_, STMTHEAP, *schema_, *catalog_);
if (isVolatile())
corrName.setIsVolatile(TRUE);
Scan scan(corrName, NULL, REL_SCAN, STMTHEAP);
ULng32 flagToSet = 0; // don't turn on flag unless next 'if' is true
if (CmpCommon::context()->sqlSession()->volatileSchemaInUse())
flagToSet = ALLOW_VOLATILE_SCHEMA_IN_TABLE_NAME;
flagToSet |= ALLOW_SPECIALTABLETYPE;
// set ALLOW_VOLATILE_SCHEMA_IN_TABLE_NAME bit in Sql_ParserFlags
// if needed, and return it to its entry value on exit
PushAndSetSqlParserFlags savedParserFlags(flagToSet);
scan.bindNode(&bindWA);
if (!bindWA.errStatus())
{
naTbl_ = bindWA.getNATable(corrName);
HS_ASSERT(naTbl_);
objectType_ = naTbl_->getObjectType();
}
}
void HSSqTableDef::GetLabelInfo(labelDetail detail)
{
//Don't read label information for objects created by OSIM
if((CmpCommon::getDefault(CREATE_OBJECTS_IN_METADATA_ONLY) == DF_ON) ||
(OSIM_runningSimulation() && !OSIM_ustatIsDisabled()) ||
isInMemoryObjectDefn())
{
labelAccessed_ = TRUE;
return;
}
}
Lng32 HSSqTableDef::getColumnNames()
{
HSErrorCatcher errorCatcher(retcode_, - UERR_UNABLE_TO_DESCRIBE_COLUMN_NAMES, "HSSqTableDef::DescribeColumnNames", TRUE);
HSFuncExecQuery("CONTROL QUERY DEFAULT DISPLAY_DIVISION_BY_COLUMNS 'ON'");
Lng32 retcode = DescribeColumnNames();
HSFuncExecQuery("CONTROL QUERY DEFAULT DISPLAY_DIVISION_BY_COLUMNS RESET");
return retcode;
}
Lng32 HSHiveTableDef::getColumnNames()
{
HSErrorCatcher errorCatcher(retcode_, - UERR_UNABLE_TO_DESCRIBE_COLUMN_NAMES, "HSHiveTableDef::DescribeColumnNames", TRUE);
Lng32 retcode = DescribeColumnNames();
return retcode;
}
Lng32 HSHbaseTableDef::getColumnNames()
{
HSErrorCatcher errorCatcher(retcode_, - UERR_UNABLE_TO_DESCRIBE_COLUMN_NAMES, "HSHbaseTableDef::DescribeColumnNames", TRUE);
Lng32 retcode = DescribeColumnNames();
return retcode;
}
// local function used by the X::DescribeColumnNames functions
NAString getAnsiName(NAString & columnName)
{
NAString ansiName = ToAnsiIdentifier(columnName);
NAString dblQuote="\"";
NAString result;
// Surround ANSI name with double quotes, if not already delimited.
if (ansiName.data()[0] == '"')
result = ansiName;
else
result = dblQuote+ansiName+dblQuote;
return result;
}
Lng32 HSSqTableDef::DescribeColumnNames()
{
Lng32 entry, len;
NAString query;
char colName[ComMAX_1_PART_INTERNAL_UTF8_NAME_LEN_IN_BYTES + 2];
HSLogMan *LM = HSLogMan::Instance();
SQLMODULE_ID module;
init_SQLMODULE_ID(&module);
SQLSTMT_ID *stmt = new(STMTHEAP) SQLSTMT_ID;
init_SQLCLI_OBJ_ID(stmt);
stmt->module = &module;
stmt->name_mode = stmt_handle;
SQLDESC_ID *srcDesc = new(STMTHEAP) SQLDESC_ID;
init_SQLCLI_OBJ_ID(srcDesc);
srcDesc->module = &module;
srcDesc->name_mode = desc_handle;
SQLDESC_ID *outputDesc = new(STMTHEAP) SQLDESC_ID;
init_SQLCLI_OBJ_ID(outputDesc);
outputDesc->module = &module;
outputDesc->name_mode = desc_handle;
// Use the header information from a 'select *' to get the column names.
// Note that this works for SJIS and UTF8 since the names returned through
// CLI are encoded correctly.
retcode_ = setHasSyskeyFlag();
HSHandleError(retcode_);
if (hasSyskey_)
query = "SELECT SYSKEY, * FROM ";
else
query = "SELECT * FROM ";
if(objActualFormat_ == SQLMP)
query += getTableName(tableName_->data(), nameSpace_);
else
query += getTableName(ansiName_->data(), nameSpace_);
retcode_ = SQL_EXEC_ClearDiagnostics(stmt);
// to prevent false alarms for statement heap memory allocation "smt"
// coverity[leaked_storage]
HSHandleError(retcode_);
retcode_ = SQL_EXEC_AllocStmt(stmt, 0);
HSHandleError(retcode_);
retcode_ = SQL_EXEC_AllocDesc(srcDesc, 1);
HSHandleError(retcode_);
retcode_ = SQL_EXEC_AllocDesc(outputDesc, 4096);
HSHandleError(retcode_);
retcode_ = SQL_EXEC_SetDescItem(srcDesc, 1, SQLDESC_TYPE_FS,
REC_BYTE_V_ANSI, 0);
HSHandleError(retcode_);
retcode_ = SQL_EXEC_SetDescItem(srcDesc, 1, SQLDESC_VAR_PTR,
(Long)query.data(), 0);
HSHandleError(retcode_);
retcode_ = SQL_EXEC_SetDescItem(srcDesc, 1, SQLDESC_LENGTH,
query.length() + 1, 0);
HSHandleError(retcode_);
// SQLDESC_CHAR_SET must be the last descriptor item set, otherwise
// it may get reset by other calls to SQL_EXEC_SetDescItem().
NAString charSet = ActiveSchemaDB()->getDefaults().getValue(ISO_MAPPING);
NAString defCS = ActiveSchemaDB()->getDefaults().getValue(DEFAULT_CHARSET);
retcode_ = SQL_EXEC_SetDescItem(srcDesc, 1, SQLDESC_CHAR_SET,
SQLCHARSETCODE_UTF8
, 0);
HSHandleError(retcode_);
// ---------------------------------------------------------------------
// Prepare the statement
// ---------------------------------------------------------------------
SQL_QUERY_COST_INFO query_cost_info;
SQL_QUERY_COMPILER_STATS_INFO comp_stats_info;
retcode_ = SQL_EXEC_Prepare2(stmt, srcDesc,NULL,0,NULL,&query_cost_info, &comp_stats_info,NULL,0,0);
HSHandleError( retcode_);
// ---------------------------------------------------------------------
// describe the column information into the output descriptor
// ---------------------------------------------------------------------
retcode_ = SQL_EXEC_DescribeStmt(stmt, 0, outputDesc);
HSHandleError(retcode_);
retcode_ = SQL_EXEC_GetDescEntryCount(outputDesc, &numCols_);
HSHandleError(retcode_);
colInfo_ = new(STMTHEAP) HSColumnStruct[numCols_];
for (Int32 i = 0; i < numCols_; i++)
{
/*== GET COLUMN NAME ==*/
entry = i + 1;
retcode_ = SQL_EXEC_GetDescItem(outputDesc, entry,
SQLDESC_NAME,
0, colName, sizeof(colName), &len, 0);
if ((retcode_ == 0) &&
(len >= sizeof(colName) ))
retcode_ = -1;
HSHandleError(retcode_);
colName[len] = '\0';
*colInfo_[i].colname = &*colName;
*colInfo_[i].externalColumnName = getAnsiName(*colInfo_[i].colname);
/*== GET COLUMN DATATYPE ==*/
retcode_ = SQL_EXEC_GetDescItem(outputDesc, entry,
SQLDESC_TYPE_FS,
&colInfo_[i].datatype,
0, 0, 0, 0);
HSHandleError(retcode_);
retcode_ = SQL_EXEC_GetDescItem(outputDesc, entry,
SQLDESC_NULLABLE,
&colInfo_[i].nullflag,
0, 0, 0, 0);
HSHandleError(retcode_);
/*== GET COLUMN LENGTH ==*/
retcode_ = SQL_EXEC_GetDescItem(outputDesc, entry,
SQLDESC_OCTET_LENGTH,
&colInfo_[i].length,
0, 0, 0, 0);
HSHandleError(retcode_);
// If applicable, get the character set, precision and scale
if (DFS2REC::isAnyCharacter(colInfo_[i].datatype))
{
retcode_ = SQL_EXEC_GetDescItem(outputDesc, entry,
SQLDESC_CHAR_SET,
(Lng32*)&colInfo_[i].charset, 0, 0, 0, 0);
HSHandleError(retcode_);
// UCS2 cols not supported in MODE_SPECIAL_1 or 2 and do not support case insensitivity.
retcode_ = SQL_EXEC_GetDescItem(outputDesc, entry,
SQLDESC_CASEINSENSITIVE,
(Lng32*)&colInfo_[i].caseInsensitive, 0, 0, 0, 0);
HSHandleError(retcode_);
retcode_ = SQL_EXEC_GetDescItem(outputDesc, entry,
SQLDESC_COLLATION,
(Lng32*)&colInfo_[i].colCollation, 0, 0, 0, 0);
HSHandleError(retcode_);
}
else if ((colInfo_[i].datatype >= REC_MIN_BINARY && // May be type NUMERIC
colInfo_[i].datatype <= REC_MAX_BINARY) // instead of INT
||
(colInfo_[i].datatype >= REC_MIN_DECIMAL &&
colInfo_[i].datatype <= REC_MAX_DECIMAL))
{
retcode_ = SQL_EXEC_GetDescItem(outputDesc, entry,
SQLDESC_PRECISION,
&colInfo_[i].precision, 0, 0, 0, 0);
HSHandleError(retcode_);
retcode_ = SQL_EXEC_GetDescItem(outputDesc, entry,
SQLDESC_SCALE,
&colInfo_[i].scale, 0, 0, 0, 0);
HSHandleError(retcode_);
}
else if (DFS2REC::isDateTime(colInfo_[i].datatype))
{
retcode_ = SQL_EXEC_GetDescItem(outputDesc, entry,
SQLDESC_DATETIME_CODE,
&colInfo_[i].precision, 0, 0, 0, 0);
HSHandleError(retcode_);
retcode_ = SQL_EXEC_GetDescItem(outputDesc, entry,
SQLDESC_PRECISION,
&colInfo_[i].scale, 0, 0, 0, 0);
HSHandleError(retcode_);
}
else if (DFS2REC::isInterval(colInfo_[i].datatype))
{
retcode_ = SQL_EXEC_GetDescItem(outputDesc, entry,
SQLDESC_INT_LEAD_PREC,
&colInfo_[i].precision, 0, 0, 0, 0);
HSHandleError(retcode_);
retcode_ = SQL_EXEC_GetDescItem(outputDesc, entry,
SQLDESC_PRECISION,
&colInfo_[i].scale, 0, 0, 0, 0);
HSHandleError(retcode_);
}
else
{
/* No additional information about column attributes needed */
}
if (LM->LogNeeded())
{
sprintf(LM->msg, "COLUMN [%s]: (%d, %d, %d, %d, %d, %d)"
, colInfo_[i].colname->data()
, colInfo_[i].datatype
, colInfo_[i].nullflag
, colInfo_[i].charset
, colInfo_[i].length
, colInfo_[i].precision
, colInfo_[i].scale
);
LM->Log(LM->msg);
}
}
retcode_ = SQL_EXEC_DeallocStmt(stmt);
HSHandleError(retcode_);
return 0;
}
// go over all the table partitions and return the most
// recent lastModTime among them
Int64 HSSqTableDef::getModTime() const
{
return 0;
}
// 3/29/2013
// NOTE: We probably don't need the following function anymore.
// It largely duplicates getRowCounts(), and is only called
// to get the number of IUD rows if getRowCounts() fails.
// However, getRowCounts() no longer gives up and does an
// estimate if any partition fails to deliver a valid row
// count, so we will have an accurate IUD row count except
// for any partitions for which -1 was returned for the current
// row count (and only if that fact means that the IUD row counts
// returned for that partition are not valid).
/****************************************************************/
/* METHOD: getRowChangeCounts() */
/* PURPOSE: Get the number of inserts, deletes, and updates */
/* since the last time statistics were updated for the */
/* table. This is called for processing of the */
/* NECESSARY clause only if the earlier call to */
/* getRowCounts() failed to yield a row count for all */
/* partitions of the table. */
/* Otherwise, the change counts are retrieved at the */
/* same time and calling this function isn't necessary.*/
/* PARAMS: inserts(out) -- Number of inserts since last time */
/* stats were updated for the table. */
/* deletes(out) -- Number of deletes since last time */
/* stats were updated for the table. */
/* updates(out) -- Number of updates since last time */
/* stats were updated for the table. */
/****************************************************************/
void HSSqTableDef::getRowChangeCounts(Int64 &inserts,
Int64 &deletes,
Int64 &updates)
{
inserts = 0;
deletes = 0;
updates = 0;
}
/****************************************************************/
/* METHOD: resetRowCounts() */
/* PURPOSE: Reset the counts of inserts, deletes, and updates */
/* stored in the file label in each partition for this */
/* table. */
/****************************************************************/
void HSSqTableDef::resetRowCounts()
#ifdef GETROWCOUNTS_UNSUPPORTED
{} // empty function if platform doesn't support getRowCounts()
#else
{
}
#endif
Int64 HSSqTableDef::getRowCount(NABoolean &isEstimate,
Int32 &errorCode,
Int32 &breadCrumb,
NABoolean estimateIfNecessary)
{
Int64 bogus;
return getRowCount(isEstimate, bogus, bogus, bogus, bogus, bogus,
errorCode, breadCrumb, estimateIfNecessary);
}
/***************************************************************************/
/* METHOD: getRowCount() */
/* PURPOSE: Attempt to get the row count for the table from the partition */
/* file labels. If unable, then instead get partition size and */
/* estimate rows. While accessing the file labels, we also get */
/* the counters for inserts, updates, and deletes since the last */
/* Update Stats using NECESSARY. However, these will be discarded */
/* if all the partitions are not accessed because at least one */
/* does not have accurate row count. These counts will be */
/* acquired later only if NECESSARY is used. */
/* ARGUMENTS: isEstimate: an output value, set to TRUE if the returned row */
/* count is an estimate, FALSE otherwise. */
/* numInserts: an output value, set to the number of inserts on */
/* the table since the last update stats using NECESSARY. */
/* numDeletes: an output value, set to the number of deletes on */
/* the table since the last update stats using NECESSARY. */
/* numUpdates: an output value, set to the number of updates on */
/* the table since the last update stats using NECESSARY. */
/* estimateIfNecessary: not used in this redefinition. */
/* RETURN VALUE: The number of rows in the table, -1 if there is an error */
/* reading a partition. */
/***************************************************************************/
Int64 HSSqTableDef::getRowCount(NABoolean &isEstimate,
Int64 &numInserts,
Int64 &numDeletes,
Int64 &numUpdates,
Int64 &numPartitions,
Int64 &minRowCtPerPartition,
Int32 &errorCode,
Int32 &breadCrumb,
NABoolean estimateIfNecessary)
{
errorCode = 0;
breadCrumb = -5;
isEstimate = TRUE;
numInserts =
numDeletes =
numUpdates = 0;
numPartitions = 1;
minRowCtPerPartition = 1000000;
return 1000000;
}
/***************************************************************************/
/* METHOD: getRowCountUsingSelect() */
/* PURPOSE: Get row count of a table using 'select count(*)'. */
/* RETURN VALUE: The number of rows in the table, -1 if there is an error. */
/***************************************************************************/
Int64 HSTableDef::getRowCountUsingSelect()
{
// disable MVQR prior to executing the FetchCount query
HSFuncExecQuery("CONTROL QUERY DEFAULT MVQR_REWRITE_LEVEL '0'");
Int64 rows = -1;
HSCursor cursor;
NAString query = "SELECT COUNT(*) FROM ";
query += getTableName(getObjectFullName(), getNameSpace());
query += " FOR READ UNCOMMITTED ACCESS;";
if (cursor.fetchNumColumn(query, NULL, &rows) < 0)
rows = -1; // Error
// reset the MVQR MVQR_REWRITE_LEVEL setting
HSFuncExecQuery("CONTROL QUERY DEFAULT MVQR_REWRITE_LEVEL RESET");
return rows;
}
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
// 10-060424-6040
//SECURITY ISSUE WORKAROUND (CATMAN):
//To facilitate all users to be able create a temporary sample table,
//Catman has allowed the creation of a PUBLIC schema, which will allow
//all users to issue DDL statements. In release 2, Catman plans to
//provide a complete solution to this problem. When the solution is
//implemented, this workaround will need to be removed.
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
NABoolean HSSqTableDef::publicSchemaExists()
{
return FALSE;
}
// Check to see if a system defined SYSKEY exists and set hasSyskey_ flag.
Lng32 HSSqTableDef::setHasSyskeyFlag()
{
HSErrorCatcher errorCatcher(retcode_, -UERR_INTERNAL_ERROR, "HSTableDef::setHasSyskeyFlag()", TRUE);
Lng32 entry, len;
NAString query;
char colName[ComMAX_1_PART_INTERNAL_UTF8_NAME_LEN_IN_BYTES + 2];
HSLogMan *LM = HSLogMan::Instance();
SQLMODULE_ID module;
init_SQLMODULE_ID(&module);
SQLSTMT_ID *stmt = new(STMTHEAP) SQLSTMT_ID;
init_SQLCLI_OBJ_ID(stmt);
stmt->module = &module;
stmt->name_mode = stmt_handle;
SQLDESC_ID *srcDesc = new(STMTHEAP) SQLDESC_ID;
init_SQLCLI_OBJ_ID(srcDesc);
srcDesc->module = &module;
srcDesc->name_mode = desc_handle;
SQLDESC_ID *outputDesc = new(STMTHEAP) SQLDESC_ID;
init_SQLCLI_OBJ_ID(outputDesc);
outputDesc->module = &module;
outputDesc->name_mode = desc_handle;
query = "SELECT SYSKEY, * FROM ";
if(objActualFormat_ == SQLMP)
query += getTableName(tableName_->data(), nameSpace_);
else
query += getTableName(ansiName_->data(), nameSpace_);
retcode_ = SQL_EXEC_ClearDiagnostics(stmt);
// to prevent false alarms for statement heap memory allocation "smt"
// coverity[leaked_storage]
HSHandleError(retcode_);
retcode_ = SQL_EXEC_AllocStmt(stmt, 0);
HSHandleError(retcode_);
retcode_ = SQL_EXEC_AllocDesc(srcDesc, 1);
HSHandleError(retcode_);
retcode_ = SQL_EXEC_AllocDesc(outputDesc, 4096);
HSHandleError(retcode_);
retcode_ = SQL_EXEC_SetDescItem(srcDesc, 1, SQLDESC_TYPE_FS,
REC_BYTE_V_ANSI, 0);
HSHandleError(retcode_);
retcode_ = SQL_EXEC_SetDescItem(srcDesc, 1, SQLDESC_VAR_PTR,
(Long)query.data(), 0);
HSHandleError(retcode_);
retcode_ = SQL_EXEC_SetDescItem(srcDesc, 1, SQLDESC_LENGTH,
query.length() + 1, 0);
HSHandleError(retcode_);
// SQLDESC_CHAR_SET must be the last descriptor item set, otherwise
// it may get reset by other calls to SQL_EXEC_SetDescItem().
NAString charSet = ActiveSchemaDB()->getDefaults().getValue(ISO_MAPPING);
NAString defCS = ActiveSchemaDB()->getDefaults().getValue(DEFAULT_CHARSET);
retcode_ = SQL_EXEC_SetDescItem(srcDesc, 1, SQLDESC_CHAR_SET,
SQLCHARSETCODE_UTF8
, 0);
HSHandleError(retcode_);
// ---------------------------------------------------------------------
// Prepare the statement
// If there is an error, there are no SYSKEYs for the table.
// (Most common case).
// ---------------------------------------------------------------------
retcode_ = SQL_EXEC_Prepare(stmt, srcDesc);
if (retcode_ == -4001) retcode_ = 0; // -4001 is 'Column not found'.
else if (retcode_ != 0) { HSHandleError(retcode_); }
else // retcode is 0 - SYSKEY column found.
{
// There were columns named SYSKEY. If there is only 1 column
// named SYSKEY, then it is a system defined SYSKEY. If there
// are two columns named SYSKEY, then both are actually the
// same column and are a user defined column.
retcode_ = SQL_EXEC_DescribeStmt(stmt, 0, outputDesc);
HSHandleError(retcode_);
retcode_ = SQL_EXEC_GetDescEntryCount(outputDesc, &numCols_);
HSHandleError(retcode_);
Int32 syskeyCnt=0;
for (Int32 i = 0; i < numCols_; i++)
{
// Check to see if column name is SYSKEY. If there are
// two present, then a system defined SYSKEY does not exist.
entry = i + 1;
retcode_ = SQL_EXEC_GetDescItem(outputDesc, entry,
SQLDESC_NAME,
0, colName, sizeof(colName), &len, 0);
if (retcode_ == 0 && len >= sizeof(colName) ) retcode_ = -1;
HSHandleError(retcode_);
colName[len] = '\0';
if (!strcmp(colName, "SYSKEY")) syskeyCnt++;
if (syskeyCnt > 1) break;
}
if (syskeyCnt == 1) hasSyskey_ = TRUE;
}
retcode_ = SQL_EXEC_DeallocStmt(stmt);
HSHandleError(retcode_);
// to prevent false alarms for statement heap memory allocation
// for "stmt", "srcDesc", "outoutDesc"
// coverity[leaked_storage]
return retcode_;
}
Lng32 HSTableDef::getColNum(const char *colName, NABoolean errIfNotFound) const
{
Lng32 retcode = -1;
NAString ansiForm(colName);
HSLogMan *LM = HSLogMan::Instance();
for (Int32 i = 0; i < numCols_; i++)
{
if ((&colInfo_[i] != NULL) &&
(ansiForm == *colInfo_[i].colname))
{
// raise an error when a LOB column is explicitly specified
if (DFS2REC::isLOB(colInfo_[i].datatype))
{
if (LM->LogNeeded())
{
sprintf(LM->msg, "***[ERROR]: Column (%s) is a LOB column.", colName);
LM->Log(LM->msg);
}
HSFuncMergeDiags(-UERR_LOB_STATS_NOT_SUPPORTED, colName);
HSHandleError(retcode);
return retcode;
}
return i;
}
}
if (!errIfNotFound)
return -1;
if (LM->LogNeeded())
{
sprintf(LM->msg, "***[ERROR]: Column (%s) does not exist.", colName);
LM->Log(LM->msg);
}
HSFuncMergeDiags( - UERR_COLUMN_NAME_DOES_NOT_EXIST
, colName
, getObjectFullName().data()
);
HSHandleError(retcode);
return retcode;
}
char* HSTableDef::getColName(Lng32 colNum) const
{
HS_ASSERT((colNum >= 0) &&
(colNum < numCols_));
return (char*)colInfo_[colNum].colname->data();
}
HSColumnStruct& HSTableDef::getColInfo(Lng32 colNum) const
{
HS_ASSERT((colNum >= 0) &&
(colNum < numCols_));
return colInfo_[colNum];
}
NAString HSSqTableDef::getNodeName() const
{
NAString node;
return node;
}
NAString HSTableDef::getObjectFullName() const
{
if(objActualFormat_ == SQLMP)
return tableName_->data();
else
return ansiName_->data();
}
NAString HSSqTableDef::getCatalogLoc(formatType format) const
{
NAString catalogName;
return catalogName;
}
NAString HSTableDef::getPrimaryLoc(formatType format) const
{
NAString loc;
if (format == INTERNAL_FORMAT)
{
loc.append(catalog_->data());
loc.append(".");
loc.append(schema_->data());
}
else
{
if (objActualFormat_ == SQLMP)
{
loc.append(catalog_->data());
loc.append(".");
loc.append(ToAnsiIdentifier(schema_->data()));
}
else
{
loc.append(ToAnsiIdentifier(catalog_->data()));
loc.append(".");
loc.append(ToAnsiIdentifier(schema_->data()));
}
}
return loc;
}
NAString HSTableDef::getCatName(formatType format) const
{
NAString cat;
if (format == INTERNAL_FORMAT ||
objActualFormat_ == SQLMP)
{
cat.append(catalog_->data());
}
else
{
cat.append(ToAnsiIdentifier(catalog_->data()));
}
return cat;
}
NAString HSTableDef::getSchemaName(formatType format) const
{
NAString sch;
if (format == INTERNAL_FORMAT)
{
sch.append(schema_->data());
}
else
{
sch.append(ToAnsiIdentifier(schema_->data()));
}
return sch;
}
NAString HSTableDef::getObjectName(formatType format) const
{
NAString obj;
if (format == INTERNAL_FORMAT)
{
obj.append(object_->data());
}
else
{
obj.append(ToAnsiIdentifier(object_->data()));
}
return obj;
}
Lng32 HSSqTableDef::getTotalVarcharLength() const
{
Lng32 length = 0;
for (Int32 i = 0; i < numCols_; i++)
{
if (DFS2REC::isAnyVarChar(colInfo_[i].datatype))
{
length += colInfo_[i].length ;
}
}
return length;
}
/***********************************************/
/* METHOD: collectFileStatistics() */
/* PURPOSE: Collect File-Level Statistics */
/* RETCODE: 0 - successful */
/* -1 - internal error, buffer */
/* length too small. */
/* SQLCODE - <0 failure */
/* >=0 successful */
/* ASSUMPTIONS: A transaction has already been */
/* started. */
/***********************************************/
Lng32 HSSqTableDef::collectFileStatistics() const
{
Lng32 retcode = 0;
char buf[2000];
char *ddl = buf;
HSLogMan *LM = HSLogMan::Instance();
HS_ASSERT(labelAccessed_ == TRUE);
LM->StartTimer("Collect file statistics");
// File-Level Statistics are only determined for MX objects
if (objActualFormat_ == SQLMX)
{
// feature is not supported
HSFuncMergeDiags(-UERR_INTERNAL_ERROR, "FILE_STATS");
retcode = -1;
}
LM->StopTimer();
return retcode;
}
//=====================================================
NABoolean HSHiveTableDef::objExists(NABoolean createExternalTable)
{
setNATable();
if (!naTbl_)
return FALSE;
if (!setObjectUID(createExternalTable))
return FALSE;
// cannot upd stats if the object is a hive view
if (naTbl_->getViewText())
{
*CmpCommon::diags()
<< DgSqlCode(-UERR_INVALID_OBJECT)
<< DgString0(naTbl_->getTableName().getQualifiedNameAsString());
return FALSE;
}
tableStats_ = naTbl_->getClusteringIndex()->getHHDFSTableStats();
*ansiName_ = *catalog_;
ansiName_->append('.');
ansiName_->append(*schema_);
ansiName_->append('.');
ansiName_->append(*object_);
HiveMetaData* hiveMetaDB;
if (CmpCommon::getDefault(HIVE_USE_FAKE_TABLE_DESC) != DF_ON)
{
hiveMetaDB = new(STMTHEAP) HiveMetaData();
if (!hiveMetaDB->init())
{
*CmpCommon::diags() << DgSqlCode(-1190)
<< DgString0(hiveMetaDB->getErrMethodName())
<< DgString1(hiveMetaDB->getErrCodeStr())
<< DgString2(hiveMetaDB->getErrDetail())
<< DgInt0(hiveMetaDB->getErrCode());
NADELETEBASIC(hiveMetaDB, STMTHEAP); // HiveMetaData not
//derived from NABasicObject
return FALSE;
}
}
else
hiveMetaDB = new(STMTHEAP) HiveMetaData(); // fake metadata
if (!HSGlobalsClass::isHiveCat(*catalog_))
{
*CmpCommon::diags()
<< DgSqlCode(-1388)
<< DgString0("Object")
<< DgString1(*object_);
return FALSE;
}
// The default schema name is what the Hive default schema is called in SeaHive.
NAString defSchema = ActiveSchemaDB()->getDefaults().getValue(HIVE_DEFAULT_SCHEMA);
defSchema.toUpper();
NAString obj = *object_;
NAString sch = *schema_;
if (sch == defSchema)
sch = hiveMetaDB->getDefaultSchemaName();
// Hive stores names in lower case.
sch.toLower();
obj.toLower();
if (CmpCommon::getDefault(HIVE_USE_FAKE_TABLE_DESC) == DF_ON)
hiveTblDesc_ = hiveMetaDB->getFakedTableDesc(obj.data());
else
hiveTblDesc_ = hiveMetaDB->getTableDesc(sch.data(), obj.data());
if (!hiveTblDesc_)
{
if ((hiveMetaDB->getErrCode() == 0)||(hiveMetaDB->getErrCode() == 100))
{
*CmpCommon::diags()
<< DgSqlCode(-1388)
<< DgString0("Object")
<< DgString1(*object_);
}
else
{
*CmpCommon::diags()
<< DgSqlCode(-1192)
<< DgString0(hiveMetaDB->getErrMethodName())
<< DgString1(hiveMetaDB->getErrCodeStr())
<< DgString2(hiveMetaDB->getErrDetail())
<< DgInt0(hiveMetaDB->getErrCode());
hiveMetaDB->resetErrorInfo();
}
return FALSE;
}
objActualFormat_ = SQLMX;
return TRUE;
}
NAString HSHiveTableDef::getNodeName() const
{
HS_ASSERT(FALSE); // MP only
return "";
}
NAString HSHiveTableDef::getCatalogLoc(formatType format) const
{
HS_ASSERT(FALSE); // MP only
return "";
}
NAString HSHiveTableDef::getHistLoc(formatType format) const
{
return HIVE_STATS_CATALOG "." HIVE_STATS_SCHEMA;
}
Int64 HSHiveTableDef::getRowCount(NABoolean &isEstimate,
Int64 &numInserts,
Int64 &numDeletes,
Int64 &numUpdates,
Int64 &numPartitions,
Int64 &minRowCtPerPartition,
Int32 &errorCode,
Int32 &breadCrumb,
NABoolean estimateIfNecessary)
{
errorCode = 0;
breadCrumb = -6;
if (minPartitionRows_ == -1)
{
Int64 partitionEstRows;
for (CollIndex i=0; i<tableStats_->entries(); i++)
{
partitionEstRows = (*tableStats_)[i]->getEstimatedRowCount();
if (minPartitionRows_ == -1 || partitionEstRows < minPartitionRows_)
minPartitionRows_ = partitionEstRows;
}
}
numInserts = numDeletes = numUpdates = 0;
numPartitions = getNumPartitions();
minRowCtPerPartition = minPartitionRows_;
return getRowCount(isEstimate, errorCode, breadCrumb, estimateIfNecessary);
}
Lng32 HSHiveTableDef::DescribeColumnNames()
{
hive_column_desc* hiveColDesc = hiveTblDesc_->getColumns();
while (hiveColDesc)
{
numCols_++;
hiveColDesc = hiveColDesc->next_;
}
colInfo_ = new(STMTHEAP) HSColumnStruct[numCols_];
hiveColDesc = hiveTblDesc_->getColumns();
for (Int32 i=0; i<numCols_; i++)
{
*(colInfo_[i].colname) = hiveColDesc->name_;
colInfo_[i].colname->toUpper();
*colInfo_[i].externalColumnName = getAnsiName(*colInfo_[i].colname);
NAType* natype = getSQColTypeForHive(hiveColDesc->type_, STMTHEAP);
colInfo_[i].datatype = natype->getFSDatatype();
colInfo_[i].nullflag = natype->supportsSQLnullLogical();
colInfo_[i].charset = natype->getCharSet();
if (DFS2REC::isAnyCharacter(natype->getFSDatatype()))
{
colInfo_[i].colCollation = (static_cast<CharType*>(natype))->getCollation();
colInfo_[i].caseInsensitive = (static_cast<CharType*>(natype))->isCaseinsensitive();
}
colInfo_[i].length = natype->getNominalSize();
colInfo_[i].precision = natype->getPrecision();
colInfo_[i].scale = natype->getScale();
hiveColDesc = hiveColDesc->next_;
}
return 0;
}
//=====================================================
//
NAString HSHbaseTableDef::getNodeName() const
{
HS_ASSERT(FALSE); // MP only
return "";
}
NAString HSHbaseTableDef::getCatalogLoc(formatType format) const
{
HS_ASSERT(FALSE); // MP only
return "";
}
NAString HSHbaseTableDef::getHistLoc(formatType format) const
{
if ( HSGlobalsClass::isNativeHbaseCat(getCatName(format))) {
return HBASE_STATS_CATALOG "." HBASE_STATS_SCHEMA;
} else {
NAString name(getCatName(format));
name.append(".");
name.append(getSchemaName(format));
return name;
}
}
static
Lng32 RegisterHiveTable(const NAString& catName, const NAString& schName, const NAString& nativeTableName)
{
HSLogMan *LM = HSLogMan::Instance();
if (LM->LogNeeded())
{
snprintf(LM->msg, sizeof(LM->msg), "Registering hive table %s on demand.",
nativeTableName.data());
LM->Log(LM->msg);
}
// do not have to worry about the catalog and schema for the new external table
// here. These names will be determined by the processing logic.
NAString ddl = "REGISTER INTERNAL HIVE TABLE IF NOT EXISTS ";
ddl.append(catName);
ddl.append(".");
ddl.append(schName);
ddl.append(".");
ddl.append(nativeTableName);
// set INTERNAL_QUERY_FROM_EXEUTIL bit in Sql_ParserFlags.
// This is needed to process 'register internal' syntax
ULng32 flagToSet = INTERNAL_QUERY_FROM_EXEUTIL;
PushAndSetSqlParserFlags savedParserFlags(flagToSet);
Lng32 retcode = HSFuncExecDDL(ddl.data(), - UERR_INTERNAL_ERROR, NULL,
"register hive table", NULL);
if (retcode < 0 && LM->LogNeeded())
{
snprintf(LM->msg, sizeof(LM->msg), "Registration of the hive table failed.");
LM->Log(LM->msg);
}
return retcode;
}
static
Lng32 RegisterHBaseTable(const NAString& catName, const NAString& schName,
const NAString& nativeTableName)
{
HSLogMan *LM = HSLogMan::Instance();
if (LM->LogNeeded())
{
snprintf(LM->msg, sizeof(LM->msg), "Registering hbase table %s on demand.",
nativeTableName.data());
LM->Log(LM->msg);
}
// do not have to worry about the catalog and schema for the new external table
// here. These names will be determined by the processing logic.
NAString ddl = "REGISTER INTERNAL HBASE TABLE IF NOT EXISTS ";
ddl.append(catName);
ddl.append(".");
ddl.append(schName);
ddl.append(".");
ddl.append(nativeTableName);
// set INTERNAL_QUERY_FROM_EXEUTIL bit in Sql_ParserFlags.
// This is needed to process 'register internal' syntax
ULng32 flagToSet = INTERNAL_QUERY_FROM_EXEUTIL;
PushAndSetSqlParserFlags savedParserFlags(flagToSet);
Lng32 retcode = HSFuncExecDDL(ddl.data(), - UERR_INTERNAL_ERROR, NULL,
"register hbase table", NULL);
if (retcode < 0 && LM->LogNeeded())
{
snprintf(LM->msg, sizeof(LM->msg), "Registration of the hbase table failed.");
LM->Log(LM->msg);
}
return retcode;
}
NABoolean HSTableDef::setObjectUID(NABoolean createExternalTable)
{
objectUID_ = naTbl_->objectUid().get_value();
if (createExternalTable && objectUID_ <= 0 &&
HSGlobalsClass::isNativeCat(getCatName(EXTERNAL_FORMAT)) ) {
// If objectUID is not set, it means there is no corresponding
// external table created for it. Need to create one here.
NAString catName = getCatName(EXTERNAL_FORMAT);
NAString schName = getSchemaName(EXTERNAL_FORMAT);
NAString objName = getObjectName(EXTERNAL_FORMAT);
Lng32 retcode = 0;
setNATable();
if (!naTbl_)
return FALSE;
if ((catName == HIVE_SYSTEM_CATALOG) &&
(naTbl_->isView()))
{
CmpCommon::diags()->clear();
*CmpCommon::diags()
<< DgSqlCode(-UERR_INVALID_OBJECT)
<< DgString0(naTbl_->getTableName().getQualifiedNameAsString());
return FALSE;
}
if (catName == HIVE_SYSTEM_CATALOG)
retcode = RegisterHiveTable(catName, schName, objName);
else
retcode = RegisterHBaseTable(catName, schName, objName);
if (retcode != 0)
return FALSE;
setNATable();
if (!naTbl_)
return FALSE;
CorrName corrName(objName, STMTHEAP, schName, catName);
if ( !naTbl_->fetchObjectUIDForNativeTable(corrName, naTbl_->isView()) )
return FALSE;
objectUID_ = naTbl_->objectUid().get_value();
HSLogMan *LM = HSLogMan::Instance();
if (LM->LogNeeded()) {
sprintf(LM->msg, "NATable::fetchObjectUIDForNativeTable() returns %ld\n", objectUID_);
LM->Log(LM->msg);
}
}
if ( createExternalTable )
return (objectUID_ > 0);
else
return TRUE;
}
NABoolean HSHbaseTableDef::objExists(NABoolean createExternalTable)
{
HSLogMan *LM = HSLogMan::Instance();
if (LM->LogNeeded()) {
sprintf(LM->msg, "call HSHbaseTableDef::objExists\n");
LM->Log(LM->msg);
}
setNATable();
if (!naTbl_)
return FALSE;
if (!setObjectUID(createExternalTable))
return FALSE;
*ansiName_ = getCatName(EXTERNAL_FORMAT);
ansiName_->append(".");
ansiName_->append(getSchemaName(EXTERNAL_FORMAT));
ansiName_->append(".");
ansiName_->append(getObjectName(EXTERNAL_FORMAT));
if (!HSGlobalsClass::isHbaseCat(*catalog_))
{
*CmpCommon::diags()
<< DgSqlCode(-1389)
<< DgTableName(*object_);
return FALSE;
}
Lng32 retcode_ = getColumnNames();
HSHandleError(retcode_);
if (LM->LogNeeded()) {
sprintf(LM->msg, "objectUID_ set to %ld\n", objectUID_);
sprintf(LM->msg, "naTbl_->objectUid() is %ld\n", naTbl_->objectUid().get_value());
LM->Log(LM->msg);
}
objActualFormat_ = SQLMX;
return TRUE;
}
Lng32 HSHbaseTableDef::getNumPartitions() const
{
return getNATable()->getClusteringIndex()->getCountOfPartitions();
}
Int64 HSHbaseTableDef::getRowCount(NABoolean &isEstimate,
Int32 &errorCode,
Int32 &breadCrumb,
NABoolean estimateIfNecessary)
{
errorCode = 0;
breadCrumb = -2;
isEstimate = TRUE;
if (estimateIfNecessary &&
!naTbl_->isSeabaseMDTable() &&
CmpCommon::getDefault(USTAT_ESTIMATE_HBASE_ROW_COUNT) == DF_ON)
// use a 4 minute retry limit (expressed in milliseconds)
return naTbl_->estimateHBaseRowCount(4*60*1000, errorCode, breadCrumb);
else
return 0;
}
Int64 HSHbaseTableDef::getRowCount(NABoolean &isEstimate,
Int64 &numInserts,
Int64 &numDeletes,
Int64 &numUpdates,
Int64 &numPartitions,
Int64 &minRowCtPerPartition,
Int32 &errorCode,
Int32 &breadCrumb,
NABoolean estimateIfNecessary)
{
// Comparable code for Hive tables:
//if (minPartitionRows_ == -1)
// {
// Int64 partitionEstRows;
// for (CollIndex i=0; i<tableStats_->entries(); i++)
// {
// partitionEstRows = (*tableStats_)[i]->getEstimatedRowCount();
// if (minPartitionRows_ == -1 || partitionEstRows < minPartitionRows_)
// minPartitionRows_ = partitionEstRows;
// }
// }
//numInserts = numDeletes = numUpdates = 0;
//numPartitions = getNumPartitions();
//minRowCtPerPartition = minPartitionRows_;
return getRowCount(isEstimate, errorCode, breadCrumb, estimateIfNecessary);
}
Lng32 HSHbaseTableDef::DescribeColumnNames()
{
// This will be called from AddTableName() with the default (NULL) argument,
// but for this subclass, it will have already been called from objExists()
// with a non-null NATable*.
if (!naTbl_)
return 0;
const NAType* natype;
const NAColumnArray& colArr = naTbl_->getNAColumnArray();
numCols_ = colArr.entries();
colInfo_ = new(STMTHEAP) HSColumnStruct[numCols_];
for (CollIndex i=0; i<numCols_; i++)
{
colInfo_[i].colnum = i; // position of col in table
*(colInfo_[i].colname) = colArr[i]->getColName();
*colInfo_[i].externalColumnName = getAnsiName(*colInfo_[i].colname);
natype = colArr[i]->getType();
colInfo_[i].datatype = natype->getFSDatatype();
colInfo_[i].nullflag = natype->supportsSQLnullLogical();
colInfo_[i].charset = natype->getCharSet();
if (DFS2REC::isAnyCharacter(natype->getFSDatatype()))
{
colInfo_[i].colCollation = (static_cast<const CharType*>(natype))->getCollation();
colInfo_[i].caseInsensitive = (static_cast<const CharType*>(natype))->isCaseinsensitive();
}
colInfo_[i].length = natype->getNominalSize();
colInfo_[i].precision = natype->getPrecision();
colInfo_[i].scale = natype->getScale();
}
return 0;
}
//
// METHOD: addTruncatedSelectList()
//
// PURPOSE: Generates a SELECT list consisting of
// column references or a SUBSTRING
// on column references which truncates the
// column to the maximum length allowed in
// UPDATE STATISTICS. Also skips LOB columns.
//
// INPUT: 'qry' - the SQL query string to append the
// select list to.
//
void HSTableDef::addTruncatedSelectList(NAString & qry)
{
bool first = true;
for (Lng32 i = 0; i < getNumCols(); i++)
{
if (DFS2REC::isLOB(getColInfo(i).datatype)) // skip LOB columns
continue;
// skip derived column names (e.g. "_SALT_", "_DIVISION_n_")
// but only in Trafodion tables
if ((getTblOrigin() != HBASE_TBL) ||
(!ComTrafReservedColName(*getColInfo(i).colname)))
{
if (!first)
qry += ", ";
getColInfo(i).addTruncatedColumnReference(qry);
first = false;
}
}
}