blob: 61faa54507d14d3ef68470946279d1e51edccd6b [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: Describe.C
* Description:
*
* Created: 4/15/95
* Language: C++
* Status: $State: Exp $
*
*
*****************************************************************************
*/
#define SQLPARSERGLOBALS_FLAGS // must precede all #include's
#define SQLPARSERGLOBALS_NADEFAULTS
#include "Platform.h"
#include <ctype.h>
#include <iostream>
#include <string.h>
#include <sys/types.h>
#include <time.h>
#ifndef SQLPARSERGLOBALS_CONTEXT_AND_DIAGS
#define SQLPARSERGLOBALS_CONTEXT_AND_DIAGS
#endif
#include "SqlParserGlobals.h" // must be the last #include.
#include "CmpCommon.h"
#include "CmpContext.h"
#include "CmpMain.h"
#include "CmpErrors.h"
#include "ComDiags.h"
#include "ComObjectName.h"
#include "ComOperators.h"
#include "ComSpace.h"
#include "ComTdbRoot.h"
#include "ComSmallDefs.h"
#include "ComUser.h"
#include "ControlDB.h"
#include "DatetimeType.h"
#include "FragDir.h"
#include "HeapLog.h"
#include "parser.h"
#include "RelControl.h"
#include "RelExpr.h"
#include "RelExeUtil.h"
#include "RelMisc.h"
#include "RelRoutine.h"
#include "RelScan.h"
#include "sql_id.h"
#include "Sqlcomp.h"
#include "ItemOther.h"
#include "NARoutine.h"
#include "LmJavaSignature.h"
#include "QueryText.h"
#include "wstr.h"
#include "SqlParserGlobals.h"
#include "hs_update.h"
#include "csconvert.h"
#include "charinfo.h"
#include "CmpDescribe.h"
#include "CmpDDLCatErrorCodes.h"
#include "CmpSeabaseDDL.h"
#include "CmpSeabaseDDLauth.h"
#include "HDFSHook.h"
#include "PrivMgrCommands.h"
#include "PrivMgrComponentPrivileges.h"
#include "Analyzer.h"
#include "ComSqlId.h"
#include "ExExeUtilCli.h"
#include "TrafDDLdesc.h"
#define CM_SIM_NAME_LEN 32
enum PrivTarget {
PRIV_SCHEMA = 2,
PRIV_TABLE,
PRIV_PROCEDURE,
PRIV_LIBRARY};
enum Display_Schema_Object {
SCHEMA_TABLE,
SCHEMA_TABLE_INDEX,
SCHEMA_TABLE_VIEW,
SCHEMA_TABLE_MV,
SCHEMA_TABLE_TRIGGER,
SCHEMA_TABLE_SYNONYM,
SCHEMA_TABLE_STORED_PROCEDURE,
SCHEMA_TABLE_TABLE_MAPPING_FUNCTION,
SCHEMA_TABLE_SCALAR_FUNCTION,
SCHEMA_TABLE_UNIVERSAL_FUNCTION,
SCHEMA_TABLE_ROUTINE_ACTION
};
extern "C"
{
Lng32 SQLCLI_GetRootTdb_Internal( /*IN*/ CliGlobals * cliGlobals,
/*INOUT*/ char * roottdb_ptr,
/*IN*/ Int32 roottdb_len,
/*INOUT*/ char * srcstr_ptr,
/*IN*/ Int32 srcstr_len,
/*IN*/ SQLSTMT_ID *statement_id);
Lng32 SQLCLI_GetRootTdbSize_Internal(/*IN*/ CliGlobals * cliGlobals,
/*INOUT*/ Lng32 * root_tdb_size,
/*INOUT*/ Lng32* srcstr_size,
/*IN*/ SQLSTMT_ID *statement_id);
}
extern CliGlobals * GetCliGlobals();
void outputLine(Space &space, NAString &outputText, size_t indent,
size_t indentDeltaOfLineFollowingLineBreak = 2,
NABoolean commentOut = FALSE,
const char *testSchema = NULL);
void outputLine(Space &space, const char *buf, size_t indent,
size_t indentDeltaOfLineFollowingLineBreak = 2,
NABoolean commentOut = FALSE,
const char *testSchema = NULL);
static size_t indexLastNewline(const NAString & text,
size_t startPos,
size_t maxLen);
static bool CmpDescribeLibrary(
const CorrName & corrName,
char * & outbuf,
ULng32 & outbuflen,
CollHeap * heap);
static short CmpDescribeRoutine(
const CorrName & corrName,
char * & outbuf,
ULng32 & outbuflen,
CollHeap * heap);
static short CmpDescribePlan(
const char *query,
ULng32 flags,
char *&outbuf,
ULng32 &outbuflen,
NAMemory *heap);
static short CmpDescribeShape(
const char *query,
char *&outbuf,
ULng32 &outbuflen,
NAMemory *h);
static short CmpDescribeTransaction(
char *&outbuf,
ULng32 &outbuflen,
NAMemory *h);
short CmpDescribeSequence (
const CorrName &dtName,
char* &outbuf,
ULng32 &outbuflen,
CollHeap *heap,
Space *inSpace);
bool CmpDescribeIsAuthorized(
SQLOperation operation = SQLOperation::UNKNOWN,
PrivMgrUserPrivs *privs = NULL,
ComObjectType objectType = COM_UNKNOWN_OBJECT);
// The real Ark catalog manager returns all object names as three-part
// identifiers, properly delimited where necessary.
// Only simple column names are returned undelimited;
// only they should use this procedure.
#define ANSI_ID(name) ToAnsiIdentifier(name).data()
// ## This only applies to CatSim; remove it!
#define CONSTRAINT_IS_NAMED(constrdesc) \
(constrdesc->constrnts_desc.constrntname && \
*constrdesc->constrnts_desc.constrntname)
// Define a shorter synonym.
#define SpacePrefix CmpDescribeSpaceCountPrefix
static short CmpDescribePlan (const char *query,
ULng32 flags,
char *&outbuf,
ULng32 &outbuflen,
NAMemory *h);
// DZC - outputToStream does nothing for SHOWDDL because outStream() returns NULL
// needed for SHOWCONTROL though, so they must be left in.
static void outputToStream(const char *buf, NABoolean commentOut = FALSE)
{
if (ActiveControlDB()->outStream())
*(ActiveControlDB()->outStream()) << (commentOut ? "--" : "") << buf << endl;
}
/*
static void outputToStreamNoNewline(const char *buf, NABoolean commentOut = FALSE)
{
if (ActiveControlDB()->outStream())
*(ActiveControlDB()->outStream()) << (commentOut ? "--" : "") << buf;
}
*/
void outputShortLine(Space &space, const char *buf, NABoolean commentOut = FALSE)
{
// DZC - if commentOut = TRUE, prepend buf with "--"
NAString outputString(buf);
if(commentOut)
outputString.prepend("--");
space.outputbuf_ = TRUE;
space.allocateAndCopyToAlignedSpace(outputString, outputString.length(), SpacePrefix);
outputToStream(buf ? buf : "", commentOut); //DZC - this does nothing
}
void outputColumnLine(Space &space, NAString pretty,
Int32 &colcount, NABoolean isForMV = FALSE,
NABoolean isDivisionColumn = FALSE)
{
// Must linebreak before prepending comma+space, else long colname won't
// display correctly.
if (isDivisionColumn)
LineBreakSqlText(pretty, FALSE/*showddlView*/, 79/*maxlen*/,
6/*pfxlen*/, 4/*pfxinitlen*/, ' '/*pfxchar*/,
NULL/*testSchema*/, isDivisionColumn/*commentOut*/);
else
LineBreakSqlText(pretty, FALSE, 79, 6, 4); // initial indent 4, subseq 6
if (colcount++) // if not first line,
pretty[(size_t)2] = ','; // change " " to " , "
space.outputbuf_ = TRUE;
space.allocateAndCopyToAlignedSpace(pretty, pretty.length(), SpacePrefix);
if (isDivisionColumn)
{
// Do not prepend the leading "--" comment prefix because we have
// already done that in the LineBreakSqlText() call.
outputToStream(pretty, FALSE/*commentOut*/);
}
else
outputToStream(pretty, isForMV);
}
void outputLine(Space &space, const char *buf, size_t indent,
size_t indentDeltaOfLineFollowingLineBreak,
NABoolean commentOut,
const char *testSchema)
{
NAString pretty(buf);
outputLine(space, pretty, indent, indentDeltaOfLineFollowingLineBreak,
commentOut, testSchema);
}
// NAstring version of outputLine so there are fewer conversions
void outputLine(Space &space, NAString &outputText, size_t indent,
size_t indentDeltaOfLineFollowingLineBreak,
NABoolean commentOut,
const char *testSchema)
{
if(commentOut)
outputText.prepend("--");
LineBreakSqlText(outputText, FALSE, 79,
indent + indentDeltaOfLineFollowingLineBreak, 0, ' ',
testSchema);
space.outputbuf_ = TRUE;
space.allocateAndCopyToAlignedSpace(outputText, outputText.length(),
SpacePrefix);
outputToStream(outputText, commentOut);
}
// To output lines with more than 3000 characters
void outputLongLine(Space &space, NAString & outputText, size_t indent,
const char *testSchema = NULL, NABoolean commentOut = FALSE)
{
if (commentOut)
LineBreakSqlText(outputText, TRUE, 79, indent+2, 0, ' ', testSchema, commentOut);
else
LineBreakSqlText(outputText, TRUE, 79, indent+2, 0, ' ', testSchema);
// Can only print out 3000 characters at a time due to generator limitation
// This limitation only applies to views because view DDL is printed out as
// a continuous string of text (vs. other DDL which is outputted piecemeal).
// This code assumes that there must be at least one space in every 3000
// chars of text.
const size_t CHUNK_SIZE = 3000;
size_t textLen = outputText.length();
space.outputbuf_ = TRUE;
// If there's only one chunk, print it
if (textLen <= CHUNK_SIZE)
{
space.allocateAndCopyToAlignedSpace(outputText, textLen, SpacePrefix);
}
else
{
// Output multiple chunks
size_t textStartPos = 0;
size_t finalTextStartPos = textLen - CHUNK_SIZE;
size_t chunkLen = 0;
NABoolean isFinalChunk = FALSE;
do
{
isFinalChunk = (textStartPos >= finalTextStartPos);
// Final chunk may be smaller than CHUNK_SIZE
chunkLen = (isFinalChunk) ? (textLen - textStartPos) : CHUNK_SIZE;
if (!isFinalChunk)
{
// Use the last newline in this chunk as the boundary between this
// chunk and the next chunk.
chunkLen = indexLastNewline(outputText, textStartPos, chunkLen);
CMPASSERT(chunkLen != NA_NPOS);
}
space.allocateAndCopyToAlignedSpace(outputText(textStartPos, chunkLen).data(),
chunkLen, SpacePrefix);
textStartPos += chunkLen + 1; // + 1 skips over newline
} while (!isFinalChunk);
}
}
// Return index of closing right quote that matches the left quote
// text(startPos). Return NA_NPOS if closing right quote is not found.
// Searches text(startPos+1) through text(endPos-1).
static size_t skipQuotedText(const NAString & text,
size_t startPos,
size_t endPos)
{
size_t closeQuotePos = NA_NPOS;
char quoteChar = text(startPos);
for (size_t pos = startPos + 1; pos < endPos; pos++)
{
char c = text(pos);
if (c == quoteChar)
{
if ( (pos != (endPos - 1))
&& (text(pos + 1) == quoteChar) )
pos++; // skip embedded quote
else
{
closeQuotePos = pos;
break;
}
}
}
return closeQuotePos;
}
// Return the offset from startPos of the last unquoted newline that occurs in
// the substring text(startPos, maxLen). Return NA_NPOS if the substring
// contains fewer than maxLen characters (and therefore doesn't need to be
// broken up) or we can't find an unquoted newline.
//
static size_t indexLastNewline(const NAString & text,
size_t startPos,
size_t maxLen)
{
size_t newlinePos = NA_NPOS;
size_t endPos = startPos + maxLen;
if (text.length() <= endPos)
return NA_NPOS;
// search text(startPos) through text(endPos - 1)
for (size_t pos = startPos; pos < endPos; pos++)
{
char c = text[pos];
if ((c == '"') OR (c == '\''))
{
pos = skipQuotedText(text, pos, endPos);
// If a quoted string was split across the chunk, we won't find the
// right-hand quote; break out of loop and return the offset of last
// found (if any) newline character.
if (pos == NA_NPOS)
break;
}
else
if (c == '\n')
{
newlinePos = pos;
}
}
// Convert newlinePos to offset from startPos
if (newlinePos != NA_NPOS)
newlinePos = (newlinePos - startPos);
return newlinePos;
}
static Int32 displayDefaultValue(const char * defVal, const char * colName,
NAString &displayableDefVal)
{
displayableDefVal.append(defVal);
return 0;
}
static short CmpDescribeShowQryStats(
const char *query,
char *&outbuf,
ULng32 &outbuflen,
NAMemory *heap)
{
// make sure we have a showstats query to process
short rc = -1;
if (!query) return rc;
// Skip leading blanks
const char *cc = query;
while(isSpace8859_1(*cc)) cc++;
// scan "showstats" token
char lowertok[10];
const char *ctok=cc;
while (isAlpha8859_1(*cc)) cc++;
strncpy(lowertok, ctok, 9);
lowertok[9] = '\0';
if (stricmp(lowertok, "showstats")) return rc;
// skip blanks
while(isSpace8859_1(*cc)) cc++;
// scan "for" token
ctok = cc;
while (isAlpha8859_1(*cc)) cc++;
strncpy(lowertok, ctok, 3);
lowertok[3] = '\0';
if (stricmp(lowertok, "for")) return rc;
// skip blanks
while(isSpace8859_1(*cc)) cc++;
// scan "query" token
ctok = cc;
while (isAlpha8859_1(*cc)) cc++;
strncpy(lowertok, ctok, 5);
lowertok[5] = '\0';
if (stricmp(lowertok, "query")) return rc;
// skip blanks
while(isSpace8859_1(*cc)) cc++;
// a "showstats for query <q>" does its work by:
// 1) at start, CmpCommon::context()->setShowQueryStats()
// 2) sqlcomp -- analyzer & cardinality estimation code will consult
// CmpCommon::context()->showQueryStats() to do their part in
// showing internal histogram stuff
// 3) at end, CmpCommon::context()->resetShowQueryStats()
CmpCommon::context()->setShowQueryStats();
// prepare this query.
char * qTree = NULL;
ULng32 dummyLen;
CmpMain sqlcomp;
CmpMain::CompilerPhase phase = CmpMain::ANALYSIS;
// "showstats for query <q>" will cause QueryAnalysis::analyzeThis() to
// call QueryAnalysis::setHistogramsToDisplay() which will set
// QueryAnalysis::Instance()->statsToDisplay_ which will be displayed
// by QueryAnalysis::Instance()->showQueryStats() below.
QueryText qText((char*)cc, SQLCHARSETCODE_ISO88591);
CmpMain::ReturnStatus rs =
sqlcomp.sqlcomp(qText, 0, &qTree, &dummyLen, heap, phase);
CmpCommon::context()->resetShowQueryStats();
if (rs)
{
return rc;
}
Space space;
char buf[10000];
QueryAnalysis::Instance()->showQueryStats(query, &space, buf);
outputShortLine(space, buf);
outbuflen = space.getAllocatedSpaceSize();
outbuf = new (heap) char[outbuflen];
space.makeContiguous(outbuf, outbuflen);
return 0;
}
// Returns -1, if error.
short CmpDescribe(const char *query, const RelExpr *queryExpr,
char* &outbuf, ULng32 &outbuflen,
CollHeap *heap)
{
short rc = 0; // assume success
// save the current parserflags setting
ULng32 savedParserFlags;
SQL_EXEC_GetParserFlagsForExSqlComp_Internal(savedParserFlags);
// OK, folks, we are about to locally change a global variable, so any returns
// must insure that the global variable gets reset back to its original value
// (saved above in "savedParserFlags"). So, if you are tempted to code a
// "return", don't do it. Set the rc instead and goto the "finally" label.
Set_SqlParser_Flags(INTERNAL_QUERY_FROM_EXEUTIL);
SQL_EXEC_SetParserFlagsForExSqlComp_Internal(INTERNAL_QUERY_FROM_EXEUTIL);
// add an exception handler around all the SQL specific code
try
{
// Display triggers using this object
NABoolean showUsingTriggers = !!getenv("SQLMX_SHOW_USING_TRIGGERS");
NABoolean showUsingMVs = !!getenv("SQLMX_SHOW_USING_MVS");
// MV
NABoolean showUnderlyingBT = !!getenv("SQLMX_SHOW_MVS_UNDERLYING_BASE_TABLE");
Lng32 replShowddl = (Lng32) CmpCommon::getDefaultNumeric(SHOWDDL_FOR_REPLICATE);
NABoolean logFormat = (CmpCommon::getDefault(SHOWDDL_DISPLAY_FORMAT) == DF_LOG);
Lng32 replIOVersion = (Lng32) CmpCommon::getDefaultNumeric(REPLICATE_IO_VERSION);
// Init SHOWDDL MX-format table regression test support for schema
// names longer than 'SCH'.
const char *testSchema = NULL;
NAString testSchemaName;
if (CmpCommon::context()->getSqlmxRegress() == 1)
{
const char *env = getenv("TEST_SCHEMA_NAME");
if (env)
{
const size_t SCH_LEN= 3; // 'SCH' schema length
testSchemaName = env;
if (testSchemaName.length() > SCH_LEN)
testSchema = testSchemaName.data();
}
}
char *buf = NULL;
Space space;
// emit an initial newline
outputShortLine(space, " ");
// initialize the returned values
outbuf = NULL;
outbuflen = 0;
CMPASSERT(queryExpr->getOperatorType() == REL_ROOT);
Describe *d = (Describe *)(queryExpr->child(0)->castToRelExpr());
CMPASSERT(d->getOperatorType() == REL_DESCRIBE);
if (d->getIsSchema())
{
if (!CmpDescribeIsAuthorized())
{
rc = -1;
goto finally;
}
NAString schemaText;
std::vector<std::string> outlines;
QualifiedName objQualName(d->getDescribedTableName().getQualifiedNameObj(),
STMTHEAP);
NABoolean isHiveRegistered = FALSE;
if (objQualName.isHive())
{
CorrName cn(SEABASE_SCHEMA_OBJECTNAME, STMTHEAP,
objQualName.getSchemaName(),
objQualName.getCatalogName());
cn.setSpecialType(ExtendedQualName::SCHEMA_TABLE);
BindWA bindWA(ActiveSchemaDB(), CmpCommon::context(), FALSE/*inDDL*/);
NATable *naTable = bindWA.getNATable(cn);
if ((naTable == NULL) || (bindWA.errStatus()))
{
CmpCommon::diags()->clear();
*CmpCommon::diags() << DgSqlCode(-CAT_SCHEMA_DOES_NOT_EXIST_ERROR)
<< DgString0(objQualName.getCatalogName())
<< DgString1(objQualName.getSchemaName());
rc = -1;
goto finally;
}
isHiveRegistered = naTable->isRegistered();
}
if (!CmpSeabaseDDL::describeSchema(objQualName.getCatalogName(),
objQualName.getSchemaName(),
isHiveRegistered,
outlines))
//schemaText))
{
rc = -1;
goto finally;
}
for(int i = 0; i < outlines.size(); i++)
outputLine(space, outlines[i].c_str(), 0);
outbuflen = space.getAllocatedSpaceSize();
outbuf = new (heap) char[outbuflen];
space.makeContiguous(outbuf, outbuflen);
goto finally; // we are done and rc is already 0
}
// If SHOWDDL USER, go get description and return
if (d->getIsUser())
{
NAString userText;
CmpSeabaseDDLuser userInfo;
if (!userInfo.describe(d->getAuthIDName(), userText))
{
rc = -1;
goto finally;
}
outputLine(space, userText,0);
outbuflen = space.getAllocatedSpaceSize();
outbuf = new (heap) char[outbuflen];
space.makeContiguous(outbuf, outbuflen);
goto finally; // we are done and rc is already 0
}
// If SHOWDDL ROLE, go get description and return
if (d->getIsRole())
{
NAString roleText;
CmpSeabaseDDLrole roleInfo(ActiveSchemaDB()->getDefaults().getValue(SEABASE_CATALOG));
if (!roleInfo.describe(d->getAuthIDName(),roleText))
{
rc = -1;
goto finally;
}
outputLine(space, roleText,0);
outbuflen = space.getAllocatedSpaceSize();
outbuf = new (heap) char[outbuflen];
space.makeContiguous(outbuf, outbuflen);
goto finally; // we are done and rc is already 0
}
// If SHOWDDL COMPONENT, go get description and return
if (d->getIsComponent())
{
if (!CmpDescribeIsAuthorized(SQLOperation::MANAGE_COMPONENTS))
{
rc = -1;
goto finally;
}
std::vector<std::string> outlines;
std::string privMDLoc = ActiveSchemaDB()->getDefaults().getValue(SEABASE_CATALOG);
privMDLoc += ".\"";
privMDLoc += SEABASE_PRIVMGR_SCHEMA;
privMDLoc += "\"";
PrivMgrCommands privMgrInterface(privMDLoc,CmpCommon::diags());
//get description in REGISTER, CREATE, GRANT statements.
CmpSeabaseDDL cmpSBD((NAHeap*)heap);
if (cmpSBD.switchCompiler())
{
*CmpCommon::diags() << DgSqlCode(-CAT_UNABLE_TO_RETRIEVE_PRIVS);
rc = -1;
goto finally;
}
if(!privMgrInterface.describeComponents(d->getComponentName().data(), outlines))
{
*CmpCommon::diags() << DgSqlCode(-CAT_TABLE_DOES_NOT_EXIST_ERROR)
<< DgTableName(d->getComponentName().data());
cmpSBD.switchBackCompiler();
rc = -1;
goto finally;
}
cmpSBD.switchBackCompiler();
for(int i = 0; i < outlines.size(); i++)
outputLine(space, outlines[i].c_str(), 0);
outbuflen = space.getAllocatedSpaceSize();
outbuf = new (heap) char[outbuflen];
space.makeContiguous(outbuf, outbuflen);
goto finally; // we are done and rc is already 0
}
if (d->getDescribedTableName().getQualifiedNameObj().getObjectNameSpace() == COM_LIBRARY_NAME)
{
if (!CmpDescribeLibrary(d->getDescribedTableName(),outbuf,outbuflen,heap))
{
rc = -1;
goto finally;
}
goto finally; // we are done and rc is already 0
}
if (d->getDescribedTableName().getQualifiedNameObj().getObjectNameSpace() ==
COM_UDF_NAME)
{
if (!CmpDescribeRoutine(d->getDescribedTableName(),outbuf,outbuflen,heap))
{
rc = -1;
goto finally;
}
goto finally; // we are done and rc is already 0
}
ExtendedQualName::SpecialTableType tType =
d->getDescribedTableName().getSpecialType();
// Don't reveal exception table (special table syntax)
if ( (CmpCommon::getDefault(IS_DB_TRANSPORTER) == DF_OFF) &&
(tType == ExtendedQualName::EXCEPTION_TABLE) )
tType = ExtendedQualName::NORMAL_TABLE;
NAString upshiftedLocName(d->getDescribedTableName().getLocationName());
upshiftedLocName.toUpper();
NAString *pLocName = NULL;
if (d->getDescribedTableName().isLocationNameSpecified())
pLocName = &upshiftedLocName;
if (d->getFormat() == Describe::PLAN_)
{
// Return runtime plan.
// This command (SHOWPLAN) is for internal debugging use only.
CMPASSERT(query);
// Skip leading blanks
for ( ; *query == ' '; query++) ;
// Skip the SHOWPLAN token & option (if specified)(length to be determined) in front of the input query.
Int32 i=8;
while(query[i] == ' ') i++;
if(str_cmp(query+i,"option",6) == 0 || str_cmp(query+i,"OPTION",6) == 0)
{
while(query[i] != '\'' && query[i] != '\0') i++;
i++;
while(query[i] != '\'' && query[i] != '\0') i++;
i++;
}
rc = CmpDescribePlan(&query[i], d->getFlags(), outbuf, outbuflen, heap);
goto finally; // we are done
}
if (d->getFormat() == Describe::SHAPE_)
{
// Return CONTROL QUERY SHAPE statement for this query.
CMPASSERT(query);
// Skip leading blanks
for ( ; *query == ' '; query++) ;
// Skip the SHOWSHAPE token (length 9) in front of the input query.
rc = CmpDescribeShape(&query[9], outbuf, outbuflen, heap);
goto finally; // we are done
}
if (d->getFormat() == Describe::SHOWQRYSTATS_)
{
// show histogram for root of this query.
rc = CmpDescribeShowQryStats(query, outbuf, outbuflen, heap);
goto finally; // we are done
}
if (d->getIsControl())
{
rc = CmpDescribeControl(d, outbuf, outbuflen, heap);
goto finally; // we are done
}
if (d->getFormat() == Describe::LEAKS_)
{
#ifdef NA_DEBUG_HEAPLOG
if ((d->getFlags()) & LeakDescribe::FLAG_ARKCMP)
outbuflen = HeapLogRoot::getPackSize();
else
outbuflen = 8;
HEAPLOG_OFF();
outbuf = (char *)heap->allocateMemory(outbuflen);
HEAPLOG_ON();
HeapLogRoot::pack(outbuf, d->getFlags());
#endif
goto finally; // we are done and rc is already 0
}
if (d->getFormat() == Describe::SHOWSTATS_)
{
rc = (short)ShowStats(query, outbuf, outbuflen, heap);
goto finally; // we are done
}
if (d->getFormat() == Describe::TRANSACTION_)
{
rc = CmpDescribeTransaction(outbuf, outbuflen, heap);
goto finally; // we are done
}
// Start SHOWDDL code
// check if this is a hive table. If so, describe using hive info from NATable.
// For now, schemaName of HIVE indicates a hive table.
// Need to fix that at a later time when multiple hive schemas are supported.
if (((d->getFormat() == Describe::INVOKE_) ||
(d->getFormat() == Describe::SHOWDDL_)) &&
(d->getDescribedTableName().isHive()) &&
(!d->getDescribedTableName().isSpecialTable()))
{
rc =
CmpDescribeHiveTable(d->getDescribedTableName(),
(d->getFormat() == Describe::INVOKE_ ? 1 : 2),
outbuf, outbuflen, heap,
d->getIsDetail());
goto finally; // we are done
}
if (d->getLabelAnsiNameSpace() == COM_SEQUENCE_GENERATOR_NAME)
{
rc =
CmpDescribeSequence(d->getDescribedTableName(),
outbuf, outbuflen, heap, NULL);
goto finally; // we are done
}
// check if this is an hbase/seabase table. If so, describe using info from NATable.
if (((d->getFormat() == Describe::INVOKE_) ||
(d->getFormat() == Describe::SHOWDDL_)) &&
((d->getDescribedTableName().isHbase()) ||
(d->getDescribedTableName().isSeabase())))
{
rc =
CmpDescribeSeabaseTable(d->getDescribedTableName(),
(d->getFormat() == Describe::INVOKE_ ? 1 : 2),
outbuf, outbuflen, heap, NULL, NULL, TRUE,
FALSE, FALSE, FALSE, FALSE, UINT_MAX, FALSE,
NULL, 0, NULL, NULL, NULL,
d->getIsDetail());
goto finally; // we are done
}
TrafDesc *tabledesc = NULL;
if ( ExtendedQualName::isDescribableTableType(tType) )
{
*CmpCommon::diags() << DgSqlCode(-4222)
<< DgString0("DESCRIBE");
}
else // special virtual table
{
HiveMDaccessFunc hiveMDF;
const NAString& virtualTableName =
d->getDescribedTableName().getQualifiedNameObj().getObjectName();
if (strncmp(virtualTableName.data(), "HIVEMD_", 7) == 0)
{
NAString mdType = virtualTableName;
mdType = mdType.strip(NAString::trailing, '_');
mdType = mdType(7, mdType.length()-7);
hiveMDF.setMDtype(mdType.data());
tabledesc = hiveMDF.createVirtualTableDesc();
}
else
{
// not supported
*CmpCommon::diags() << DgSqlCode(-3131);
rc = -1;
goto finally;
}
}
if (!tabledesc)
{
rc = -1;
goto finally;
}
NAString tableName(tabledesc->tableDesc()->tablename) ;
NABoolean external = d->getIsExternal();
//strip catalog off of table name
if (external)
{
ComObjectName externName(tableName, COM_TABLE_NAME);
if (logFormat || (replShowddl != 0))
{
if ((replIOVersion >= 5 && replIOVersion <= 10) ||
(replIOVersion >= 14))
tableName = externName.getObjectNamePartAsAnsiString();
else
tableName = externName.getExternalName(FALSE, TRUE);
}
else
tableName = externName.getExternalName(FALSE, TRUE);
}
NABoolean isVolatile =
FALSE;
NABoolean isInMemoryObjectDefn =
FALSE;
if(isVolatile)
Set_SqlParser_Flags(ALLOW_VOLATILE_SCHEMA_IN_TABLE_NAME);
// Allocate enough for a big view or constraint definition
const Int32 LOCAL_BIGBUF_SIZE = 30000;
buf = new (CmpCommon::statementHeap()) char[LOCAL_BIGBUF_SIZE];
CMPASSERT(buf);
TrafDesc *viewdesc = tabledesc->tableDesc()->views_desc;
if (d->getFormat() == Describe::INVOKE_)
{
time_t tp;
time(&tp);
if (viewdesc)
sprintf(buf, "-- Definition of view %s\n"
"-- Definition current %s",
tableName.data(), ctime(&tp));
else if ( tType == ExtendedQualName::TRIGTEMP_TABLE )
sprintf(buf, "-- Definition of table (TEMP_TABLE %s)\n"
"-- Definition current %s",
tableName.data(), ctime(&tp));
else if ( tType == ExtendedQualName::EXCEPTION_TABLE )
sprintf(buf, "-- Definition of table (EXCEPTION_TABLE %s)\n"
"-- Definition current %s",
tableName.data(), ctime(&tp));
else if ( tType == ExtendedQualName::IUD_LOG_TABLE )
sprintf(buf, "-- Definition of table (IUD_LOG_TABLE %s)\n"
"-- Definition current %s",
tableName.data(), ctime(&tp));
else if ( tType == ExtendedQualName::RANGE_LOG_TABLE )
sprintf(buf, "-- Definition of table (RANGE_LOG_TABLE %s)\n"
"-- Definition current %s",
tableName.data(), ctime(&tp));
else
{
if (isVolatile)
{
ComObjectName cn(tableName.data());
sprintf(buf, "-- Definition of %svolatile table %s\n"
"-- Definition current %s",
(isInMemoryObjectDefn ? "InMemory " : ""),
cn.getObjectNamePartAsAnsiString().data(),
ctime(&tp));
}
else if (isInMemoryObjectDefn)
{
sprintf(buf, "-- Definition of InMemory table %s\n"
"-- Definition current %s",
tableName.data(), ctime(&tp));
}
else
{
sprintf(buf, "-- Definition of table %s\n"
"-- Definition current %s",
tableName.data(), ctime(&tp));
}
}
outputShortLine(space, buf);
outputShortLine(space, " ( ");
NABoolean displayAddedCols = FALSE; // dummy variable
// this may be a problem when describing virtual tables like EXPLAIN
*CmpCommon::diags() << DgSqlCode(-4222)
<< DgString0("INVOKE for TABLE");
outputShortLine(space, " )");
outbuflen = space.getAllocatedSpaceSize();
outbuf = new (heap) char[outbuflen];
space.makeContiguous(outbuf, outbuflen);
NADELETEBASIC(buf, CmpCommon::statementHeap());
goto finally; // we are done and rc is already 0
}
// This is done for SHOWDDL only. Not for SHOWLABEL
if(logFormat)
outputShortLine(space, "--> BT ");
sprintf(buf, "CREATE TABLE %s",
tableName.data());
outputLine(space, buf, 0, 2, FALSE, testSchema);
const NABoolean commentOut =
FALSE;
const NABoolean mustShowBT =
TRUE;
if(mustShowBT)
{
outputShortLine(space, " (", commentOut);
}
NABoolean displayAddedCols = FALSE;
// this may be a problem when describing virtual tables like EXPLAIN
*CmpCommon::diags() << DgSqlCode(-4222)
<< DgString0("SHOWDDL for TABLE");
Int32 pkey_colcount = 0;
// Flag for additional alter table statements for constraints
NABoolean displayAlterTable = FALSE;
// Flag for whether primary key belongs in a ALTER TABLE statement
NABoolean alterTablePrimaryKey = FALSE;
buf[0] = '\0';
if(mustShowBT)
{
outputShortLine(space, " ;", commentOut);
}
outbuflen = space.getAllocatedSpaceSize();
outbuf = new (heap) char[outbuflen];
space.makeContiguous(outbuf, outbuflen);
Reset_SqlParser_Flags(ALLOW_VOLATILE_SCHEMA_IN_TABLE_NAME);
NADELETEBASIC(buf, CmpCommon::statementHeap());
} // end of try block
// exception handling
catch(...)
{
// Check diags area, if it doesn't contain an error, add an
// internal exception
if (CmpCommon::diags()->getNumber() == 0)
{
*CmpCommon::diags() << DgSqlCode(-2006);
*CmpCommon::diags() << DgString0("Unknown error returned while retrieving metadata");
*CmpCommon::diags() << DgString1(__FILE__);
*CmpCommon::diags() << DgInt0(__LINE__);
}
rc = -1;
}
finally:
// Restore parser flags settings to what they originally were
Assign_SqlParser_Flags(savedParserFlags);
SQL_EXEC_AssignParserFlagsForExSqlComp_Internal(savedParserFlags);
return rc;
} // SHOWDDL
short exeImmedCQD(const char *cqd, NABoolean hold)
{
Int32 retcode = 0;
ExeCliInterface cliInterface(CmpCommon::statementHeap());
if (hold)
retcode = cliInterface.holdAndSetCQD(cqd, "ON");
else
retcode = cliInterface.restoreCQD(cqd);
if (retcode < 0)
{
cliInterface.retrieveSQLDiagnostics(CmpCommon::diags());
return retcode;
}
return 0;
}
short exeImmedOneStmt(const char *controlStmt)
{
Int32 retcode = 0;
ExeCliInterface cliInterface(CmpCommon::statementHeap());
retcode = cliInterface.executeImmediate(controlStmt);
if (retcode < 0)
{
cliInterface.retrieveSQLDiagnostics(CmpCommon::diags());
return retcode;
}
return 0;
}
short sendAllControls(NABoolean copyCQS,
NABoolean sendAllCQDs,
NABoolean sendUserCQDs,
enum COM_VERSION versionOfCmplrRcvCntrlInfo,
NABoolean sendUserCSs,
CmpContext* prevContext)
{
// -----------------------------------------------------------------------
// Given a SQL query, this procedure invokes the appropriate
// CLI calls to prepare and execute the statement.
// -----------------------------------------------------------------------
Int32 retcode = 0;
char *buf = new (CmpCommon::statementHeap()) char[15000];
if (copyCQS)
{
if (ActiveControlDB()->getRequiredShape())
{
retcode =
exeImmedOneStmt(ActiveControlDB()->getRequiredShape()->getShapeText());
if (retcode)
return (short)retcode;
}
else if (ActiveControlDB()->requiredShapeWasOnceNonNull())
{
// Genesis solution 10-040528-6511: If we possibly
// sent a CQS down once before, we need to send a
// CQS CUT to get rid of it if it is no longer
// active.
strcpy(buf,"CONTROL QUERY SHAPE CUT;");
retcode = exeImmedOneStmt(buf);
if (retcode)
return((short)retcode);
}
}
CollIndex i;
ControlDB *cdb = NULL;
// if prevContext is defined, get the controlDB from the previous context so the
// defaults are copied from the previous cmp context to the new cmp context. This is only
// required for embedded compilers where a SWITCH is taking place
if (prevContext)
cdb = prevContext->getControlDB();
else
cdb = ActiveControlDB();
if ((sendAllCQDs) ||
(sendUserCQDs))
{
// send all externalized CQDs.
NADefaults &defs = CmpCommon::context()->schemaDB_->getDefaults();
for (i = 0; i < defs.numDefaultAttributes(); i++)
{
const char *attrName, *val;
if (defs.getCurrentDefaultsAttrNameAndValue(i, attrName, val,
sendUserCQDs))
{
if (NOT defs.isReadonlyAttribute(attrName))
{
if (strcmp(attrName, "ISO_MAPPING") == 0)
{
// ISO_MAPPING is a read-only default attribute --
// But for internal development and testing purpose,
// we sometimes want to change the setting within
// an MXCI session. Make sure that we send the CQD
// COMP_BOOL_58 'ON' before sending CQD ISO_MAPPING
// so that the child/receiving MXCMP does not reject
// the CQD ISO_MAPPING request.
sprintf(buf, "CONTROL QUERY DEFAULT COMP_BOOL_58 'ON';");
exeImmedOneStmt(buf);
}
if (strcmp(attrName, "TERMINAL_CHARSET") == 0 &&
versionOfCmplrRcvCntrlInfo < COM_VERS_2300)
{
sprintf(buf, "CONTROL QUERY DEFAULT TERMINAL_CHARSET 'ISO88591';");
}
else
{
if (strcmp(attrName, "REPLICATE_IO_VERSION") == 0)
{
ULng32 originalParserFlags = Get_SqlParser_Flags(0xFFFFFFFF);
SQL_EXEC_SetParserFlagsForExSqlComp_Internal (originalParserFlags);
}
NAString quotedString;
ToQuotedString(quotedString, NAString(val), TRUE);
sprintf(buf, "CONTROL QUERY DEFAULT %s %s;", attrName, quotedString.data());
}
retcode = exeImmedOneStmt(buf);
if (retcode)
return((short)retcode);
}
}
}
}
if (NOT sendUserCQDs && prevContext)
{
// Send only to different context (prevContext != NULL)
// and send the CQDs that were entered by user and were not 'reset reset'
for (i = 0; i < cdb->getCQDList().entries(); i++)
{
ControlQueryDefault * cqd = cdb->getCQDList()[i];
NAString quotedString;
ToQuotedString (quotedString, cqd->getValue());
if (strcmp(cqd->getToken().data(), "TERMINAL_CHARSET") == 0 &&
versionOfCmplrRcvCntrlInfo < COM_VERS_2300)
{
sprintf(buf, "CONTROL QUERY DEFAULT TERMINAL_CHARSET 'ISO88591';");
}
else
{
if (strcmp(cqd->getToken().data(), "REPLICATE_IO_VERSION") == 0)
{
ULng32 originalParserFlags = Get_SqlParser_Flags(0xFFFFFFFF);
SQL_EXEC_SetParserFlagsForExSqlComp_Internal (originalParserFlags);
}
sprintf(buf, "CONTROL QUERY DEFAULT %s %s;",
cqd->getToken().data(),
quotedString.data());
}
retcode = exeImmedOneStmt(buf);
if (retcode)
return((short)retcode);
}
}
for (i = 0; i < cdb->getCTList().entries(); i++)
{
ControlTableOptions *cto = cdb->getCTList()[i];
for (CollIndex j = 0; j < cto->numEntries(); j++)
{
sprintf(buf, "CONTROL TABLE %s %s '%s';",
cto->tableName().data(),
cto->getToken(j).data(),
cto->getValue(j).data());
retcode = exeImmedOneStmt(buf);
if (retcode)
return((short)retcode);
} // j
} // i
// pass on the parserflags to the new compiler
// used to enable SHOWPLAN for MV INTERNAL REFRESH
if (CmpCommon::getDefault(MV_ENABLE_INTERNAL_REFRESH_SHOWPLAN) == DF_ON)
{
ULng32 originalParserFlags = Get_SqlParser_Flags(0xFFFFFFFF);
SQL_EXEC_SetParserFlagsForExSqlComp_Internal (originalParserFlags);
}
if (sendUserCSs)
{
for (i = 0; i < cdb->getCSList().entries(); i++)
{
ControlSessionOption *cso = cdb->getCSList()[i];
sprintf(buf, "CONTROL SESSION '%s' '%s';",
cso->getToken().data(),
cso->getValue().data());
retcode = exeImmedOneStmt(buf);
if (retcode)
return((short)retcode);
}
}
if (CmpCommon::context()->sqlSession()->volatileSchemaInUse())
{
// sendAllControls is called by mxcmp when it prepares internal
// queries. Tablenames used in these queries may already be fully
// qualified with volatile schema name.
// Set the flag to indicate that an error should not be returned
// if volatile schema name has been explicitely specified.
SQL_EXEC_SetParserFlagsForExSqlComp_Internal
(ALLOW_VOLATILE_SCHEMA_IN_TABLE_NAME);
}
else
{
SQL_EXEC_ResetParserFlagsForExSqlComp_Internal
(ALLOW_VOLATILE_SCHEMA_IN_TABLE_NAME);
}
return 0;
}
void sendParserFlag (ULng32 flag)
{
SQL_EXEC_SetParserFlagsForExSqlComp_Internal (flag);
}
short setParentQidAtSession(NAHeap *heap, const char *parentQid)
{
Int32 retcode = 0;
short len = (short)strlen(parentQid);
char *srcBuf = new (heap) char[len+50];
strcpy(srcBuf, "SET SESSION DEFAULT PARENT_QID '");
strcat(srcBuf, parentQid);
strcat(srcBuf, "'");
retcode = exeImmedOneStmt(srcBuf);
NADELETEBASIC(srcBuf, heap);
return (short) retcode;
}
/*
static long describeError(long retcode)
{
*CmpCommon::diags() << DgSqlCode(retcode);
return -1;
}
*/
/////////////////////////////////////////////////////////////////
//
// flags:
// 0x00000001 display all expressions
// 0x00000002 display pcode expressions
// 0x00000004 display clause expressions
// 0x00000008 display TDBs
// 0x00000010 do not regenerate pcode for showplan.
// 0x00000010 do downrev compile for R2. Used when pcode is
// regenerated during display
// 0x00000020 do downrev compile for RR. Used when pcode is
// regenerated during display
/////////////////////////////////////////////////////////////////
static short CmpGetPlan(SQLSTMT_ID &stmt_id,
ULng32 flags,
Space &space,
CollHeap * heap,
char* &rootTdbBuf, Lng32 &rootTdbSize,
char* &srcStrBuf, Lng32 &srcStrSize)
{
Lng32 retcode = 0;
ULong stmtHandle = (ULong)stmt_id.handle;
// Now get the generated code to describe the plan.
// do not advance to next statement yet, if all stmts are to be retrieved.
if ((stmt_id.handle) && (stmt_id.name_mode != stmt_handle) &&
((stmtHandle & 0x0001) != 0))
stmt_id.handle = (void *)(stmtHandle & ~0x0004);
retcode = SQLCLI_GetRootTdbSize_Internal(GetCliGlobals(),
&rootTdbSize,
&srcStrSize,
&stmt_id);
if (retcode)
return ((retcode < 0) ? -1 : (short)retcode);
rootTdbBuf = new (heap) char[rootTdbSize];
srcStrBuf = new (heap) char[srcStrSize+1];
// now advance to the next statement
stmtHandle = (ULong)stmt_id.handle;
if ((stmt_id.handle) && (stmt_id.name_mode != stmt_handle) &&
((stmtHandle & 0x0001) != 0))
stmt_id.handle = (void*)(stmtHandle | 0x0004);
retcode = SQLCLI_GetRootTdb_Internal(GetCliGlobals(),
rootTdbBuf,
rootTdbSize,
srcStrBuf,
srcStrSize,
&stmt_id);
if (retcode)
return ((retcode < 0) ? -1 : (short)retcode);
if (srcStrSize > 0)
srcStrBuf[srcStrSize] = 0;
return (short)retcode;
}
/////////////////////////////////////////////////////////////////
//
// flags:
// 0x00000001 display all expressions
// 0x00000002 display pcode expressions
// 0x00000004 display clause expressions
// 0x00000008 display TDBs
// 0x00000010 do downrev compile. Used when pcode is regenerated
// during display
/////////////////////////////////////////////////////////////////
static Lng32 CmpFormatPlan(SQLSTMT_ID &stmt_id,
ULng32 flags,
char *rootTdbBuf, Lng32 rootTdbSize,
char *srcStrBuf, Lng32 srcStrSize,
NABoolean outputSrcInfo,
Space &space, CollHeap * heap)
{
char buf[200];
if (outputSrcInfo)
{
// output module and statement name
sprintf(buf, "\nModule: %s Statement: %s\n",
stmt_id.module->module_name, stmt_id.identifier);
outputShortLine(space, buf);
if (srcStrSize > 0)
{
Int32 i = 0;
Int32 j = 0;
while (i < srcStrSize)
{
if (srcStrBuf[i] == '\n')
{
buf[j] = 0;
outputShortLine(space, buf);
j = 0;
}
else
{
buf[j] = srcStrBuf[i];
j++;
}
i++;
}
buf[j] = 0;
outputShortLine(space, buf);
sprintf(buf, "\n");
outputShortLine(space, buf);
}
}
ComTdbRoot *rootTdb = (ComTdbRoot*) rootTdbBuf;
// unpack the root TDB
ComTdb dummyTdb;
if ( (rootTdb = (ComTdbRoot *)
rootTdb->driveUnpack((void *)rootTdb,&dummyTdb,NULL)) == NULL )
{
// ERROR during unpacking. Shouldn't occur here since we have just
// freshly prepared the statement using the latest version of the
// compiler. This is an unexpected error.
//
return -1;
}
UInt32 planVersion = rootTdb->getPlanVersion();
// This fragment corresponds to the MASTER.
// Get to the fragment directory from rootTdb.
void * baseAddr = (void *)rootTdb;
ExFragDir *fragDir = rootTdb->getFragDir();
ComTdb *fragTdb = rootTdb;
// a sanity check to see that it was the MASTER fragment.
CMPASSERT(fragDir->getType(0) == ExFragDir::MASTER);
// unpack each fragment independently;
// unpacking converts offsets to actual pointers.
for (Int32 i = 0; i < fragDir->getNumEntries(); i++)
{
void * fragBase = (void *)((char *)baseAddr + fragDir->getGlobalOffset(i));
void * fragStart = (void *)((char *)fragBase + fragDir->getTopNodeOffset(i));
switch (fragDir->getType(i))
{
case ExFragDir::MASTER:
{
// already been unpacked. Nothing to be done.
sprintf(buf, "MASTER Executor fragment");
outputShortLine(space, buf);
sprintf(buf, "========================\n");
outputShortLine(space, buf);
sprintf(buf, "Fragment ID: %d, Length: %d\n",
i, fragDir->getFragmentLength(i));
outputShortLine(space, buf);
}
break;
case ExFragDir::ESP:
{
sprintf(buf, "ESP fragment");
outputShortLine(space, buf);
sprintf(buf, "===========\n");
outputShortLine(space, buf);
sprintf(buf, "Fragment ID: %d, Parent ID: %d, Length: %d\n",
i, fragDir->getParentId(i), fragDir->getFragmentLength(i));
outputShortLine(space, buf);
ComTdb tdb;
fragTdb = (ComTdb *)fragStart;
fragTdb = (ComTdb *)(fragTdb->driveUnpack(fragBase,&tdb,NULL));
}
break;
case ExFragDir::DP2:
{
sprintf(buf, "EID fragment");
outputShortLine(space, buf);
sprintf(buf, "===========\n");
outputShortLine(space, buf);
sprintf(buf, "Fragment ID: %d, Parent ID: %d, Length: %d\n",
i, fragDir->getParentId(i), fragDir->getFragmentLength(i));
outputShortLine(space, buf);
}
break;
case ExFragDir::EXPLAIN:
// Not using explain frag here!
fragTdb = NULL;
break;
} // switch
// Now display expressions.
flags = flags | 0x00000001;
if (fragTdb)
{
if ((planVersion > COM_VERS_R1_8) &&
(planVersion < COM_VERS_R2_1))
{
// downrev compile needed.
flags |= 0x00000020;
}
else if (planVersion == COM_VERS_R2_1)
flags |= 0x0000020;
if ((CmpCommon::getDefaultLong(QUERY_OPTIMIZATION_OPTIONS) & QO_EXPR_OPT) == 0)
{
flags |= 0x00000020;
}
fragTdb->displayContents(&space, flags);
}
} // for
return 0;
}
/////////////////////////////////////////////////////////////////
//
// flags:
// 0x00000001 display all expressions
// 0x00000002 display pcode expressions
// 0x00000004 display clause expressions
// 0x00000008 display TDBs
// 0x00000010 do downrev compile. Used when pcode is regenerated
// during display
/////////////////////////////////////////////////////////////////
static Lng32 CmpGetAndFormatPlan(SQLSTMT_ID &stmt_id,
ULng32 flags,
NABoolean outputSrcInfo,
Space &space, CollHeap * heap)
{
Lng32 retcode = 0;
char *rootTdbBuf = NULL;
char *srcStrBuf = NULL;
Lng32 rootTdbSize;
Lng32 srcStrSize;
retcode = CmpGetPlan(stmt_id, flags, space, heap,
rootTdbBuf, rootTdbSize,
srcStrBuf, srcStrSize);
if (retcode)
return ((retcode < 0) ? -1 : retcode);
retcode = CmpFormatPlan(stmt_id, flags,
rootTdbBuf, rootTdbSize,
srcStrBuf, srcStrSize,
outputSrcInfo,
space, heap);
if (retcode)
return ((retcode < 0) ? -1 : retcode);
return retcode;
}
static short CmpDescribePlan(
const char *query,
ULng32 flags,
char *&outbuf,
ULng32 &outbuflen,
NAMemory *heap)
{
// prepare this query.
Lng32 retcode;
Lng32 resetRetcode;
SQLSTMT_ID stmt_id; // added for multi charset module names
SQLMODULE_ID module;
SQLDESC_ID sql_src;
Space space;
ULng32 originalParserFlags = Get_SqlParser_Flags(0xFFFFFFFF);
char *genCodeBuf = NULL;
Lng32 genCodeSize = 0;
char uniqueStmtId[ComSqlId::MAX_QUERY_ID_LEN+1];
Lng32 uniqueStmtIdLen = ComSqlId::MAX_QUERY_ID_LEN;
init_SQLCLI_OBJ_ID(&stmt_id);
init_SQLMODULE_ID(&module);
init_SQLCLI_OBJ_ID(&sql_src);
retcode = SQL_EXEC_ClearDiagnostics(NULL);
if (retcode)
return ((retcode < 0) ? -1 : (short)retcode);
//Allocate a SQL statement
stmt_id.name_mode = stmt_handle;
stmt_id.module = &module;
module.module_name = 0;
stmt_id.identifier = 0;
stmt_id.handle = 0;
retcode = SQL_EXEC_AllocStmt(&stmt_id, 0);
if (retcode)
return ((retcode < 0) ? -1 : (short)retcode);
// Allocate a descriptor which will hold the SQL statement source
sql_src.name_mode = desc_handle;
sql_src.module = &module;
module.module_name = 0;
sql_src.identifier = 0;
sql_src.handle = 0;
retcode = SQL_EXEC_AllocDesc(&sql_src, (SQLDESC_ID *)0);
if (retcode)
return ((retcode < 0) ? -1 : (short)retcode);
retcode = SQL_EXEC_SetDescItem(&sql_src, 1, SQLDESC_CHAR_SET,
SQLCHARSETCODE_UTF8
, 0);
if (retcode)
return ((retcode < 0) ? -1 : (short)retcode);
// The arkcmp that will be used to compile this query does not
// know about the control statements that were issued.
// Send all the CONTROL statements before preparing this statement.
retcode = sendAllControls(TRUE, FALSE, TRUE);
if (retcode)
return (short)retcode;
// send control session to indicate showplan is being done
retcode = exeImmedOneStmt("CONTROL SESSION SET 'SHOWPLAN' 'ON';");
if (retcode)
goto label_error;
// Now prepare the query to be 'showplan'ed
retcode = SQL_EXEC_SetDescItem(&sql_src, 1, SQLDESC_VAR_PTR,
(Long)query, 0);
if (retcode)
{
goto label_error_1;
}
retcode = SQL_EXEC_SetDescItem(&sql_src, 1, SQLDESC_LENGTH,
strlen(query) + 1, 0);
if (retcode)
{
goto label_error_1;
}
SQL_EXEC_SetParserFlagsForExSqlComp_Internal (originalParserFlags);
// prepare it and get the generated code size
strcpy(uniqueStmtId, " ");
retcode = SQL_EXEC_Prepare2(&stmt_id, &sql_src,
NULL, 0,
&genCodeSize, NULL, NULL,
uniqueStmtId,
&uniqueStmtIdLen,0);
if ((retcode == -CLI_GENCODE_BUFFER_TOO_SMALL) &&
(genCodeSize > 0))
{
retcode = SQL_EXEC_ClearDiagnostics(NULL);
// retrieve the generated code
genCodeBuf = new (heap) char[genCodeSize];
strcpy(uniqueStmtId, " ");
retcode = SQL_EXEC_Prepare2(&stmt_id, NULL,
genCodeBuf, genCodeSize,
NULL, NULL, NULL,
uniqueStmtId,
&uniqueStmtIdLen,0);
}
if (retcode < 0) // ignore warnings
{
resetRetcode = SQL_EXEC_MergeDiagnostics_Internal(*CmpCommon::diags());
goto label_error_1;
}
retcode = CmpFormatPlan(stmt_id, flags,
genCodeBuf, genCodeSize,
NULL, 0,
FALSE,
space, heap);
if (retcode)
{
goto label_error_1;
}
outbuflen = space.getAllocatedSpaceSize();
outbuf = new (heap) char[outbuflen];
space.makeContiguous(outbuf, outbuflen);
retcode = exeImmedOneStmt("CONTROL SESSION RESET 'SHOWPLAN';");
if (retcode)
goto label_error;
// free up resources
retcode = SQL_EXEC_DeallocDesc(&sql_src);
if (retcode)
return ((retcode < 0) ? -1 : (short)retcode);
retcode = SQL_EXEC_DeallocStmt(&stmt_id);
if (retcode)
return ((retcode < 0) ? -1 : (short)retcode);
return 0;
label_error_1:
resetRetcode = exeImmedOneStmt("CONTROL SESSION RESET 'SHOWPLAN';");
label_error:
return ((retcode < 0) ? -1 : (short)retcode);
} // CmpDescribePlan
// TRUE if ident is nonempty and contained in comparand string c1.
inline static NABoolean identSpecifiedMatches(const NAString &id, const char *c1)
{ return (!id.isNull() && strstr(c1, id)); } // strstr(fullstring, substring)
// TRUE if ident is empty (not specified), or is contained in c1.
inline static NABoolean identMatches(const NAString &id, const char *c1)
{ return (id.isNull() || strstr(c1, id)); } // strstr(fullstring, substring)
// If not exact match:
// TRUE if ident is empty, or is contained in c1, or c1 equals c2.
// If exact:
// TRUE if ident equals c1, period.
inline static NABoolean identMatches2(const NAString &id, const char *c1, const char *c2,
NABoolean exactMatch)
{
return exactMatch ? (strcmp(id, c1) == 0)
: (identMatches(id, c1) || strcmp(c1, c2) == 0);
}
#define IDENTMATCHES(c1,c2) identMatches2(ident, c1, c2, exactMatch)
// defined in generator/GenExplain.cpp
NABoolean displayDuringRegressRun(DefaultConstants attr);
// these CQDs are used for internal purpose and are set/sent by SQL.
// Do not display them.
static NABoolean isInternalCQD(DefaultConstants attr)
{
if ((attr == SESSION_ID) ||
(attr == SESSION_IN_USE) ||
(attr == LDAP_USERNAME) ||
(attr == VOLATILE_CATALOG) ||
(attr == VOLATILE_SCHEMA_IN_USE) ||
(attr == IS_SQLCI) ||
(attr == NVCI_PROCESS))
return TRUE;
if ((getenv("SQLMX_REGRESS")) &&
((NOT displayDuringRegressRun(attr)) ||
(attr == TRAF_ALIGNED_ROW_FORMAT)))
return TRUE;
return FALSE;
}
short CmpDescribeControl(Describe *d,
char *&outbuf,
ULng32 &outbuflen,
CollHeap *heap)
{
// Two kludgy passing mechanisms from SqlParser.y ...
NAString ident =
d->getDescribedTableName().getQualifiedNameObj().getObjectName();
NABoolean exactMatch =
!d->getDescribedTableName().getCorrNameAsString().isNull();
CMPASSERT(!(ident.isNull() && exactMatch));
NAString fmtdIdent;
if (!ident.isNull()) fmtdIdent = NAString(' ') + ident;
static const char fmtNoMatch [] = "No CONTROL %s%s settings are in effect.";
static const char fmtNoMatch2[] = "No DEFAULTS attribute%s exists.";
static const char fmtNoMatch3[] = "No externalized DEFAULTS attribute%s exists.";
//static const char fmtExactMatch[] = "\n%-32s\t%s";
static const char fmtFuzzyMatch[] = " %-30s\t%s";
//const char *fmtInfo = exactMatch ? fmtExactMatch : fmtFuzzyMatch;
const char *fmtInfo = fmtFuzzyMatch;
// SHOWCONTROL DEFAULT CAT will display both CATALOG and SCHEMA defaults;
// SHOWCONTROL DEFAULT SCH will too.
static const char *defCatSchStrings[] = { "", "CATALOG", "SCHEMA" };
size_t ix = identSpecifiedMatches(ident, "CATALOG") ? 2 :
identSpecifiedMatches(ident, "SCHEMA") ? 1 : 0;
const char *defCatSch = defCatSchStrings[ix];
NABoolean showShape, showSession, showTable, showDefault, match = FALSE;
NABoolean showAll = d->getFormat() == Describe::CONTROL_ALL_;
if (showAll)
{
showShape = TRUE;
showSession = TRUE;
showTable = TRUE;
showDefault = TRUE;
}
else
{
showShape = d->getFormat() == Describe::CONTROL_SHAPE_;
showSession = d->getFormat() == Describe::CONTROL_SESSION_;
showTable = d->getFormat() == Describe::CONTROL_TABLE_;
showDefault = d->getFormat() == Describe::CONTROL_DEFAULTS_;
}
Space space;
char * buf = new (heap) char[15000];
CMPASSERT(buf);
ControlDB *cdb = ActiveControlDB();
if (showShape)
{
outputShortLine(space, "");
if ((cdb->getRequiredShape()) &&
(cdb->getRequiredShape()->getShape()))
{
NAString shape(cdb->getRequiredShape()->getShapeText());
PrettifySqlText(shape);
outputLine(space, shape, 2);
}
else
{
// Only one shape at a time (no history-list), so no ident-matching...
sprintf(buf, fmtNoMatch, "QUERY SHAPE", "");
outputLine(space, buf, 0);
}
} // SHOWCONTROL SHAPE
if (showSession)
{
outputShortLine(space, "");
match = FALSE;
for (CollIndex i = 0; i < cdb->getCSList().entries(); i++)
{
ControlSessionOption *cso = cdb->getCSList()[i];
if (IDENTMATCHES(cso->getToken().data(), "*"))
{
if (!match)
outputShortLine(space, "CONTROL SESSION");
sprintf(buf, fmtInfo,
cso->getToken().data(),
cso->getValue().data());
outputLine(space, buf, 2);
match = TRUE;
}
}
if (!match)
{
sprintf(buf, fmtNoMatch, "SESSION", fmtdIdent.data());
outputLine(space, buf, 0);
}
} // SHOWCONTROL SESSION
if (showTable)
{
outputShortLine(space, "");
match = FALSE;
for (CollIndex i = 0; i < cdb->getCTList().entries(); i++)
{
ControlTableOptions *cto = cdb->getCTList()[i];
if (IDENTMATCHES(cto->tableName().data(), "*") &&
cto->numEntries() > 0)
{
sprintf(buf, "CONTROL TABLE %s", cto->tableName().data());
outputLine(space, buf, 0);
match = TRUE;
for (CollIndex j = 0; j < cto->numEntries(); j++)
{
sprintf(buf, fmtInfo,
cto->getToken(j).data(),
cto->getValue(j).data());
outputLine(space, buf, 2);
} // j
} // ident absent or it matches
} // i
if (!match)
{
sprintf(buf, fmtNoMatch, "TABLE", fmtdIdent.data());
outputLine(space, buf, 0);
}
} // SHOWCONTROL TABLE
if (showDefault)
{
{
if (d->getHeader())
outputShortLine(space, "");
match = FALSE;
for (CollIndex i = 0; i < cdb->getCQDList().entries(); i++)
{
ControlQueryDefault * cqd = cdb->getCQDList()[i];
if (IDENTMATCHES(cqd->getToken().data(), defCatSch))
{
// This is the NO HEADER option. We just want the value of the default.
if (!(d->getHeader())) {
strcpy(buf, cqd->getValue().data());
outputLine(space, buf, 2);
outbuflen = space.getAllocatedSpaceSize();
outbuf = new (heap) char[outbuflen];
space.makeContiguous(outbuf, outbuflen);
NADELETEBASIC(buf, heap);
return 0;
}
else {
if (NOT isInternalCQD(cqd->getAttrEnum()))
{
if (!match)
outputShortLine(space, "CONTROL QUERY DEFAULT");
sprintf(buf, fmtInfo,
cqd->getToken().data(),
cqd->getValue().data());
outputLine(space, buf, 2);
match = TRUE;
}
}
}
}
if (!match && d->getHeader())
{
sprintf(buf, fmtNoMatch, "QUERY DEFAULT", fmtdIdent.data());
outputLine(space, buf, 0);
}
}
// This is a nice little extra for partial-match, and
// essential for exactMatch:
if (!ident.isNull()) showAll = TRUE;
} // SHOWCONTROL DEFAULTS
if (showAll)
{
if (d->getHeader())
outputShortLine(space, "");
match = FALSE;
NADefaults &defs = CmpCommon::context()->schemaDB_->getDefaults();
for (CollIndex i = 0; i < defs.numDefaultAttributes(); i++)
{
const char *attrName, *val;
if (defs.getCurrentDefaultsAttrNameAndValue(i, attrName, val, FALSE) &&
IDENTMATCHES(attrName, defCatSch))
{
// This is the NO HEADER option. We just want the value of the default.
if (!(d->getHeader())) {
strcpy(buf, val);
outputLine(space, buf, 2);
outbuflen = space.getAllocatedSpaceSize();
outbuf = new (heap) char[outbuflen];
space.makeContiguous(outbuf, outbuflen);
NADELETEBASIC(buf, heap);
return 0;
}
else {
if (!match)
outputShortLine(space, "Current DEFAULTS");
sprintf(buf, fmtInfo, attrName, val);
outputLine(space, buf, 2);
match = TRUE;
}
}
}
if (!match)
{
if (CmpCommon::getDefault(SHOWCONTROL_SHOW_ALL) != DF_ON)
sprintf(buf, fmtNoMatch3, fmtdIdent.data());
else
sprintf(buf, fmtNoMatch2, fmtdIdent.data());
outputLine(space, buf, 0);
}
}
outbuflen = space.getAllocatedSpaceSize();
outbuf = new (heap) char[outbuflen];
space.makeContiguous(outbuf, outbuflen);
NADELETEBASIC(buf, heap);
return 0;
}
static short CmpDescribeShape(
const char *query,
char *&outbuf,
ULng32 &outbuflen,
NAMemory *heap)
{
// prepare this query.
char * qTree = NULL;
ULng32 dummyLen;
CmpMain sqlcomp;
CmpMain::CompilerPhase phase = CmpMain::PRECODEGEN;
#ifdef _DEBUG
char * sp = getenv("SHOWSHAPE_PHASE");
if (sp)
{
switch (sp[0])
{
case 'S':
phase = CmpMain::PARSE;
break;
case 'B':
phase = CmpMain::BIND;
break;
case 'T':
phase = CmpMain::TRANSFORM;
break;
case 'N':
phase = CmpMain::NORMALIZE;
break;
case 'O':
phase = CmpMain::OPTIMIZE;
break;
case 'P':
phase = CmpMain::PRECODEGEN;
break;
case 'G':
phase = CmpMain::GENERATOR;
break;
default:
phase = CmpMain::PRECODEGEN;
break;
} // switch
} // if
#endif
QueryText qText((char*)query, SQLCHARSETCODE_UTF8);
if (sqlcomp.sqlcomp(qText, 0, &qTree, &dummyLen, heap, phase))
{
CMPASSERT(query);
return -1;
}
RelExpr * queryTree = (RelExpr *)qTree;
Space space;
char buf[1000];
sprintf(buf, "control query shape ");
queryTree->generateShape(&space, buf);
strcat(buf, ";");
outputShortLine(space, buf);
outbuflen = space.getAllocatedSpaceSize();
outbuf = new (heap) char[outbuflen];
space.makeContiguous(outbuf, outbuflen);
return 0;
}
// show transaction
static short CmpDescribeTransaction(
char *&outbuf,
ULng32 &outbuflen,
NAMemory *heap)
{
Space space;
char buf[100];
if (CmpCommon::transMode()->getIsolationLevel() == TransMode::READ_UNCOMMITTED_)
outputShortLine(space, "ISOLATION LEVEL : READ UNCOMMITTED");
else if (CmpCommon::transMode()->getIsolationLevel() == TransMode::READ_COMMITTED_)
outputShortLine(space, "ISOLATION LEVEL : READ COMMITTED");
else if (CmpCommon::transMode()->getIsolationLevel() == TransMode::REPEATABLE_READ_)
outputShortLine(space, "ISOLATION LEVEL : REPEATABLE READ");
else if (CmpCommon::transMode()->getIsolationLevel() == TransMode::SERIALIZABLE_)
outputShortLine(space, "ISOLATION LEVEL : SERIALIZABLE");
else if (CmpCommon::transMode()->getIsolationLevel() == TransMode::IL_NOT_SPECIFIED_)
outputShortLine(space, "ISOLATION LEVEL : NOT SPECIFIED");
if (CmpCommon::transMode()->getAccessMode() == TransMode::READ_ONLY_ ||
CmpCommon::transMode()->getAccessMode() == TransMode::READ_ONLY_SPECIFIED_BY_USER_)
outputShortLine(space, "ACCESS MODE : READ ONLY");
else if (CmpCommon::transMode()->getAccessMode() == TransMode::READ_WRITE_)
outputShortLine(space, "ACCESS MODE : READ WRITE");
else if (CmpCommon::transMode()->getAccessMode() == TransMode::AM_NOT_SPECIFIED_)
outputShortLine(space, "ACCESS MODE : NOT SPECIFIED");
if (CmpCommon::transMode()->getAutoCommit() == TransMode::ON_)
outputShortLine(space, "AUTOCOMMIT : ON");
else if (CmpCommon::transMode()->getAutoCommit() == TransMode::OFF_)
outputShortLine(space, "AUTOCOMMIT : OFF");
else if (CmpCommon::transMode()->getAutoCommit() == TransMode::AC_NOT_SPECIFIED_)
outputShortLine(space, "AUTOCOMMIT : NOT SPECIFIED");
if (CmpCommon::transMode()->getRollbackMode() == TransMode::NO_ROLLBACK_)
outputShortLine(space, "NO ROLLBACK : ON");
else if (CmpCommon::transMode()->getRollbackMode() == TransMode::ROLLBACK_MODE_WAITED_)
outputShortLine(space, "NO ROLLBACK : OFF");
else
outputShortLine(space, "NO ROLLBACK : NOT SPECIFIED");
sprintf(buf, "DIAGNOSTICS SIZE : %d", CmpCommon::transMode()->getDiagAreaSize());
outputLine(space, buf, 0);
Lng32 val = CmpCommon::transMode()->getAutoAbortIntervalInSeconds() ;
if (val == -2) // user specified never abort setting
val = 0;
if (val == -3) // user specified reset to TMFCOM setting
val = -1;
sprintf(buf, "AUTOABORT : %d SECONDS", val);
outputLine(space, buf, 0);
if (CmpCommon::transMode()->getMultiCommit() == TransMode::MC_ON_)
outputShortLine(space, "MULTI COMMIT : ON");
else if (CmpCommon::transMode()->getMultiCommit() == TransMode::MC_OFF_)
outputShortLine(space, "MULTI COMMIT : OFF");
else if (CmpCommon::transMode()->getMultiCommit() == TransMode::MC_NOT_SPECIFIED_)
outputShortLine(space, "MULTI COMMIT : NOT SPECIFIED");
if (CmpCommon::transMode()->getAutoBeginOn())
outputShortLine(space, "AUTOBEGIN : ON");
else if (CmpCommon::transMode()->getAutoBeginOff())
outputShortLine(space, "AUTOBEGIN : OFF");
else
outputShortLine(space, "AUTOBEGIN : NOT SPECIFIED");
outbuflen = space.getAllocatedSpaceSize();
outbuf = new (heap) char[outbuflen];
space.makeContiguous(outbuf, outbuflen);
return 0;
}
static NAString CmpDescribe_ptiToInfCS(const NAString &inputInLatin1)
{
return Latin1StrToUTF8 ( inputInLatin1 // in - const NAString & latin1Str
, STMTHEAP // in - NAMemory * heap
);
}
short CmpDescribeHiveTable (
const CorrName &dtName,
short type, // 1, invoke. 2, showddl. 3, createLike
char* &outbuf,
ULng32 &outbuflen,
CollHeap *heap,
NABoolean isDetail,
UInt32 columnLengthLimit)
{
const NAString& tableName =
dtName.getQualifiedNameObj().getQualifiedNameAsString();
BindWA bindWA(ActiveSchemaDB(), CmpCommon::context(), FALSE/*inDDL*/);
NATable *naTable = bindWA.getNATable((CorrName&)dtName);
if (naTable == NULL || bindWA.errStatus())
return -1;
else
{
// if showddl and this hive table has an associated external table,
// show the ddl of underlying hive table first.
if ((type == 2) &&
(naTable->isHiveTable()) &&
(naTable->hasHiveExtTable()))
{
// remove current cache key and turn off ext table attr cqd.
// This will return the underlying hive natable.
bindWA.getSchemaDB()->getNATableDB()->remove(naTable->getKey());
// retrieve underlying hive table definition
bindWA.setReturnHiveTableDefn(TRUE);
naTable = bindWA.getNATable((CorrName&)dtName);
if (naTable == NULL || bindWA.errStatus())
return -1;
}
bindWA.createTableDesc(naTable, (CorrName&)dtName);
if (bindWA.errStatus())
return -1;
}
if (NOT naTable->isHiveTable())
return -1;
char * buf = new (heap) char[15000];
CMPASSERT(buf);
time_t tp;
time(&tp);
Space space;
// emit an initial newline
outputShortLine(space, " ");
if (!CmpDescribeIsAuthorized(SQLOperation::UNKNOWN,
naTable->getPrivInfo(),
COM_BASE_TABLE_OBJECT))
return -1;
NABoolean isView = (naTable->getViewText() ? TRUE : FALSE);
if ((type == 2) && (isView))
{
outputShortLine(space,"Original native Hive view text:");
NAString origViewText(naTable->getHiveOriginalViewText());
outputLongLine(space, origViewText, 0);
outputShortLine(space, " ");
outputShortLine(space,"Expanded native Hive view text:");
NAString viewtext(naTable->getViewText());
viewtext = viewtext.strip(NAString::trailing, ';');
viewtext += " ;";
outputLongLine(space, viewtext, 0);
// if this hive view is registered in traf metadata, show that.
if (naTable->isRegistered())
{
Int64 objectUID = (Int64)naTable->objectUid().get_value();
outputShortLine(space, " ");
sprintf(buf, "REGISTER%sHIVE VIEW %s;",
(naTable->isInternalRegistered() ? " /*INTERNAL*/ " : " "),
naTable->getTableName().getQualifiedNameAsString().data());
NAString bufnas(buf);
outputLongLine(space, bufnas, 0);
str_sprintf(buf, "/* ObjectUID = %ld */", objectUID);
outputShortLine(space, buf);
}
outbuflen = space.getAllocatedSpaceSize();
outbuf = new (heap) char[outbuflen];
space.makeContiguous(outbuf, outbuflen);
NADELETEBASIC(buf, heap);
return 0;
}
if (type == 1)
{
if (isView)
sprintf(buf, "-- Definition of native Hive view %s\n"
"-- Definition current %s",
tableName.data(), ctime(&tp));
else
sprintf(buf, "-- Definition of hive table %s\n"
"-- Definition current %s",
tableName.data(), ctime(&tp));
outputShortLine(space, buf);
}
else if (type == 2)
{
outputShortLine(space,"/* Hive DDL */");
if (naTable->isHiveExternalTable())
sprintf(buf, "CREATE EXTERNAL TABLE %s",
tableName.data());
else
sprintf(buf, "CREATE TABLE %s",
tableName.data());
outputShortLine(space, buf);
}
outputShortLine(space, " ( ");
for (Int32 i = 0; i < (Int32)naTable->getColumnCount(); i++)
{
NAColumn * nac = naTable->getNAColumnArray()[i];
const NAString &colName = nac->getColName();
const NAType * nat = nac->getType();
sprintf(buf, "%-*s ", CM_SIM_NAME_LEN,
ANSI_ID(colName.data()));
NAString nas;
if ((type == 1) || (type == 3))
nat->getMyTypeAsText(&nas, FALSE);
else
nat->getMyTypeAsHiveText(&nas);
// if it is a character type and it is longer than the length
// limit in bytes, then shorten the target type
if ((type == 3) &&
(nat->getTypeQualifier() == NA_CHARACTER_TYPE) &&
(!nat->isLob()) &&
(columnLengthLimit < UINT_MAX))
{
const CharType * natc = (const CharType *)nat;
if (natc->getDataStorageSize() > columnLengthLimit)
{
CharType * newType = (CharType *)natc->newCopy(NULL);
newType->setDataStorageSize(columnLengthLimit);
nas.clear();
newType->getMyTypeAsText(&nas, FALSE);
delete newType;
}
}
sprintf(&buf[strlen(buf)], "%s", nas.data());
NAString colString(buf);
Int32 j = i;
outputColumnLine(space, colString, j);
}
outputShortLine(space, " )");
const HHDFSTableStats* hTabStats = NULL;
if (naTable->getClusteringIndex())
hTabStats = naTable->getClusteringIndex()->getHHDFSTableStats();
if (hTabStats)
{
if (hTabStats->isOrcFile())
{
if (type == 1)
outputShortLine(space, " /* stored as orc */");
else if (type == 2)
outputShortLine(space, " stored as orc ");
}
else if (hTabStats->isTextFile())
{
if (type == 1)
outputShortLine(space, " /* stored as textfile */");
else if (type == 2)
outputShortLine(space, " stored as textfile ");
}
else if (hTabStats->isSequenceFile())
{
if (type == 1)
outputShortLine(space, " /* stored as sequencefile */");
else if (type == 2)
outputShortLine(space, " stored as sequencefile ");
}
}
if (type == 2)
{
outputShortLine(space, ";");
outputShortLine(space," ");
outputShortLine(space,"/* Trafodion DDL */");
}
// if this hive table is registered in traf metadata, show that.
if (type == 2)
{
if (naTable->isRegistered())
{
Int64 objectUID = (Int64)naTable->objectUid().get_value();
outputShortLine(space, " ");
sprintf(buf, "REGISTER%sHIVE %s %s;",
(naTable->isInternalRegistered() ? " /*INTERNAL*/ " : " "),
(isView ? "VIEW" : "TABLE"),
naTable->getTableName().getQualifiedNameAsString().data());
NAString bufnas(buf);
outputLongLine(space, bufnas, 0);
str_sprintf(buf, "/* ObjectUID = %ld */", objectUID);
outputShortLine(space, buf);
}
else if (isDetail)
{
// show a comment that this object should be registered
outputShortLine(space, " ");
outputShortLine(space, "-- Object is not registered in Trafodion Metadata.");
outputShortLine(space, "-- Register it using the next command:");
sprintf(buf, "-- REGISTER HIVE %s %s;",
(isView ? "VIEW" : "TABLE"),
naTable->getTableName().getQualifiedNameAsAnsiString().data());
NAString bufnas(buf);
outputLongLine(space, bufnas, 0);
}
}
// if this hive table has an associated external table, show ddl
// for that external table.
if ((type == 2) &&
(bindWA.returnHiveTableDefn()))
{
// remove table key from natable cache. Next call to get natable
// will get the external table defn, if one exists
bindWA.getSchemaDB()->getNATableDB()->remove(naTable->getKey());
bindWA.setReturnHiveTableDefn(FALSE);
char * dummyBuf;
ULng32 dummyLen;
NAString extName = ComConvertNativeNameToTrafName(
dtName.getQualifiedNameObj().getCatalogName(),
dtName.getQualifiedNameObj().getSchemaName(),
dtName.getQualifiedNameObj().getObjectName());
QualifiedName qn(extName, 3);
CorrName cn(qn);
short rc = CmpDescribeSeabaseTable(cn,
type,
dummyBuf, dummyLen, heap,
NULL, NULL,
TRUE, FALSE, FALSE, FALSE,
FALSE,
UINT_MAX, TRUE,
NULL, 0, NULL, NULL, &space);
outputShortLine(space, ";");
}
// If SHOWDDL and authorization is enabled, display GRANTS
if (type == 2)
{
int64_t objectUID = (int64_t)naTable->objectUid().get_value();
char * sqlmxRegr = getenv("SQLMX_REGRESS");
NABoolean displayPrivilegeGrants = TRUE;
if (((CmpCommon::getDefault(SHOWDDL_DISPLAY_PRIVILEGE_GRANTS) == DF_SYSTEM) && sqlmxRegr) ||
(CmpCommon::getDefault(SHOWDDL_DISPLAY_PRIVILEGE_GRANTS) == DF_OFF) ||
(NOT CmpCommon::context()->isAuthorizationEnabled()) ||
(objectUID <= 0))
displayPrivilegeGrants = FALSE;
if (displayPrivilegeGrants)
{
// Used for context switches
CmpSeabaseDDL cmpSBD((NAHeap*)heap);
// now get the grant stmts
std::string privMDLoc(ActiveSchemaDB()->getDefaults().getValue(SEABASE_CATALOG));
privMDLoc += std::string(".\"") +
std::string(SEABASE_PRIVMGR_SCHEMA) +
std::string("\"");
PrivMgrCommands privInterface(privMDLoc, CmpCommon::diags(),
PrivMgr::PRIV_INITIALIZED);
PrivMgrObjectInfo objectInfo(naTable);
std::string privilegeText;
if (cmpSBD.switchCompiler())
{
*CmpCommon::diags() << DgSqlCode(-CAT_UNABLE_TO_RETRIEVE_PRIVS);
return -1;
}
if (privInterface.describePrivileges(objectInfo, privilegeText))
{
outputShortLine(space, " ");
outputLine(space, privilegeText.c_str(), 0);
}
cmpSBD.switchBackCompiler();
}
}
outbuflen = space.getAllocatedSpaceSize();
outbuf = new (heap) char[outbuflen];
space.makeContiguous(outbuf, outbuflen);
NADELETEBASIC(buf, heap);
return 0;
}
// type: 1, invoke. 2, showddl. 3, create_like
short cmpDisplayColumn(const NAColumn *nac,
char * inColName,
const NAType *inNAT,
short displayType,
Space *inSpace,
char * buf,
Lng32 &ii,
NABoolean namesOnly,
NABoolean &identityCol,
NABoolean isExternalTable,
NABoolean isAlignedRowFormat,
UInt32 columnLengthLimit,
NAList<const NAColumn *> * truncatedColumnList)
{
Space lSpace;
Space * space;
if (inSpace)
space = inSpace;
else
space = &lSpace;
identityCol = FALSE;
NAString colName(inColName ? inColName : nac->getColName());
NATable * naTable = (NATable*)nac->getNATable();
NAString colFam;
if ((nac->getNATable() && nac->getNATable()->isSQLMXAlignedTable()) ||
(nac->getHbaseColFam() == SEABASE_DEFAULT_COL_FAMILY) ||
isExternalTable)
colFam = "";
else if (nac->getNATable() && nac->getNATable()->isSeabaseTable())
{
const char * col_fam = NULL;
if (nac->getNATable()->isHbaseMapTable())
{
col_fam = nac->getHbaseColFam().data();
}
else
{
int index = 0;
CmpSeabaseDDL::extractTrafColFam(nac->getHbaseColFam(), index);
if (index >= naTable->allColFams().entries())
return -1;
col_fam = naTable->allColFams()[index].data();
}
colFam = ANSI_ID(col_fam);
colFam += ".";
}
if (displayType == 3)
{
NAString quotedColName = "\"";
quotedColName += colName.data();
quotedColName += "\"";
sprintf(buf, "%s%-*s ",
colFam.data(),
CM_SIM_NAME_LEN,
quotedColName.data());
}
else
{
sprintf(buf, "%s%-*s ",
colFam.data(),
CM_SIM_NAME_LEN-(int)colFam.length(),
ANSI_ID(colName.data()));
}
if (namesOnly)
{
NAString colString(buf);
Int32 j = ii;
outputColumnLine(*space, colString, j);
return 0;
}
const NAType * nat = (inNAT ? inNAT : nac->getType());
NAString nas;
nat->getMyTypeAsText(&nas, FALSE);
// if it is a character type and it is longer than the length
// limit in bytes, then shorten the target type
if ((nat->getTypeQualifier() == NA_CHARACTER_TYPE) &&
(!nat->isLob()) &&
(columnLengthLimit < UINT_MAX) &&
(truncatedColumnList))
{
const CharType * natc = (const CharType *)nat;
if (natc->getDataStorageSize() > columnLengthLimit)
{
CharType * newType = (CharType *)natc->newCopy(NULL);
newType->setDataStorageSize(columnLengthLimit);
nas.clear();
newType->getMyTypeAsText(&nas, FALSE);
delete newType;
truncatedColumnList->insert(nac);
}
}
NAString attrStr;
NAString defVal;
if (nac->getDefaultClass() == COM_NO_DEFAULT)
defVal = "NO DEFAULT";
else if (nac->getDefaultClass() == COM_NULL_DEFAULT)
defVal = "DEFAULT NULL";
else if (nac->getDefaultClass() == COM_CURRENT_DEFAULT)
defVal = "DEFAULT CURRENT";
else if (nac->getDefaultClass() == COM_CURRENT_UT_DEFAULT)
defVal = "DEFAULT CURRENT UNIXTIME";
else if (nac->getDefaultClass() == COM_USER_FUNCTION_DEFAULT)
defVal = "DEFAULT USER";
else if (nac->getDefaultClass() == COM_UUID_DEFAULT)
defVal = "DEFAULT UUID";
else if (nac->getDefaultClass() == COM_USER_DEFINED_DEFAULT || nac->getDefaultClass() == COM_FUNCTION_DEFINED_DEFAULT)
{
defVal = "DEFAULT ";
if (displayDefaultValue(nac->getDefaultValue(), colName.data(),
defVal))
{
return -1;
}
}
else if ((nac->getDefaultClass() == COM_IDENTITY_GENERATED_BY_DEFAULT) ||
(nac->getDefaultClass() == COM_IDENTITY_GENERATED_ALWAYS))
{
if (nac->getDefaultClass() == COM_IDENTITY_GENERATED_BY_DEFAULT)
defVal = "GENERATED BY DEFAULT AS IDENTITY";
else
defVal = "GENERATED ALWAYS AS IDENTITY";
NAString idOptions;
if ((displayType != 1) && (nac->getNATable()->getSGAttributes()))
nac->getNATable()->getSGAttributes()->display(NULL, &idOptions, TRUE);
if (NOT idOptions.isNull())
defVal += " (" + idOptions + " )";
identityCol = TRUE;
}
else
defVal = "NO DEFAULT";
attrStr = defVal;
if (nac->getHeading())
{
NAString heading = "HEADING ";
NAString externalHeading = "";
ToQuotedString(externalHeading, nac->getHeading());
heading += externalHeading;
attrStr += " ";
attrStr += heading;
}
if (NOT nat->supportsSQLnull())
{
NAString nullVal = "NOT NULL NOT DROPPABLE";
attrStr += " ";
attrStr += nullVal;
}
char * sqlmxRegr = getenv("SQLMX_REGRESS");
if ((! sqlmxRegr) ||
(displayType == 3))
{
if ((NOT isAlignedRowFormat) &&
CmpSeabaseDDL::isSerialized(nac->getHbaseColFlags()))
attrStr += " SERIALIZED";
else if ((CmpCommon::getDefault(HBASE_SERIALIZATION) == DF_ON) ||
(displayType == 3))
attrStr += " NOT SERIALIZED";
}
if (displayType != 3)
{
if (nac->isAlteredColumn())
{
attrStr += " /*altered_col*/ ";
}
else if (nac->isAddedColumn())
{
attrStr += " /*added_col*/ ";
}
}
sprintf(&buf[strlen(buf)], "%s %s",
nas.data(),
attrStr.data());
NAString colString(buf);
Int32 j = ii;
if (inSpace)
outputColumnLine(*space, colString, j);
return 0;
}
// type: 1, invoke. 2, showddl. 3, create_like
short cmpDisplayColumns(const NAColumnArray & naColArr,
short displayType,
Space &space, char * buf,
NABoolean displaySystemCols,
NABoolean namesOnly,
Lng32 &identityColPos,
NABoolean isExternalTable,
NABoolean isAlignedRowFormat,
NABoolean omitLobColumns = FALSE,
char * inColName = NULL,
short ada = 0, // 0,add. 1,drop. 2,alter
const NAColumn * nacol = NULL,
const NAType * natype = NULL,
UInt32 columnLengthLimit = UINT_MAX,
NAList<const NAColumn *> * truncatedColumnList = NULL)
{
Lng32 ii = 0;
identityColPos = -1;
NABoolean identityCol = FALSE;
for (Int32 i = 0; i < (Int32)naColArr.entries(); i++)
{
NAColumn * nac = naColArr[i];
if ((NOT displaySystemCols) &&
(nac->isSystemColumn()))
{
continue;
}
if (omitLobColumns &&
(nac->getType()->isLob()))
{
continue;
}
const NAString &colName = nac->getColName();
if ((inColName) && (ada == 1))
{
if (colName == inColName) // remove this column
continue;
}
if ((inColName) && (colName == inColName) &&
(ada == 2) && (nacol) && (natype))
{
if (cmpDisplayColumn(nac, NULL, natype, displayType, &space, buf, ii, namesOnly, identityCol,
isExternalTable, isAlignedRowFormat, columnLengthLimit, truncatedColumnList))
return -1;
}
else
{
if (cmpDisplayColumn(nac, NULL, NULL, displayType, &space, buf, ii, namesOnly, identityCol,
isExternalTable, isAlignedRowFormat, columnLengthLimit, truncatedColumnList))
return -1;
}
if (identityCol)
identityColPos = i;
ii++;
}
if ((inColName) && (ada == 0) && (nacol))
{
if (cmpDisplayColumn(nacol, NULL, NULL, displayType, &space, buf, ii, namesOnly, identityCol,
isExternalTable, isAlignedRowFormat, columnLengthLimit, truncatedColumnList))
return -1;
}
return 0;
}
short cmpDisplayPrimaryKey(const NAColumnArray & naColArr,
Lng32 numKeys,
NABoolean displaySystemCols,
Space &space, char * buf,
NABoolean displayCompact,
NABoolean displayAscDesc,
NABoolean displayParens)
{
if (numKeys > 0)
{
if (displayParens)
{
if (displayCompact)
sprintf(&buf[strlen(buf)], "(");
else
{
outputShortLine(space, " ( ");
}
}
NABoolean isFirst = TRUE;
Int32 j = -1;
for (Int32 jj = 0; jj < numKeys; jj++)
{
NAColumn * nac = naColArr[jj];
if ((NOT displaySystemCols) &&
(nac->isSystemColumn()))
{
continue;
}
else
j++; // increment num of columns displayed
const NAString &keyName = nac->getColName();
if (displayCompact)
{
sprintf(&buf[strlen(buf)], "%s%s%s",
(NOT isFirst ? ", " : ""),
ANSI_ID(keyName.data()),
(displayAscDesc ?
(! naColArr.isAscending(jj) ? " DESC" : " ASC") :
" "));
}
else
{
sprintf(buf, "%s%s",
ANSI_ID(keyName.data()),
(displayAscDesc ?
(! naColArr.isAscending(jj) ? " DESC" : " ASC") :
" "));
NAString colString(buf);
outputColumnLine(space, colString, j);
}
isFirst = FALSE;
} // for
if (displayParens)
{
if (displayCompact)
{
sprintf(&buf[strlen(buf)], ")");
outputLine(space, buf, 2);
}
else
{
outputShortLine(space, " )");
}
}
} // if
return 0;
}
// type: 1, invoke. 2, showddl. 3, create_like
short CmpDescribeSeabaseTable (
const CorrName &dtName,
short type,
char* &outbuf,
ULng32 &outbuflen,
CollHeap *heap,
const char * pkeyName,
const char * pkeyStr,
NABoolean withPartns,
NABoolean withoutSalt,
NABoolean withoutDivisioning,
NABoolean withoutRowFormat,
NABoolean withoutLobColumns,
UInt32 columnLengthLimit,
NABoolean noTrailingSemi,
char * colName,
short ada,
const NAColumn * nacol,
const NAType * natype,
Space *inSpace,
NABoolean isDetail)
{
const NAString& tableName =
dtName.getQualifiedNameObj().getQualifiedNameAsAnsiString(TRUE);
const NAString& objectName =
dtName.getQualifiedNameObj().getObjectName();
if (CmpCommon::context()->isUninitializedSeabase())
{
*CmpCommon::diags() << DgSqlCode(CmpCommon::context()->uninitializedSeabaseErrNum());
return -1;
}
// set isExternalTable to allow Hive External tables to be described
BindWA bindWA(ActiveSchemaDB(), CmpCommon::context(), FALSE/*inDDL*/);
NATable *naTable = bindWA.getNATableInternal((CorrName&)dtName);
TableDesc *tdesc = NULL;
if (naTable == NULL || bindWA.errStatus())
return -1;
else
{
tdesc = bindWA.createTableDesc(naTable, (CorrName&)dtName);
if (bindWA.errStatus())
return -1;
}
if (NOT naTable->isHbaseTable())
{
if (CmpCommon::diags()->getNumber() == 0)
*CmpCommon::diags() << DgSqlCode(-CAT_UNSUPPORTED_COMMAND_ERROR);
return -1;
}
NABoolean isVolatile = naTable->isVolatileTable();
NABoolean isExternalTable = naTable->isTrafExternalTable();
NABoolean isImplicitExternalTable = naTable->isImplicitTrafExternalTable();
NABoolean isHbaseMapTable = naTable->isHbaseMapTable();
NABoolean isHbaseCellOrRowTable =
(naTable->isHbaseCellTable() || naTable->isHbaseRowTable());
NABoolean isExternalHbaseTable = FALSE;
NABoolean isExternalHiveTable = FALSE;
NAString extName;
if (isExternalTable)
{
extName = ComConvertTrafNameToNativeName(
dtName.getQualifiedNameObj().getCatalogName(),
dtName.getQualifiedNameObj().getUnqualifiedSchemaNameAsAnsiString(),
dtName.getQualifiedNameObj().getUnqualifiedObjectNameAsAnsiString());
QualifiedName qn(extName, 3);
if (qn.getCatalogName() == HBASE_SYSTEM_CATALOG)
isExternalHbaseTable = TRUE;
else if (qn.getCatalogName() == HIVE_SYSTEM_CATALOG)
isExternalHiveTable = TRUE;
}
char * buf = new (heap) char[15000];
CMPASSERT(buf);
time_t tp;
time(&tp);
Space lSpace;
Space * space;
if (inSpace)
space = inSpace;
else
space = &lSpace;
char * sqlmxRegr = getenv("SQLMX_REGRESS");
NABoolean displayPrivilegeGrants = TRUE;
if (((CmpCommon::getDefault(SHOWDDL_DISPLAY_PRIVILEGE_GRANTS) == DF_SYSTEM) && sqlmxRegr) ||
(CmpCommon::getDefault(SHOWDDL_DISPLAY_PRIVILEGE_GRANTS) == DF_OFF))
displayPrivilegeGrants = FALSE;
// display syscols for invoke if not running regrs
//
NABoolean displaySystemCols = (type == 1);
NABoolean isView = (naTable->getViewText() ? TRUE : FALSE);
// emit an initial newline
outputShortLine(*space, " ");
// Used for context switches
CmpSeabaseDDL cmpSBD((NAHeap*)heap);
// Verify that user can perform the describe command
// No need to check privileges for create like operations (type 3)
// since the create code performs authorization checks
// Nor for hiveExternal tables - already checked
if (!isExternalHiveTable)
{
if (type != 3)
{
// For native HBase tables that have no objectUID, we can't check
// user privileges so only allow operation for privileged users
if (isHbaseCellOrRowTable &&
!ComUser::isRootUserID() && !ComUser::currentUserHasRole(HBASE_ROLE_ID) &&
naTable->objectUid().get_value() == 0)
{
*CmpCommon::diags() << DgSqlCode(-CAT_UNABLE_TO_RETRIEVE_PRIVS);
return -1;
}
PrivMgrUserPrivs privs;
PrivMgrUserPrivs *pPrivInfo = NULL;
// metadata tables do not cache privilege information, go get it now
if (CmpCommon::context()->isAuthorizationEnabled() &&
naTable->getPrivInfo() == NULL)
{
std::string privMDLoc(ActiveSchemaDB()->getDefaults().getValue(SEABASE_CATALOG));
privMDLoc += std::string(".\"") +
std::string(SEABASE_PRIVMGR_SCHEMA) +
std::string("\"");
PrivMgrCommands privInterface(privMDLoc, CmpCommon::diags(),
PrivMgr::PRIV_INITIALIZED);
// we should switch to another CI only if we are in an embedded CI
if (cmpSBD.switchCompiler())
{
*CmpCommon::diags() << DgSqlCode(-CAT_UNABLE_TO_RETRIEVE_PRIVS);
return -1;
}
PrivStatus retcode = privInterface.getPrivileges((int64_t)naTable->objectUid().get_value(),
naTable->getObjectType(),
ComUser::getCurrentUser(),
privs);
// switch back the original commpiler, ignore error for now
cmpSBD.switchBackCompiler();
if (retcode == STATUS_ERROR)
{
*CmpCommon::diags() << DgSqlCode(-CAT_UNABLE_TO_RETRIEVE_PRIVS);
return -1;
}
pPrivInfo = &privs;
}
else
pPrivInfo = naTable->getPrivInfo();
// Allow object owners to perform showddl operation
if ((naTable->getOwner() != ComUser::getCurrentUser()) &&
!ComUser::currentUserHasRole(naTable->getOwner()))
{
if (!CmpDescribeIsAuthorized(SQLOperation::UNKNOWN,
pPrivInfo,
COM_BASE_TABLE_OBJECT))
return -1;
}
}
}
Int64 objectUID = (Int64) naTable->objectUid().get_value();
if ((type == 2) && (isView))
{
NAString viewtext(naTable->getViewText());
viewtext = viewtext.strip(NAString::trailing, ';');
viewtext += " ;";
outputLongLine(*space, viewtext, 0);
//display comment for VIEW
if (objectUID > 0)
{
if (cmpSBD.switchCompiler())
{
*CmpCommon::diags() << DgSqlCode(-CAT_UNABLE_TO_RETRIEVE_COMMENTS);
return -1;
}
ComTdbVirtObjCommentInfo objCommentInfo;
if (cmpSBD.getSeabaseObjectComment(objectUID, COM_VIEW_OBJECT, objCommentInfo, heap))
{
*CmpCommon::diags() << DgSqlCode(-CAT_UNABLE_TO_RETRIEVE_COMMENTS);
cmpSBD.switchBackCompiler();
return -1;
}
//display VIEW COMMENT statements
if (objCommentInfo.objectComment != NULL)
{
//new line
outputLine(*space, "", 0);
sprintf(buf, "COMMENT ON VIEW %s IS '%s' ;",
tableName.data(),
objCommentInfo.objectComment);
outputLine(*space, buf, 0);
}
if (objCommentInfo.numColumnComment > 0 && objCommentInfo.columnCommentArray != NULL)
{
//display Column COMMENT statements
outputLine(*space, "", 0);
for (int idx = 0; idx < objCommentInfo.numColumnComment; idx++)
{
sprintf(buf, "COMMENT ON COLUMN %s.%s IS '%s' ;",
tableName.data(),
objCommentInfo.columnCommentArray[idx].columnName,
objCommentInfo.columnCommentArray[idx].columnComment);
outputLine(*space, buf, 0);
}
}
//do a comment info memory clean
NADELETEARRAY(objCommentInfo.columnCommentArray, objCommentInfo.numColumnComment, ComTdbVirtColumnCommentInfo, heap);
cmpSBD.switchBackCompiler();
}
// Display grant statements
if (CmpCommon::context()->isAuthorizationEnabled() && displayPrivilegeGrants)
{
std::string privMDLoc(ActiveSchemaDB()->getDefaults().getValue(SEABASE_CATALOG));
privMDLoc += std::string(".\"") +
std::string(SEABASE_PRIVMGR_SCHEMA) +
std::string("\"");
PrivMgrCommands privInterface(privMDLoc, CmpCommon::diags(),
PrivMgr::PRIV_INITIALIZED);
std::string privilegeText;
PrivMgrObjectInfo objectInfo(naTable);
if (cmpSBD.switchCompiler())
{
*CmpCommon::diags() << DgSqlCode(-CAT_UNABLE_TO_RETRIEVE_PRIVS);
return -1;
}
if (privInterface.describePrivileges(objectInfo, privilegeText))
{
outputShortLine(*space, " ");
outputLine(*space, privilegeText.c_str(), 0);
}
cmpSBD.switchBackCompiler();
}
outbuflen = space->getAllocatedSpaceSize();
outbuf = new (heap) char[outbuflen];
space->makeContiguous(outbuf, outbuflen);
NADELETEBASIC(buf, heap);
return 0;
}
if (type == 1)
{
if (isView)
sprintf(buf, "-- Definition of Trafodion view %s\n"
"-- Definition current %s",
tableName.data(), ctime(&tp));
else
sprintf(buf, "-- Definition of Trafodion%stable %s\n"
"-- Definition current %s",
(isVolatile ? " volatile " :
(isHbaseMapTable ? " HBase mapped " :
(isExternalTable ? " external " : " "))),
(isHbaseMapTable ? objectName.data() :
tableName.data()),
ctime(&tp));
outputShortLine(*space, buf);
}
else if (type == 2)
{
if (isHbaseCellOrRowTable)
outputShortLine(*space, "/*");
NAString tabType;
if (isVolatile)
tabType = " VOLATILE ";
else if (isExternalTable)
{
if (isImplicitExternalTable)
tabType = " /*IMPLICIT*/ EXTERNAL ";
else
tabType = " EXTERNAL ";
}
else
tabType = " ";
sprintf(
buf, "CREATE%sTABLE %s",
tabType.data(),
(isExternalTable ? objectName.data() : tableName.data()));
outputShortLine(*space, buf);
}
Lng32 identityColPos = -1;
NABoolean closeParan = FALSE;
NAList<const NAColumn *> truncatedColumnList(heap);
if ((NOT isExternalTable) ||
((isExternalTable) &&
((isExternalHbaseTable && ((type == 1) || (type == 3))) ||
(isExternalHbaseTable && naTable->isHbaseMapTable() && (type == 2)) ||
(isExternalHiveTable && (type != 2)) ||
(isExternalHiveTable && (type == 2) && (naTable->hiveExtColAttrs())))))
{
outputShortLine(*space, " ( ");
cmpDisplayColumns(naTable->getNAColumnArray(),
type, *space, buf,
displaySystemCols,
FALSE,
identityColPos,
(isExternalTable && (NOT isHbaseMapTable)),
naTable->isSQLMXAlignedTable(),
withoutLobColumns,
colName, ada, nacol, natype,
columnLengthLimit,
&truncatedColumnList);
closeParan = TRUE;
}
Int32 nonSystemKeyCols = 0;
NABoolean isStoreBy = FALSE;
NABoolean forceStoreBy = FALSE;
NABoolean isSalted = FALSE;
NABoolean isDivisioned = FALSE;
ItemExpr *saltExpr = NULL;
LIST(NAString) divisioningExprs(heap);
LIST(NABoolean) divisioningExprAscOrders(heap);
if (naTable->getClusteringIndex())
{
NAFileSet * naf = naTable->getClusteringIndex();
for (Lng32 i = 0; i < naf->getIndexKeyColumns().entries(); i++)
{
NAColumn * nac = naf->getIndexKeyColumns()[i];
if (nac->isComputedColumnAlways())
{
if (nac->isSaltColumn() && !withoutSalt)
{
isSalted = TRUE;
ItemExpr * saltBaseCol =
tdesc->getColumnList()[nac->getPosition()].getItemExpr();
CMPASSERT(saltBaseCol->getOperatorType() == ITM_BASECOLUMN);
saltExpr = ((BaseColumn *) saltBaseCol)->getComputedColumnExpr().getItemExpr();
}
else if (nac->isDivisioningColumn() && !withoutDivisioning)
{
NABoolean divColIsAsc = naf->getIndexKeyColumns().isAscending(i);
// any other case of computed column is treated as divisioning for now
isDivisioned = TRUE;
divisioningExprs.insert(NAString(nac->getComputedColumnExprString()));
divisioningExprAscOrders.insert(divColIsAsc);
}
}
if (NOT nac->isSystemColumn())
nonSystemKeyCols++;
else if (nac->isSyskeyColumn())
isStoreBy = TRUE;
// if we are shortening a column, set isStoreBy to TRUE since truncating
// a character string may cause formerly distinct values to become equal
// (that is, we want to change PRIMARY KEY to STORE BY)
for (Lng32 j = 0; j < truncatedColumnList.entries(); j++)
{
const NAColumn * truncatedColumn = truncatedColumnList[j];
if (nac->getColName() == truncatedColumn->getColName())
{
isStoreBy = TRUE;
forceStoreBy = TRUE;
}
}
}
}
if ((nonSystemKeyCols == 0) && (!forceStoreBy))
isStoreBy = FALSE;
if (type == 1)
outputShortLine(*space, " )");
Lng32 numBTpkeys = 0;
NAFileSet * naf = naTable->getClusteringIndex();
NABoolean isAudited = (naf ? naf->isAudited() : TRUE);
NABoolean isAligned = naTable->isSQLMXAlignedTable();
if ((type == 3) && (pkeyStr))
{
if (pkeyName)
{
NAString pkeyPrefix(", CONSTRAINT ");
pkeyPrefix += NAString(pkeyName) + " PRIMARY KEY ";
outputLine(*space, pkeyPrefix.data(), 0);
}
else
{
outputShortLine(*space, " , PRIMARY KEY ");
}
outputLine(*space, pkeyStr, 2);
}
else
{
if ((naf) &&
(nonSystemKeyCols > 0) &&
(NOT isStoreBy))
{
NAString pkeyConstrName;
NAString pkeyConstrObjectName;
if (type == 2) // showddl
{
const AbstractRIConstraintList &uniqueList = naTable->getUniqueConstraints();
for (Int32 i = 0; i < uniqueList.entries(); i++)
{
AbstractRIConstraint *ariConstr = uniqueList[i];
UniqueConstraint * uniqConstr = (UniqueConstraint*)ariConstr;
if (uniqConstr->isPrimaryKeyConstraint())
{
pkeyConstrName =
uniqConstr->getConstraintName().getQualifiedNameAsAnsiString(TRUE);
pkeyConstrObjectName =
uniqConstr->getConstraintName().getObjectName();
break;
}
} // for
} // type 2
numBTpkeys = naf->getIndexKeyColumns().entries();
if (type == 1)
sprintf(buf, " PRIMARY KEY ");
else
{
// Display primary key name for showddl (type == 2).
// First check to see if pkey name is a generated random name or
// a user specified name.
// If it is a generated random name, then dont display it.
// This is being done for backward compatibility in showddl
// output as well as avoid the need to update multiple
// regressions files.
// Currently we check to see if the name has random generated
// format to determine whether to display it or not.
// If it so happens that a user specified primary key constraint
// has that exact format, then it will not be displayed.
// At some point in future, we can store in metadata if pkey
// name was internally generated or user specified.
if ((type == 2) &&
(NOT pkeyConstrObjectName.isNull()) &&
(NOT ComIsRandomInternalName(pkeyConstrObjectName)))
sprintf(buf, " , CONSTRAINT %s PRIMARY KEY ",
pkeyConstrName.data());
else
sprintf(buf, " , PRIMARY KEY ");
}
// if all primary key columns are 'not serialized primary key',
// then display that.
NABoolean serialized = FALSE;
for (Int32 jj = 0;
((NOT serialized) && (jj < naf->getIndexKeyColumns().entries())); jj++)
{
NAColumn * nac = (naf->getIndexKeyColumns())[jj];
if (NOT nac->isPrimaryKeyNotSerialized())
serialized = TRUE;
}
if (((type == 1) || (type == 2)) && (NOT serialized))
{
strcat(&buf[strlen(buf)], "NOT SERIALIZED ");
}
cmpDisplayPrimaryKey(naf->getIndexKeyColumns(),
naf->getIndexKeyColumns().entries(),
displaySystemCols,
*space, buf, TRUE, TRUE, TRUE);
} // if
}
if (type != 1)
{
if (closeParan)
outputShortLine(*space, " )");
if (isStoreBy)
{
sprintf(buf, " STORE BY ");
cmpDisplayPrimaryKey(naf->getIndexKeyColumns(),
naf->getIndexKeyColumns().entries(),
displaySystemCols,
*space, buf, TRUE, TRUE, TRUE);
}
if ((isSalted) && !withoutSalt)
{
Lng32 currPartitions = naf->getCountOfPartitions();
Lng32 numPartitions = naf->numSaltPartns();
if (numPartitions != currPartitions)
sprintf(buf, " SALT USING %d PARTITIONS /* ACTUAL PARTITIONS %d */", numPartitions, currPartitions);
else
sprintf(buf, " SALT USING %d PARTITIONS", numPartitions);
outputShortLine(*space, buf);
ValueIdList saltCols;
// get leaf nodes in left-to-right order from the salt expression,
// those are the salt columns
saltExpr->getLeafValueIds(saltCols);
// remove any nodes that are not base columns (e.g. # of partns)
CollIndex i = 0;
while (i < saltCols.entries())
if (saltCols[i].getItemExpr()->getOperatorType() == ITM_BASECOLUMN)
i++;
else
saltCols.removeAt(i);
// print a list of salt columns if they are a subset of the
// (non-system) clustering key columns or if they appear
// in a different order
NABoolean printSaltCols = (saltCols.entries() < nonSystemKeyCols);
if (!printSaltCols)
for (CollIndex j=0; j<saltCols.entries(); j++)
{
BaseColumn *bc = (BaseColumn *) saltCols[j].getItemExpr();
// compare col # with clustering key col #,
// but skip leading salt col in clustering key
if (bc->getColNumber() != naf->getIndexKeyColumns()[j+1]->getPosition())
printSaltCols = TRUE;
}
if (printSaltCols)
{
NAString sc = " ON (";
for (CollIndex k=0; k<saltCols.entries(); k++)
{
BaseColumn *bc = (BaseColumn *) saltCols[k].getItemExpr();
if (k > 0)
sc += ", ";
sc += ANSI_ID(bc->getColName().data());
}
sc += ")";
outputShortLine(*space, sc.data());
}
}
else if ((NOT isSalted) && (withPartns))
{
Lng32 currPartitions = naf->getCountOfPartitions();
if (currPartitions > 1)
{
sprintf(buf, " /* ACTUAL PARTITIONS %d */", currPartitions);
outputShortLine(*space, buf);
}
}
if (isDivisioned && !withoutDivisioning)
{
NAString divByClause = " DIVISION BY (";
for (CollIndex d=0; d<divisioningExprs.entries(); d++)
{
if (d > 0)
divByClause += ", ";
divByClause += divisioningExprs[d];
if (!divisioningExprAscOrders[d])
divByClause += " DESC";
}
outputShortLine(*space, divByClause.data());
divByClause = " NAMED AS (";
NAFileSet * naf = naTable->getClusteringIndex();
NABoolean firstDivCol = TRUE;
for (Lng32 i = 0; i < naf->getIndexKeyColumns().entries(); i++)
{
NAColumn * nac = naf->getIndexKeyColumns()[i];
if (nac->isDivisioningColumn())
{
if (firstDivCol)
firstDivCol = FALSE;
else
divByClause += ", ";
divByClause += "\"";
divByClause += nac->getColName();
divByClause += "\"";
}
}
divByClause += "))";
outputShortLine(*space, divByClause.data());
}
NABoolean attributesSet = FALSE;
NABoolean formatSet = FALSE;
char attrs[2000];
if ((type == 3/*create like*/) && (NOT withoutRowFormat))
{
strcpy(attrs, " ATTRIBUTES ");
if (isAligned)
strcat(attrs, "ALIGNED FORMAT ");
else
strcat(attrs, "HBASE FORMAT ");
attributesSet = TRUE;
formatSet = TRUE;
}
if (((NOT isAudited) || (isAligned)) ||
((sqlmxRegr) && (type == 3) && ((NOT isAudited) || (isAligned))) ||
((NOT naTable->defaultColFam().isNull()) &&
(naTable->defaultColFam() != SEABASE_DEFAULT_COL_FAMILY)))
{
if (NOT attributesSet)
strcpy(attrs, " ATTRIBUTES ");
if (NOT isAudited)
strcat(attrs, "NO AUDIT ");
if ((NOT formatSet) && isAligned)
strcat(attrs, "ALIGNED FORMAT ");
if ((NOT naTable->defaultColFam().isNull()) &&
(naTable->defaultColFam() != SEABASE_DEFAULT_COL_FAMILY))
{
strcat(attrs, "DEFAULT COLUMN FAMILY '");
strcat(attrs, naTable->defaultColFam());
strcat(attrs, "'");
}
attributesSet = TRUE;
}
if (attributesSet)
outputShortLine(*space, attrs);
if (!isView && (naTable->hbaseCreateOptions()) &&
(naTable->hbaseCreateOptions()->entries() > 0))
{
outputShortLine(*space, " HBASE_OPTIONS ");
outputShortLine(*space, " ( ");
for (Lng32 i = 0; i < naTable->hbaseCreateOptions()->entries(); i++)
{
HbaseCreateOption * hco = (*naTable->hbaseCreateOptions())[i];
NABoolean comma = FALSE;
if (i < naTable->hbaseCreateOptions()->entries() - 1)
comma = TRUE;
sprintf(buf, " %s = '%s'%s", hco->key().data(), hco->val().data(),
(comma ? "," : " "));
outputShortLine(*space, buf);
}
outputShortLine(*space, " ) ");
}
if ((isExternalTable) &&
(NOT isHbaseMapTable) &&
(type == 2))
{
sprintf(buf, " FOR %s", extName.data());
outputShortLine(*space, buf);
}
if ((isHbaseMapTable) && (type != 3))
{
sprintf(buf, " MAP TO HBASE TABLE %s DATA FORMAT %s",
dtName.getQualifiedNameObj().getObjectName().data(),
(naTable->isHbaseDataFormatString() ? "VARCHAR" : "NATIVE"));
outputShortLine(*space, buf);
}
if (NOT noTrailingSemi)
outputShortLine(*space, ";");
if ((type == 2) && isHbaseCellOrRowTable)
outputShortLine(*space, "*/");
}
// showddl internal sequences created for identity cols
if ((identityColPos >= 0) && (type == 2) && (NOT sqlmxRegr))
{
NAString seqName;
SequenceGeneratorAttributes::genSequenceName
(dtName.getQualifiedNameObj().getCatalogName(),
dtName.getQualifiedNameObj().getSchemaName(),
dtName.getQualifiedNameObj().getObjectName(),
naTable->getNAColumnArray()[identityColPos]->getColName(),
seqName);
CorrName csn(seqName, STMTHEAP,
dtName.getQualifiedNameObj().getSchemaName(),
dtName.getQualifiedNameObj().getCatalogName());
outputLine(*space, "\n-- The following sequence is a system created sequence --", 0);
char * dummyBuf;
ULng32 dummyLen;
CmpDescribeSequence(csn, dummyBuf, dummyLen, STMTHEAP, space);
}
if (((type == 1) && (NOT sqlmxRegr)) || (type == 2))
{
const NAFileSetList &indexList = naTable->getIndexList();
for (Int32 i = 0; i < indexList.entries(); i++)
{
const NAFileSet * naf = indexList[i];
isAligned = naf->isSqlmxAlignedRowFormat();
if (naf->getKeytag() == 0)
continue;
const QualifiedName &qn = naf->getFileSetName();
const NAString& indexName =
qn.getObjectName();
if (type == 1)
{
char vu[40];
strcpy(vu, " ");
if (isVolatile)
strcat(vu, "volatile ");
if (naf->uniqueIndex())
strcat(vu, "unique ");
sprintf(buf, "\n-- Definition of%sTrafodion%sindex %s\n"
"-- Definition current %s",
((NOT naf->isCreatedExplicitly()) ? " implicit " : " "),
vu,
indexName.data(),
ctime(&tp));
outputShortLine(*space, buf);
}
else
{
char vu[40];
strcpy(vu, " ");
if (isVolatile)
strcat(vu, "VOLATILE ");
if (naf->uniqueIndex())
strcat(vu, "UNIQUE ");
if (NOT naf->isCreatedExplicitly())
{
outputLine(*space, "\n-- The following index is a system created index --", 0);
}
sprintf(buf, "%sCREATE%sINDEX %s ON %s",
(naf->isCreatedExplicitly() ? "\n" : ""),
vu,
indexName.data(),
tableName.data());
outputLine(*space, buf, 0);
}
if (type == 1)
{
Lng32 dummy;
outputShortLine(*space, " ( ");
cmpDisplayColumns(naf->getAllColumns(),
type, *space, buf,
displaySystemCols,
(type == 2),
dummy,
isExternalTable,
isAligned,
withoutLobColumns);
outputShortLine(*space, " )");
sprintf(buf, " PRIMARY KEY ");
outputShortLine(*space, buf);
}
Lng32 numIndexCols = ((type == 1) ?
naf->getIndexKeyColumns().entries() :
naf->getCountOfColumns(
TRUE,
TRUE, // user-spedified index cols only
FALSE,
FALSE));
cmpDisplayPrimaryKey(naf->getIndexKeyColumns(), numIndexCols,
displaySystemCols,
*space, buf, FALSE, TRUE, TRUE);
if ((NOT sqlmxRegr) && isAligned)
{
char attrs[2000];
strcpy(attrs, " ATTRIBUTES ");
if (isAligned)
strcat(attrs, "ALIGNED FORMAT ");
outputShortLine(*space, attrs);
}
if ((naf->hbaseCreateOptions()) && (type == 2) &&
(naf->hbaseCreateOptions()->entries() > 0))
{
outputShortLine(*space, " HBASE_OPTIONS ");
outputShortLine(*space, " ( ");
for (Lng32 i = 0; i < naf->hbaseCreateOptions()->entries(); i++)
{
HbaseCreateOption * hco = (*naf->hbaseCreateOptions())[i];
char separator =
((i < naf->hbaseCreateOptions()->entries() - 1) ?
',' : ' ') ;
sprintf(buf, " %s = '%s'%c", hco->key().data(),
hco->val().data(),separator);
outputShortLine(*space, buf);
}
outputShortLine(*space, " ) ");
}
if ((naf->numSaltPartns() > 0) && (type == 2))
outputShortLine(*space, " SALT LIKE TABLE ");
if (type == 2)
outputShortLine(*space, ";");
} // for
if (type == 2) // showddl
{
const AbstractRIConstraintList &uniqueList = naTable->getUniqueConstraints();
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->isPrimaryKeyConstraint())
continue;
const NAString& ansiTableName =
uniqConstr->getDefiningTableName().getQualifiedNameAsAnsiString(TRUE);
const NAString &ansiConstrName =
uniqConstr->getConstraintName().getQualifiedNameAsAnsiString(TRUE);
sprintf(buf, "\nALTER TABLE %s ADD CONSTRAINT %s UNIQUE ",
ansiTableName.data(),
ansiConstrName.data());
outputLine(*space, buf, 0);
NAColumnArray nacarr;
for (Lng32 j = 0; j < uniqConstr->keyColumns().entries(); j++)
{
nacarr.insert(uniqConstr->keyColumns()[j]);
}
cmpDisplayPrimaryKey(nacarr,
uniqConstr->keyColumns().entries(),
FALSE,
*space, &buf[strlen(buf)], FALSE, FALSE, TRUE);
outputShortLine(*space, ";");
} // for
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;
const ComplementaryRIConstraint &uniqueConstraintReferencedByMe
= refConstr->getUniqueConstraintReferencedByMe();
NATable *otherNaTable = NULL;
CorrName otherCN(uniqueConstraintReferencedByMe.getTableName());
otherNaTable = bindWA.getNATable(otherCN);
if (otherNaTable == NULL || bindWA.errStatus())
return -1;
const NAString& ansiTableName =
refConstr->getDefiningTableName().getQualifiedNameAsAnsiString(TRUE);
const NAString &ansiConstrName =
refConstr->getConstraintName().getQualifiedNameAsAnsiString(TRUE);
sprintf(buf, "\nALTER TABLE %s ADD CONSTRAINT %s FOREIGN KEY ",
ansiTableName.data(),
ansiConstrName.data());
outputLine(*space, buf, 0);
NAColumnArray nacarr;
for (Lng32 j = 0; j < refConstr->keyColumns().entries(); j++)
{
nacarr.insert(refConstr->keyColumns()[j]);
}
cmpDisplayPrimaryKey(nacarr,
refConstr->keyColumns().entries(),
FALSE,
*space, &buf[strlen(buf)], FALSE, FALSE, TRUE);
const NAString& ansiOtherTableName =
uniqueConstraintReferencedByMe.getTableName().getQualifiedNameAsAnsiString(TRUE);
sprintf(buf, " REFERENCES %s ",
ansiOtherTableName.data());
outputLine(*space, buf, 0);
AbstractRIConstraint * otherConstr =
refConstr->findConstraint(&bindWA, refConstr->getUniqueConstraintReferencedByMe());
NAColumnArray nacarr2;
for (Lng32 j = 0; j < otherConstr->keyColumns().entries(); j++)
{
nacarr2.insert(otherConstr->keyColumns()[j]);
}
cmpDisplayPrimaryKey(nacarr2,
otherConstr->keyColumns().entries(),
FALSE,
*space, &buf[strlen(buf)], FALSE, FALSE, TRUE);
if (NOT refConstr->getIsEnforced())
{
outputShortLine(*space, " NOT ENFORCED ");
}
outputShortLine(*space, ";");
} // for
const CheckConstraintList &checkList = naTable->getCheckConstraints();
for (Int32 i = 0; i < checkList.entries(); i++)
{
CheckConstraint *checkConstr = (CheckConstraint*)checkList[i];
const NAString &ansiConstrName =
checkConstr->getConstraintName().getQualifiedNameAsAnsiString(TRUE);
sprintf(buf, "\nALTER TABLE %s ADD CONSTRAINT %s CHECK %s",
tableName.data(),
ansiConstrName.data(),
checkConstr->getConstraintText().data());
outputLine(*space, buf, 0);
} // for
} // showddl
}
if ((type == 2) &&
(naTable->isHbaseCellTable() || naTable->isHbaseRowTable()) &&
(NOT isView))
{
outputShortLine(*space, " ");
outputShortLine(*space,"/* HBase DDL */");
sprintf(buf, "CREATE HBASE TABLE %s ( COLUMN FAMILY '%s') ",
naTable->getTableName().getObjectName().data(),
"#1");
outputShortLine(*space, buf);
// if this hbase table is registered in traf metadata, show that.
if (naTable->isRegistered())
{
outputShortLine(*space, " ");
sprintf(buf, "REGISTER%sHBASE %s %s;",
(naTable->isInternalRegistered() ? " /*INTERNAL*/ " : " "),
"TABLE",
naTable->getTableName().getObjectName().data());
NAString bufnas(buf);
outputLongLine(*space, bufnas, 0);
str_sprintf(buf, "/* ObjectUID = %ld */", objectUID);
outputShortLine(*space, buf);
}
else if (isDetail)
{
// show a comment that this object should be registered
outputShortLine(*space, " ");
outputShortLine(*space, "-- Object is not registered in Trafodion Metadata.");
outputShortLine(*space, "-- Register it using the next command:");
sprintf(buf, "-- REGISTER HBASE TABLE %s;",
naTable->getTableName().getQualifiedNameAsAnsiString().data());
NAString bufnas(buf);
outputLongLine(*space, bufnas, 0);
}
}
//display comments
if (type == 2 && objectUID > 0)
{
enum ComObjectType objType = COM_BASE_TABLE_OBJECT;
if (isView)
{
objType = COM_VIEW_OBJECT;
}
if (cmpSBD.switchCompiler())
{
*CmpCommon::diags() << DgSqlCode(-CAT_UNABLE_TO_RETRIEVE_COMMENTS);
return -1;
}
ComTdbVirtObjCommentInfo objCommentInfo;
if (cmpSBD.getSeabaseObjectComment(objectUID, objType, objCommentInfo, heap))
{
*CmpCommon::diags() << DgSqlCode(-CAT_UNABLE_TO_RETRIEVE_COMMENTS);
cmpSBD.switchBackCompiler();
return -1;
}
//display Table COMMENT statements
if (objCommentInfo.objectComment != NULL)
{
//new line
outputLine(*space, "", 0);
sprintf(buf, "COMMENT ON %s %s IS '%s' ;",
objType == COM_BASE_TABLE_OBJECT? "TABLE" : "VIEW",
tableName.data(),
objCommentInfo.objectComment);
outputLine(*space, buf, 0);
}
//display Column COMMENT statements
if (objCommentInfo.numColumnComment > 0 && objCommentInfo.columnCommentArray != NULL)
{
outputLine(*space, "", 0);
for (int idx = 0; idx < objCommentInfo.numColumnComment; idx++)
{
sprintf(buf, "COMMENT ON COLUMN %s.%s IS '%s' ;",
tableName.data(),
objCommentInfo.columnCommentArray[idx].columnName,
objCommentInfo.columnCommentArray[idx].columnComment);
outputLine(*space, buf, 0);
}
}
//display Index COMMENT statements
if (objCommentInfo.numIndexComment > 0 && objCommentInfo.indexCommentArray != NULL)
{
outputLine(*space, "", 0);
for (int idx = 0; idx < objCommentInfo.numIndexComment; idx++)
{
sprintf(buf, "COMMENT ON INDEX %s IS '%s' ;",
objCommentInfo.indexCommentArray[idx].indexFullName,
objCommentInfo.indexCommentArray[idx].indexComment);
outputLine(*space, buf, 0);
}
}
//do a comment info memory clean
NADELETEARRAY(objCommentInfo.columnCommentArray, objCommentInfo.numColumnComment, ComTdbVirtColumnCommentInfo, heap);
NADELETEARRAY(objCommentInfo.indexCommentArray, objCommentInfo.numIndexComment, ComTdbVirtIndexCommentInfo, heap);
cmpSBD.switchBackCompiler();
}
// If SHOWDDL and authorization is enabled, display GRANTS
if (type == 2)
{
//objectUID = (int64_t)naTable->objectUid().get_value();
if ((CmpCommon::context()->isAuthorizationEnabled()) &&
displayPrivilegeGrants &&
(objectUID > 0))
{
// now get the grant stmts
std::string privMDLoc(ActiveSchemaDB()->getDefaults().getValue(SEABASE_CATALOG));
privMDLoc += std::string(".\"") +
std::string(SEABASE_PRIVMGR_SCHEMA) +
std::string("\"");
PrivMgrCommands privInterface(privMDLoc, CmpCommon::diags(),
PrivMgr::PRIV_INITIALIZED);
PrivMgrObjectInfo objectInfo(naTable);
std::string privilegeText;
if (cmpSBD.switchCompiler())
{
*CmpCommon::diags() << DgSqlCode(-CAT_UNABLE_TO_RETRIEVE_PRIVS);
return -1;
}
if (privInterface.describePrivileges(objectInfo, privilegeText))
{
outputShortLine(*space, " ");
outputLine(*space, privilegeText.c_str(), 0);
}
cmpSBD.switchBackCompiler();
}
}
outbuflen = space->getAllocatedSpaceSize();
outbuf = new (heap) char[outbuflen];
space->makeContiguous(outbuf, outbuflen);
NADELETEBASIC(buf, heap);
return 0;
}
short CmpDescribeSequence(
const CorrName &dtName,
char* &outbuf,
ULng32 &outbuflen,
CollHeap *heap,
Space *inSpace)
{
CorrName cn(dtName, heap);
cn.setSpecialType(ExtendedQualName::SG_TABLE);
// remove NATable for this table so latest values in the seq table could be read.
ActiveSchemaDB()->getNATableDB()->removeNATable
(cn,
ComQiScope::REMOVE_MINE_ONLY, COM_SEQUENCE_GENERATOR_OBJECT,
FALSE, FALSE);
ULng32 savedParserFlags = Get_SqlParser_Flags (0xFFFFFFFF);
Set_SqlParser_Flags(ALLOW_VOLATILE_SCHEMA_IN_TABLE_NAME);
BindWA bindWA(ActiveSchemaDB(), CmpCommon::context(), FALSE/*inDDL*/);
NATable *naTable = bindWA.getNATable(cn);
Assign_SqlParser_Flags (savedParserFlags);
TableDesc *tdesc = NULL;
if (naTable == NULL || bindWA.errStatus())
return -1;
// Verify user can perform commands
if (!CmpDescribeIsAuthorized(SQLOperation::UNKNOWN,
naTable->getPrivInfo(),
COM_SEQUENCE_GENERATOR_OBJECT))
return -1;
const SequenceGeneratorAttributes* sga = naTable->getSGAttributes();
const NAString& seqName =
cn.getQualifiedNameObj().getQualifiedNameAsAnsiString(TRUE);
Space lSpace;
Space * space;
if (inSpace)
space = inSpace;
else
space = &lSpace;
char buf[1000];
// CMPASSERT(buf);
outputShortLine(*space, " ");
char seqType[40];
if (sga->getSGSGType() == COM_INTERNAL_SG)
{
strcpy(seqType, "/* INTERNAL */ ");
}
else
strcpy(seqType, " ");
sprintf(buf, "CREATE SEQUENCE %s %s",
seqName.data(), seqType);
outputShortLine(*space, buf);
sga->display(space, NULL, FALSE);
outputShortLine(*space, ";");
char * sqlmxRegr = getenv("SQLMX_REGRESS");
NABoolean displayPrivilegeGrants = TRUE;
if (((CmpCommon::getDefault(SHOWDDL_DISPLAY_PRIVILEGE_GRANTS) == DF_SYSTEM) && sqlmxRegr) ||
(CmpCommon::getDefault(SHOWDDL_DISPLAY_PRIVILEGE_GRANTS) == DF_OFF))
displayPrivilegeGrants = FALSE;
int64_t objectUID = (int64_t)naTable->objectUid().get_value();
CmpSeabaseDDL cmpSBD((NAHeap*)heap);
//display comment
if (objectUID > 0)
{
if (cmpSBD.switchCompiler())
{
*CmpCommon::diags() << DgSqlCode(-CAT_UNABLE_TO_RETRIEVE_COMMENTS);
return -1;
}
ComTdbVirtObjCommentInfo objCommentInfo;
if (cmpSBD.getSeabaseObjectComment(objectUID, COM_SEQUENCE_GENERATOR_OBJECT, objCommentInfo, heap))
{
*CmpCommon::diags() << DgSqlCode(-CAT_UNABLE_TO_RETRIEVE_COMMENTS);
cmpSBD.switchBackCompiler();
return -1;
}
if (objCommentInfo.objectComment != NULL)
{
//new line
outputLine(*space, "", 0);
sprintf(buf, "COMMENT ON SEQUENCE %s IS '%s' ;",
cn.getQualifiedNameObj().getQualifiedNameAsAnsiString(TRUE).data(),
objCommentInfo.objectComment);
outputLine(*space, buf, 0);
}
cmpSBD.switchBackCompiler();
}
// If authorization enabled, display grant statements
if (CmpCommon::context()->isAuthorizationEnabled() && displayPrivilegeGrants)
{
// now get the grant stmts
NAString privMDLoc;
CONCAT_CATSCH(privMDLoc, CmpSeabaseDDL::getSystemCatalogStatic(), SEABASE_MD_SCHEMA);
NAString privMgrMDLoc;
CONCAT_CATSCH(privMgrMDLoc, CmpSeabaseDDL::getSystemCatalogStatic(), SEABASE_PRIVMGR_SCHEMA);
PrivMgrCommands privInterface(std::string(privMDLoc.data()),
std::string(privMgrMDLoc.data()),
CmpCommon::diags());
std::string privilegeText;
PrivMgrObjectInfo objectInfo(naTable);
if (cmpSBD.switchCompiler())
{
*CmpCommon::diags() << DgSqlCode(-CAT_UNABLE_TO_RETRIEVE_PRIVS);
return -1;
}
if (privInterface.describePrivileges(objectInfo, privilegeText))
{
outputShortLine(*space, " ");
outputLine(*space, privilegeText.c_str(), 0);
}
cmpSBD.switchBackCompiler();
}
if (! inSpace)
{
outbuflen = space->getAllocatedSpaceSize();
outbuf = new (heap) char[outbuflen];
space->makeContiguous(outbuf, outbuflen);
}
return 0;
}
// ----------------------------------------------------------------------------
// Function: CmpDescribeIsAuthorized
//
// Determines if current user is authorized to perform operations
//
// parameters: PrivMgrUserPrivs *privs - pointer to granted privileges
// operation - SQLOperation to check in addition to SHOW
//
// returns: TRUE if authorized, FALSE otherwise
// ----------------------------------------------------------------------------
bool CmpDescribeIsAuthorized(
SQLOperation operation,
PrivMgrUserPrivs *privs,
ComObjectType objectType)
{
if (!CmpCommon::context()->isAuthorizationEnabled())
return true;
if (ComUser::isRootUserID())
return true;
// check to see if user has select privilege
if (privs)
{
switch (objectType)
{
case COM_LIBRARY_OBJECT:
case COM_SEQUENCE_GENERATOR_OBJECT:
if (privs->hasUsagePriv())
return true;
break;
case COM_STORED_PROCEDURE_OBJECT:
case COM_USER_DEFINED_ROUTINE_OBJECT:
if (privs->hasExecutePriv())
return true;
break;
case COM_PRIVATE_SCHEMA_OBJECT:
case COM_SHARED_SCHEMA_OBJECT:
break;
case COM_VIEW_OBJECT:
case COM_BASE_TABLE_OBJECT:
default:
if (privs->hasSelectPriv())
return true;
}
}
// check to see if user has SHOW component privilege
std::string privMDLoc(ActiveSchemaDB()->getDefaults().getValue(SEABASE_CATALOG));
privMDLoc += std::string(".\"") +
std::string(SEABASE_PRIVMGR_SCHEMA) +
std::string("\"");
PrivMgrComponentPrivileges componentPrivileges(privMDLoc,CmpCommon::diags());
if (componentPrivileges.hasSQLPriv(ComUser::getCurrentUser(),SQLOperation::SHOW,true))
return true;
if (operation != SQLOperation::UNKNOWN &&
componentPrivileges.hasSQLPriv(ComUser::getCurrentUser(),operation,true))
return true;
*CmpCommon::diags() << DgSqlCode(-CAT_NOT_AUTHORIZED);
return false;
}
// *****************************************************************************
// * *
// * Function: CmpDescribeLibrary *
// * *
// * Describes the DDL for a library object with normalized syntax. *
// * *
// *****************************************************************************
// * *
// * Parameters: *
// * *
// * <corrName> const CorrName & In *
// * is a reference to correlation name for the library object. *
// * *
// * <outbuf> char * & Out *
// * is a reference to a pointed to a character array. The desribe output *
// * is stored here. *
// * *
// * <outbuflen> ULng32 & Out *
// * is the number of characters stored in outbuf. Note, ULng32 is an *
// * unsigned 32-bit integer, aka uint32_t or unsigned int. Not a long. *
// * *
// * <heap> CollHeap * In *
// * is the heap to use for any dynamic allocations. *
// * *
// *****************************************************************************
// * *
// * Returns: bool *
// * *
// * true: Describe text added to outbuf. *
// * false: Desribe text not added. A CLI error is put into the diags area. *
// * *
// *****************************************************************************
bool CmpDescribeLibrary(
const CorrName & corrName,
char * & outbuf,
ULng32 & outbuflen,
CollHeap * heap)
{
CmpSeabaseDDL cmpSBD((NAHeap *)heap);
CorrName cn(corrName, heap);
cn.setSpecialType(ExtendedQualName::LIBRARY_TABLE);
const NAString& libraryName = cn.getQualifiedNameObj().getQualifiedNameAsAnsiString(TRUE);
ComObjectName libName(libraryName);
NAString libCatNamePart = libName.getCatalogNamePartAsAnsiString();
NAString libSchNamePart = libName.getSchemaNamePartAsAnsiString(TRUE);
NAString libObjNamePart = libName.getObjectNamePartAsAnsiString(TRUE);
const NAString extLibraryName = libName.getExternalName(TRUE);
ExeCliInterface cliInterface(heap);
TrafDesc *tDesc = cmpSBD.getSeabaseLibraryDesc(libCatNamePart,
libSchNamePart,
libObjNamePart);
if (tDesc == NULL)
{
*CmpCommon::diags() << DgSqlCode(-4082)
<< DgTableName(extLibraryName.data());
return 0;
}
Int64 libraryUID = tDesc->libraryDesc()->libraryUID;
if (libraryUID <= 0) // does not exist
{
*CmpCommon::diags() << DgSqlCode(-CAT_LIBRARY_DOES_NOT_EXIST)
<< DgTableName(extLibraryName.data());
return false;
}
// For libraries, we need to check if the user has the USAGE privilege;
// if so, they can perform SHOWDDL on this library.
NAString privMgrMDLoc;
CONCAT_CATSCH(privMgrMDLoc,CmpSeabaseDDL::getSystemCatalogStatic(),SEABASE_PRIVMGR_SCHEMA);
PrivMgrCommands privInterface(privMgrMDLoc.data(),CmpCommon::diags());
if (CmpCommon::context()->isAuthorizationEnabled())
{
PrivMgrUserPrivs privs;
if (cmpSBD.switchCompiler())
{
*CmpCommon::diags() << DgSqlCode(-CAT_UNABLE_TO_RETRIEVE_PRIVS);
return -1 ;
}
PrivStatus retcode = privInterface.getPrivileges(libraryUID, COM_LIBRARY_OBJECT,
ComUser::getCurrentUser(),
privs);
cmpSBD.switchBackCompiler();
// Verify user can perform the SHOWDDL LIBRARY command on the specified library.
if (!CmpDescribeIsAuthorized(SQLOperation::MANAGE_LIBRARY,&privs,
COM_LIBRARY_OBJECT))
return false;
}
Space localSpace;
Space * space = &localSpace;
char buf[1000];
sprintf(buf,"CREATE LIBRARY %s FILE '%s'",
extLibraryName.data(), tDesc->libraryDesc()->libraryFilename);
outputShortLine(*space,buf);
outputShortLine(*space,";");
// Determine if privilege grants should be displayed
NABoolean displayPrivilegeGrants =
((CmpCommon::getDefault(SHOWDDL_DISPLAY_PRIVILEGE_GRANTS) == DF_OFF) ||
((CmpCommon::getDefault(SHOWDDL_DISPLAY_PRIVILEGE_GRANTS) == DF_SYSTEM)
&& getenv("SQLMX_REGRESS"))) ? FALSE : TRUE;
//display library comment
if (libraryUID > 0)
{
if (cmpSBD.switchCompiler())
{
*CmpCommon::diags() << DgSqlCode(-CAT_UNABLE_TO_RETRIEVE_PRIVS);
return -1;
}
ComTdbVirtObjCommentInfo objCommentInfo;
if (cmpSBD.getSeabaseObjectComment(libraryUID, COM_LIBRARY_OBJECT, objCommentInfo, heap))
{
*CmpCommon::diags() << DgSqlCode(-CAT_UNABLE_TO_RETRIEVE_COMMENTS);
cmpSBD.switchBackCompiler();
return -1;
}
if (objCommentInfo.objectComment != NULL)
{
//new line
outputLine(*space, "", 0);
sprintf(buf, "COMMENT ON LIBRARY %s IS '%s' ;",
cn.getQualifiedNameObj().getQualifiedNameAsAnsiString(TRUE).data(),
objCommentInfo.objectComment);
outputLine(*space, buf, 0);
}
cmpSBD.switchBackCompiler();
}
// If authorization is enabled, display grant statements for library
if (CmpCommon::context()->isAuthorizationEnabled() && displayPrivilegeGrants)
{
// now get the grant stmts
NAString trafMDLoc;
CONCAT_CATSCH(trafMDLoc,CmpSeabaseDDL::getSystemCatalogStatic(),SEABASE_MD_SCHEMA);
PrivMgrCommands privInterface(std::string(trafMDLoc.data()),
std::string(privMgrMDLoc.data()),
CmpCommon::diags());
std::string privilegeText;
PrivMgrObjectInfo objectInfo (
libraryUID, extLibraryName.data(),
tDesc->libraryDesc()->libraryOwnerID,
tDesc->libraryDesc()->librarySchemaOwnerID,
COM_LIBRARY_OBJECT );
if (cmpSBD.switchCompiler())
{
*CmpCommon::diags() << DgSqlCode(-CAT_UNABLE_TO_RETRIEVE_PRIVS);
return -1;
}
if (privInterface.describePrivileges(objectInfo,privilegeText))
{
outputShortLine(*space," ");
outputLine(*space,privilegeText.c_str(),0);
}
cmpSBD.switchBackCompiler();
}
outbuflen = space->getAllocatedSpaceSize();
outbuf = new (heap) char[outbuflen];
space->makeContiguous(outbuf, outbuflen);
return true;
}
//************************ End of CmpDescribeLibrary ***************************
// Routine to support SHOWDDL [ PROCEDURE | FUNCTION | TABLE_MAPPING FUNCTION ]
// <routine-name>
short CmpDescribeRoutine (const CorrName & cn,
char * & outbuf,
ULng32 & outbuflen,
CollHeap * heap)
{
BindWA bindWA(ActiveSchemaDB(), CmpCommon::context(), FALSE/*inDDL*/);
NARoutine *routine = bindWA.getNARoutine(cn.getQualifiedNameObj());
const NAString& rName =
cn.getQualifiedNameObj().getQualifiedNameAsAnsiString(TRUE);
if (routine == NULL || bindWA.errStatus())
{
*CmpCommon::diags() << DgSqlCode(-4082)
<< DgTableName(rName.data());
return 0;
}
// Verify user can perform commands
if (!CmpDescribeIsAuthorized(SQLOperation::UNKNOWN,
routine->getPrivInfo(),
COM_USER_DEFINED_ROUTINE_OBJECT))
return 0;
NABoolean logFormat =
(CmpCommon::getDefault(SHOWDDL_DISPLAY_FORMAT) == DF_LOG);
Space localSpace;
Space * space = &localSpace;
outputShortLine(*space," ");
// Start populating our output buffer
// buffer is reused for each line of output. Longets line will be the
// java signature for SPJs. Currently this has an upper limit of 8K.
// We allocate another 2K bytes for the name and any small changes
// in size due to formatting.
char * buf = new (STMTHEAP) char[10000];
CMPASSERT(buf);
NABoolean buildRETURNSclause = TRUE;
switch (routine->getRoutineType())
{
case COM_SCALAR_UDF_TYPE:
sprintf ( buf, "CREATE FUNCTION %s", rName.data() );
break;
case COM_TABLE_UDF_TYPE:
sprintf ( buf, "CREATE TABLE_MAPPING FUNCTION %s", rName.data() );
break;
case COM_PROCEDURE_TYPE:
sprintf ( buf, "CREATE PROCEDURE %s", rName.data() );
buildRETURNSclause = FALSE;
break;
default:
ComASSERT(FALSE);
}
if (logFormat)
outputShortLine(*space,"--> UR ");
outputShortLine(*space, buf);
outputShortLine (*space, " (" );
// Format the parameters
Int32 numParams = routine->getParamCount();
Int32 firstRETURNSparamIndex = -1;
const NAColumnArray &paramList = routine->getParams();
for ( Int32 i=0; i < numParams; i++ )
{
NAColumn &param = *(paramList[i]);
ComColumnDirection direction = param.getColumnMode ();
if (buildRETURNSclause AND direction EQU COM_OUTPUT_COLUMN)
{
firstRETURNSparamIndex = i;
i = numParams; // i.e., exit loop
continue;
}
if (i == 0)
strcpy(buf, " ");
else
strcpy(buf, " , ");
switch ( direction )
{
case COM_INPUT_COLUMN:
strcat ( buf, "IN " );
break;
case COM_OUTPUT_COLUMN:
strcat ( buf, "OUT " );
break;
case COM_INOUT_COLUMN:
strcat ( buf, "INOUT " );
break;
} // switch
// Next step for this parameter is to print its name. If a heading
// is defined we print that. Otherwise if a column name is defined
// we print that. Otherwise it is an unnamed parameter and we do
// nothing.
const NAString &heading = param.getHeading ();
const NAString &colName = param.getColName ();
if (heading.compareTo("") != 0)
{
strcat(buf, ANSI_ID(heading));
strcat(buf, " ");
}
else if (colName.compareTo("") != 0)
{
strcat(buf, ANSI_ID(colName));
strcat(buf, " ");
}
char typeString[80];
strcpy (typeString, (param.getType ())->getTypeSQLname (TRUE));
if (routine->getLanguage() EQU COM_LANGUAGE_JAVA)
{
// Java does not support unsigned / signed as
// it converts NUMERIC types to a Java BigDecimal.
Int32 typeLen = static_cast<Int32>(strlen(typeString));
if (typeLen >= 9 &&
0 == strcmp ( &typeString[typeLen - 9], " UNSIGNED" ))
{
typeString[typeLen - 9] = '\0';
}
else if (typeLen >= 7 &&
0 == strcmp ( &typeString[typeLen - 7], " SIGNED" ))
{
typeString[typeLen - 7] = '\0';
}
} // if Language Java
strcat ( buf, typeString );
outputShortLine (*space, buf);
} // for
// add the closing ")" for the formal parameter list
strcpy ( buf, " )");
outputShortLine (*space, buf);
if (buildRETURNSclause AND firstRETURNSparamIndex > -1)
{
strcpy ( buf, " RETURNS " );
outputShortLine (*space, buf);
outputShortLine (*space, " (" );
// Build RETURN[S] clause from param list
for (Int32 i7 = firstRETURNSparamIndex; i7 < numParams; i7++)
{
NAColumn &param7 = *(paramList[i7]);
ComColumnDirection direction7 = param7.getColumnMode ();
if (i7 EQU firstRETURNSparamIndex)
strcpy(buf, " ");
else
strcpy(buf, " , ");
switch ( direction7 )
{
case COM_INPUT_COLUMN:
strcat ( buf, "IN " ); // not supposed to happen
break;
case COM_OUTPUT_COLUMN:
strcat ( buf, "OUT " );
break;
case COM_INOUT_COLUMN:
strcat ( buf, "INOUT " ); // not supposed to happen
break;
} // switch
// Next step for this parameter is to print its name. If a heading
// is defined we print that. Otherwise if a column name is defined
// we print that. Otherwise it is an unnamed parameter and we do
// nothing.
const NAString &heading7 = param7.getHeading ();
const NAString &colName7 = param7.getColName ();
if (heading7.compareTo("") != 0)
{
strcat(buf, ANSI_ID(heading7));
strcat(buf, " ");
}
else if (colName7.compareTo("") != 0)
{
strcat(buf, ANSI_ID(colName7));
strcat(buf, " ");
}
char typeString7[80];
strcpy (typeString7, (param7.getType ())->getTypeSQLname (TRUE));
if (routine->getLanguage() EQU COM_LANGUAGE_JAVA)
{
// Java does not support UNSIGNED and SIGNED as
// it converts NUMERIC types to a Java BigDecimal.
Int32 typeLen7 = static_cast<Int32>(strlen(typeString7));
if (typeLen7 >= 9 AND 0 EQU
strcmp ( &typeString7[typeLen7 - 9], " UNSIGNED" ))
{
typeString7[typeLen7 - 9] = '\0';
}
else if (typeLen7 >= 7 AND 0 EQU
strcmp ( &typeString7[typeLen7 - 7], " SIGNED" ))
{
typeString7[typeLen7 - 7] = '\0';
}
} // if Language Java
strcat (buf, typeString7);
outputShortLine (*space, buf);
} // for
strcpy ( buf, " )");
outputShortLine (*space, buf);
} // if (buildRETURNSclause AND firstRETURNSparamIndex > -1)
// EXTERNAL NAME clause
NABoolean isProcedure =
(routine->getRoutineType() EQU COM_PROCEDURE_TYPE ? TRUE : FALSE);
if (isProcedure)
{
strcpy ( buf, " EXTERNAL NAME '" );
NAString exNamePrefixInStrLitFormat44;
NAString exNamePrefixInInternalFormat;
exNamePrefixInInternalFormat += routine->getFile();
exNamePrefixInInternalFormat += ".";
exNamePrefixInInternalFormat += routine->getExternalName();
ToQuotedString ( exNamePrefixInStrLitFormat44 // out - NAString &
, exNamePrefixInInternalFormat // in - const NAString &
, FALSE // in - NABoolean encloseInQuotes
);
strcat ( buf, exNamePrefixInStrLitFormat44.data() );
// Get the actual signature size
LmJavaSignature lmSig(routine->getSignature().data(), heap);
Int32 sigSize = lmSig.getUnpackedSignatureSize();
if ( 0 == sigSize)
{
*CmpCommon::diags() << DgSqlCode(-11223)
<< DgString0(". Unable to determine signature size.");
return 0;
}
char *sigBuf = new (STMTHEAP) char[sigSize + 1];
if (lmSig.unpackSignature(sigBuf) == -1)
{
*CmpCommon::diags() << DgSqlCode(-11223)
<< DgString0(". Unable to determine signature.");
return 0;
}
sigBuf[sigSize] = '\0';
strcat ( buf, " " );
strcat ( buf, sigBuf );
strcat ( buf, "'" );
outputShortLine (*space, buf);
}
else // this is not a procedure
{
strcpy ( buf, " EXTERNAL NAME " );
NAString externalNameInStrLitFormat(STMTHEAP);
ToQuotedString ( externalNameInStrLitFormat // out - NAString &
, routine->getExternalName() // in - const NAString &
, TRUE // in - NABoolean encloseInQuotes
);
strcat ( buf, externalNameInStrLitFormat.data() );
outputShortLine (*space, buf);
}
// LIBRARY clause
NAString libName(routine->getLibrarySqlName().getExternalName());
if ((libName.length() > 0) && (libName.data()[0] != ' '))
{
strcpy ( buf, " LIBRARY " );
strcat ( buf, libName.data());
outputShortLine (*space, buf);
}
// EXTERNAL SECURITY clause
if (isProcedure)
{
switch ( routine->getExternalSecurity ())
{
case COM_ROUTINE_EXTERNAL_SECURITY_INVOKER:
outputShortLine (*space, " EXTERNAL SECURITY INVOKER");
break;
case COM_ROUTINE_EXTERNAL_SECURITY_DEFINER:
outputShortLine (*space, " EXTERNAL SECURITY DEFINER");
break;
default:
ComASSERT(FALSE);
break;
}
}
switch ( routine->getLanguage ())
{
case COM_LANGUAGE_JAVA:
outputShortLine (*space, " LANGUAGE JAVA");
break;
case COM_LANGUAGE_C:
outputShortLine (*space, " LANGUAGE C");
break;
case COM_LANGUAGE_SQL:
outputShortLine (*space, " LANGUAGE SQL");
break;
case COM_LANGUAGE_CPP:
outputShortLine (*space, " LANGUAGE CPP");
break;
default:
ComASSERT(FALSE);
break;
}
switch ( routine->getParamStyle ())
{
case COM_STYLE_GENERAL:
outputShortLine (*space, " PARAMETER STYLE GENERAL");
break;
case COM_STYLE_JAVA_CALL:
outputShortLine (*space, " PARAMETER STYLE JAVA");
break;
case COM_STYLE_SQL:
outputShortLine (*space, " PARAMETER STYLE SQL");
break;
case COM_STYLE_SQLROW:
outputShortLine (*space, " PARAMETER STYLE SQLROW");
break;
case COM_STYLE_JAVA_OBJ:
case COM_STYLE_CPP_OBJ:
case COM_STYLE_SQLROW_TM:
break;
default:
ComASSERT(FALSE);
break;
}
switch (routine->getSqlAccess ())
{
case COM_NO_SQL:
outputShortLine (*space, " NO SQL");
break;
case COM_MODIFIES_SQL:
outputShortLine (*space, " MODIFIES SQL DATA");
break;
case COM_CONTAINS_SQL:
outputShortLine (*space, " CONTAINS SQL");
break;
case COM_READS_SQL:
outputShortLine (*space, " READS SQL DATA");
break;
default:
// Unknown SQL access mode
ComASSERT(FALSE);
break;
} // switch
if (isProcedure)
{
// max result sets
strcpy ( buf, " DYNAMIC RESULT SETS " );
sprintf ( &buf[strlen (buf)], "%d", (Int32) routine->getMaxResults () );
outputShortLine (*space, buf);
// transaction required clause needs to be shown in the output from M9
switch ( routine->getTxAttrs () )
{
case COM_NO_TRANSACTION_REQUIRED:
strcpy ( buf, " NO TRANSACTION REQUIRED" );
break;
case COM_TRANSACTION_REQUIRED:
strcpy ( buf, " TRANSACTION REQUIRED" );
break;
default:
ComASSERT(FALSE);
break;
}
outputShortLine (*space, buf);
}
else
{
if (routine->getLanguage() == COM_LANGUAGE_C)
{
// final call
if (routine->isFinalCall()) // same as isExtraCall()
strcpy ( buf, " FINAL CALL" );
else
strcpy ( buf, " NO FINAL CALL" );
outputShortLine (*space, buf);
// state area size
if ( routine->getStateAreaSize () > 0 )
{
strcpy ( buf, " STATE AREA SIZE " );
sprintf ( &buf[strlen (buf)], "%d", routine->getStateAreaSize ());
}
else
{
strcpy ( buf, " NO STATE AREA" );
}
outputShortLine (*space, buf);
}
}
if (routine->isScalarUDF())
{
if ( routine->getParallelism() == "AP")
strcpy ( buf, " ALLOW ANY PARALLELISM" );
else
strcpy ( buf, " NO PARALLELISM" );
outputShortLine (*space, buf);
// Deterministic clause
if ( routine->isDeterministic ())
strcpy ( buf, " DETERMINISTIC" );
else
strcpy ( buf, " NOT DETERMINISTIC" );
outputShortLine (*space, buf);
}
if (!isProcedure)
{
switch ( routine->getExecutionMode() )
{
case COM_ROUTINE_FAST_EXECUTION:
strcpy ( buf, " FAST EXECUTION MODE" );
break;
case COM_ROUTINE_SAFE_EXECUTION:
strcpy ( buf, " SAFE EXECUTION MODE" );
break;
default:
ComASSERT(FALSE);
break;
}
outputShortLine (*space, buf);
}
if (isProcedure)
{
if ( routine->isIsolate ())
{
strcpy ( buf, " ISOLATE" );
}
else
{
strcpy ( buf, " NO ISOLATE" );
}
outputShortLine (*space, buf);
} // routine type is SPJ
outputShortLine (*space, " ;");
CmpSeabaseDDL cmpSBD((NAHeap*)heap);
char * sqlmxRegr = getenv("SQLMX_REGRESS");
NABoolean displayPrivilegeGrants = TRUE;
if (((CmpCommon::getDefault(SHOWDDL_DISPLAY_PRIVILEGE_GRANTS) == DF_SYSTEM) && sqlmxRegr) ||
(CmpCommon::getDefault(SHOWDDL_DISPLAY_PRIVILEGE_GRANTS) == DF_OFF))
displayPrivilegeGrants = FALSE;
//display comment of routine
Int64 routineUID = routine->getRoutineID();
if ( routineUID > 0)
{
if (cmpSBD.switchCompiler())
{
*CmpCommon::diags() << DgSqlCode(-CAT_UNABLE_TO_RETRIEVE_PRIVS);
return -1;
}
ComTdbVirtObjCommentInfo objCommentInfo;
if (cmpSBD.getSeabaseObjectComment(routineUID, COM_USER_DEFINED_ROUTINE_OBJECT, objCommentInfo, heap))
{
*CmpCommon::diags() << DgSqlCode(-CAT_UNABLE_TO_RETRIEVE_COMMENTS);
cmpSBD.switchBackCompiler();
return -1;
}
if (objCommentInfo.objectComment != NULL)
{
//new line
outputLine(*space, "", 0);
sprintf(buf, "COMMENT ON %s %s IS '%s' ;",
routine->getRoutineType() == COM_PROCEDURE_TYPE ? "PROCEDURE" : "FUNCTION",
cn.getQualifiedNameObj().getQualifiedNameAsAnsiString(TRUE).data(),
objCommentInfo.objectComment);
outputLine(*space, buf, 0);
}
cmpSBD.switchBackCompiler();
}
// If authorization enabled, display grant statements
if (CmpCommon::context()->isAuthorizationEnabled() && displayPrivilegeGrants)
{
// now get the grant stmts
int64_t objectUID = (int64_t)routine->getRoutineID();
NAString privMDLoc;
CONCAT_CATSCH(privMDLoc, CmpSeabaseDDL::getSystemCatalogStatic(), SEABASE_MD_SCHEMA);
NAString privMgrMDLoc;
CONCAT_CATSCH(privMgrMDLoc, CmpSeabaseDDL::getSystemCatalogStatic(), SEABASE_PRIVMGR_SCHEMA);
PrivMgrCommands privInterface(std::string(privMDLoc.data()),
std::string(privMgrMDLoc.data()),
CmpCommon::diags());
std::string objectName(rName);
std::string privilegeText;
PrivMgrObjectInfo objectInfo(
objectUID, objectName,
(int32_t)routine->getObjectOwner(),
(int32_t)routine->getSchemaOwner(),
COM_USER_DEFINED_ROUTINE_OBJECT);
if (cmpSBD.switchCompiler())
{
*CmpCommon::diags() << DgSqlCode(-CAT_UNABLE_TO_RETRIEVE_PRIVS);
return -1;
}
if (privInterface.describePrivileges(objectInfo, privilegeText))
{
outputShortLine(*space, " ");
outputLine(*space, privilegeText.c_str(), 0);
}
cmpSBD.switchBackCompiler();
}
outbuflen = space->getAllocatedSpaceSize();
outbuf = new (heap) char[outbuflen];
space->makeContiguous(outbuf, outbuflen);
NADELETEBASIC(buf, CmpCommon::statementHeap());
return 1;
} // CmpDescribeShowddlProcedure