blob: 9f52ebfbbc29e742bfa859b6a9c4c7528a4c0847 [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: ObjectNames.C
* Description: External SQL object names
*
* Created: 10/25/95
* Language: C++
*
*
******************************************************************************
*/
#define SQLPARSERGLOBALS_FLAGS // must precede all #include's
#define SQLPARSERGLOBALS_CONTEXT_AND_DIAGS // must be first
#define SQLPARSERGLOBALS_NADEFAULTS // must be first
#include "NAWinNT.h" // platform-independent stuff
#include "ObjectNames.h"
#include "ComMPLoc.h"
#include "ComRtUtils.h"
#include "SchemaDB.h"
#include "BindWA.h"
#include "ItemColRef.h"
#include "parser.h"
#include "RelScan.h"
#include "StmtNode.h"
#include "CmpSeabaseDDL.h"
#include "ComSmallDefs.h"
#include "ComResWords.h"
#include "SqlParserGlobals.h" // must be last
// -----------------------------------------------------------------------
// Context variable for "getXxxAsAnsiString()" methods simplifies the
// calling interface (we don't have to pass a boolean all over the place).
//
// The Parser has made all identifiers into a canonical form:
// regular ones are uppercased, with no enclosing quotes;
// delimited ones have internal double-doublequotes reduced to one dquote,
// and also with no enclosing quotes.
//
// This allows all equality tests (in particular, those done by NAKeyLookup)
// to work correctly. Output of identifiers, in error messages or in a
// SQL DESCRIBE statement (in the Generator), uses getXxxAsAnsiString()
// to properly re-delimit any delimited identifiers.
// Note that such outputting is only going to be done once per object,
// so there's no need to really optimize it.
// See ToAnsiIdentifier() in NAString.C for details of this operation.
// -----------------------------------------------------------------------
static THREAD_P NABoolean formatAsAnsiIdentifier = FALSE;
#define FORMAT(s) formatAsAnsiIdentifier ? ToAnsiIdentifier(s) : s
#define FORMAT_NO_ASSERT(s) formatAsAnsiIdentifier ? ToAnsiIdentifier(s, FALSE) : s
// -----------------------------------------------------------------------
// Function GetAnsiNameCharSet()
// -----------------------------------------------------------------------
CharInfo::CharSet GetAnsiNameCharSet()
{
return OBJECTNAMECHARSET;
}
// -----------------------------------------------------------------------
// Methods for class CatalogName
// -----------------------------------------------------------------------
// See .h file comments re Genesis 10-970902-0878.
void CatalogName::setNamePosition(StringPos namePos, NABoolean setDelimited)
{
namePos_ = namePos;
isDelimited_ = setDelimited;
}
// -----------------------------------------------------------------------
// Methods for class QualifiedName
// -----------------------------------------------------------------------
NABoolean QualifiedName::operator==(const NAString& simpleName) const
{
// This method is just syntactic sugar to compare if QualifiedName is empty
CMPASSERT(simpleName == (const char *)"");
// Ignore the name space attribute - i.e. use this name space.
QualifiedName rhs(simpleName);
rhs.setObjectNameSpace(this->getObjectNameSpace());
return *this == rhs;
}
QualifiedName & QualifiedName::operator=(const QualifiedName& rhs)
{
if (&rhs == this) return *this;
setCatalogName (rhs.getCatalogName ());
setSchemaName (rhs.getSchemaName ());
setObjectName (rhs.getObjectName ());
setObjectNameSpace (rhs.getObjectNameSpace());
setNamePosition(rhs.getNamePosition(), FALSE);
setIsDelimited (rhs.isDelimited ());
flagbits_ = rhs.flagbits_ ;
return *this;
}
NAString QualifiedName::getQualifiedNameAsString(NABoolean formatForDisplay,
NABoolean externalDisplay) const
{
// Preallocate a result buffer that'll be big enough most of the time
// (so += won't reallocate+copy most of the time).
NAString result((NASize_T)40, CmpCommon::statementHeap());
// The object name can be empty if it's an ambiguous column reference
// (in a join), e.g. In that case, do NOT prepend "cat.sch." to colrefname
// which would yield the incorrect string "cat.sch..col".
//
if (NOT getObjectName().isNull())
{
// If volatile, only output the object part of the external name.
// cat/sch names are internal.
if ((formatForDisplay) &&
(isVolatile()))
{
result += FORMAT(getObjectName());
}
else
{
if (NOT getCatalogName().isNull() && NOT externalDisplay)
{
if ((SqlParser_NADefaults_Glob != NULL) AND
(SqlParser_NADefaults_Glob->NAMETYPE_ == DF_SHORTANSI) AND
(*getCatalogName().data() == '\\'))
{
formatAsAnsiIdentifier = FALSE;
}
result = FORMAT(getCatalogName());
result += ".";
CMPASSERT(NOT getSchemaName().isNull());
}
if (NOT getSchemaName().isNull())
{
result += FORMAT(getSchemaName());
result += ".";
}
result += FORMAT(getObjectName());
}
}
return result;
}
// -----------------------------------------------------------------------
// makeSafeFilenamePart() and
// QualifiedName::getQualifiedNameAsAnsiNTFilenameString()
//
// Genesis 10-990113-5782
// Make sure that the end result of this function results in a valid
// file name for the system -- whether NT or OSS.
//
// Convert any invalid NT filename characters to underscores.
//
// A valid NT (or OSS) filename may be up to 255 characters including spaces.
// The characters
// \/:*?<>|"
// are not allowed in the filename at all.
// Furthermore, a POSIX shell (MKS KornShell on NT, OSS on NSK)
// treats the following specially, so they do not make good chars for filenames:
// $%&();' and space
//
// SQL identifiers can be up to 128 characters long in regular or
// delimited format.
//
// Regular identifiers begin with A-Z or a-z and can contain digits 0-9 or
// underscores. Regular identifiers are not case sensitive. Reserved words
// may not be used in a regular identifier.
//
// Delimited identifiers always begin with a " character, and can contain
// both upper and lowercase Latin-1 characters, as well as
// \/|<>*?:"
// $%&();' and space
// +-=[],.
// digits 0-9 and underscore
//
// This routine will convert all non-alphanumeric chars
// to the underscore character, and result in a filename which when treated
// as an Ansi qualified name (a MODULE name), is composed only of regular
// identifiers -- no "quoting" needed.
//
// The length of a module name that might get generated
// could be a string of over 255 characters. 128 for each of the three parts.
// 2 characters for each part if delimited plus the period separators not
// counting any quotes which are embedded and doubled which might be
// singled again.
//
// There might still be problems because NT is not case sensitive but
// SQL is where delimited identifiers are concerned and that is not being
// addressed here. We're just going to assume that we won't have two
// catalogs and schemas that are the same delimited if case is not considered
// that will cause problems in NT. We will be replacing all characters
// that cause the name to be delimited with underscore.
//
// If we need to truncate any one of the three parts (not generally the
// user supplied portion (mainly just the module name portion), then we
// will need to verify that the truncated result does not result in a
// reserved word. Might possibly happen depending on how we decide to
// handle the case where the length of 2 of the parts nears the 255
// character file name limit for NT and we decide to truncate one part
// down to a size that might result in a reserved word.
// -----------------------------------------------------------------------
//
static void makeSafeFilenamePart(NAString &ns, const NAString &prefix)
{
size_t len = ns.length();
for (size_t i=0; i<len; i++) {
if (!isalnum(ns[i]) && ns[i] != '_')
ns[i] = '_';
}
if (!len || !isalpha(ns[(size_t)0])) // must begin with an alphabetic
ns.prepend(prefix);
}
const NAString QualifiedName::getQualifiedNameAsAnsiNTFilenameString() const
{
// Preallocate a result buffer that'll be big enough most of the time
// (so += won't reallocate+copy most of the time).
NAString result((NASize_T)40, CmpCommon::statementHeap());
NAString catName(CmpCommon::statementHeap());
NAString schName(CmpCommon::statementHeap());
NAString objName(CmpCommon::statementHeap());
formatAsAnsiIdentifier = TRUE; // put quotes on delimited identifiers
if ( NOT getCatalogName().isNull() ) {
catName = FORMAT(getCatalogName());
makeSafeFilenamePart(catName, "SQLMX_DEFAULT_CATALOG_");
}
if ( NOT getSchemaName().isNull() ) {
schName = FORMAT(getSchemaName());
makeSafeFilenamePart(schName, "SQLMX_DEFAULT_SCHEMA_");
}
if ( NOT getObjectName().isNull() ) {
objName = FORMAT(getObjectName());
}
makeSafeFilenamePart(objName, "SQLMX_DEFAULT_FILE_");
formatAsAnsiIdentifier = FALSE; // reset to initial value
size_t totlen = catName.length() + schName.length() + objName.length() + 2;
if ( totlen > 255 ) { // need to truncate
// +1 so round off doesn't give us less than what we need to chop
size_t chopLen = totlen - 255 + 1;
if ( catName.length() - chopLen/2 <= 0 ) // cat too short
schName.remove( schName.length() - chopLen );
else if ( schName.length() - chopLen/2 <= 0 ) // sch too short
catName.remove( catName.length() - chopLen );
else { // chop from both
// remember position starts at 0 and length is 1 more
chopLen /= 2;
catName.remove( catName.length() - chopLen - 1 );
schName.remove( schName.length() - chopLen - 1 );
}
}
if (NOT catName.isNull()) {
result = catName;
result += ".";
}
if (NOT schName.isNull()) {
result += schName;
result += ".";
}
result += objName;
return result;
}
const NAString QualifiedName::getQualifiedNameAsAnsiString(NABoolean formatForDisplay,
NABoolean externalDisplay) const
{
formatAsAnsiIdentifier = TRUE;
NAString result(getQualifiedNameAsString(formatForDisplay, externalDisplay),
CmpCommon::statementHeap());
formatAsAnsiIdentifier = FALSE;
return result;
}
NABoolean SchemaName::matchDefaultPublicSchema()
{
if (schemaName_.isNull())
return TRUE;
NABoolean matched = FALSE;
// get default schema
NAString defCat;
NAString defSch;
ActiveSchemaDB()->getDefaults().getCatalogAndSchema(defCat, defSch);
ToInternalIdentifier(defCat);
ToInternalIdentifier(defSch);
// get public schema
NAString publicSchema = ActiveSchemaDB()->getDefaults().getValue(PUBLIC_SCHEMA_NAME);
ComSchemaName pubSchema(publicSchema);
NAString pubCat = pubSchema.getCatalogNamePart().getInternalName();
NAString pubSch = pubSchema.getSchemaNamePart().getInternalName();
// if catalog was not specified
NAString catName = (catalogName_.isNull()? defCat:catalogName_);
pubCat = (pubCat.isNull()? defCat:pubCat);
if (((catName==defCat) && (schemaName_==defSch)) ||
((catName==pubCat) && (schemaName_==pubSch)))
matched = TRUE;
return matched;
}
const NAString SchemaName::getSchemaNameAsAnsiString() const
{
QualifiedName q("X", getSchemaName(), getCatalogName());
NAString result(q.getQualifiedNameAsAnsiString(), CmpCommon::statementHeap());
CMPASSERT(result[result.length()-1] == 'X');
result.remove(result.length()-2); // remove the '.X'
return result;
}
void SchemaName::getHiveSchemaName(
NAString &hiveSchemaName // OUT: Hive schema name
) const
{
NAString hiveDefSchema =
ActiveSchemaDB()->getDefaults().getValue(HIVE_DEFAULT_SCHEMA);
hiveDefSchema.toUpper();
if (schemaName_ == hiveDefSchema)
hiveSchemaName = HiveMetaData::getDefaultSchemaName();
else
{
hiveSchemaName = schemaName_;
hiveSchemaName.toLower();
}
}
// ODBC SHORTANSI -- the actual MPLoc is encoded in the schName
// using underscore delimiters, i.e. "systemName_volumeName_subvolName".
// We make a real MPLoc out of that.
NABoolean QualifiedName::applyShortAnsiDefault(NAString& catName,
NAString& schName) const
{
ComMPLoc loc;
loc.parse(schName, ComMPLoc::SUBVOL, TRUE/*SHORTANSI*/);
if (loc.isValid(ComMPLoc::SUBVOL)) {
catName = loc.getSysDotVol();
schName = loc.getSubvolName();
return TRUE;
}
//else schName actually was a real Ansi schema,
//so we return cat & schName unchanged.
//## Is this the desired behavior, or does this represent an undetected error?
return FALSE;
}
// Name parts return in string parameters, defaulted if not yet present;
// this object is not modified.
// Function return value is the number of names that match the default,
// {0, 1, 2} = {no matches, catalog matches, catalog&schema match}.
//
// If NAMETYPE is NSK, the SchemaDB puts the current MPLOC into the defCatSch;
// so this method has to handle **only one** tiny NSK naming detail.
//
Int32 QualifiedName::extractAndDefaultNameParts(const SchemaName& defCatSch
, NAString& catName // OUT
, NAString& schName // OUT
, NAString& objName // OUT
) const
{
catName = getCatalogName();
schName = getSchemaName();
objName = getObjectName();
CMPASSERT(NOT objName.isNull()); // no default for this!
{
if (catName.isNull()) {
if((ActiveSchemaDB()->getDefaults().schSetToUserID()) &&
(SqlParser_NAMETYPE == DF_SHORTANSI))
{
// If NAMETYPE is SHORTANSI and schema is not set
// in DEFAULTS table or by user, for dml, catName
// gets \SYS.$VOL from set or default MPLOC.
catName = SqlParser_MPLOC.getSysDotVol();
}
else
{
// If NAMETYPE NSK, catName will become \SYS.$VOL
catName = defCatSch.getCatalogName();
}
}
if (schName.isNull()) {
if((ActiveSchemaDB()->getDefaults().schSetToUserID()) &&
(SqlParser_NAMETYPE == DF_SHORTANSI))
{
// If NAMETYPE is SHORTANSI and schema is not set
// in DEFAULTS table or by user, for dml, schName
// gets subvol from set or default MPLOC.
schName = SqlParser_MPLOC.getSubvolName();
}
else
schName = defCatSch.getSchemaName();
}
}
CMPASSERT(NOT catName.isNull());
CMPASSERT(NOT schName.isNull());
Int32 defaultMatches = 0;
if (catName == defCatSch.getCatalogName()) {
defaultMatches++;
if (schName == defCatSch.getSchemaName())
defaultMatches++;
}
// Next comes support for table name resolution for SHORTANSI nametype,
// implemented as internal feature for ODBC use only.
//
// For the name resolution of table name when nametype is SHORTANSI,
// check is made to see if schName contains an '_', thus ensuring
// the method applyShortAnsiDefault is called only once.
// Correct syntax for schName is "systemName_volumeName_subvolName"
// of the MPLoc where the objName is actually located.
// Complete syntax checking is done inside applyShortAnsiDefault.
//
if (SqlParser_NAMETYPE == DF_SHORTANSI && schName.first('_') != NA_NPOS) {
applyShortAnsiDefault(catName, schName);
}
return defaultMatches;
}
// Applies the default catalog & schema to *this -- if either name part of this
// is empty, it is filled in (updated) with the default.
//
Int32 QualifiedName::applyDefaults(const SchemaName& defCatSch)
{
return extractAndDefaultNameParts( defCatSch
, catalogName_
, schemaName_
, objectName_
);
}
// This function copies the above applyDefaults() function
// and includes checking for the object existence and
// search in the public schema if necessary.
// This is used to replace the above function when
// we need to consider PUBLIC_SCHEMA_NAME
Int32 QualifiedName::applyDefaultsValidate(const SchemaName& defCatSch,
ComAnsiNameSpace nameSpace)
{
// need to try public schema if it is specified
// and the object schema is not specified
NAString publicSchema = "";
CmpCommon::getDefault(PUBLIC_SCHEMA_NAME, publicSchema, FALSE);
ComSchemaName pubSchema(publicSchema);
NAString pubSchemaIntName = "";
if ( getSchemaName().isNull() &&
!pubSchema.isEmpty() )
{
pubSchemaIntName = pubSchema.getSchemaNamePart().getInternalName();
}
Int32 ret = extractAndDefaultNameParts( defCatSch
, catalogName_
, schemaName_
, objectName_
);
// try public schema if the table does not exist
if (!pubSchemaIntName.isNull())
{
*(CmpCommon::diags()) << DgSqlCode(-4222)
<< DgString0("Public Access Schema");
}
return ret;
}
// Constructor that parses a 1-, 2-, or 3-part external (Ansi) name string
// and optionally applies default catalog and schema to it.
// Use this on a string gotten from a trusted source (Sql Catalog), because
// if it doesn't parse, the ctor cannot return an error so it CMPASSERTs.
//
// This code cloned for CorrName::applyPrototype below.
//
QualifiedName::QualifiedName(const NAString &ansiString,
Int32 minNameParts,
CollHeap * h,
BindWA *bindWA) :
SchemaName(h),
objectName_(h),
objectNameSpace_(COM_UNKNOWN_NAME),
flagbits_(0)
{
if (HasMPLocPrefix(ansiString.data())) {
ComMPLoc loc(ansiString);
catalogName_ = loc.getSysDotVol();
schemaName_ = loc.getSubvolName();
objectName_ = loc.getFileName();
}
else
{
CmpContext *cmpContext = bindWA ? bindWA->currentCmpContext() : NULL;
Parser parser(cmpContext);
NAString ns("TABLE " + ansiString + ";", CmpCommon::statementHeap());
// save the current parserflags setting
ULng32 savedParserFlags = Get_SqlParser_Flags (0xFFFFFFFF);
StmtQuery *stmt = (StmtQuery *)parser.parseDML(ns, ns.length(), GetAnsiNameCharSet());
// Restore parser flags settings
Set_SqlParser_Flags (savedParserFlags);
if (stmt) {
CMPASSERT(stmt->getOperatorType() == STM_QUERY);
*this = stmt->getQueryExpression()->getScanNode()->getTableName().getQualifiedNameObj();
delete stmt;
} else {
// It is possible for the parser to get errors when parsing SQL/MP
// stored text. The caller is expected to check the contents of
// this QualifiedName.
//
return;
}
}
Int32 nameParts = 0;
if (minNameParts > 0) {
nameParts = getCatalogName() != "" ? 3 :
getSchemaName() != "" ? 2 :
getObjectName() != "" ? 1 : 0;
CMPASSERT(nameParts >= minNameParts);
}
if (bindWA && nameParts < 3)
applyDefaults(bindWA->getDefaultSchema());
} // end of QualifiedName::QualifiedName
QualifiedName::QualifiedName(const ComObjectName &comObjNam, CollHeap * h)
: SchemaName (comObjNam.getSchemaNamePart ().getInternalName(),
comObjNam.getCatalogNamePart().getInternalName(), h),
objectName_(comObjNam.getObjectNamePart ().getInternalName(), h),
objectNameSpace_(comObjNam.getNameSpace()),
flagbits_(0)
{}
// See comments for ComMPLoc::getMPName(int *lenArray).
// The array size of 5 is CollationInfo::MAX_NAME_PARTS + 1.
//
const NAString QualifiedName::getQualifiedNameAsAnsiString(
size_t *lenArray /* array[5] */
) const
{
lenArray[0] = lenArray[1] = lenArray[2] = lenArray[3] = lenArray[4] = 0;
NAString n( getQualifiedNameAsAnsiString(), CmpCommon::statementHeap());
lenArray[1] = n.length(); // [1] = length of full name
size_t a = 1;
size_t i = 0;
const char *s = n.data();
for (NABoolean quoted = FALSE; *s; i++, s++) {
if (*s == '"')
quoted = !quoted;
if (*s == '.' && !quoted) {
lenArray[++a] = i + 1; // [2] thru [4] = offsets of trailing name parts
}
}
lenArray[0] = a; // [0] = the count of size_t's being returned
// (length + up to 3 offsets)
// (aka the number of nameparts)
return n; // Return the external-format string as well.
}
// If any parts of the name were defaulted (input param = nbr)
// and NAMETYPE was specified as other than ANSI
// return FALSE; else return TRUE.
NABoolean QualifiedName::verifyAnsiNameQualification(
Int32 nbrPartsDefaulted) const
{
if (nbrPartsDefaulted > 0)
if ((SqlParser_NADefaults_Glob != NULL) AND
(SqlParser_NADefaults_Glob->NAMETYPE_ != DF_ANSI))
return FALSE;
return TRUE;
}
NABoolean QualifiedName::isHive(const NAString &catName)
{
NAString hiveDefCatName = "";
CmpCommon::getDefault(HIVE_CATALOG, hiveDefCatName, FALSE);
hiveDefCatName.toUpper();
if (CmpCommon::getDefault(MODE_SEAHIVE) == DF_ON &&
((NOT catName.isNull()) &&
((catName == HIVE_SYSTEM_CATALOG) ||
(catName == hiveDefCatName))))
return TRUE;
return FALSE;
}
NABoolean QualifiedName::isHive() const
{
return isHive(getCatalogName());
}
NABoolean QualifiedName::isHbase(const NAString &catName)
{
return CmpSeabaseDDL::isHbase(catName);
}
NABoolean QualifiedName::isHbase() const
{
return isHbase(getCatalogName());
}
NABoolean QualifiedName::isSeabase(const NAString &catName)
{
return CmpSeabaseDDL::isSeabase(catName);
}
NABoolean QualifiedName::isSeabase() const
{
return isSeabase(getCatalogName());
}
NABoolean QualifiedName::isSeabaseMD() const
{
return CmpSeabaseDDL::isSeabaseMD(
getCatalogName(), getSchemaName(), getObjectName());
}
NABoolean QualifiedName::isSeabasePrivMgrMD() const
{
return CmpSeabaseDDL::isSeabasePrivMgrMD
(getCatalogName(), getSchemaName());
}
NABoolean QualifiedName::isHbaseMappedName() const
{
return ((isSeabase(getCatalogName())) &&
(ComIsHbaseMappedSchemaName(getSchemaName())));
}
NABoolean QualifiedName::isHbaseCell() const
{
if (isHbase() && (getSchemaName() == HBASE_CELL_SCHEMA))
return TRUE;
else
return FALSE;
}
NABoolean QualifiedName::isHbaseRow() const
{
if (isHbase() && (getSchemaName() == HBASE_ROW_SCHEMA))
return TRUE;
else
return FALSE;
}
NABoolean QualifiedName::isHbaseCellOrRow() const
{
if (isHbase() &&
((getSchemaName() == HBASE_CELL_SCHEMA) ||
(getSchemaName() == HBASE_ROW_SCHEMA)))
return TRUE;
else
return FALSE;
}
NABoolean QualifiedName::isLOBDesc() const
{
if ((getObjectName().index(LOB_DESC_HANDLE_PREFIX) == 0) || (getObjectName().index(LOB_DESC_CHUNK_PREFIX) ==0))
return TRUE;
else
return FALSE;
}
// -----------------------------------------------------------------------
// Methods for class CorrName
// -----------------------------------------------------------------------
ULng32 CorrName::hash() const
{
if (corrName_ != (const char *)"") {
if (formatAsAnsiIdentifier)
return ToAnsiIdentifier(corrName_).hash();
else
return corrName_.hash();
} else
return getQualifiedNameObj().hash();
}
CorrName & CorrName::operator = (const CorrName & rhs)
{
if (this==&rhs) return *this ;
qualName_ = rhs.qualName_ ;
corrName_ = rhs.corrName_ ;
//ct-bug-10-030102-3803 -Begin
ugivenName_ = rhs.ugivenName_ ;
//ct-bug-10-030102-3803 -End
bound_ = rhs.bound_ ;
flagbits_ = rhs.flagbits_ ;
prototype_ = rhs.prototype_ ;
defaultMatchCount_ = rhs.defaultMatchCount_ ;
return *this ;
}
void CorrName::setCorrName(const NAString& corrName)
{
// This used to be called only by Parser, and these asserts worked fine.
// Now called by RI and IM binding, these asserts are no longer valid.
//
// CMPASSERT(corrName != ""); // parameter nonempty
// CMPASSERT(corrName_ == "" // prev name empty
// // kludge for SQLMP(NSK) name; initial (non-ANSI) release only ##
// || getQualifiedNameObj().getCatalogName().data()[0] == '\\'
// );
corrName_ = corrName;
}
//ct-bug-10-030102-3803 -Begin
void CorrName::setUgivenName(const NAString& ugivenName)
{
ugivenName_ = ugivenName;
}
//ct-bug-10-030102-3803 -End
// We come here from syntax like
// SELECT * FROM :hv PROTOTYPE 'cat.sch.tbl'; -- host variable, static SQL
// TABLE $ev; -- env var, static or dynam
// (Internally, both host vars and env vars are HostVar objects.)
//
// If there's an environment variable, get its value at time of compilation,
// and stick that into the internal prototype value. Generator will need
// to save these env var name/value pairs in the generated code;
// Executor needs to use the saved compile-time value of any name that is not
// defined at run-time.
//
// If there's a prototype value, parse it as an actual table name
// (1, 2, or 3-part name) and overwrite the bogus values in *this with the
// parsed prototype value. Our caller, applyDefaults, will overwrite any
// remaining blank name parts. Generator needs to save the host var names
// for actual input at run-time, and to save the prototype values for
// similarity check at run-time.
//
// We avoid re-parsing and re-overwriting this CorrName by checking/setting
// its bound state. Note that we do not rely on its prototype's bound state
// because that is a separate, pointed at object: some Binder subroutines
// make local copies of CorrNames, and any apply methods invoked on the locals
// would not be propagated to the caller's originals: relying on the then True
// value of the prototype's bound state would be fallacious.
//
// If no error in proto, node is bound and bindWA errStatus unchanged
// (note that not having a proto is not an error).
// If error in proto, node is left unbound and bindWA errStatus is set.
//
void CorrName::applyPrototype(BindWA *bindWA)
{
if (nodeIsBound()) return;
HostVar *proto = getPrototype();
if (!proto) {
markAsBound();
return;
}
// CMPASSERT(this == proto->getPrototypeTarget());
CMPASSERT(!proto->getName().isNull());
if (proto->isEnvVar()) {
char *value = getenv(proto->getName());
if (!value) {
// Environment variable has no defined value.
*CmpCommon::diags() << DgSqlCode(-4086) << DgString0(proto->getName());
bindWA->setErrStatus();
return;
}
// upcase value returned by getenv
Int32 len = strlen(value);
char * ucValue = new (bindWA->wHeap()) char[len+1];
str_cpy_convert(ucValue, value, len, -1/*upshift*/);
ucValue[len] = 0;
proto->getPrototypeValue() = ucValue;
// do not free "ucValue" here, it is still used in "proto"
// to prevent Coverity RESOURCE_LEAK error, add the following
// coverity[leaked_storage]
}
// defines can not be used on linux platform
if (proto->isDefine()) {
*CmpCommon::diags() << DgSqlCode(-4155) << DgString0(proto->getName());
bindWA->setErrStatus();
return;
}
CMPASSERT(!proto->getPrototypeValue().isNull());
// Some of the following code is cloned from the QualifiedName ctor above
Parser parser(bindWA->currentCmpContext());
NAString ns("TABLE " + proto->getPrototypeValue() + ";",
CmpCommon::statementHeap());
// save the current parserflags setting
ULng32 savedParserFlags = Get_SqlParser_Flags (0xFFFFFFFF);
StmtQuery *stmt = (StmtQuery *)parser.parseDML(ns, ns.length(), GetAnsiNameCharSet());
// Restore parser flags settings
Set_SqlParser_Flags (savedParserFlags);
if (stmt) {
CMPASSERT(stmt->getOperatorType() == STM_QUERY);
CorrName &protoCorrName =
stmt->getQueryExpression()->getScanNode()->getTableName();
// Unless the hostvar type was forced directly,
// copy the special table type to me, the prototype may be a
// resource fork
if (getSpecialType() == ExtendedQualName::NORMAL_TABLE)
setSpecialType(protoCorrName);
// This if-test prevents pathologies such as
// SELECT col FROM :hv1 PROTOTYPE ':hv2 PROTOTYPE ''tbl''';
// but allows
// SELECT col FROM :hv1 PROTOTYPE '$ev';
//
// (The assertion below ensures that only host var syntax allows prototypes,
// that you can't say ... FROM $ev PROTOTYPE '...'.)
//
HostVar *proto2 = protoCorrName.getPrototype();
CMPASSERT(!proto2 || !proto->isEnvVar());
if (!proto2 || proto2->isEnvVar()) {
if (proto2) {
// Here if proto2->isEnvVar.
// Recurse (once only; the assertion above ensures that)
// to get the value of the var, parse it and all.
protoCorrName.applyPrototype(bindWA);
if (bindWA->errStatus()) return;
}
#ifndef NDEBUG
if (getenv("HV_DEBUG"))
cout << "HostVar/Prototype: parsed ("
<< (Int32)proto->nodeIsBound() << ") "
<< proto->getName() << " "
<< protoCorrName.getExposedNameAsAnsiString() << endl;
#endif
// assert *before* overwriting with 0
// CMPASSERT(!getQualifiedNameObj().getNamePosition());
getQualifiedNameObj() = protoCorrName.getQualifiedNameObj();
proto->setPrototypeType(HostVar::QUALIFIEDNAME);
// mark that we, the trusted CorrName, are bound
markAsBound();
}
}
if (!nodeIsBound()) {
// Clear parser syntax error and emit "Prototype value not valid"
#ifndef NDEBUG
if (!getenv("HV_DEBUG"))
#endif
CmpCommon::diags()->clear();
*CmpCommon::diags() << DgSqlCode(-4087)
<< DgString0(proto->getPrototypeValue());
bindWA->setErrStatus();
}
delete stmt;
} // applyPrototype
// First, always calls applyPrototype -- so may fill in one or more of
// this's name parts -- hence this method is not const.
//
// Second, delegates to QualifiedName::extractAndDefaultNameParts
// to fill in the return name parts --
// *EXCEPT* in the case that this CorrName contains a correlation name,
// masking a qualified name like "c.s.t", -- then we always return 0
// and the name parts are *not* filled in with defaults (they're meaningless).
//
Int32 CorrName::extractAndDefaultNameParts(BindWA *bindWA,
const SchemaName& defCatSch,
NAString& catName, // OUT
NAString& schName, // OUT
NAString& objName) // OUT
{
// For performance, avoid redoing work if we've done it before
if (defaultMatchCount_ < 0) { // initially -1
applyPrototype(bindWA);
// if (!nodeIsBound()) return -1; // caller will check bindWA-errStatus()
if (getCorrNameAsString() == "") { // CorrName is "qual", not "corr"
CMPASSERT(NOT isFabricated()); // only corr names can be fabricated
defaultMatchCount_ = getQualifiedNameObj().applyDefaults(defCatSch);
// override schema, if default schema is "from" schema
// increase count so columns like t.a will be valid
if ( bindWA->overrideSchemaEnabled()
&& (bindWA->getOsFromSchema() == defCatSch.getSchemaName())
&& (bindWA->getOsToSchema() == getQualifiedNameObj().getSchemaName()) )
defaultMatchCount_++;
} else
defaultMatchCount_ = 0; // "corr" masks "qual", always return 0
}
catName = getQualifiedNameObj().getCatalogName(); // OUT
schName = getQualifiedNameObj().getSchemaName(); // OUT
objName = getQualifiedNameObj().getObjectName(); // OUT
return defaultMatchCount_;
}
// Same as above except *ALWAYS* delegates to QN::eADNParts,
// *even if* this CorrName contains a correlation name string.
// (And thus it's not safe to set the defaultMatchCount_ member.)
//
Int32 CorrName::applyDefaults(BindWA *bindWA,
const SchemaName& defCatSch)
{
if (defaultMatchCount_ >= 0) return defaultMatchCount_; // for perf
applyPrototype(bindWA);
// if (!nodeIsBound()) return -1; // caller will check bindWA-errStatus()
if (isFabricated()) return (defaultMatchCount_ = 0); // assignment, not ==
Int32 retval = getQualifiedNameObj().applyDefaults(defCatSch);
if (retval == -1) // Only NSK platform will return -1
bindWA->setErrStatus();
return retval;
}
NABoolean CorrName::isHive() const
{
return getQualifiedNameObj().isHive();
}
NABoolean CorrName::isInHiveDefaultSchema() const
{
return (isHive() &&
getQualifiedNameObj().getSchemaName() ==
HIVE_SYSTEM_SCHEMA);
}
NABoolean CorrName::isSeabase() const
{
return getQualifiedNameObj().isSeabase();
}
NABoolean CorrName::isSeabaseMD() const
{
return getQualifiedNameObj().isSeabaseMD();
}
NABoolean CorrName::isSeabasePrivMgrMD() const
{
return getQualifiedNameObj().isSeabasePrivMgrMD();
}
NABoolean CorrName::isHbase() const
{
return getQualifiedNameObj().isHbase();
}
NABoolean CorrName::isHbaseCell() const
{
return getQualifiedNameObj().isHbaseCell();
}
NABoolean CorrName::isHbaseRow() const
{
return getQualifiedNameObj().isHbaseRow();
}
NABoolean CorrName::isHbaseMap() const
{
return getQualifiedNameObj().isHbaseMappedName();
}
NAString CorrName::getCorrNameAsString() const
{
return FORMAT(corrName_);
}
//## inline?
NAString CorrName::getQualifiedNameAsString(NABoolean formatForDisplay) const
{
return getQualifiedNameObj().getQualifiedNameAsString(formatForDisplay);
}
//## inline?
const NAString CorrName::getText() const
{
NAString result = getExtendedQualNameObj().getText();
if (getCorrNameAsString() != "")
result += NAString(" ") + ToAnsiIdentifier(getCorrNameAsString());
return result;
}
// See ANSI 6.3.
// Fabricated names do not get exposed.
const NAString CorrName::getExposedNameAsString
(NABoolean debug,
NABoolean formatForDisplay) const
{
if (isFabricated() AND NOT debug)
return "";
else if (NOT getCorrNameAsString().isNull())
return getCorrNameAsString();
else
return getQualifiedNameAsString(formatForDisplay); //##forceAnsi
}
const NAString CorrName::getExposedNameAsAnsiString
(NABoolean debug,
NABoolean formatForDisplay) const
{
formatAsAnsiIdentifier = TRUE;
NAString result(getExposedNameAsString(debug, formatForDisplay),
CmpCommon::statementHeap());
formatAsAnsiIdentifier = FALSE;
return result;
}
const NAString CorrName::getExposedNameAsStringWithPartitionNames() const
{
if (isFabricated())
return "";
else if (NOT getCorrNameAsString().isNull())
return getCorrNameAsString();
else
return getExtendedQualNameObj().getExtendedQualifiedNameAsString();
}
// This method was the == operator before the partnClause was added
// Since we need to skip PartnClause when comparing corrnames that are
// contained in a ColRefName, we are placing the comparision of all
// other data members in this method. This method will be called
// by the new == operator.
NABoolean CorrName::isEqualWithPartnClauseSkipped(const CorrName& other) const
{
if (isFabricated() ^ other.isFabricated())
return FALSE;
NABoolean result;
if (!corrName_.isNull()) {
if (!other.corrName_.isNull())
result = corrName_ == other.corrName_;
else {
QualifiedName thisQual(corrName_);
result = thisQual == other.getQualifiedNameObj();
}
} else if (!other.corrName_.isNull()) {
QualifiedName otherQual(other.corrName_);
result = getQualifiedNameObj() == otherQual;
} else {
result = getQualifiedNameObj() == other.getQualifiedNameObj();
}
// // The names must match, and
// // the special types must match OR one of them must be "normal" --
// // thus in "delete from TABLE (RESOURCE_FORK %s) where rfsection = ?;",
// // unbound column "rfsection"'s corrname is initially empty/default/normal
// // but it will hereby compare equal to the RETDesc xcnm "rfsection" which
// // is marked "special/rfork type".
// return result && (getSpecialType() == other.getSpecialType() ||
// getSpecialType() == NORMAL_TABLE ||
// NORMAL_TABLE == other.getSpecialType()
// );
//
// The preceding is foolishly, overly rigorous -- it would only ever catch
// a situation where we had two distinct special types in the same query,
// or if we were reusing (cached) NATables across queries --
// neither of which we are currently doing.
// So, the names must match, and that's all!
return result;
}
// Real comparison operator
//
// Are you adding an extra field to be compared here (like specialType was)?
// Then modify CorrName::isEmpty() and RETDesc.C and TableNameMap.C accordingly
// (emulate the setSpecialType() logic).
//
NABoolean CorrName::operator==(const CorrName& other) const
{
// if two corrnames have different Partition clauses then they are different.
// This is needed because we are caching natables for which PARTITION or LOCATION
// clause is specified.
if (getPartnClause() != other.getPartnClause())
return FALSE;
return isEqualWithPartnClauseSkipped(other);
}
PartitionClause & PartitionClause::operator=(const PartitionClause & rhs)
{
if (this==&rhs) return *this ;
partName_ = rhs.partName_ ;
beginPartNumber_ = rhs.beginPartNumber_ ;
endPartNumber_ = rhs.endPartNumber_ ;
locationName_ = rhs.locationName_;
partnNameSpecified_ = rhs.partnNameSpecified_;
partnNumSpecified_ = rhs.partnNumSpecified_;
partnRangeSpecified_ = rhs.partnRangeSpecified_;
return *this ;
}
// -----------------------------------------------------------------------
// Methods for class ExtendedQualName
// -----------------------------------------------------------------------
NABoolean ExtendedQualName::operator==(const ExtendedQualName& other) const
{
if ((getQualifiedNameObj() != other.getQualifiedNameObj()) ||
(getPartnClause() != other.getPartnClause()))
{
// different name
return FALSE;
}
SpecialTableType thisType = getSpecialType();
SpecialTableType otherType = other.getSpecialType();
if (thisType == otherType)
{
// name & special-type are the same
return TRUE;
}
// We reach this point when the only difference between the two objects
// is in the special-type.
//
// The special-type MV_TABLE is used only as a security mechanism.
// Directly updating Materialized Views if prohibited unless using this
// special-type (see GenericUpdate::bindNode()), while directly selecting
// from it is approved even under NORMAL_TABLE special-type. Thus, if the
// two objects refer to the same name, and the only change is the
// special-type (MV_TABLE vs. NORMAL_TABLE), they shuold still considered
// equal. This will lead creation of only one NATable object for the MV
// object.
if ((thisType == NORMAL_TABLE && otherType == MV_TABLE) ||
(thisType == MV_TABLE && otherType == NORMAL_TABLE))
{
return TRUE;
}
return FALSE;
}
NAString ExtendedQualName::getExtendedQualifiedNameAsString() const
{
if (hasPartnClause())
{
// Preallocate a result buffer that'll be big enough most of the time
// (so += won't reallocate+copy most of the time).
NAString result((NASize_T)65, CmpCommon::statementHeap());
result = getQualifiedNameObj().getQualifiedNameAsString();
if (!(getPartnClause().getPartitionName().isNull()))
{
result += " : PARTITION NAME ";
result += getPartnClause().getPartitionName();
}
else if (getPartnClause().getPartitionNumber() > 0)
{
result += " : PARTITION NUMBER ";
char buf[10];
sprintf(buf, "%d", getPartnClause().getPartitionNumber());
result += buf;
if (getPartnClause().getEndPartitionNumber() > 0)
{
char buf[12];
sprintf(buf, ",%d", getPartnClause().getEndPartitionNumber());
result += buf;
}
}
else if (!(getPartnClause().getLocationName().isNull()))
{
result += " : LOCATION NAME ";
result += getPartnClause().getLocationName();
}
return result ;
}
else
return getQualifiedNameObj().getQualifiedNameAsString();
}
// -----------------------------------------------------------------------
// Methods for class ColRefName
// -----------------------------------------------------------------------
NABoolean ColRefName::operator==(const ColRefName& other) const
{
return (isStar() == other.isStar() &&
getColName() == other.getColName() &&
getCorrNameObj().isEqualWithPartnClauseSkipped(other.getCorrNameObj()));
}
NABoolean ColRefName::operator!=(const ColRefName& other) const
{
return NOT operator==(other);
}
NABoolean ColRefName::isQualified() const
{
return corrName_ != "";
}
const NAString ColRefName::getColRefAsString(NABoolean debug,
NABoolean formatForDisplay) const
{
// Call static method to return "col", "corr.col", or "cat.sch.tbl.col"
NAString tmp(FORMAT_NO_ASSERT(getColName()), CmpCommon::statementHeap());
return getColRefAsString(tmp,
corrName_.getExposedNameAsString
(debug,
formatForDisplay));
}
const NAString ColRefName::getColRefAsAnsiString(NABoolean debug,
NABoolean formatForDisplay) const
{
formatAsAnsiIdentifier = TRUE;
NAString result(getColRefAsString(debug, formatForDisplay),
CmpCommon::statementHeap());
formatAsAnsiIdentifier = FALSE;
return result;
}
const NAString ColRefName::getColNameAsAnsiString() const
{
NAString tempColHeading(CmpCommon::statementHeap());
tempColHeading = ToAnsiIdentifier(getColName());
char buff[ComAnsiNamePart::MAX_IDENTIFIER_EXT_LEN];
char *finalptr = buff;
const char *initptr = tempColHeading.data();
size_t len = tempColHeading.length();
// remove the double double-quotes in case of delimited identifiers.
// Also change any embedded doubled double quotes to single double quote.
// This will change a name of the form "a""b" to a"b
size_t i = 0;
size_t f = 0;
if (initptr[i] == '"')
{
i++;
while (i < (len - 1))
{
finalptr[f] = initptr[i];
if ((initptr[i] == '"') &&
(initptr[i+1] == '"'))
i++;
i++;
f++;
}
finalptr[f] = '\0';
tempColHeading = buff;
} // delimited name
return tempColHeading;
}
// -----------------------------------------------------------------------
// -- Triggers
// Methods for class TableRefName
// -----------------------------------------------------------------------
// Find the table names in the specified RETDesc.
// Returns TRUE if found.
NABoolean TableRefName::lookupTableName(RETDesc *retDesc)
{
if (retDesc == NULL)
return FALSE;
if (getColumnList() != NULL) // Have we already found this one?
return FALSE;
// Lookup the table name in the RETDesc
ColumnDescList *columnList = retDesc->getQualColumnList(getTableCorr());
if (columnList == NULL)
return FALSE;
setColumnList(columnList); // Save the pointer to the ColumnDescList
return TRUE; // One reference less to find.
}
// Add to the RETDesc of the current BindScope new columns,
// each with the information found by lookupTableName(), but with the refName
// as a correlation name to the table.
void TableRefName::bindRefColumns(BindWA *bindWA) const
{
if (getColumnList() == NULL)
return; // REFERENCING an unused transition name.
RETDesc *currentRETDesc = bindWA->getCurrentScope()->getRETDesc();
// Create a new CorrName for the table, with the refName as a correllation
// name. Since it's the same table for all columns, take the table name
// from the first column.
const ColumnDesc *firstCol = getColumnList()->at(0);
CorrName updatedCorrName(firstCol->getColRefNameObj().getCorrNameObj());
updatedCorrName.setCorrName(getRefName());
// Insert this CorrName into the XTNM of the current BindScope.
// bindWA->getCurrentScope()->getXTNM()->insertNames(bindWA,updatedCorrName);
for (CollIndex i=0; i<getColumnList()->entries(); i++)
{
// For each column of the table
const ColumnDesc *currentCol = getColumnList()->at(i);
// Create a new column ref, with the updated corellation name.
ColRefName renamedColumn(currentCol->getColRefNameObj().getColName(),
updatedCorrName);
// Add it to the RETDesc of the current scope.
currentRETDesc->addColumn(bindWA,
renamedColumn,
currentCol->getValueId(),
USER_COLUMN,
currentCol->getHeading());
}
}
// -----------------------------------------------------------------------
// Methods for class TableRefList
// -----------------------------------------------------------------------
// Default Ctor, make the LIST allocated it's internal data from the
// statement heap instead of the system heap.
TableRefList::TableRefList(CollHeap *heap) :
LIST(TableRefName)(heap)
{}
const TableRefName *TableRefList::findTable(const CorrName& tableCorr) const
{
for (CollIndex i=0; i<entries(); i++)
{
if (at(i).getTableCorr() == tableCorr)
return &at(i);
}
return NULL;
}
// -----------------------------------------------------------------------
// Additional non-inline functions for all ``ObjectNames'' classes
// -----------------------------------------------------------------------
// Display/print, for debugging.
void CatalogName::display() const { print(); }
void CorrName::display() const { print(); }
void ColRefName::display() const { print(); }
void ExtendedQualName::display() const { print(); }
void CatalogName::print(FILE* ofd, const char* indent, const char* title) const
{
#ifndef NDEBUG
fprintf(ofd,"catalog=%s%s",
getCatalogName().data(),
indent); // just to prevent warnings
if (strcmp(title,"")) fprintf(ofd,"\n");
#endif
}
void SchemaName::print(FILE* ofd, const char* indent, const char* title) const
{
#ifndef NDEBUG
fprintf(ofd,"c=%s s=%s%s",
getCatalogName().data(),
getSchemaName().data(),
indent); // just to prevent warnings
if (strcmp(title,"")) fprintf(ofd,"\n");
#endif
}
void QualifiedName::print(FILE* ofd, const char* indent, const char* title) const
{
#ifndef NDEBUG
fprintf(ofd,"c=%s s=%s o=%s%s",
getCatalogName().data(),
getSchemaName().data(),
getObjectName().data(),
indent); // just to prevent warnings
if (strcmp(title,"")) fprintf(ofd,"\n");
#endif
}
NABoolean QualifiedName::isHistograms() const
{
return (getObjectName() == HBASE_HIST_NAME);
}
NABoolean QualifiedName::isHistogramIntervals() const
{
return (getObjectName() == HBASE_HISTINT_NAME);
}
NABoolean QualifiedName::isHistogramTable() const
{
const NAString objName = getObjectName();
return (objName == HBASE_HIST_NAME ||
objName == HBASE_HISTINT_NAME ||
objName == HBASE_PERS_SAMP_NAME );
}
void ExtendedQualName::print(FILE* ofd, const char* indent, const char* title) const
{
#ifndef NDEBUG
fprintf(ofd,"%s ", getLocationName().data());
getQualifiedNameObj().print(ofd, indent, "");
if (strcmp(title,"")) fprintf(ofd,"\n");
#endif
}
void CorrName::print(FILE* ofd, const char* indent, const char* title) const
{
#ifndef NDEBUG
fprintf(ofd,"%s ", getExposedNameAsString().data());
if (isFabricated())
fprintf(ofd,"(%s) ", getExposedNameAsString(TRUE).data());
getQualifiedNameObj().print(ofd, indent, "");
if (strcmp(title,"")) fprintf(ofd,"\n");
#endif
}
void ColRefName::print(FILE* ofd, const char* indent, const char* title,
NABoolean brief) const
{
#ifndef NDEBUG
if (strcmp(title, "")) fprintf(ofd,"%s ", title);
fprintf(ofd,"%s", getColRefAsString().data());
if (isFabricated())
fprintf(ofd," (%s)", getColRefAsString(TRUE).data());
if (brief) return;
fprintf(ofd," ");
getCorrNameObj().print(ofd, indent, "");
if (strcmp(title,"")) fprintf(ofd,"\n");
#endif
}
// ++MV
ComAnsiNameSpace ExtendedQualName::convSpecialTableTypeToAnsiNameSpace( const SpecialTableType type )
{
switch (type)
{
case NORMAL_TABLE:
case LOAD_TABLE:
case ISP_TABLE:
case MV_TABLE:
case PARTITION_TABLE:
case TRIGTEMP_TABLE:
case VIRTUAL_TABLE:
case MVS_UMD:
return COM_TABLE_NAME;
case INDEX_TABLE:
return COM_INDEX_NAME;
case IUD_LOG_TABLE:
return COM_IUD_LOG_TABLE_NAME;
case RANGE_LOG_TABLE:
return COM_RANGE_LOG_TABLE_NAME;
case SCHEMA_SECURITY_TABLE:
return COM_SCHEMA_LABEL_NAME;
case EXCEPTION_TABLE:
return COM_EXCEPTION_TABLE_NAME;
case GHOST_TABLE:
case GHOST_MV_TABLE:
return COM_GHOST_TABLE_NAME;
case GHOST_INDEX_TABLE:
return COM_GHOST_INDEX_NAME;
case GHOST_IUD_LOG_TABLE:
return COM_GHOST_IUD_LOG_TABLE_NAME;
case SG_TABLE:
return COM_SEQUENCE_GENERATOR_NAME;
case LIBRARY_TABLE: // not really a table, but that is what we call 3 part names
return COM_LIBRARY_NAME;
default:
return COM_UNKNOWN_NAME;
}
}
ComAnsiNameSpace ExtendedQualName::getAnsiNameSpace() const
{
return convSpecialTableTypeToAnsiNameSpace(getSpecialType());
}
// In the display tool, it is usefull to know the special type also.
const NAString ExtendedQualName::getSpecialTypeName() const
{
NAString result;
switch (getSpecialType())
{
case MV_TABLE:
result += "MV";
break;
case TRIGTEMP_TABLE:
result += "TrigTemp";
break;
case INDEX_TABLE:
result += "Index";
break;
case IUD_LOG_TABLE:
result += "IudLog";
break;
case RANGE_LOG_TABLE:
result += "RangeLog";
break;
case EXCEPTION_TABLE:
result += "Exception";
break;
case GHOST_TABLE:
result += "GhostTable";
break;
case GHOST_INDEX_TABLE:
result += "GhostIndex";
break;
case GHOST_MV_TABLE:
result += "GhostMV";
break;
case LIBRARY_TABLE:
result += "Library";
break;
default: ;
}
return result;
}
const NAString ExtendedQualName::getText() const
{
NAString result(getQualifiedNameObj().getQualifiedNameAsAnsiString(TRUE),
CmpCommon::statementHeap());
return result;
}
const NAString ExtendedQualName::getTextWithSpecialType() const
{
NAString tableType(getSpecialTypeName());
if (tableType == "")
return getText();
else
{
NAString tableName(getText());
tableName += " (";
tableName += tableType;
tableName += ")";
return tableName;
}
}
// --MV
// For NAKeyLookup
ULng32 hashKey(const QualifiedName& name) { return name.hash(); }
ULng32 hashKey(const ExtendedQualName& name) { return name.hash(); }
ULng32 hashKey(const CorrName& name) { return name.hash(); }
ULng32 hashKey(const ColRefName& name) { return name.hash(); }
// For TaskMonitor display
ostream& operator<< (ostream& out, TaskMonitor t)
{
// return the time in microseconds. The unit indicator ("ms") should be "us".
// But we right now we keep it as "ms".
out.fixed;
out.precision(6);
return out<< "Time = " <<
((double) t.timer()) / CLOCKS_PER_SEC
<< " us (microsecond)" <<
"\tET = " << t.elapsed_time() << " s" <<
" \tCounts = "<<t.count()<<" \tGoodCnts = "<<t.goodcount();
}