blob: 459950811e2e3f622cc27419bda673b7c736fe66 [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: CmpContext.C
* Description: The implementation of CmpContext class, this class contains
* the information of the global (across statement) variables
* for compiler components.
*
*
* Created: 9/05/96
* Language: C++
*
*
*
*
*****************************************************************************
*/
#include "Platform.h"
#define SQLPARSERGLOBALS_CONTEXT_AND_DIAGS // first #include
#include "CmpCommon.h"
#include "CmpContext.h"
#include "CmpStatement.h"
#include "ControlDB.h"
#include "CmpMemoryMonitor.h"
#include "NAHeap.h"
#include "NewDel.h"
#include "OptimizerSimulator.h"
#include "SchemaDB.h"
#include "CmpCommon.h"
#include "Rule.h"
#include "ImplRule.h" // for CreateImplementationRules()
#include "TransRule.h" // for CreateTransformationRules()
#include "PhyProp.h" // for InitCostVariables()
#include "NAClusterInfo.h"
#include "UdfDllInteraction.h"
#define SQLPARSERGLOBALS_FLAGS // needed to set SqlParser_Flags
#include "SqlParserGlobals.h" // last #include
#include "CmpErrLog.h"
#include "QRLogger.h"
#include "logmxevent.h"
#include "CmpSeabaseDDL.h"
#include "Globals.h"
#include "sqludr.h"
#include "hs_globals.h"
#include "PCodeExprCache.h"
#include "HBaseClient_JNI.h"
#include "CompException.h"
#include "CostMethod.h"
//++MV
extern "C" {
#include "cextdecs/cextdecs.h"
}
//--MV
#define ENVIRON environ
#define PUTENV putenv
#include "NATable.h"
#include "CompilerTracking.h"
#include "HDFSHook.h"
ostream &operator<<(ostream &dest, const ComDiagsArea& da);
UInt32 hashCursor( const NAString& s ) { return s.hash(); }
// Global pointer to the Optimzer Memory Monitor
extern THREAD_P CmpMemoryMonitor *cmpMemMonitor;
// Global classes/structs initialized when CmpContext is constructed
extern THREAD_P NABoolean GU_DEBUG;
extern THREAD_P const SqlParser_NADefaults *SqlParser_NADefaults_Glob;
// Global classes/structs used in CmpContext scope
extern THREAD_P jmp_buf ExportJmpBuf;
extern THREAD_P jmp_buf CmpInternalErrorJmpBuf;
// -----------------------------------------------------------------------
// Methods for CmpContext
// -----------------------------------------------------------------------
CmpContext::CmpContext(UInt32 f, CollHeap * h)
: heap_((NAHeap *)h),
statements_(h, 16),
flags_(f),
internalCompile_(NOT_INTERNAL_COMPILE),
// Template changes for Yosemite compiler incompatible with others
staticCursors_(hashCursor),
schemaDB_(NULL), controlDB_(NULL),tmpFileNumber_(-1),
isRuntimeCompile_(TRUE),
mxcmpPrimarySecondaryStatusSet_(FALSE),
sqlmxRegress_(0),
reservedMemory_(NULL),
showQueryStats_(FALSE),
recursionLevel_(0),
parserResetIsNeeded_(FALSE),
sqlTextBuf_(NULL),
uninitializedSeabaseErrNum_(0),
hbaseErrNum_(0),
numSQNodes_(0),
hasVirtualSQNodes_(FALSE),
trafMDDescsInfo_(NULL),
transMode_(TransMode::IL_NOT_SPECIFIED_, // init'd below
TransMode::READ_WRITE_,
TransMode::OFF_),
ciClass_(CmpContextInfo::CMPCONTEXT_TYPE_NONE),
qcache_(NULL), // just to be safe ...
optPCodeCache_(NULL), // just to be safe ...
CDBList_(NULL),
allControlCount_(0),
optSimulator_(NULL),
hosts_(h),
invocationInfos_(h),
planInfos_(h),
routineHandles_(h),
ddlObjs_(h),
statementNum_(0),
hiveClient_(NULL)
{
SetMode(isDynamicSQL() ? STMT_DYNAMIC : STMT_STATIC);
cmpCurrentContext = this;
CMPASSERT(heap_ != NULL);
heap_->setErrorCallback(&CmpErrLog::CmpErrLogCallback);
// Reserve memory that can be used for out-of-memory reporting.
reserveMemory();
envs_ = new (heap_) ProcessEnv(heap_);
sqlSession_ = new (heap_) CmpSqlSession(heap_);
// MV
// Adding support for multi threaded requestor (multi transactions) handling
// in the arkcmp
// This is needed because arkcmp is also serves as a server for the utilities
// store procedures
OpenTMFFile();
// MV
// initialize CmpStatement related members.
statements_.insert(0);
currentStatement_ = statements_.index(0);
currentStatementPtrCache_ = statements_[currentStatement_];
diags_ = ComDiagsArea::allocate(heap_);
SqlParser_Diags = diags_;
char* streamName;
outFstream_ = NULL;
// Set up the Optimizer Memory Monitor environment
cmpMemMonitor_ = new(CmpCommon::contextHeap()) CmpMemoryMonitor(CmpCommon::contextHeap());
cmpMemMonitor = cmpMemMonitor_;
//## Commenting this out for now. Eventually all ISP-arkcmp's we start up
//## will need to have the *originating* arkcmp's context passed in,
//## else the two arkcmp's *could* be inconsistent.
//## if (!isISP())
{
if (!isStandalone())
{
gpClusterInfo = NULL;
setUpClusterInfo(CmpCommon::contextHeap()); // global cluster info
// Store the cluster info in CmpContext
clusterInfo_ = gpClusterInfo;
}
CDBList_ = new (heap_) CollationDBList(heap_);
// globals for Optimizer -- also causes NADefaults table to be read in
schemaDB_ = new(heap_) SchemaDB();
// error during nadefault creation. Cannot proceed. Return.
if (! schemaDB_->getDefaults().getSqlParser_NADefaults_Ptr())
return;
size_t memLimit = (size_t) 1024 * CmpCommon::getDefaultLong(MEMORY_LIMIT_NATABLECACHE_UPPER_KB);
schemaDB_->getNATableDB()->getHeap()->setUpperLimit(memLimit);
memLimit = (size_t) 1024 * CmpCommon::getDefaultLong(MEMORY_LIMIT_HISTCACHE_UPPER_KB);
const Lng32 initHeapSize = 16 * 1024; // ## 16K
NAHeap *histogramCacheHeap = new (heap_)
NAHeap((const char *)"HistogramCache Heap",
heap_,
initHeapSize,
memLimit);
// Setting up the cache for histogram
histogramCache_ = new(histogramCacheHeap) HistogramCache(histogramCacheHeap, 107);
// extern TransMode controlTransInfo; // defined in Generator.C, should
// // come from Compiler Stmt Context in future.
// schemaDB_->
// getDefaults().initAccessOption( controlTransInfo.accessOption());
// schemaDB_->
// getDefaults().initIsolationLevel( controlTransInfo.isolationLevel());
}
CloseTMFFile();
// tzset() sets extern var timezone to the diff(in seconds) between gmt and local.
tzset();
gmtDiff_ = timezone / 60;
CmpProcess p;
p.getCompilerId(compilerId_, COMPILER_ID_LEN);
// CmpSeabaseDDL cmpSBD;
// cmpSBD.processSystemCatalog();
// initialize thread local variables (used to be globals) BEGIN
USER_WANTS_DIVZERO_FAILURES = ( getenv( DIVZERO_ENV_VAR ) == NULL ) ? FALSE : TRUE ;
#ifndef NDEBUG
GU_DEBUG = (getenv("GU_DEBUG") != NULL);
#endif
optDbg_ = new (heap_) OptDebug();
// initialize the Optimizer rules
ruleSet_ = new (heap_) RuleSet(90, heap_) ;
//
// The creation of the implementaion and transformation
// rules has to be waited until ruleSet_ is pointing at
// a true RuleSet. This is because during the creation,
// the GlobalRulSet (aka CmpCommon::context()->getRuleSet(), or
// this->ruleSet_) is referenced.
//
CreateImplementationRules(ruleSet_);
CreateTransformationRules(ruleSet_);
// initialize thread local variables (used to be globals) END
qcache_ = new (heap_) QueryCache();
// set the QCache memory upper limit - currently only used to test setjmp/lonjmp logic
qcache_->setHeapUpperLimit((size_t) 1024 * CmpCommon::getDefaultLong(MEMORY_LIMIT_QCACHE_UPPER_KB));
tableIdent_ = 0;
//
// Initialize context-local optimized PCode Expression cache
//
optPCodeCache_ = new (heap_) OptPCodeCache();
// Allocate (static) host_data_ if it's not already allocated.
// This will never be deleted and stays until the process dies.
tmfudf_dll_interface_host_data_ = new (CmpCommon::contextHeap())
char[SQLUDR_STATEAREA_BUFFER_SIZE + 128];
CMPASSERT(tmfudf_dll_interface_host_data_);
memset((char *)tmfudf_dll_interface_host_data_, 0,
SQLUDR_STATEAREA_BUFFER_SIZE + 128);
TimeVal currTime ;
GETTIMEOFDAY(&currTime, 0);
setPrev_QI_time( currTime ); // Initialize previous Query Invalidation time.
lastUpdateStatsTime_ = -1;
HHDFSMasterHostList::resetNumSQNodes();
HHDFSMasterHostList::resethasVirtualSQNodes();
optDefaults_ = new (heap_) OptDefaults(heap_);
// create dynamic metadata descriptors
CmpSeabaseDDL cmpSeabaseDDL(heap_);
cmpSeabaseDDL.createMDdescs(trafMDDescsInfo_);
}
// MV
// ---------------------------------------------------------------------------
// Adding support for multi threaded requestor (multi transactions) handling
// in the arkcmp
// This is needed because arkcmp is also serves as a server for the utilities
// store procedures
// ---------------------------------------------------------------------------
void CmpContext::OpenTMFFile()
{
if (FALSE == isISP())
return;
// now open $RECEIVE
}
void CmpContext::CloseTMFFile()
{
if (FALSE == isISP())
return;
}
// -----------------------------------------------------------------------
// destructor
// -----------------------------------------------------------------------
// MV
CmpContext::~CmpContext()
{
// cleanup the optimizer rules
// delete ruleSet_; -- don't do this, it causes access violations
// -- (due to delete'ing same memory twice: our
// -- trees are more often DAGs...)!
ruleSet_ = NULL;
if (diags_)
diags_->decrRefCount();
delete schemaDB_;
delete controlDB_;
NADELETE(optDefaults_, OptDefaults, heap_);
// trafMDDescsInfo_ is of type MDDescsInfo but it is created as an array of char
// look at the creation of trafMDDescsInfo_ in method CmpSeabaseDDL::createMDdescs
NADELETEBASIC((char *)trafMDDescsInfo_, heap_);
if(optSimulator_)
delete optSimulator_;
optSimulator_ = NULL;
schemaDB_ = 0;
controlDB_ = 0;
optDefaults_ = 0;
trafMDDescsInfo_ = NULL;
delete envs_;
envs_ = 0;
if (outFstream_ != NULL)
delete outFstream_;
currentStatementPtrCache_ = NULL;
if ( isRuntimeCompile_) // Seems like QueryCache is not initialized for static compiler
qcache_->finalize((char *)"Drop Session");
if ( CTXTHEAP ) // Defensive coding - if NULL, the Context Heap is gone.
delete optPCodeCache_ ;
optPCodeCache_ = NULL ;
resetContext();
// reset thread global variables
HSGlobalsClass::resetJitLogThresholdHash();
}
NABoolean CmpContext::initContextGlobals()
{
NABoolean rtnStatus = TRUE ; // assume the best
// globals for ustat
uStatID_ = 0;
// retrieve SQLMX_REGRESS environmnet variable
const char *env;
env = getenv("SQLMX_REGRESS");
if (env)
{
sqlmxRegress_ = atoi(env);
}
return rtnStatus;
}
NAHeap* CmpContext::statementHeap()
{
return statement() ? statement()->heap() : 0;
}
void CmpContext::setSecondaryMxcmp(){
if(mxcmpPrimarySecondaryStatusSet_)
return;
mxcmpPrimarySecondaryStatusSet_ = TRUE;
// Check for env var that indicates this is a secondary mxcmp process.
// Keep this value in CmpContext so that secondary mxcmp on NSK
// will allow MP DDL issued from a parent mxcmp process.
NABoolean IsSecondaryMxcmp = FALSE;
if (getenv("SECONDARY_MXCMP") != NULL)
{
IsSecondaryMxcmp = TRUE;
}
flags_ = flags_ | (IsSecondaryMxcmp ? CmpContext::IS_SECONDARY_MXCMP : 0);
// Any downstream process will be a "SECONDARY_MXCMP".
PUTENV((char *)"SECONDARY_MXCMP=1");
Lng32 rc = SQL_EXEC_SetEnviron_Internal(0);
}
// ----------------------------------------------------------------------------
// method: setAuthorizationState
//
// This method is called during compiler context startup to determine if
// authorization has been enabled. It sets two flags in the compiler context
// structure based on the passed in state:
//
// IS_AUTHORIZATION_ENABLED
// set to TRUE if one or more privmgr metadata tables exists
//
// IS_AUTHORIZATION_READY
// set to TRUE if all privmgr metadata tables exist
//
// input: state
// 0: no metadata tables exist, authorization is not enabled
// 1: all metadata tables exist, authorization is enabled
// 2: some metadata tables exist, privmgr metadata is not ready
// -nnnn: an unexpected error occurred
// ----------------------------------------------------------------------------
void CmpContext::setAuthorizationState (Int32 state)
{
switch (state)
{
// state = 0, not initialized
case 0:
setIsAuthorizationEnabled(FALSE);
setIsAuthorizationReady(FALSE);
break;
// state = 1, initialized
case 1:
setIsAuthorizationEnabled(TRUE);
setIsAuthorizationReady(TRUE);
break;
// state = 2, partially initialized
case 2:
setIsAuthorizationEnabled(TRUE);
setIsAuthorizationReady(FALSE);
break;
// else unexpected error
default:
// Unable to determine authorization status, set
// authorizationReady to FALSE.
setIsAuthorizationReady(FALSE);
// Get status from the TRAFODION_ENABLE_AUTHORIZATION envvar.
// The TRAFODION_ENABLE_AUTHENTICATION envvar defined in the
// sqenvcom.sh file. Since authorization can be initialized
// independently from setting the envvar, we cannot necessarily
// depend on its value. So we only use it if we can't get the
// information from anywhere else.
char * env = getenv("TRAFODION_ENABLE_AUTHENTICATION");
if (env)
{
setIsAuthorizationEnabled
((strcmp(env, "YES") == 0) ? TRUE : FALSE);
}
else
{
// Can't determine status, so be on the safe side and set
// to TRUE
setIsAuthorizationEnabled(TRUE);
}
// setup an internal error
*diags_
<< DgSqlCode(-1001)
<< DgString0(__FILE__)
<< DgInt0(__LINE__)
<< DgString1("Unable to determine authorization status");
}
}
// ----------------------------------------------------------------------------
// method: isAuthorizationEnabled
//
// Return the value of IS_AUTHORIZATION_ENABLED
//
// input:
// errIfNotReady:
// TRUE - generate an error if authorization is enabled and privmgr
// metadata table(s) are missing or inaccessible (incomplete)
// ----------------------------------------------------------------------------
NABoolean CmpContext::isAuthorizationEnabled( NABoolean errIfNotReady)
{
if (flags_ & IS_AUTHORIZATION_ENABLED)
{
if (errIfNotReady && !isAuthorizationReady())
{
if (!diags_->contains(-1234))
{
*diags_ << DgSqlCode(-1234);
CMPASSERT (FALSE);
}
}
return TRUE;
}
return FALSE;
}
HiveClient_JNI * CmpContext::getHiveClient(ComDiagsArea *diags)
{
if(NULL == hiveClient_)
{
hiveClient_ = HiveClient_JNI::getInstance();
if ( hiveClient_->isInitialized() == FALSE ||
hiveClient_->isConnected() == FALSE)
{
HVC_RetCode retCode = hiveClient_->init();
if (retCode != HVC_OK)
{
hiveClient_ = NULL;
}
}
}
if (hiveClient_ == NULL && diags)
*diags << DgSqlCode(-1213);
return hiveClient_;
}
NABoolean CmpContext::execHiveSQL(const char* hiveSQL, ComDiagsArea *diags)
{
NABoolean result = FALSE;
if (!hiveClient_)
getHiveClient(diags);
if (hiveClient_)
{
HVC_RetCode retcode = hiveClient_->executeHiveSQL(hiveSQL);
switch (retcode)
{
case HVC_OK:
result = TRUE;
break;
default:
result = FALSE;
}
if (!result && diags)
*diags << DgSqlCode(-1214)
<< DgString0(GetCliGlobals()->getJniErrorStr())
<< DgString1(hiveSQL);
}
return result;
}
// -----------------------------------------------------------------------
// The CmpStatement related methods
// -----------------------------------------------------------------------
void CmpContext::setStatement(CmpStatement* s)
{
init();
statements_.insert(s);
s->setPrvCmpStatement(statements_[currentStatement_]);
currentStatement_ = statements_.index(s);
currentStatementPtrCache_ = statements_[currentStatement_];
// Commented this out, as init() is now a no-op:
// if (statements_.entries() == 2) init();
}
void CmpContext::unsetStatement(CmpStatement* s, NABoolean exceptionRaised)
{
CollIndex i = statements_.index(s);
statements_.removeAt(i);
currentStatement_ = statements_.index(s->prvCmpStatement());
currentStatementPtrCache_ = statements_[currentStatement_];
for ( i = 0; i < statements_.entries(); i++ )
if (statements_[i] && statements_[i]->prvCmpStatement() == s)
statements_[i]->setPrvCmpStatement(s->prvCmpStatement());
if ( statements_.entries() == 1 ) {
cleanup(exceptionRaised);
if (s->diags()) s->diags()->clear();
}
}
void CmpContext::setCurrentStatement(CmpStatement* s)
{
CollIndex i = statements_.index(s);
currentStatement_ = ( i == NULL_COLL_INDEX ) ? 0 : i;
currentStatementPtrCache_ = statements_[currentStatement_];
CMPASSERT(s->diags()->getNumber() == 0);
// diags()->clear();
}
// Method to initialize the context at the beginning of statement
void CmpContext::init()
{
// initSchemaDB(); -- This was done in the ctor.
// diags()->clear(); -- This loses any initialization errors;
// -- clear() is done in unsetStatement above.
statementNum_++;
}
// -----------------------------------------------------------------------
// Method to cleanup the context contents at the end of each statement
// -----------------------------------------------------------------------
void CmpContext::cleanup(NABoolean exception)
{
//if(isISP()) return;
if (exception)
{
// TODO, we should consider cleaning up other members in CmpCOntext once
// exception raised since they might not be reliable anymore.
}
schemaDB_->cleanupPerStatement();
if(optSimulator_)
optSimulator_->cleanupAfterStatement();
if(cmpMemMonitor)
cmpMemMonitor->cleanupPerStatement();
if (invocationInfos_.entries() > 0)
{
// Clean up UDR structures that are allocated from the
// system heap. Plan infos can only exist if we also have
// invocation infos.
for (CollIndex i=0; i<invocationInfos_.entries(); i++)
TMUDFInternalSetup::deleteUDRInvocationInfo(invocationInfos_[i]);
for (CollIndex p=0; p<planInfos_.entries(); p++)
TMUDFInternalSetup::deleteUDRPlanInfo(planInfos_[p]);
invocationInfos_.clear();
planInfos_.clear();
}
if (routineHandles_.entries() > 0)
{
ExeCliInterface cliInterface(
statementHeap(),
NULL,
NULL,
CmpCommon::context()->sqlSession()->getParentQid());
for (CollIndex r=0; r<routineHandles_.entries(); r++)
cliInterface.putRoutine(routineHandles_[r],
CmpCommon::diags());
routineHandles_.clear();
}
}
// -----------------------------------------------------------------------
// Methods for optimizer globals
// -----------------------------------------------------------------------
void CmpContext::initControlDB()
{
delete controlDB_;
controlDB_ = new(heap_) ControlDB;
controlDB_->initPerStatement();
}
void CmpContext::initSchemaDB()
{
// TODO the initialization of valueDArray_ at the beginning of each statement.
if (schemaDB_) schemaDB_->initPerStatement();
if (controlDB_) controlDB_->initPerStatement();
}
// CmpContext::reserveMemory() reserves some memory in the context heap
// that is freed on certain out-of-memory situations. This allows the
// condition to be reported to MXCI or MXOSRVR.
void CmpContext::reserveMemory()
{
if (reservedMemory_ == NULL)
reservedMemory_ = heap_->allocateMemory(2048);
}
// CmpContext::freeReservedMemory() frees the memory that was reserved for
// out-of-memory reporting.
void CmpContext::freeReservedMemory()
{
if (reservedMemory_ != NULL && heap_ != NULL)
{
heap_->deallocateMemory(reservedMemory_);
reservedMemory_ = NULL;
}
}
void CmpContext::switchContext()
{
SqlParser_NADefaults_Glob =
ActiveSchemaDB()->getDefaults().getSqlParser_NADefaults_Ptr();
gpClusterInfo = clusterInfo_;
SqlParser_Diags = diags();
cmpMemMonitor = cmpMemMonitor_;
}
void CmpContext::switchBackContext()
{
SqlParser_NADefaults_Glob =
ActiveSchemaDB()->getDefaults().getSqlParser_NADefaults_Ptr();
gpClusterInfo = clusterInfo_;
SqlParser_Diags = diags();
cmpMemMonitor = cmpMemMonitor_;
}
void CmpContext::resetContext()
{
SqlParser_NADefaults_Glob = NULL;
gpClusterInfo = NULL;
SqlParser_Diags = NULL;
if (CmpCommon::diags())
CmpCommon::diags()->clear();
cmpMemMonitor = NULL;
}
CmpStatementISP* CmpContext::getISPStatement(Int64 id)
{
NAList<CmpStatement*> & statements = this->statements();
CmpStatementISP* ispStatement;
for ( CollIndex i = 0; i < statements.entries(); i++)
if ( statements[i] && ( ispStatement = (statements[i])->ISPStatement() )
&& ispStatement->ISPReqId() == id )
return ispStatement;
return 0;
}
// Interface to the embedded arkcmp, used for executor master to compile
// query statement using this SQL compiler inside the same process.
//
// Return value: (should sync with ExSqlComp::ReturnStatus)
// 0 - SUCCESS:
// 1 - WARNING: (not used)
// 2 - ERROR: any compiler internal errors
// 3 - MORE_DATA: only for REPLY_ISP_
Int32
CmpContext::compileDirect(char *data, UInt32 data_len, CollHeap *outHeap,
Int32 charset, CmpMessageObj::MessageTypeEnum op,
char *&gen_code, UInt32 &gen_code_len,
UInt32 parserFlags, const char *parentQid,
Int32 parentQidLen,
ComDiagsArea *&diagsArea)
{
CmpStatement::ReturnStatus rs = CmpStatement::CmpStatement_SUCCESS;
CmpStatement *cmpStatement = NULL;
NABoolean copyFrags = FALSE, copyData = FALSE;
// save the callers cin/cout and redirect compiler's cin/cout
std::streambuf *savedCoutBuf = std::cout.rdbuf() ; // Save cout's streambuf
std::streambuf *savedCinBuf = std::cin.rdbuf(); //Save cin's streambuf
incrRecursionLevel();
if (outFstream_)
{
cout.rdbuf(outFstream_->rdbuf());
cin.rdbuf(outFstream_->rdbuf());
}
// keep track of the parser flags we started with and passed in
// to the compiler.
UInt32 savedCliParserFlags = parserFlags;
switchContext();
// set jmpbuf for compilation of the statement
// the reference of the ExportJmpBuf will be hept in CmpStatement heap
// shortly in the construction of CmpStatement
jmp_buf savedJB, savedInternalErrJB;
memcmp(savedJB, ExportJmpBuf, sizeof(jmp_buf));
memcmp(savedInternalErrJB, CmpInternalErrorJmpBuf, sizeof(jmp_buf));
Int32 jRc = setjmp(ExportJmpBuf);
if (jRc)
{ // longjmp here
if (cmpStatement)
delete cmpStatement;
// populate error
if (diagsArea)
if (jRc == MEMALLOC_FAILURE)
*diagsArea << DgSqlCode(arkcmpErrorOutOfMemory);
else
*diagsArea << DgSqlCode(arkcmpErrorAssert);
// Log this error to the file indicated by CMP_ERR_LOG_FILE CQD.
if (jRc == MEMALLOC_FAILURE)
CmpErrLog("Memory allocation failure");
decrRecursionLevel();
// restore jmp_buf contents
memcpy(ExportJmpBuf, savedJB, sizeof(jmp_buf));
memcpy(CmpInternalErrorJmpBuf, savedInternalErrJB, sizeof(jmp_buf));
// restore callers cin and cout
if(outFstream_)
{
//std::cout << std::endl ; // Flush anything in the data buffer
cout.rdbuf( savedCoutBuf ) ; // Restore cout's streambuf
cin.rdbuf(savedCinBuf);
}
return CmpStatement::CmpStatement_ERROR; // temp use of this error;
}
Int32 jRc2 = setjmp(CmpInternalErrorJmpBuf);
if (jRc2)
{ // longjmp here
if (cmpStatement)
delete cmpStatement;
CostMethod::cleanUpAllCostMethods();
// populate error
if (diagsArea)
if (jRc2 == MEMALLOC_FAILURE)
{
freeReservedMemory();
*diagsArea << DgSqlCode(arkcmpErrorOutOfMemory);
}
else
*diagsArea << DgSqlCode(arkcmpErrorAssert);
// Log this error to the file indicated by CMP_ERR_LOG_FILE CQD.
if (jRc2 == MEMALLOC_FAILURE)
CmpErrLog("Memory allocation failure");
decrRecursionLevel();
// restore jmp_buf contents
memcpy(ExportJmpBuf, savedJB, sizeof(jmp_buf));
memcpy(CmpInternalErrorJmpBuf, savedInternalErrJB, sizeof(jmp_buf));
// restore callers cin and cout
if(outFstream_)
{
//std::cout << std::endl ; // Flush anything in the data buffer
cout.rdbuf( savedCoutBuf ) ; // Restore cout's streambuf
cin.rdbuf(savedCinBuf);
}
return CmpStatement::CmpStatement_ERROR; // temp use of this error;
}
// make sure we have reserved memory in the context
reserveMemory();
try
{
switch (op)
{
case CmpMessageObj::SQLTEXT_RECOMPILE :
case CmpMessageObj::SQLTEXT_COMPILE :
{
// request is from cli interface for compiling most sql statements
// NAMemory.h.
cmpStatement = new CTXTHEAP CmpStatement(this);
CmpMessageSQLText sqltext(data, data_len, CTXTHEAP, charset, op);
Assign_SqlParser_Flags(parserFlags);
rs = cmpStatement->process(sqltext);
copyFrags = TRUE;
break;
}
case CmpMessageObj::SQLTEXT_STATIC_RECOMPILE :
case CmpMessageObj::SQLTEXT_STATIC_COMPILE :
{
// request is from ex_control_tcb::work() for setting compiler CQDs
cmpStatement = new CTXTHEAP CmpStatement(this);
CmpMessageCompileStmt compileStmt(data, data_len, op, CTXTHEAP, charset);
Assign_SqlParser_Flags(parserFlags);
rs = cmpStatement->process(compileStmt);
copyData = TRUE;
break;
}
case (CmpMessageObj::DATABASE_USER) :
{
// request is from ContextCli::createMxcmpSession() to set user id
cmpStatement = new CTXTHEAP CmpStatement(this);
CmpMessageDatabaseUser databaseUserStmt(data, data_len, CTXTHEAP);
Assign_SqlParser_Flags(parserFlags);
rs = cmpStatement->process(databaseUserStmt);
copyData = TRUE;
break;
} // end of case (CmpMessageObj::DATABASE_USER)
case (CmpMessageObj::DDL) :
{
// request is from ExDDLTcb::work() to get statement explain
cmpStatement = new CTXTHEAP CmpStatement(this);
CmpMessageDDL ddlStmt(data, data_len, CTXTHEAP, charset,
parentQid, parentQidLen);
Assign_SqlParser_Flags(parserFlags);
rs = cmpStatement->process(ddlStmt);
copyData = TRUE;
break;
} // end of case (CmpMessageObj::DDL)
case (CmpMessageObj::DESCRIBE) :
{
// request is from ExDescribeTcb::work() to get statement explain
cmpStatement = new CTXTHEAP CmpStatement(this);
CmpMessageDescribe describeStmt(data, data_len, CTXTHEAP, charset);
Assign_SqlParser_Flags(parserFlags);
rs = cmpStatement->process(describeStmt);
copyData = TRUE;
break;
} // end of case (CmpMessageObj::DESCRIBE)
case (CmpMessageObj::END_SESSION) :
{
// request is from ContextCli::endMxcmpSession()
cmpStatement = new CTXTHEAP CmpStatement(this);
CmpMessageEndSession endSessionStmt(data, data_len, CTXTHEAP);
Assign_SqlParser_Flags(parserFlags);
rs = cmpStatement->process(endSessionStmt);
copyData = TRUE;
break;
} // end of case (CmpMessageObj::END_SESSION)
case (CmpMessageObj::SET_TRANS) :
{
// request is from ExDescribeTcb::work() for getting compiler CQDs
cmpStatement = new CTXTHEAP CmpStatement(this);
CmpMessageSetTrans setTransStmt(data, data_len, CTXTHEAP);
Assign_SqlParser_Flags(parserFlags);
rs = cmpStatement->process(setTransStmt);
copyData = TRUE;
break;
} // end of case (CmpMessageObj::SET_TRANS)
case (CmpMessageObj::DDL_NATABLE_INVALIDATE) :
{
cmpStatement = new CTXTHEAP CmpStatement(this);
CmpMessageDDLNATableInvalidate ddlInvalidateStmt(data, data_len, CTXTHEAP);
Assign_SqlParser_Flags(parserFlags);
rs = cmpStatement->process(ddlInvalidateStmt);
copyData = TRUE;
break;
} // end of case (CmpMessageObj::DDL_NATABLE_INVALIDATE)
case (CmpMessageObj::INTERNALSP_REQUEST) :
{
//request is from ExStoredProcTcb::work(),
cmpStatement = new CTXTHEAP CmpStatementISP(this);
//ISP request is passed as data argument
CMPASSERT(data);
CmpMessageISPRequest & ispRequest = *(CmpMessageISPRequest *)data;
Assign_SqlParser_Flags(parserFlags);
//process request
rs = cmpStatement->process(ispRequest);
copyData = TRUE;
break;
}
case (CmpMessageObj::INTERNALSP_GETNEXT) :
{
//request is from ExStoredProcTcb::work()
CMPASSERT(data);
//ISPGetNext request is passed as data argument
CmpMessageISPGetNext & ispGetNext = *(CmpMessageISPGetNext *)data;
//do not create new statement for GetNext,
//find previous-created statement in current context through requestId
cmpStatement = getISPStatement(ispGetNext.ispRequest());
if (!cmpStatement)
{
// There must be a previous ispStatement, otherwise it is an
// internal error. Instantiate a dummy CmpStatement here, just
// to place the error information.
cmpStatement = new CTXTHEAP CmpStatement(this);
CMPASSERT(FALSE);
}
Assign_SqlParser_Flags(parserFlags);//What is this for??
//process request
rs = cmpStatement->process(ispGetNext);
copyData = TRUE;
break;
}
default : // the embedded compiler can not handle other operation yet
{
char emsText[120];
str_sprintf(emsText,
"Embedded arkcmp does not support this operation: %d.",
op);
SQLMXLoggingArea::logExecRtInfo(__FILE__, __LINE__, emsText, 0);
rs = CmpStatement::CmpStatement_ERROR; // temp use of this error
}
} // switch (op)
}
catch (CmpInternalException &exInternal)
{
if (cmpStatement)
{
cmpStatement->error(arkcmpErrorAssert, exInternal.getMsg());
cmpStatement->exceptionRaised();
}
else
{
ComDiagsArea *diags = ComDiagsArea::allocate(heap_);
*diags << DgSqlCode(arkcmpErrorAssert)
<< DgInt0(0) << DgString0("from CMPASSERT")
<< DgString1("CmpConnection::actOnReceive,EH_INTERNAL_EXCEPTION");
}
rs = CmpStatement::CmpStatement_ERROR; // temp use of this error
}
catch (...)
{
rs = CmpStatement::CmpStatement_ERROR; // temp use of this error
}
char *result;
IpcMessageObjSize rp_len;
// todo: need to translate CmpStatement::ReturnStatus to
// ExSqlComp::ReturnStatus
if (rs == CmpStatement::CmpStatement_SUCCESS && cmpStatement->reply())
{
// get the plan
Int32 objType = cmpStatement->reply()->getType();
switch (objType)
{
case CmpMessageObj::REPLY_CODE :
{
CmpMessageReplyCode *rp = (CmpMessageReplyCode*)cmpStatement->reply();
rp_len = rp->getSize(); // get the size of all fragments
result = (char *)outHeap->allocateMemory(rp_len);
gen_code = result;
if (copyFrags == TRUE)// copy all frags into the buffer
{
// for regular dynamic statement, the generated plan fragments
// are saved in the fragmentDir_ unless the plan was from cache
if (rp->getFragmentDir())
IpcMessageObjSize rt_len = rp->copyFragsToBuffer(result);
else // cached plan was linked to data_
memcpy(result, rp->getData(), rp->getSize());
}
else if (copyData == TRUE)
memcpy(result, rp->getData(), rp->getSize());
gen_code_len = rp_len;
break;
}
case CmpMessageObj::REPLY_ISP :
{
if(copyData == TRUE && rs == CmpStatement::CmpStatement_SUCCESS)
{
CmpMessageReplyISP *rp = (CmpMessageReplyISP*)cmpStatement->reply();
//Receiving buffer is pointed by gen_code, which should be allocated by caller ( ExStoredProcTcb::work() ).
//Check receiving buffer length is larger than data length.
if(gen_code_len >= rp->getSize())
memcpy(gen_code, rp->getData(), rp->getSize());
else
rs = CmpStatement::CmpStatement_ERROR;
//caller shoud check if replied data length exceeds the gen_code_len passed in.
gen_code_len = rp->getSize();
}
break;
}
default :
break;
}
}
ComDiagsArea *compileDiagsArea = CmpCommon::diags();
if (compileDiagsArea->getNumber() > 0)
{
// get any errors or warnings from compilation out before distroy it
if (diagsArea == NULL)
diagsArea = ComDiagsArea::allocate(outHeap);
diagsArea->mergeAfter(*compileDiagsArea);
compileDiagsArea->clear();
}
// cleanup and return
if (cmpStatement && cmpStatement->readyToDie())
delete cmpStatement;
// Restore the CLI flags as they were. The compiler may have changed the CLI
// parser flags using SQL_EXEC_SetParserFlagsExSqlComp_Internal.
SQL_EXEC_AssignParserFlagsForExSqlComp_Internal(savedCliParserFlags);
// Restore jmp_buf
memcpy(ExportJmpBuf, savedJB, sizeof(jmp_buf));
memcpy(CmpInternalErrorJmpBuf, savedInternalErrJB, sizeof(jmp_buf));
// restore callers cin and cout
if(outFstream_)
{
//std::cout << std::endl ; // Flush anything in the data buffer
cout.rdbuf( savedCoutBuf ) ; // Restore cout's streambuf
cin.rdbuf(savedCinBuf);
}
decrRecursionLevel();
if (rs == CmpStatement::CmpStatement_SUCCESS)
return 0; // SUCCESS
return 2; // FAILURE
}
// set/reset an env in compiler envs
void
CmpContext::setArkcmpEnvDirect(const char *name,
const char *value,
NABoolean unset)
{
if (unset)
{
// unset means remove the env name from CmpContext::envs_ list and call
// putenv("<name>"), see ProcessEnv::removeEnv() (not ::unsetEnv())
envs()->resetEnv((char*)name);
return; // we done.
}
// prepare the env string "name=value" first
char *envStr;
Int32 strLen;
strLen = str_len(name) + str_len(value) + 1; // name=value
if (strLen <= 0)
return; // do nothing
envStr = new (heap_) char[strLen + 1];
str_sprintf(envStr, "%s=%s", name, value);
// set the env
envs()->addOrChangeEnv(&envStr, 1);
NADELETEBASIC(envStr, heap_);
// the following is copied from arkcmp/CmpStatement.cpp as the side-effect
// altering env in compiler.
// see CmpStatement::process(const CmpMessageEnvs& envMessage) for details
const char * env;
env = getenv("SQLMX_REGRESS");
if (env)
{
setSqlmxRegress(atoi(env));
// turn mode_special_1 OFF during regressions run.
// Special1 features cause
// many regressions to return mismatches due to special TD semantics.
// When some
// of the special1 features are externalized and enabled for general
// NEO users, then we can remove these lines.
NAString value("OFF");
ActiveSchemaDB()->getDefaults().validateAndInsert(
"MODE_SPECIAL_1", value, FALSE);
}
}
// return compiler tracking information
// there is one per compiler context
CompilerTrackingInfo*
CmpContext::getCompilerTrackingInfo()
{
if (compilerTrackingInfo_ == NULL)
compilerTrackingInfo_ = new (heap_) CompilerTrackingInfo(heap_);
compilerTrackingInfo_->resetIntervalIfNeeded();
return compilerTrackingInfo_;
}
ULng32 CmpContext::getTMFUDF_DLL_InterfaceHostDataBufferLen()
{ return SQLUDR_STATEAREA_BUFFER_SIZE; }
// Set the SQL text for later use. If the buffer is not empty, this
// call does nothing.
//
void CmpContext::setLogmxEventSqlText(const NAWString& x)
{
if ( sqlTextBuf_ == NULL )
sqlTextBuf_ = new NAWString(x) ;
}
//
// clear up the SQL text so that next setSqlText() call can have effect.
//
void CmpContext::resetLogmxEventSqlText()
{
delete sqlTextBuf_ ;
sqlTextBuf_ = NULL ;
}
void CmpContext::clearAllCaches()
{
qcache_->makeEmpty();
schemaDB_->getNATableDB()->setCachingOFF();
schemaDB_->getNATableDB()->setCachingON();
schemaDB_->getNARoutineDB()->setCachingOFF();
schemaDB_->getNARoutineDB()->setCachingON();
if(histogramCache_)
histogramCache_->invalidateCache();
}