| /********************************************************************** |
| // @@@ 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: ComDiags.cpp (previously under /common) |
| * Description: |
| * |
| * Created: 5/6/98 |
| * Language: C++ |
| * |
| * |
| **************************************************************************** |
| */ |
| |
| #include "Platform.h" |
| |
| |
| |
| #include "NAStdlib.h" |
| |
| #include "ComDiags.h" |
| #include "IpcMessageObj.h" |
| #include "str.h" |
| #include "Int64.h" |
| #include "ExpError.h" |
| |
| #include "seabed/ms.h" |
| #include <stdlib.h> |
| #include <unistd.h> |
| extern void releaseRTSSemaphore(); // Functions implemented in SqlStats.cpp |
| #include "logmxevent.h" |
| |
| #include <byteswap.h> |
| |
| #include "ComRtUtils.h" |
| |
| #ifdef _DEBUG |
| #include <time.h> |
| #include <sys/time.h> |
| #include "PortProcessCalls.h" |
| #endif |
| |
| |
| // This is a "helper" function that factors out a bunch of code |
| // from the packedLength() routines. |
| |
| static |
| inline void advanceSize(IpcMessageObjSize &size, const char * const buffPtr) |
| { |
| const Int32 lenSize = sizeof( Lng32); |
| size += lenSize; |
| if (buffPtr != NULL) |
| size += str_len(buffPtr) + 1; // 1 is for the buffer's null-terminator |
| } |
| |
| //UR2 |
| static |
| inline void advanceSize(IpcMessageObjSize &size, const NAWchar * const buffPtr) |
| { |
| const Int32 lenSize = sizeof( Lng32); |
| size += lenSize; |
| if (buffPtr != NULL) |
| size += (na_wcslen(buffPtr) + 1)*sizeof(NAWchar); // 1 is for null-terminator |
| } |
| |
| |
| |
| // static NABoolean isValidIsoMappingCharSet(CharInfo::CharSet cs) |
| // { |
| // if (cs == CharInfo::ISO88591 || |
| // cs == CharInfo::SJIS || |
| // cs == CharInfo::UTF8) |
| // return TRUE; |
| // else |
| // return FALSE; |
| // } |
| |
| static NABoolean isSingleByteCharSet(CharInfo::CharSet cs) |
| { |
| if (cs == CharInfo::ISO88591) return TRUE; |
| if (cs == CharInfo::UTF8) return TRUE; // is variable-length/width multi-byte char-set but treat it as a C/C++ string |
| if (cs == CharInfo::SJIS) return TRUE; // is variable-length/width multi-byte char-set but treat it as a C/C++ string |
| if (cs == CharInfo::UNICODE) return FALSE; |
| |
| // a "mini-cache" to avoid proc call, for performance. |
| static THREAD_P CharInfo::CharSet cachedCS = CharInfo::UnknownCharSet; |
| static THREAD_P Int32 cachedSByte = TRUE; |
| |
| if (cachedCS != cs) { |
| cachedCS = cs; |
| cachedSByte = (CharInfo::maxBytesPerChar(cs) == 1); |
| } |
| return cachedSByte; |
| } |
| |
| |
| // The type of message is IPC_SQL_DIAG_AREA, and the version |
| // is hard coded to zero here. |
| // |
| // What should the version of IpcMessageObj be set to? |
| |
| ComCondition::ComCondition (CollHeap* heapPtr) : |
| IpcMessageObj(IPC_SQL_CONDITION,0), |
| serverName_(NULL), |
| connectionName_(NULL), |
| constraintCatalog_(NULL), |
| constraintSchema_(NULL), |
| constraintName_(NULL), |
| triggerCatalog_(NULL), |
| triggerSchema_(NULL), |
| triggerName_(NULL), |
| catalogName_(NULL), |
| schemaName_(NULL), |
| tableName_(NULL), |
| customSQLState_(NULL), |
| columnName_(NULL), |
| sqlID_(NULL), |
| messageText_(NULL), |
| messageLen_(0), |
| conditionNumber_(0), |
| usageMap_(0), |
| rowNumber_(ComCondition::INVALID_ROWNUMBER), |
| nskCode_(0), |
| numStringParamsUsed_(0), |
| numIntParamsUsed_(0), |
| flagsTBS_(0), |
| theSQLCODE_(0), |
| emsEventVisits_(0), |
| // iso88591MappingCharSet_(CharInfo::UnknownCharSet), |
| collHeapPtr_(heapPtr), |
| isLocked_(FALSE) |
| { |
| // Set optional string parameters to NULL |
| // and optional integers to a theoretically recognizably bad value. |
| for (Int32 i=NumOptionalParms; i--; ) { |
| optionalString_[i]=NULL; |
| optionalStringCharSet_[i]=CharInfo::UTF8; |
| optionalInteger_[i]=ComDiags_UnInitialized_Int; |
| } |
| // Initialize fillers space to 0 |
| memset(fillers_, 0, sizeof(fillers_)); |
| // Make sure the size of ComCondition remains constant |
| // If you hit this after change or add new member, adjust the fillers_ size |
| Int32 classSize = sizeof(ComCondition); |
| assert(classSize == 376); |
| } |
| |
| ComCondition::ComCondition () : |
| IpcMessageObj(IPC_SQL_CONDITION,0), |
| serverName_(NULL), |
| connectionName_(NULL), |
| constraintCatalog_(NULL), |
| constraintSchema_(NULL), |
| constraintName_(NULL), |
| triggerCatalog_(NULL), |
| triggerSchema_(NULL), |
| triggerName_(NULL), |
| catalogName_(NULL), |
| schemaName_(NULL), |
| tableName_(NULL), |
| customSQLState_(NULL), |
| columnName_(NULL), |
| sqlID_(NULL), |
| messageText_(NULL), |
| messageLen_(0), |
| conditionNumber_(0), |
| usageMap_(0), |
| rowNumber_(ComCondition::INVALID_ROWNUMBER), |
| nskCode_(0), |
| numStringParamsUsed_(0), |
| numIntParamsUsed_(0), |
| flagsTBS_(0), |
| theSQLCODE_(0), |
| emsEventVisits_(0), |
| // iso88591MappingCharSet_(CharInfo::UnknownCharSet), |
| collHeapPtr_(NULL), |
| isLocked_(FALSE) |
| { |
| // Set optional string parameters to NULL |
| // and optional integers to a theoretically recognizably bad value. |
| for (Int32 i=NumOptionalParms; i--; ) { |
| optionalString_[i]=NULL; |
| optionalStringCharSet_[i]=CharInfo::UTF8; |
| optionalInteger_[i]=ComDiags_UnInitialized_Int; |
| } |
| // Initialize fillers space to 0 |
| memset(fillers_, 0, sizeof(fillers_)); |
| // Make sure the size of ComCondition remains constant |
| // If you hit this after change or add new member, adjust the fillers_ size |
| Int32 classSize = sizeof(ComCondition); |
| assert(classSize == 376); |
| } |
| |
| // The destructor must free all of the char buffers which |
| // this object owns, and it must do so using the proper heap. |
| |
| ComCondition::~ComCondition () |
| { |
| clear(); |
| collHeapPtr_=NULL; |
| } |
| |
| // The assignment operator pretty much just copies each of |
| // the members over ``by hand.'' |
| |
| ComCondition& ComCondition::operator=(const ComCondition& c) |
| { |
| this->IpcMessageObj::operator=(c); |
| |
| assignStringMember(serverName_, c.serverName_); |
| assignStringMember(connectionName_, c.connectionName_); |
| assignStringMember(constraintCatalog_, c.constraintCatalog_); |
| assignStringMember(constraintSchema_, c.constraintSchema_); |
| assignStringMember(constraintName_, c.constraintName_); |
| assignStringMember(triggerCatalog_, c.triggerCatalog_); |
| assignStringMember(triggerSchema_, c.triggerSchema_); |
| assignStringMember(triggerName_, c.triggerName_); |
| assignStringMember(catalogName_, c.catalogName_); |
| assignStringMember(schemaName_, c.schemaName_); |
| assignStringMember(tableName_, c.tableName_); |
| assignStringMember(customSQLState_, c.customSQLState_); |
| assignStringMember(columnName_, c.columnName_); |
| assignStringMember(sqlID_, c.sqlID_); |
| assignStringMember(messageText_, c.messageText_); |
| |
| for (Int32 i=NumOptionalParms; i--; ) { |
| if ( isSingleByteCharSet(c.optionalStringCharSet_[i]) ) |
| assignStringMember((char* &)optionalString_[i], (char*)c.optionalString_[i]); |
| else |
| assignStringMember((NAWchar*&)optionalString_[i], (NAWchar*)c.optionalString_[i]); |
| |
| optionalStringCharSet_[i] = c.optionalStringCharSet_[i]; |
| optionalInteger_[i] = c.optionalInteger_[i]; |
| } |
| |
| messageLen_ = c.messageLen_; |
| // conditionNumber_ = c.conditionNumber_; |
| usageMap_ = c.usageMap_; |
| rowNumber_ = c.rowNumber_; |
| nskCode_ = c.nskCode_; |
| numStringParamsUsed_ = c.numStringParamsUsed_; |
| numIntParamsUsed_ = c.numIntParamsUsed_; |
| flagsTBS_ = c.flagsTBS_; |
| theSQLCODE_ = c.theSQLCODE_; |
| isLocked_ = c.isLocked_; |
| emsEventVisits_ = c.emsEventVisits_; |
| // iso88591MappingCharSet_ = c.iso88591MappingCharSet_; |
| |
| return *this; |
| } |
| |
| // The clear function resets this ComCondition object to what it |
| // would be just after construction, EXCEPT, that the collHeapPtr_ |
| // member is left as is. |
| |
| void ComCondition::clear() |
| { |
| if (collHeapPtr_==NULL) { |
| |
| // We delete the individual buffers, and then the elements of |
| // the array of the optional string parameters. |
| delete [] serverName_; |
| delete [] connectionName_; |
| delete [] constraintCatalog_; |
| delete [] constraintSchema_; |
| delete [] constraintName_; |
| delete [] triggerCatalog_; |
| delete [] triggerSchema_; |
| delete [] triggerName_; |
| delete [] catalogName_; |
| delete [] schemaName_; |
| delete [] tableName_; |
| delete [] customSQLState_; |
| delete [] columnName_; |
| delete [] sqlID_; |
| delete [] messageText_; |
| |
| for (Int32 i=NumOptionalParms; i--; ) { |
| if (optionalString_[i]) |
| if ( isSingleByteCharSet(optionalStringCharSet_[i]) ) |
| delete (char*)optionalString_[i]; |
| else |
| delete (NAWchar*)optionalString_[i]; |
| } |
| } |
| else { |
| |
| // Deallocate space for all buffers: these are simple char arrays |
| // so there is no destructor to call. |
| |
| collHeapPtr_->deallocateMemory(serverName_); |
| collHeapPtr_->deallocateMemory(connectionName_); |
| collHeapPtr_->deallocateMemory(constraintCatalog_); |
| collHeapPtr_->deallocateMemory(constraintSchema_); |
| collHeapPtr_->deallocateMemory(constraintName_); |
| collHeapPtr_->deallocateMemory(triggerCatalog_); |
| collHeapPtr_->deallocateMemory(triggerSchema_); |
| collHeapPtr_->deallocateMemory(triggerName_); |
| collHeapPtr_->deallocateMemory(catalogName_); |
| collHeapPtr_->deallocateMemory(schemaName_); |
| collHeapPtr_->deallocateMemory(tableName_); |
| collHeapPtr_->deallocateMemory(customSQLState_); |
| collHeapPtr_->deallocateMemory(columnName_); |
| collHeapPtr_->deallocateMemory(sqlID_); |
| collHeapPtr_->deallocateMemory(messageText_); |
| |
| // Deallocate space for optional string parameters: no |
| // destructor need be called. |
| |
| for (Int32 i=NumOptionalParms; i--; ) { |
| if (optionalString_[i]) |
| if ( isSingleByteCharSet(optionalStringCharSet_[i]) ) |
| collHeapPtr_->deallocateMemory(optionalString_[i]); |
| else |
| collHeapPtr_->deallocateMemory((NAWchar*)optionalString_[i]); |
| } |
| } |
| |
| // Set pointers to NULL for safety, in case anybody's using |
| // these pointers and shouldn't be. |
| |
| serverName_ = NULL; |
| connectionName_ = NULL; |
| constraintCatalog_ = NULL; |
| constraintSchema_ = NULL; |
| constraintName_ = NULL; |
| triggerCatalog_ = NULL; |
| triggerSchema_ = NULL; |
| triggerName_ = NULL; |
| catalogName_ = NULL; |
| schemaName_ = NULL; |
| tableName_ = NULL; |
| customSQLState_ = NULL; |
| columnName_ = NULL; |
| sqlID_ = NULL; |
| messageText_ = NULL; |
| |
| // set optional string parameters to NULL |
| // and optional integers to a theoretically recognizably bad value. |
| |
| for (Int32 i=NumOptionalParms; i--; ) { |
| optionalString_[i]=NULL; |
| optionalStringCharSet_[i]=CharInfo::UTF8; |
| optionalInteger_[i]=ComDiags_UnInitialized_Int; |
| } |
| |
| messageLen_ = 0; |
| rowNumber_ = INVALID_ROWNUMBER; |
| nskCode_ = 0; |
| flagsTBS_ = 0; |
| conditionNumber_ = 0; |
| usageMap_ = 0; |
| theSQLCODE_ = 0; |
| isLocked_ = FALSE; |
| emsEventVisits_ = 0; |
| // iso88591MappingCharSet_ = CharInfo::UnknownCharSet; |
| |
| // Reset the filler_ space to 0 |
| memset(fillers_, 0, sizeof(fillers_)); |
| } |
| |
| IpcMessageRefCount ComDiagsArea::decrRefCount() |
| { |
| if (getRefCount() == 1) |
| { |
| deAllocate(); |
| return 0; |
| } |
| |
| // Let base class do the work. |
| return this->IpcMessageObj::decrRefCount(); |
| } |
| |
| // These IPC functions are definitions for virtual functions. |
| // We do not currently make (any) use of most of the |
| // arguments of unpackObj(). |
| |
| void ComCondition::unpackObj(IpcMessageObjType objType, |
| IpcMessageObjVersion objVersion, |
| NABoolean sameEndianness, |
| IpcMessageObjSize objSize, |
| IpcConstMessageBufferPtr buffer) |
| { |
| // NOTE: changes to any of the following methods also require |
| // corresponding changes in the others: |
| // - packedLength() |
| // - packObjIntoMessage() |
| // - unpackObj() |
| // - checkObj() |
| |
| NABoolean foundUprevFieldsInBuffer = FALSE; |
| |
| unpackBaseClass(buffer); |
| // unconditional fields |
| unpackBuffer(buffer,conditionNumber_); |
| unpackBuffer(buffer,usageMap_); |
| unpackBuffer(buffer,emsEventVisits_); |
| |
| // fields that are sent conditionally |
| if (usageMap_ & USED_FLAGS) |
| unpackBuffer(buffer,flagsTBS_); |
| if (usageMap_ & USED_SQLCODE) |
| unpackBuffer(buffer,theSQLCODE_); |
| else |
| assert(0); // should never have a missing SQLCODE field |
| if (usageMap_ & USED_SERVER_NAME) |
| unpackBuffer(buffer,serverName_,collHeapPtr_); |
| if (usageMap_ & USED_CONNECTION_NAME) |
| unpackBuffer(buffer,connectionName_,collHeapPtr_); |
| if (usageMap_ & USED_CONSTRAINT_CATALOG) |
| unpackBuffer(buffer,constraintCatalog_,collHeapPtr_); |
| if (usageMap_ & USED_CONSTRAINT_SCHEMA) |
| unpackBuffer(buffer,constraintSchema_,collHeapPtr_); |
| if (usageMap_ & USED_CONSTRAINT_NAME) |
| unpackBuffer(buffer,constraintName_,collHeapPtr_); |
| if (usageMap_ & USED_TRIGGER_CATALOG) |
| unpackBuffer(buffer,triggerCatalog_,collHeapPtr_); |
| if (usageMap_ & USED_TRIGGER_SCHEMA) |
| unpackBuffer(buffer,triggerSchema_,collHeapPtr_); |
| if (usageMap_ & USED_TRIGGER_NAME) |
| unpackBuffer(buffer,triggerName_,collHeapPtr_); |
| if (usageMap_ & USED_CATALOG_NAME) |
| unpackBuffer(buffer,catalogName_,collHeapPtr_); |
| if (usageMap_ & USED_SCHEMA_NAME) |
| unpackBuffer(buffer,schemaName_,collHeapPtr_); |
| if (usageMap_ & USED_TABLE_NAME) |
| unpackBuffer(buffer,tableName_,collHeapPtr_); |
| if (usageMap_ & USED_COLUMN_NAME) |
| unpackBuffer(buffer,columnName_,collHeapPtr_); |
| if (usageMap_ & USED_SQLID) |
| unpackBuffer(buffer,sqlID_,collHeapPtr_); |
| if (usageMap_ & USED_ROW_NUMBER) |
| unpackBuffer(buffer,rowNumber_); |
| if (usageMap_ & USED_NSK_CODE) |
| unpackBuffer(buffer,nskCode_); |
| if (usageMap_ & USED_CUSTOM_SQLSTATE) |
| unpackBuffer(buffer,customSQLState_,collHeapPtr_); |
| // if (usageMap_ & USED_ISO_MAPPING_CHARSET) |
| // unpackBuffer(buffer,iso88591MappingCharSet_); |
| |
| if (usageMap_ & USED_NUM_STRING_PARAMS) |
| { |
| Lng32 charSet; |
| |
| unpackBuffer(buffer,numStringParamsUsed_); |
| |
| for (Int32 i=0; i < numStringParamsUsed_; i++) |
| { |
| if (i < NumOptionalParms) |
| { |
| unpackBuffer(buffer, (char*&)optionalString_[i],collHeapPtr_); |
| |
| unpackBuffer(buffer,charSet); |
| optionalStringCharSet_[i] = (CharInfo::CharSet)charSet; |
| } |
| else |
| { |
| // Some future release might increase NumOptionalParms. |
| // In this case, ignore those additional parameters |
| // and set a flag indicating this. |
| skipCharStarInBuffer(buffer); |
| unpackBuffer(buffer,charSet); |
| foundUprevFieldsInBuffer = TRUE; |
| } |
| } |
| } |
| |
| if (usageMap_ & USED_NUM_INT_PARAMS) |
| { |
| Lng32 dummy; |
| |
| unpackBuffer(buffer,numIntParamsUsed_); |
| |
| for (Int32 i=0; i < numIntParamsUsed_; i++) |
| { |
| if (i < NumOptionalParms) |
| { |
| unpackBuffer(buffer,optionalInteger_[i]); |
| } |
| else |
| { |
| // Some future release might increase NumOptionalParms. |
| // In this case, ignore those additional parameters |
| // and set a flag indicating this. |
| unpackBuffer(buffer,dummy); |
| foundUprevFieldsInBuffer = TRUE; |
| } |
| } |
| } |
| |
| // Check whether there are more fields than we expect. For certain |
| // simple additions, we will not increase the version number of |
| // the diagnostics area or of the ComCondition object. |
| if ((usageMap_ & USED_FUTURE_FIELDS) || foundUprevFieldsInBuffer) |
| flagsTBS_ |= FLAGS_TBS_SUPPRESSED_UPREV_FIELDS; |
| } |
| |
| // These IPC functions are definitions for virtual functions. |
| // We do not currently make (any) use of most of the |
| // arguments of unpackObj(). |
| |
| void ComCondition::unpackObj32(IpcMessageObjType objType, |
| IpcMessageObjVersion objVersion, |
| NABoolean sameEndianness, |
| IpcMessageObjSize objSize, |
| IpcConstMessageBufferPtr buffer) |
| { |
| // NOTE: changes to any of the following methods also require |
| // corresponding changes in the others: |
| // - packedLength() |
| // - packObjIntoMessage() |
| // - unpackObj() |
| // - checkObj() |
| |
| NABoolean foundUprevFieldsInBuffer = FALSE; |
| |
| unpackBaseClass32(buffer); |
| // unconditional fields |
| unpackBuffer(buffer,conditionNumber_); |
| unpackBuffer(buffer,usageMap_); |
| unpackBuffer(buffer,emsEventVisits_); |
| |
| // fields that are sent conditionally |
| if (usageMap_ & USED_FLAGS) |
| unpackBuffer(buffer,flagsTBS_); |
| if (usageMap_ & USED_SQLCODE) |
| unpackBuffer(buffer,theSQLCODE_); |
| else |
| assert(0); // should never have a missing SQLCODE field |
| if (usageMap_ & USED_SERVER_NAME) |
| unpackBuffer(buffer,serverName_,collHeapPtr_); |
| if (usageMap_ & USED_CONNECTION_NAME) |
| unpackBuffer(buffer,connectionName_,collHeapPtr_); |
| if (usageMap_ & USED_CONSTRAINT_CATALOG) |
| unpackBuffer(buffer,constraintCatalog_,collHeapPtr_); |
| if (usageMap_ & USED_CONSTRAINT_SCHEMA) |
| unpackBuffer(buffer,constraintSchema_,collHeapPtr_); |
| if (usageMap_ & USED_CONSTRAINT_NAME) |
| unpackBuffer(buffer,constraintName_,collHeapPtr_); |
| if (usageMap_ & USED_TRIGGER_CATALOG) |
| unpackBuffer(buffer,triggerCatalog_,collHeapPtr_); |
| if (usageMap_ & USED_TRIGGER_SCHEMA) |
| unpackBuffer(buffer,triggerSchema_,collHeapPtr_); |
| if (usageMap_ & USED_TRIGGER_NAME) |
| unpackBuffer(buffer,triggerName_,collHeapPtr_); |
| if (usageMap_ & USED_CATALOG_NAME) |
| unpackBuffer(buffer,catalogName_,collHeapPtr_); |
| if (usageMap_ & USED_SCHEMA_NAME) |
| unpackBuffer(buffer,schemaName_,collHeapPtr_); |
| if (usageMap_ & USED_TABLE_NAME) |
| unpackBuffer(buffer,tableName_,collHeapPtr_); |
| if (usageMap_ & USED_COLUMN_NAME) |
| unpackBuffer(buffer,columnName_,collHeapPtr_); |
| if (usageMap_ & USED_SQLID) |
| unpackBuffer(buffer,sqlID_,collHeapPtr_); |
| if (usageMap_ & USED_ROW_NUMBER) |
| unpackBuffer(buffer,rowNumber_); |
| if (usageMap_ & USED_NSK_CODE) |
| unpackBuffer(buffer,nskCode_); |
| if (usageMap_ & USED_CUSTOM_SQLSTATE) |
| unpackBuffer(buffer,customSQLState_,collHeapPtr_); |
| // if (usageMap_ & USED_ISO_MAPPING_CHARSET) |
| // unpackBuffer(buffer,iso88591MappingCharSet_); |
| |
| if (usageMap_ & USED_NUM_STRING_PARAMS) |
| { |
| Lng32 charSet; |
| |
| unpackBuffer(buffer,numStringParamsUsed_); |
| |
| for (Int32 i=0; i < numStringParamsUsed_; i++) |
| { |
| if (i < NumOptionalParms) |
| { |
| unpackBuffer(buffer, (char*&)optionalString_[i],collHeapPtr_); |
| |
| unpackBuffer(buffer,charSet); |
| optionalStringCharSet_[i] = (CharInfo::CharSet)charSet; |
| } |
| else |
| { |
| // Some future release might increase NumOptionalParms. |
| // In this case, ignore those additional parameters |
| // and set a flag indicating this. |
| skipCharStarInBuffer(buffer); |
| unpackBuffer(buffer,charSet); |
| foundUprevFieldsInBuffer = TRUE; |
| } |
| } |
| } |
| |
| if (usageMap_ & USED_NUM_INT_PARAMS) |
| { |
| Lng32 dummy; |
| |
| unpackBuffer(buffer,numIntParamsUsed_); |
| |
| for (Int32 i=0; i < numIntParamsUsed_; i++) |
| { |
| if (i < NumOptionalParms) |
| { |
| unpackBuffer(buffer,optionalInteger_[i]); |
| } |
| else |
| { |
| // Some future release might increase NumOptionalParms. |
| // In this case, ignore those additional parameters |
| // and set a flag indicating this. |
| unpackBuffer(buffer,dummy); |
| foundUprevFieldsInBuffer = TRUE; |
| } |
| } |
| } |
| |
| // Check whether there are more fields than we expect. For certain |
| // simple additions, we will not increase the version number of |
| // the diagnostics area or of the ComCondition object. |
| if ((usageMap_ & USED_FUTURE_FIELDS) || foundUprevFieldsInBuffer) |
| flagsTBS_ |= FLAGS_TBS_SUPPRESSED_UPREV_FIELDS; |
| } |
| |
| // So for each |
| // integer, we take its size. For each string, we add sizeof(long) |
| // to the length of the string plus 1 (except in the case of empty |
| // strings, that plus 1 is omitted, since NULL strings are considered |
| // empty and so have no buffers). |
| // |
| // Note that "long" is the type we use within the buffer |
| // to represent the length of a null-terminted buffer array. |
| // |
| // collHeapPtr_ is never passed via IPC; it gets setup in the constructor |
| // and the IPC unpack method fills in the other data using the heap |
| // specified in collHeapPtr_ to allocate string buffers as needed. |
| |
| IpcMessageObjSize ComCondition::packedLength(void) |
| { |
| // NOTE: changes to any of the following methods also require |
| // corresponding changes in the others: |
| // - packedLength() |
| // - packObjIntoMessage() |
| // - unpackObj() |
| // - checkObj() |
| |
| IpcMessageObjSize size=baseClassPackedLength(); |
| |
| // for now we set the usageMap_ flags here, but they |
| // could also be set in the accessor methods. This fields is needed |
| // in method packObjIntoMessage() |
| usageMap_ = 0; |
| |
| // the first two fields get sent unconditionally |
| size += sizeof(conditionNumber_); |
| size += sizeof(usageMap_); |
| size += sizeof(emsEventVisits_); |
| |
| // all other fields get sent only when needed |
| if (flagsTBS_) |
| { |
| size += sizeof(flagsTBS_); |
| usageMap_ += USED_FLAGS; |
| } |
| if (theSQLCODE_) |
| { |
| size += sizeof(theSQLCODE_); |
| usageMap_ |= USED_SQLCODE; |
| } |
| if (serverName_) |
| { |
| advanceSize(size,serverName_); |
| usageMap_ |= USED_SERVER_NAME; |
| } |
| if (connectionName_) |
| { |
| advanceSize(size,connectionName_); |
| usageMap_ |= USED_CONNECTION_NAME; |
| } |
| if (constraintCatalog_) |
| { |
| advanceSize(size,constraintCatalog_); |
| usageMap_ |= USED_CONSTRAINT_CATALOG; |
| } |
| if (constraintSchema_) |
| { |
| advanceSize(size,constraintSchema_); |
| usageMap_ |= USED_CONSTRAINT_SCHEMA; |
| } |
| if (constraintName_) |
| { |
| advanceSize(size,constraintName_); |
| usageMap_ |= USED_CONSTRAINT_NAME; |
| } |
| if (triggerCatalog_) |
| { |
| advanceSize(size,triggerCatalog_); |
| usageMap_ |= USED_TRIGGER_CATALOG; |
| } |
| if (triggerSchema_) |
| { |
| advanceSize(size,triggerSchema_); |
| usageMap_ |= USED_TRIGGER_SCHEMA; |
| } |
| if (triggerName_) |
| { |
| advanceSize(size,triggerName_); |
| usageMap_ |= USED_TRIGGER_NAME; |
| } |
| if (catalogName_) |
| { |
| advanceSize(size,catalogName_); |
| usageMap_ |= USED_CATALOG_NAME; |
| } |
| if (schemaName_) |
| { |
| advanceSize(size,schemaName_); |
| usageMap_ |= USED_SCHEMA_NAME; |
| } |
| if (tableName_) |
| { |
| advanceSize(size,tableName_); |
| usageMap_ |= USED_TABLE_NAME; |
| } |
| if (columnName_) |
| { |
| advanceSize(size,columnName_); |
| usageMap_ |= USED_COLUMN_NAME; |
| } |
| if (sqlID_) |
| { |
| advanceSize(size,sqlID_); |
| usageMap_ |= USED_SQLID; |
| } |
| if (rowNumber_ != INVALID_ROWNUMBER) |
| { |
| size += sizeof(rowNumber_); |
| usageMap_ |= USED_ROW_NUMBER; |
| } |
| if (nskCode_) |
| { |
| size += sizeof(nskCode_); |
| usageMap_ += USED_NSK_CODE; |
| } |
| if (customSQLState_) |
| { |
| advanceSize(size,customSQLState_); |
| usageMap_ |= USED_CUSTOM_SQLSTATE; |
| } |
| // if (isValidIsoMappingCharSet(iso88591MappingCharSet_)) |
| // { |
| // size += sizeof(iso88591MappingCharSet_); |
| // usageMap_ |= USED_ISO_MAPPING_CHARSET; |
| // } |
| |
| // set these two variables for later use in packObjIntoMessage() |
| numStringParamsUsed_ = 0; |
| numIntParamsUsed_ = 0; |
| for (Int32 i=NumOptionalParms; i--; ) |
| { |
| if (optionalString_[i] && numStringParamsUsed_ == 0) |
| { |
| // found the last string parameter used |
| numStringParamsUsed_ = i+1; |
| usageMap_ |= USED_NUM_STRING_PARAMS; |
| size += sizeof(numStringParamsUsed_); |
| } |
| if (optionalInteger_[i] != ComDiags_UnInitialized_Int && |
| numIntParamsUsed_ == 0) |
| { |
| // found the last integer parameter used |
| numIntParamsUsed_ = i+1; |
| usageMap_ |= USED_NUM_INT_PARAMS; |
| size += sizeof(numIntParamsUsed_); |
| } |
| |
| if (numStringParamsUsed_ > i) |
| { |
| // this string parameter needs to be sent |
| if ( isSingleByteCharSet(optionalStringCharSet_[i]) ) |
| advanceSize(size,(char*)optionalString_[i]); |
| else |
| advanceSize(size,(NAWchar*)optionalString_[i]); |
| size += sizeof(Lng32); // for optionalStringCharSet_[]; |
| } |
| if (numIntParamsUsed_ > i) |
| { |
| // this integer parameter needs to be sent |
| size += sizeof(optionalInteger_[0]); |
| } |
| } |
| |
| return size; |
| } |
| |
| IpcMessageObjSize ComCondition::packedLength32(void) |
| { |
| IpcMessageObjSize size = packedLength(); |
| // packed items should not include Longs or pointers |
| return size - (baseClassPackedLength() - baseClassPackedLength32()); |
| } |
| |
| IpcMessageObjSize ComCondition::packObjIntoMessage(char* buffer) |
| { |
| return packObjIntoMessage(buffer, FALSE); |
| } |
| |
| // Let us observe consistency (and thereby, hopefully, simplicity) by |
| // packing this object following the same order of visiting member data |
| // as we did in the packedLength() member function above. |
| |
| IpcMessageObjSize ComCondition::packObjIntoMessage(char* buffer, |
| NABoolean swapBytes) |
| { |
| // NOTE: changes to any of the following methods also require |
| // corresponding changes in the others: |
| // - packedLength() |
| // - packObjIntoMessage() |
| // - unpackObj() |
| // - checkObj() |
| |
| IpcMessageObjSize size=packBaseClassIntoMessage(buffer, swapBytes); |
| |
| // should have been set by packedLength() |
| assert(usageMap_); |
| |
| // pack some fields unconditionally |
| size += packIntoBuffer(buffer,conditionNumber_, swapBytes); |
| size += packIntoBuffer(buffer,usageMap_, swapBytes); |
| size += packIntoBuffer(buffer,emsEventVisits_, swapBytes); |
| |
| // fields packed conditionally |
| if (usageMap_ & USED_FLAGS) |
| size += packIntoBuffer(buffer,flagsTBS_, swapBytes); |
| if (usageMap_ & USED_SQLCODE) |
| size += packIntoBuffer(buffer,theSQLCODE_, swapBytes); |
| if (usageMap_ & USED_SERVER_NAME) |
| size += packCharStarIntoBuffer(buffer,serverName_, swapBytes); |
| if (usageMap_ & USED_CONNECTION_NAME) |
| size += packCharStarIntoBuffer(buffer,connectionName_, swapBytes); |
| if (usageMap_ & USED_CONSTRAINT_CATALOG) |
| size += packCharStarIntoBuffer(buffer,constraintCatalog_, swapBytes); |
| if (usageMap_ & USED_CONSTRAINT_SCHEMA) |
| size += packCharStarIntoBuffer(buffer,constraintSchema_, swapBytes); |
| if (usageMap_ & USED_CONSTRAINT_NAME) |
| size += packCharStarIntoBuffer(buffer,constraintName_, swapBytes); |
| if (usageMap_ & USED_TRIGGER_CATALOG) |
| size += packCharStarIntoBuffer(buffer,triggerCatalog_, swapBytes); |
| if (usageMap_ & USED_TRIGGER_SCHEMA) |
| size += packCharStarIntoBuffer(buffer,triggerSchema_, swapBytes); |
| if (usageMap_ & USED_TRIGGER_NAME) |
| size += packCharStarIntoBuffer(buffer,triggerName_, swapBytes); |
| if (usageMap_ & USED_CATALOG_NAME) |
| size += packCharStarIntoBuffer(buffer,catalogName_, swapBytes); |
| if (usageMap_ & USED_SCHEMA_NAME) |
| size += packCharStarIntoBuffer(buffer,schemaName_, swapBytes); |
| if (usageMap_ & USED_TABLE_NAME) |
| size += packCharStarIntoBuffer(buffer,tableName_, swapBytes); |
| if (usageMap_ & USED_COLUMN_NAME) |
| size += packCharStarIntoBuffer(buffer,columnName_, swapBytes); |
| if (usageMap_ & USED_SQLID) |
| size += packCharStarIntoBuffer(buffer,sqlID_, swapBytes); |
| if (usageMap_ & USED_ROW_NUMBER) |
| size += packIntoBuffer(buffer,rowNumber_, swapBytes); |
| if (usageMap_ & USED_NSK_CODE) |
| size += packIntoBuffer(buffer,nskCode_, swapBytes); |
| if (usageMap_ & USED_CUSTOM_SQLSTATE) |
| size += packCharStarIntoBuffer(buffer,customSQLState_, swapBytes); |
| // if (usageMap_ & USED_ISO_MAPPING_CHARSET) |
| // size += packIntoBuffer(buffer,iso88591MappingCharSet_); |
| |
| // pack string parameters up to the last used one |
| if (usageMap_ & USED_NUM_STRING_PARAMS) |
| { |
| size += packIntoBuffer(buffer,numStringParamsUsed_, swapBytes); |
| |
| for (Int32 i=0; i < numStringParamsUsed_; i++) |
| { |
| if ( isSingleByteCharSet(optionalStringCharSet_[i]) ) |
| size += packCharStarIntoBuffer(buffer, |
| (char*)optionalString_[i], swapBytes); |
| else |
| size += packCharStarIntoBuffer(buffer, |
| (NAWchar*)optionalString_[i], swapBytes); |
| |
| size += packIntoBuffer(buffer,(Lng32)optionalStringCharSet_[i], swapBytes); |
| } |
| } |
| |
| // pack integer parameters up to the last used one |
| if (usageMap_ & USED_NUM_INT_PARAMS) |
| { |
| size += packIntoBuffer(buffer, numIntParamsUsed_, swapBytes); |
| for (Int32 i=0; i < numIntParamsUsed_; i++) |
| { |
| size += packIntoBuffer(buffer,optionalInteger_[i], swapBytes); |
| } |
| } |
| |
| return size; |
| } |
| |
| IpcMessageObjSize ComCondition::packObjIntoMessage32(char* buffer) |
| { |
| return packObjIntoMessage32(buffer, FALSE); |
| } |
| |
| // Let us observe consistency (and thereby, hopefully, simplicity) by |
| // packing this object following the same order of visiting member data |
| // as we did in the packedLength() member function above. |
| |
| IpcMessageObjSize ComCondition::packObjIntoMessage32(char* buffer, |
| NABoolean swapBytes) |
| { |
| // NOTE: changes to any of the following methods also require |
| // corresponding changes in the others: |
| // - packedLength32() |
| // - packObjIntoMessage32() |
| // - unpackObj() |
| // - checkObj() |
| |
| IpcMessageObjSize size=packBaseClassIntoMessage32(buffer, swapBytes); |
| |
| // should have been set by packedLength() |
| assert(usageMap_); |
| |
| // pack some fields unconditionally |
| size += packIntoBuffer(buffer,conditionNumber_, swapBytes); |
| size += packIntoBuffer(buffer,usageMap_, swapBytes); |
| size += packIntoBuffer(buffer,emsEventVisits_, swapBytes); |
| |
| // fields packed conditionally |
| if (usageMap_ & USED_FLAGS) |
| size += packIntoBuffer(buffer,flagsTBS_, swapBytes); |
| if (usageMap_ & USED_SQLCODE) |
| size += packIntoBuffer(buffer,theSQLCODE_, swapBytes); |
| if (usageMap_ & USED_SERVER_NAME) |
| size += packCharStarIntoBuffer(buffer,serverName_, swapBytes); |
| if (usageMap_ & USED_CONNECTION_NAME) |
| size += packCharStarIntoBuffer(buffer,connectionName_, swapBytes); |
| if (usageMap_ & USED_CONSTRAINT_CATALOG) |
| size += packCharStarIntoBuffer(buffer,constraintCatalog_, swapBytes); |
| if (usageMap_ & USED_CONSTRAINT_SCHEMA) |
| size += packCharStarIntoBuffer(buffer,constraintSchema_, swapBytes); |
| if (usageMap_ & USED_CONSTRAINT_NAME) |
| size += packCharStarIntoBuffer(buffer,constraintName_, swapBytes); |
| if (usageMap_ & USED_TRIGGER_CATALOG) |
| size += packCharStarIntoBuffer(buffer,triggerCatalog_, swapBytes); |
| if (usageMap_ & USED_TRIGGER_SCHEMA) |
| size += packCharStarIntoBuffer(buffer,triggerSchema_, swapBytes); |
| if (usageMap_ & USED_TRIGGER_NAME) |
| size += packCharStarIntoBuffer(buffer,triggerName_, swapBytes); |
| if (usageMap_ & USED_CATALOG_NAME) |
| size += packCharStarIntoBuffer(buffer,catalogName_, swapBytes); |
| if (usageMap_ & USED_SCHEMA_NAME) |
| size += packCharStarIntoBuffer(buffer,schemaName_, swapBytes); |
| if (usageMap_ & USED_TABLE_NAME) |
| size += packCharStarIntoBuffer(buffer,tableName_, swapBytes); |
| if (usageMap_ & USED_COLUMN_NAME) |
| size += packCharStarIntoBuffer(buffer,columnName_, swapBytes); |
| if (usageMap_ & USED_SQLID) |
| size += packCharStarIntoBuffer(buffer,sqlID_, swapBytes); |
| if (usageMap_ & USED_ROW_NUMBER) |
| size += packIntoBuffer(buffer,rowNumber_, swapBytes); |
| if (usageMap_ & USED_NSK_CODE) |
| size += packIntoBuffer(buffer,nskCode_, swapBytes); |
| if (usageMap_ & USED_CUSTOM_SQLSTATE) |
| size += packCharStarIntoBuffer(buffer,customSQLState_, swapBytes); |
| // if (usageMap_ & USED_ISO_MAPPING_CHARSET) |
| // size += packIntoBuffer(buffer,iso88591MappingCharSet_); |
| |
| // pack string parameters up to the last used one |
| if (usageMap_ & USED_NUM_STRING_PARAMS) |
| { |
| size += packIntoBuffer(buffer,numStringParamsUsed_, swapBytes); |
| |
| for (Int32 i=0; i < numStringParamsUsed_; i++) |
| { |
| if ( isSingleByteCharSet(optionalStringCharSet_[i]) ) |
| size += packCharStarIntoBuffer(buffer, |
| (char*)optionalString_[i], swapBytes); |
| else |
| size += packCharStarIntoBuffer(buffer, |
| (NAWchar*)optionalString_[i], swapBytes); |
| |
| size += packIntoBuffer(buffer,(Lng32)optionalStringCharSet_[i], swapBytes); |
| } |
| } |
| |
| // pack integer parameters up to the last used one |
| if (usageMap_ & USED_NUM_INT_PARAMS) |
| { |
| size += packIntoBuffer(buffer, numIntParamsUsed_, swapBytes); |
| for (Int32 i=0; i < numIntParamsUsed_; i++) |
| { |
| size += packIntoBuffer(buffer,optionalInteger_[i], swapBytes); |
| } |
| } |
| |
| return size; |
| } |
| |
| NABoolean ComCondition::checkObj(IpcMessageObjType objType, |
| IpcMessageObjVersion objVersion, |
| NABoolean sameEndianness, |
| IpcMessageObjSize objSize, |
| IpcConstMessageBufferPtr buffer) const |
| { |
| // NOTE: changes to any of the following methods also require |
| // corresponding changes in the others: |
| // - packedLength() |
| // - packObjIntoMessage() |
| // - unpackObj() |
| // - checkObj() |
| |
| const IpcConstMessageBufferPtr lastByte = buffer + objSize - 1; |
| |
| if (!checkBaseClass(objType, objVersion, sameEndianness, objSize, buffer)) |
| return FALSE; |
| |
| // Some fields are packed unconditionally |
| if (!checkBuffer(buffer, sizeof(conditionNumber_), lastByte)) |
| return FALSE; |
| |
| Int32 map = 0; |
| if (!checkAndUnpackBuffer(buffer, sizeof(map), (char *) &map, lastByte)) |
| return FALSE; |
| if (!sameEndianness) |
| swapFourBytes(map); |
| |
| if (!checkBuffer(buffer, sizeof(emsEventVisits_), lastByte)) |
| return FALSE; |
| |
| // Some fields are packed conditionally |
| if (map & USED_FLAGS) |
| if (!checkBuffer(buffer, sizeof(flagsTBS_), lastByte)) |
| return FALSE; |
| |
| if (map & USED_SQLCODE) |
| { |
| if (!checkBuffer(buffer, sizeof(theSQLCODE_), lastByte)) |
| return FALSE; |
| } |
| else |
| { |
| return FALSE; |
| } |
| |
| if (map & USED_SERVER_NAME) |
| if (!checkCharStarInBuffer(buffer, sameEndianness, lastByte)) |
| return FALSE; |
| if (map & USED_CONNECTION_NAME) |
| if (!checkCharStarInBuffer(buffer, sameEndianness, lastByte)) |
| return FALSE; |
| if (map & USED_CONSTRAINT_CATALOG) |
| if (!checkCharStarInBuffer(buffer, sameEndianness, lastByte)) |
| return FALSE; |
| if (map & USED_CONSTRAINT_SCHEMA) |
| if (!checkCharStarInBuffer(buffer, sameEndianness, lastByte)) |
| return FALSE; |
| if (map & USED_CONSTRAINT_NAME) |
| if (!checkCharStarInBuffer(buffer, sameEndianness, lastByte)) |
| return FALSE; |
| if (map & USED_TRIGGER_CATALOG) |
| if (!checkCharStarInBuffer(buffer, sameEndianness, lastByte)) |
| return FALSE; |
| if (map & USED_TRIGGER_SCHEMA) |
| if (!checkCharStarInBuffer(buffer, sameEndianness, lastByte)) |
| return FALSE; |
| if (map & USED_TRIGGER_NAME) |
| if (!checkCharStarInBuffer(buffer, sameEndianness, lastByte)) |
| return FALSE; |
| if (map & USED_CATALOG_NAME) |
| if (!checkCharStarInBuffer(buffer, sameEndianness, lastByte)) |
| return FALSE; |
| if (map & USED_SCHEMA_NAME) |
| if (!checkCharStarInBuffer(buffer, sameEndianness, lastByte)) |
| return FALSE; |
| if (map & USED_TABLE_NAME) |
| if (!checkCharStarInBuffer(buffer, sameEndianness, lastByte)) |
| return FALSE; |
| if (map & USED_COLUMN_NAME) |
| if (!checkCharStarInBuffer(buffer, sameEndianness, lastByte)) |
| return FALSE; |
| if (map & USED_SQLID) |
| if (!checkCharStarInBuffer(buffer, sameEndianness, lastByte)) |
| return FALSE; |
| if (map & USED_ROW_NUMBER) |
| if (!checkBuffer(buffer, sizeof(rowNumber_), lastByte)) |
| return FALSE; |
| if (map & USED_NSK_CODE) |
| if (!checkBuffer(buffer, sizeof(nskCode_), lastByte)) |
| return FALSE; |
| if (map & USED_CUSTOM_SQLSTATE) |
| if (!checkCharStarInBuffer(buffer, sameEndianness, lastByte)) |
| return FALSE; |
| // if (map & USED_ISO_MAPPING_CHARSET) |
| // if (!checkBuffer(buffer, sizeof(iso88591MappingCharSet_), lastByte)) |
| // return FALSE; |
| |
| // Optional string parameters |
| if (map & USED_NUM_STRING_PARAMS) |
| { |
| Int32 numParams = 0; |
| if (!checkAndUnpackBuffer(buffer, sizeof(numParams), |
| (char *) &numParams, lastByte)) |
| return FALSE; |
| if (!sameEndianness) |
| swapFourBytes(numParams); |
| |
| for (Lng32 i = 0; i < numParams; i++) |
| { |
| if (!checkCharStarInBuffer(buffer, sameEndianness, lastByte)) |
| return FALSE; |
| if (!checkBuffer(buffer, sizeof(Lng32), lastByte)) // character set |
| return FALSE; |
| } |
| } |
| |
| // Optional integer parameters |
| if (map & USED_NUM_INT_PARAMS) |
| { |
| Int32 numParams = 0; |
| if (!checkAndUnpackBuffer(buffer, sizeof(numParams), |
| (char *) &numParams, lastByte)) |
| return FALSE; |
| if (!sameEndianness) |
| swapFourBytes(numParams); |
| |
| for (Lng32 i = 0; i < numParams; i++) |
| if (!checkBuffer(buffer, sizeof(Lng32), lastByte)) |
| return FALSE; |
| } |
| |
| return TRUE; |
| } |
| |
| // The set methods. |
| // |
| // Questions |
| // |
| // * Since each of these member functions is so similar, how about |
| // using C++ templates, or some mechanism, to factor the code? |
| // |
| // * Would the ``properties'' trick, shown in C++ Report magazine do the |
| // job? |
| // |
| // The pattern for how set strings |
| |
| void ComCondition::setServerName (const char *const name) |
| { |
| assert(!isLocked_); |
| assignStringMember(serverName_,name); |
| } |
| |
| // We can use this function in each of the char* ``set'' routines |
| // of the ComCondition class. |
| |
| // UR2 |
| void ComCondition::assignStringMember(NAWchar *& memberBuff,const NAWchar *const src) |
| { |
| if (collHeapPtr_ != NULL) { |
| // Just a char array, so no destructor call. |
| collHeapPtr_->deallocateMemory(memberBuff); |
| } |
| else |
| delete [] memberBuff; |
| memberBuff=NULL; // now memberBuff is cleared... |
| |
| // if src is non-NULL then we need to create a buff, copy it over... |
| if (src != NULL) { |
| UInt32 sourceLen = na_wcslen(src); // length in wide characters |
| UInt32 buffsize = (sourceLen + 1) * sizeof(NAWchar); // length in bytes |
| if (collHeapPtr_ != NULL) { |
| // Just a char array, so no construction needed. |
| memberBuff = (NAWchar*) (collHeapPtr_->allocateMemory(buffsize)); |
| assert(memberBuff != NULL); |
| } |
| else { |
| memberBuff = new NAWchar[sourceLen + 1]; |
| assert(memberBuff != NULL); |
| } |
| na_wcscpy(memberBuff,src); |
| memberBuff[sourceLen] = 0; |
| } |
| } |
| |
| void ComCondition::assignStringMember(char *& memberBuff,const char *const src) |
| { |
| if (collHeapPtr_ != NULL) { |
| // Just a char array, so no destructor call. |
| collHeapPtr_->deallocateMemory(memberBuff); |
| } |
| else |
| delete [] memberBuff; |
| memberBuff=NULL; // now memberBuff is cleared... |
| |
| // if src is non-NULL then we need to create a buff, copy it over... |
| if (src != NULL) { |
| UInt32 buffsize = str_len(src) + 1; |
| if (collHeapPtr_ != NULL) { |
| // Just a char array, so no construction needed. |
| memberBuff = (char*) (collHeapPtr_->allocateMemory(buffsize)); |
| assert(memberBuff != NULL); |
| } |
| else { |
| memberBuff = new char[buffsize]; |
| assert(memberBuff != NULL); |
| } |
| str_cpy(memberBuff,src,buffsize); |
| memberBuff[buffsize-1]=0; |
| } |
| } |
| |
| // Now we continue with the rest of the code for implementing the |
| // string-set functions. |
| |
| void ComCondition::setConnectionName (const char *const name) |
| { |
| assert(!isLocked_); |
| assert(name != NULL); |
| assignStringMember(connectionName_,name); |
| } |
| |
| void ComCondition::setConstraintCatalog (const char *const catalog) |
| { |
| assert(!isLocked_); |
| assert(catalog != NULL); |
| assignStringMember(constraintCatalog_,catalog); |
| } |
| |
| void ComCondition::setConstraintSchema (const char *const schema) |
| { |
| assert(!isLocked_); |
| assert(schema != NULL); |
| assignStringMember(constraintSchema_,schema); |
| } |
| |
| void ComCondition::setConstraintName (const char *const name) |
| { |
| assert(!isLocked_); |
| assert(name != NULL); |
| assignStringMember(constraintName_,name); |
| } |
| |
| void ComCondition::setTriggerCatalog (const char *const catalog) |
| { |
| assert(!isLocked_); |
| assert(catalog != NULL); |
| assignStringMember(triggerCatalog_,catalog); |
| } |
| |
| void ComCondition::setTriggerSchema (const char *const schema) |
| { |
| assert(!isLocked_); |
| assert(schema != NULL); |
| assignStringMember(triggerSchema_,schema); |
| } |
| |
| void ComCondition::setTriggerName (const char *const name) |
| { |
| assert(!isLocked_); |
| assert(name != NULL); |
| assignStringMember(triggerName_,name); |
| } |
| |
| void ComCondition::setCatalogName (const char *const name) |
| { |
| assert(!isLocked_); |
| assert(name != NULL); |
| assignStringMember(catalogName_,name); |
| } |
| |
| void ComCondition::setSchemaName (const char *const name) |
| { |
| assert(!isLocked_); |
| assert(name != NULL); |
| assignStringMember(schemaName_,name); |
| } |
| |
| void ComCondition::setTableName (const char *const name) |
| { |
| assert(!isLocked_); |
| assert(name != NULL); |
| assignStringMember(tableName_,name); |
| } |
| |
| void ComCondition::setCustomSQLState (const char *const customSQLState) |
| { |
| assert(!isLocked_); |
| assert(customSQLState != NULL); |
| assignStringMember(customSQLState_,customSQLState); |
| } |
| |
| void ComCondition::setColumnName (const char *const name) |
| { |
| assert(!isLocked_); |
| assert(name != NULL); |
| assignStringMember(columnName_,name); |
| } |
| |
| void ComCondition::setSqlID (const char *const name) |
| { |
| assert(!isLocked_); |
| assert(name != NULL); |
| assignStringMember(sqlID_,name); |
| } |
| |
| // Now we have three members which are concerned with setting intlike |
| // values. |
| |
| void ComCondition::setConditionNumber(ComDiagBigInt newCondition) |
| { |
| conditionNumber_ = newCondition; |
| } |
| |
| void ComCondition::setSQLCODE (Lng32 newSQLCODE) |
| { |
| theSQLCODE_ = newSQLCODE; |
| |
| if ( ! (theSQLCODE_ < 0) ) return; // if not an error return |
| |
| Lng32 theError = (theSQLCODE_ < 0) ? -theSQLCODE_ : theSQLCODE_; |
| |
| char *reqErrorStr = NULL; // user requested error to loop/abort on |
| Lng32 reqError = 0; |
| |
| if ( reqErrorStr = getenv("LOOP_ON_ERROR") ) { |
| reqError = strtol( reqErrorStr, (char **)NULL, 10) ; |
| if ( reqError > INT_MIN && reqError < INT_MAX && // no error in env var |
| reqError == theError ) // and this one is the requested error |
| { |
| UInt32 timeDelay = 3 ; // 3 seconds |
| short loopCount = 60; // 60 * 3 seconds = 3 minutes |
| Lng32 loopError = 1; |
| |
| while ( loopError ) // To exit loop in gdb do: set var loopError=0 |
| { |
| #ifdef _DEBUG |
| // In the debug build, notify the user we are looping by |
| // printing to stdout every 60 seconds |
| if (loopCount % 20 == 0) |
| { |
| NAProcessHandle myPhandle; |
| myPhandle.getmine(); |
| myPhandle.decompose(); |
| int pid = (int) myPhandle.getPin(); |
| int node = (int) myPhandle.getNodeNumber(); |
| |
| char timeString[40]; |
| timeval tv; |
| tm tx; |
| gettimeofday(&tv, NULL); |
| localtime_r(&tv.tv_sec, &tx); |
| snprintf(timeString, 40, "%04d-%02d-%02d %02d:%02d:%02d.%06d", |
| tx.tm_year + 1900, tx.tm_mon + 1, tx.tm_mday, |
| tx.tm_hour, tx.tm_min, tx.tm_sec, (int) tv.tv_usec); |
| |
| printf("(%d,%d) %s LOOP_ON_ERROR %d\n", |
| node, pid, timeString, (int) theError); |
| fflush(stdout); |
| } |
| #endif |
| |
| // log a message (with the process ID) every three minutes |
| if ( loopCount == 60 ) |
| SQLMXLoggingArea::logSQLMXDebugEvent("Loop on error", reqError,__LINE__); |
| |
| // Suspend the process for 'timeDelay' |
| sleep( timeDelay ); |
| |
| loopCount = (loopCount == 1) ? 60 : --loopCount; |
| } |
| } |
| } |
| |
| if ( reqErrorStr = getenv("ABORT_ON_ERROR") ) { |
| reqError = strtol( reqErrorStr, (char **)NULL, 10) ; |
| if ( reqError > INT_MIN && reqError < INT_MAX && // no error in env var |
| reqError == theError ) // and this one is the requested error |
| { |
| releaseRTSSemaphore(); |
| |
| // log a message |
| SQLMXLoggingArea::logSQLMXDebugEvent("Abort on error", reqError,__LINE__); |
| |
| abort(); // dump core |
| } |
| } |
| |
| // This code has been unit tested and most is also tested by |
| // executor/TEST082 |
| if ((theError == CLI_TCB_EXECUTE_ERROR) || // 8816 |
| (theError == CLI_INTERNAL_ERROR ) || // 8898 |
| (theError == EXE_INTERNAL_ERROR )) // 8001 |
| { |
| // make a core-file to help understand this scenario. But do |
| // return the error to the user. Notice that this Linux-only |
| // code is not compiled for EID. If this behavior make problems, |
| // it can be controlled by setting envvars . |
| static bool InternErrorMakesCorefileInitialized = false; |
| static bool corefile8816 = false; |
| static bool corefile8898 = false; |
| static bool corefile8001 = false; |
| if (!InternErrorMakesCorefileInitialized) |
| { |
| InternErrorMakesCorefileInitialized = true; |
| char *envvar = NULL; |
| envvar = getenv("SQLMX_COREFILE_8816"); |
| if (envvar && envvar[0] == '1') |
| corefile8816 = true; |
| envvar = getenv("SQLMX_COREFILE_8898"); |
| if (envvar && envvar[0] == '1') |
| corefile8898 = true; |
| envvar = getenv("SQLMX_COREFILE_8001"); |
| if (envvar && envvar[0] == '1') |
| corefile8001 = true; |
| } |
| if ( (corefile8816 && theError == CLI_TCB_EXECUTE_ERROR) || |
| (corefile8898 && theError == CLI_INTERNAL_ERROR ) || |
| (corefile8001 && theError == EXE_INTERNAL_ERROR ) ) |
| genLinuxCorefile( (char *) |
| "Generating core-file to capture internal error scenario."); |
| } |
| } |
| |
| void ComCondition::setRowNumber( Lng32 newRowNumber) |
| { |
| rowNumber_ = newRowNumber; |
| } |
| |
| void ComCondition::setNskCode( Lng32 newNskCode) |
| { |
| nskCode_ = newNskCode; |
| |
| char *reqErrorStr = NULL; |
| Lng32 reqError = 0; |
| |
| if ( reqErrorStr = getenv("LOOP_ON_NSK_ERROR") ) |
| { |
| reqError = strtol(reqErrorStr, (char **)NULL, 10); |
| if ( reqError > INT_MIN && reqError < INT_MAX && // no error in env var |
| reqError == newNskCode ) // and this one is the requested NSK error |
| { |
| UInt32 timeDelay = 3; // 3 seconds |
| short loopCount = 60; // 60 * 3 seconds = 3 minutes |
| Lng32 loopError = 1; |
| |
| while ( loopError ) // To exit loop in gdb do: set var loopError=0 |
| { |
| // log a message (with the process ID) every three minutes |
| if ( loopCount == 60 ) |
| SQLMXLoggingArea::logSQLMXDebugEvent("Loop on error", reqError,__LINE__); |
| |
| // Suspend the process for 'timeDelay' |
| sleep( timeDelay ); |
| |
| loopCount = (loopCount == 1) ? 60 : --loopCount; |
| } |
| } |
| } |
| |
| if ( reqErrorStr = getenv("ABORT_ON_NSK_ERROR") ) |
| { |
| reqError = strtol(reqErrorStr, (char **)NULL, 10); |
| if ( reqError > INT_MIN && reqError < INT_MAX && // no error in env var |
| reqError == newNskCode ) // and this one is the requested NSK error |
| { |
| releaseRTSSemaphore(); |
| |
| // log a message |
| SQLMXLoggingArea::logSQLMXDebugEvent("Abort on NSK error", reqError,__LINE__); |
| |
| abort(); // dump core |
| } |
| } |
| } |
| |
| // Getting and Setting the Optional Parameters |
| |
| Lng32 ComCondition::getOptionalInteger(Lng32 index) const |
| { |
| assert(index < NumOptionalParms); |
| // add the following to prevent false alarm on "index" |
| // without considering the above assert |
| // coverity[overrun_local] |
| return optionalInteger_[index]; |
| } |
| |
| void ComCondition::setOptionalInteger(Lng32 index, Lng32 newValue) |
| { |
| assert(index < NumOptionalParms); |
| // add the following to prevent false alarm on "index" |
| // without considering the above assert |
| // coverity[overrun_local] |
| optionalInteger_[index] = newValue; |
| } |
| |
| CharInfo::CharSet |
| ComCondition::getOptionalStringCharSet(Lng32 index) const |
| { |
| assert(index < NumOptionalParms); |
| // add the following to prevent false alarm on "index" |
| // without considering the above assert |
| // coverity[overrun_local] |
| return optionalStringCharSet_[index]; |
| } |
| |
| NABoolean ComCondition::hasOptionalString(Lng32 index) const |
| { |
| assert(index < NumOptionalParms); |
| |
| return optionalString_[index] != NULL; |
| } |
| |
| const char * ComCondition::getOptionalString(Lng32 index) const |
| { |
| assert(index < NumOptionalParms); |
| // add the following to prevent false alarm on "index" |
| // without considering the above assert |
| // coverity[overrun_local] |
| if (isSingleByteCharSet(optionalStringCharSet_[index])) |
| return (const char*)optionalString_[index]; |
| return NULL; |
| } |
| |
| const NAWchar * |
| ComCondition::getOptionalWString(Lng32 index) const |
| { |
| assert(index < NumOptionalParms); |
| // add the following to prevent false alarm on "index" |
| // without considering the above assert |
| // coverity[overrun_local] |
| if (optionalString_[index] == NULL) |
| return NULL; |
| if (! isSingleByteCharSet(optionalStringCharSet_[index])) |
| return (const NAWchar*)optionalString_[index]; |
| return NULL; |
| } |
| |
| void ComCondition::setOptionalString(Lng32 index, |
| const char* const source, |
| CharInfo::CharSet cs) |
| { |
| if (isSingleByteCharSet(cs)) { |
| // Do NOT "assert(source != NULL);" -- it's ok to pass in a NULL string |
| assert(index < NumOptionalParms); |
| // add the following to prevent false alarm on "index" |
| // without considering the above assert |
| // coverity[overrun_local] |
| optionalStringCharSet_[index] = cs; |
| assignStringMember((char*&)optionalString_[index],source); |
| } |
| else |
| setOptionalWString(index, (NAWchar*)source); |
| } |
| |
| void ComCondition::setOptionalWString(Lng32 index, |
| const NAWchar* const source) |
| // CharInfo::CharSet cs) ##hardcoded for now |
| { |
| CharInfo::CharSet cs = CharInfo::UNICODE; //hardcoded |
| // if (! isSingleByteCharSet(cs)) { ...as above... |
| |
| // Do NOT "assert(source != NULL);" -- it's ok to pass in a NULL string |
| assert(index < NumOptionalParms); |
| // add the following to prevent false alarm on "index" |
| // without considering the above assert |
| // coverity[overrun_local] |
| optionalStringCharSet_[index] = cs; |
| assignStringMember((NAWchar*&)optionalString_[index],source); |
| } |
| |
| // CharInfo::CharSet |
| // ComCondition::getIso88591MappingCharSet() const |
| // { |
| // // Return CharInfo::UnknownCharSet if the data member not set yet |
| // if ((usageMap_ & USED_ISO_MAPPING_CHARSET) && |
| // isValidIsoMappingCharSet(iso88591MappingCharSet_)) |
| // return iso88591MappingCharSet_; |
| // else |
| // return CharInfo::UnknownCharSet; |
| // } |
| |
| // void ComCondition::setIso88591MappingCharSet(CharInfo::CharSet cs) |
| // { |
| // // assert(isValidIsoMappingCharSet(cs)); |
| // usageMap_ |= USED_ISO_MAPPING_CHARSET; |
| // iso88591MappingCharSet_ = cs; |
| // } |
| |
| // ComDiags Methods Implemented |
| // |
| |
| ComDiagsArea::ComDiagsArea (CollHeap* ptr): IpcMessageObj(IPC_SQL_DIAG_AREA,0), |
| collHeapPtr_(ptr), |
| errors_(ptr), |
| warnings_(ptr), |
| newCondition_(NULL), |
| lengthLimit_(30), |
| areMore_(ComCondition::NO_MORE), |
| maxDiagsId_(0), |
| rowCount_(0), |
| avgStreamWaitTime_(-1), |
| cost_(0), |
| theSQLFunction_(NULL_FUNCTION), |
| flags_(0), |
| rowsetRowCountArray_(NULL) |
| { |
| // Initialize fillers space to 0 |
| memset(fillers_, 0, sizeof(fillers_)); |
| // Make sure the size of ComDiagsArea remains constant |
| // If you hit this after change or add new member, adjust the fillers_ size |
| Int32 classSize = sizeof(ComDiagsArea); |
| assert(classSize == 328); |
| } |
| |
| ComDiagsArea::ComDiagsArea () : IpcMessageObj(IPC_SQL_DIAG_AREA,0), |
| collHeapPtr_(NULL), |
| errors_(NULL), |
| warnings_(NULL), |
| newCondition_(NULL), |
| lengthLimit_(30), |
| areMore_(ComCondition::NO_MORE), |
| maxDiagsId_(0), |
| rowCount_(0), |
| avgStreamWaitTime_(-1), |
| cost_(0), |
| theSQLFunction_(NULL_FUNCTION), |
| flags_(0), |
| rowsetRowCountArray_(NULL) |
| { |
| // Initialize fillers space to 0 |
| memset(fillers_, 0, sizeof(fillers_)); |
| // Make sure the size of ComDiagsArea remains constant |
| // If you hit this after change or add new member, adjust the fillers_ size |
| Int32 classSize = sizeof(ComDiagsArea); |
| |
| |
| // if (classSize != 320) printf("classSize=%d @ %d\n", classSize, __LINE__); |
| assert(classSize == 328); |
| } |
| |
| |
| // We want to clear out the errors and warnings lists, and free |
| // the objects contained therein. We want to set collHeapPtr_ to |
| // NULL (just in case!). |
| // |
| // Questions |
| // |
| // * Is there a better way to iterate over all members of a LIST? |
| |
| ComDiagsArea::~ComDiagsArea () |
| { |
| CollIndex i=0; |
| while (i!=errors_.entries()) errors_[i++]->deAllocate(); |
| i=0; |
| while (i!=warnings_.entries()) warnings_[i++]->deAllocate(); |
| if (newCondition_ != NULL) { |
| newCondition_->deAllocate(); |
| newCondition_=NULL; |
| } |
| errors_.clear(); |
| warnings_.clear(); |
| flags_ = 0; |
| if (rowsetRowCountArray_ != NULL) { |
| rowsetRowCountArray_->deallocate(); |
| rowsetRowCountArray_ = NULL; |
| } |
| } |
| |
| void ComDiagsArea::enforceLengthLimit() |
| { |
| const Lng32 currentCount = getNumber(); |
| if ((lengthLimit_ != ComCondition::NO_LIMIT_ON_ERROR_CONDITIONS) && |
| (currentCount > lengthLimit_)) { |
| Lng32 numToDiscard = currentCount - lengthLimit_; |
| // soln:10-050204-4441 : maxDiagsId_ member needs to be updated so as to |
| // maintain consistency between count(error) + count(warnings) and maxDiagsId_ |
| // upon exceeding lengthLimit_.This is done here as numToDiscard is modified |
| // in this function. |
| maxDiagsId_ = maxDiagsId_ - numToDiscard; |
| if (numToDiscard > (Lng32) warnings_.entries()) { |
| assert(errors_.entries() >= (numToDiscard-warnings_.entries())); |
| |
| // First, drop all warnings. |
| CollIndex i=0; |
| while (i!=warnings_.entries()) warnings_[i++]->deAllocate(); |
| warnings_.clear(); |
| |
| // Second, drop the proper number of errors from the end of the list. |
| // make errors a sequence 1..j, where j = errors_.entries() - |
| // (numToDiscard-warnings_.entries()) |
| |
| numToDiscard = numToDiscard - warnings_.entries(); |
| CollIndex j = errors_.entries() - numToDiscard; |
| while (numToDiscard-- != 0) { |
| errors_[j]->deAllocate();// remove near end and slide towards front |
| NABoolean removeResult = errors_.removeAt(j); |
| assert(removeResult); // sanity check |
| } |
| areMore_ = ComCondition::MORE_ERRORS ; |
| } |
| else { |
| // make warnings a sequence 1..j, where j = warnings_.entries() - |
| // numToDiscard |
| CollIndex j = warnings_.entries() - numToDiscard; |
| while (numToDiscard-- != 0) { |
| warnings_[j]->deAllocate();// remove near end and slide towards front |
| NABoolean removeResult = warnings_.removeAt(j); |
| assert(removeResult); // sanity check |
| } |
| areMore_ = ComCondition::MORE_WARNINGS ; |
| } |
| } |
| } |
| |
| |
| void ComDiagsArea::unpackObj(IpcMessageObjType objType, |
| IpcMessageObjVersion objVersion, |
| Int32 sameEndianness, |
| IpcMessageObjSize objSize, |
| const char* buffer) |
| { |
| // NOTE: changes to any of the following methods also require |
| // corresponding changes in the others: |
| // - packedLength() |
| // - packObjIntoMessage() |
| // - unpackObj() |
| // - checkObj() |
| |
| short extraFieldsLen; |
| |
| assert(newCondition_ == NULL); |
| // rowsetRowCountArray should be null as it is shipped across process boundaries. |
| assert(rowsetRowCountArray_ == NULL); |
| unpackBaseClass(buffer); |
| unpackBuffer(buffer,areMore_); |
| unpackBuffer(buffer,lengthLimit_); |
| unpackBuffer(buffer,rowCount_); |
| unpackBuffer(buffer,avgStreamWaitTime_); |
| unpackBuffer(buffer,cost_); |
| unpackBuffer(buffer,theSQLFunction_); |
| unpackBuffer(buffer,maxDiagsId_); |
| unpackBuffer(buffer,flags_); |
| // length of fields added in a later version, just skip them |
| unpackBuffer(buffer,extraFieldsLen); |
| buffer += extraFieldsLen; |
| |
| short num; |
| unpackBuffer(buffer,num); |
| CollIndex index=0; |
| while (index!=(CollIndex)num) { |
| // don't forget to append a new object...created on which heap |
| // is the right one! |
| DiagsCondition *newObject = DiagsCondition::allocate(collHeapPtr_); |
| assert(newObject != NULL); |
| newObject->unpackDependentObjFromBuffer(buffer, sameEndianness); |
| errors_.insert(newObject); |
| index++; |
| } |
| unpackBuffer(buffer,num); |
| index = 0; |
| while (index!=(CollIndex) num) { |
| // don't forget to append a new object...created on which heap |
| // is the right one! And, yes, it's true that this loop body |
| // is a copy/paste of the loop body of the above while loop. |
| DiagsCondition *newObject = DiagsCondition::allocate(collHeapPtr_); |
| assert(newObject != NULL); |
| newObject->unpackDependentObjFromBuffer(buffer, sameEndianness); |
| warnings_.insert(newObject); |
| index++; |
| } |
| if (lengthLimit_ != ComCondition::NO_LIMIT_ON_ERROR_CONDITIONS) |
| assert( getNumber() <= lengthLimit_ ); |
| |
| // unpack fillers_ part |
| unpackStrFromBuffer(buffer, fillers_, sizeof(fillers_)); |
| } |
| |
| |
| // unpack ComDiagsArea sent from 32-bit (BDR) server |
| void ComDiagsArea::unpackObj32(IpcMessageObjType objType, |
| IpcMessageObjVersion objVersion, |
| Int32 sameEndianness, |
| IpcMessageObjSize objSize, |
| const char* buffer) |
| { |
| // NOTE: changes to any of the following methods also require |
| // corresponding changes in the others: |
| // - packedLength() |
| // - packObjIntoMessage() |
| // - unpackObj() |
| // - checkObj() |
| |
| short extraFieldsLen; |
| |
| assert(newCondition_ == NULL); |
| // rowsetRowCountArray should be null as it is shipped across process boundaries. |
| assert(rowsetRowCountArray_ == NULL); |
| unpackBaseClass32(buffer); |
| unpackBuffer(buffer,areMore_); |
| unpackBuffer(buffer,lengthLimit_); |
| unpackBuffer(buffer,rowCount_); |
| unpackBuffer(buffer,avgStreamWaitTime_); |
| unpackBuffer(buffer,cost_); |
| unpackBuffer(buffer,theSQLFunction_); |
| unpackBuffer(buffer,maxDiagsId_); |
| unpackBuffer(buffer,flags_); |
| // length of fields added in a later version, just skip them |
| unpackBuffer(buffer,extraFieldsLen); |
| buffer += extraFieldsLen; |
| |
| short num; |
| unpackBuffer(buffer,num); |
| CollIndex index=0; |
| while (index!=(CollIndex)num) { |
| // don't forget to append a new object...created on which heap |
| // is the right one! |
| DiagsCondition *newObject = DiagsCondition::allocate(collHeapPtr_); |
| assert(newObject != NULL); |
| newObject->unpackDependentObjFromBuffer32(buffer, sameEndianness); |
| errors_.insert(newObject); |
| index++; |
| } |
| unpackBuffer(buffer,num); |
| index = 0; |
| while (index!=(CollIndex) num) { |
| // don't forget to append a new object...created on which heap |
| // is the right one! And, yes, it's true that this loop body |
| // is a copy/paste of the loop body of the above while loop. |
| DiagsCondition *newObject = DiagsCondition::allocate(collHeapPtr_); |
| assert(newObject != NULL); |
| newObject->unpackDependentObjFromBuffer32(buffer, sameEndianness); |
| warnings_.insert(newObject); |
| index++; |
| } |
| if (lengthLimit_ != ComCondition::NO_LIMIT_ON_ERROR_CONDITIONS) |
| assert( getNumber() <= lengthLimit_ ); |
| |
| // unpack fillers_ part |
| unpackStrFromBuffer(buffer, fillers_, sizeof(fillers_)); |
| } |
| |
| |
| // The packed length of a ComDiagsObject is the sum of the sizes |
| // of the integer members plus the sum of the sizes of the string |
| // members (see the comments for ComCondition::packedLength() to see |
| // how string length is determined). We omit the collHeapPtr_ since |
| // it is not transferred via IPC (see comments for |
| // ComCondition::packedLength). |
| // |
| // We must include the length of the warning and error lists as well. |
| // the length of a list is the sum of the size of an short |
| // (which tells number of elements) and the sum of the sizes of the |
| // individual member ComCondition objects. |
| // |
| // Let us not forget the size of the base class. |
| // |
| // We do not pack newCondition_. |
| IpcMessageObjSize ComDiagsArea::packedLength(void) |
| { |
| // NOTE: changes to any of the following methods also require |
| // corresponding changes in the others: |
| // - packedLength() |
| // - packObjIntoMessage() |
| // - unpackObj() |
| // - checkObj() |
| |
| IpcMessageObjSize size=baseClassPackedLength(); |
| |
| short extraFieldsLen = 0; // no extra fields yet in Release 1.5 |
| |
| // rowsetRowCountArray was added in after R2. It does not need |
| // to be packed/unpacked as it is used only in the master. Just |
| // skip this data member during pack/unpack. |
| extraFieldsLen = sizeof(rowsetRowCountArray_); |
| |
| size += sizeof(areMore_); |
| size += sizeof(lengthLimit_); |
| size += sizeof(rowCount_); |
| size += sizeof(avgStreamWaitTime_); |
| size += sizeof(cost_); |
| size += sizeof(theSQLFunction_); |
| size += sizeof(maxDiagsId_); |
| size += sizeof(flags_); |
| size += sizeof(extraFieldsLen); |
| size += sizeof(rowsetRowCountArray_); |
| |
| // For the error and warning list (in that order) we add the size |
| // for two shorts, for lengths, then we visit all |
| // DiagsCondition objects and sum their sizes as well. |
| |
| size += sizeof(short); |
| CollIndex index = 0; |
| while (index != errors_.entries()) { |
| alignSizeForNextObj(size); |
| size += (errors_[index])->packedLength(); |
| index++; |
| } |
| size += sizeof(short); |
| index = 0; |
| while (index != warnings_.entries()) { |
| alignSizeForNextObj(size); |
| size += (warnings_[index])->packedLength(); |
| index++; |
| } |
| |
| // Add the fillers_ size too |
| size += sizeof(fillers_); |
| |
| return size; |
| } |
| |
| |
| IpcMessageObjSize ComDiagsArea::packedLength32(void) |
| { |
| // NOTE: changes to any of the following methods also require |
| // corresponding changes in the others: |
| // - packedLength32() |
| // - packObjIntoMessage32() |
| // - unpackObj() |
| // - checkObj() |
| |
| IpcMessageObjSize size=baseClassPackedLength32(); |
| |
| short extraFieldsLen = 0; // no extra fields yet in Release 1.5 |
| |
| // rowsetRowCountArray was added in after R2. It does not need |
| // to be packed/unpacked as it is used only in the master. Just |
| // skip this data member during pack/unpack. |
| extraFieldsLen = sizeof(rowsetRowCountArray_); |
| |
| size += sizeof(areMore_); |
| size += sizeof(lengthLimit_); |
| size += sizeof(rowCount_); |
| size += sizeof(avgStreamWaitTime_); |
| size += sizeof(cost_); |
| size += sizeof(theSQLFunction_); |
| size += sizeof(maxDiagsId_); |
| size += sizeof(flags_); |
| size += sizeof(extraFieldsLen); |
| size += sizeof(rowsetRowCountArray_); |
| |
| // For the error and warning list (in that order) we add the size |
| // for two shorts, for lengths, then we visit all |
| // DiagsCondition objects and sum their sizes as well. |
| |
| size += sizeof(short); |
| CollIndex index = 0; |
| while (index != errors_.entries()) { |
| alignSizeForNextObj(size); |
| size += (errors_[index])->packedLength32(); |
| index++; |
| } |
| size += sizeof(short); |
| index = 0; |
| while (index != warnings_.entries()) { |
| alignSizeForNextObj(size); |
| size += (warnings_[index])->packedLength32(); |
| index++; |
| } |
| |
| // Add the fillers_ size too |
| size += sizeof(fillers_); |
| |
| return size; |
| } |
| |
| IpcMessageObjSize ComDiagsArea::packObjIntoMessage(char *buffer) |
| { |
| return packObjIntoMessage(buffer, FALSE); |
| } |
| |
| IpcMessageObjSize ComDiagsArea::packObjIntoMessage(char* buffer, |
| NABoolean swapBytes) |
| { |
| // NOTE: changes to any of the following methods also require |
| // corresponding changes in the others: |
| // - packedLength() |
| // - packObjIntoMessage() |
| // - unpackObj() |
| // - checkObj() |
| IpcMessageObjSize size=packBaseClassIntoMessage(buffer, swapBytes); |
| |
| |
| short extraFieldsLen = 0; // no extra fields yet in Release 1.5 |
| |
| // rowsetRowCountArray was added in after R2. It does not need |
| // to be packed/unpacked as it is used only in the master. Just |
| // skip this data member during pack/unpack. |
| extraFieldsLen = sizeof(rowsetRowCountArray_); |
| |
| size += packIntoBuffer(buffer,areMore_, swapBytes); |
| size += packIntoBuffer(buffer,lengthLimit_, swapBytes); |
| size += packIntoBuffer(buffer,rowCount_, swapBytes); |
| size += packIntoBuffer(buffer,avgStreamWaitTime_, swapBytes); |
| double tempCost = cost_; |
| // Double scalar data type will not work with bswap_64 |
| // hence doing it here by casting it Int64 |
| if (swapBytes) |
| tempCost = bswap_64((Int64)cost_); |
| size += packIntoBuffer(buffer,tempCost); |
| size += packIntoBuffer(buffer,theSQLFunction_, swapBytes); |
| size += packIntoBuffer(buffer,maxDiagsId_, swapBytes); |
| size += packIntoBuffer(buffer,flags_, swapBytes); |
| size += packIntoBuffer(buffer,extraFieldsLen, swapBytes); |
| |
| // If fields get added after Release 1.5 without wanting to do |
| // major versioning changes, add them here and set extraFieldsLen |
| // to their length. Release 1.5 code will then simply ignore the extra |
| // fields. |
| |
| // rowsetRowCountArray should be null as it is shipped across process boundaries. |
| assert(rowsetRowCountArray_ == NULL); |
| size += packIntoBuffer(buffer,rowsetRowCountArray_); |
| |
| short num = (short) errors_.entries(); |
| short numToPack = num; |
| |
| #ifdef _DEBUG |
| // In the debug build we allow the UDR server to generate a corrupt |
| // packed object. This allows us to test error handling in the |
| // executor. The MXUDR_DEBUG_BUILD variable is always set by the |
| // debug UDR server and we only test it once. We test |
| // MXUDR_CORRUPT_DIAGS_REPLY every time we come here in the UDR |
| // server. |
| static NABoolean inUdrServer = (getenv("MXUDR_DEBUG_BUILD") != NULL); |
| if (inUdrServer) |
| { |
| char *val = getenv("MXUDR_CORRUPT_DIAGS_REPLY"); |
| if (val && val[0]) |
| { |
| numToPack++; |
| } |
| } |
| #endif |
| |
| size += packIntoBuffer(buffer, numToPack, swapBytes); |
| |
| |
| CollIndex index=0; |
| while (index!= (CollIndex) num) { |
| IpcMessageObjSize temp = |
| (errors_[index])->packDependentObjIntoMessage(buffer, swapBytes); |
| size += temp; |
| buffer += temp; |
| index++; |
| } |
| num = ( short) warnings_.entries(); |
| size += packIntoBuffer(buffer,num, swapBytes); |
| index = 0; |
| while (index!= (CollIndex) num) { |
| IpcMessageObjSize temp = |
| (warnings_[index])->packDependentObjIntoMessage(buffer, swapBytes); |
| size += temp; |
| buffer += temp; |
| index++; |
| } |
| |
| // Pack the fillers part too |
| size += packStrIntoBuffer(buffer, fillers_, sizeof(fillers_)); |
| |
| return size; |
| } |
| |
| |
| // pack object to buffer to be read by 32-bit (BDR) client |
| IpcMessageObjSize ComDiagsArea::packObjIntoMessage32(char *buffer) |
| { |
| return packObjIntoMessage32(buffer, FALSE); |
| } |
| |
| IpcMessageObjSize ComDiagsArea::packObjIntoMessage32(char* buffer, |
| NABoolean swapBytes) |
| { |
| // NOTE: changes to any of the following methods also require |
| // corresponding changes in the others: |
| // - packedLength32() |
| // - packObjIntoMessage32() |
| // - unpackObj() |
| // - checkObj() |
| IpcMessageObjSize size=packBaseClassIntoMessage32(buffer, swapBytes); |
| |
| |
| short extraFieldsLen = 0; // no extra fields yet in Release 1.5 |
| |
| // rowsetRowCountArray was added in after R2. It does not need |
| // to be packed/unpacked as it is used only in the master. Just |
| // skip this data member during pack/unpack. |
| extraFieldsLen = sizeof(rowsetRowCountArray_); |
| |
| size += packIntoBuffer(buffer,areMore_, swapBytes); |
| size += packIntoBuffer(buffer,lengthLimit_, swapBytes); |
| size += packIntoBuffer(buffer,rowCount_, swapBytes); |
| size += packIntoBuffer(buffer,avgStreamWaitTime_, swapBytes); |
| double tempCost = cost_; |
| // Double scalar data type will not work with bswap_64 |
| // hence doing it here by casting it Int64 |
| if (swapBytes) |
| tempCost = bswap_64((Int64)cost_); |
| size += packIntoBuffer(buffer,tempCost); |
| size += packIntoBuffer(buffer,theSQLFunction_, swapBytes); |
| size += packIntoBuffer(buffer,maxDiagsId_, swapBytes); |
| size += packIntoBuffer(buffer,flags_, swapBytes); |
| size += packIntoBuffer(buffer,extraFieldsLen, swapBytes); |
| |
| // If fields get added after Release 1.5 without wanting to do |
| // major versioning changes, add them here and set extraFieldsLen |
| // to their length. Release 1.5 code will then simply ignore the extra |
| // fields. |
| |
| // rowsetRowCountArray should be null as it is shipped across process boundaries. |
| assert(rowsetRowCountArray_ == NULL); |
| size += packIntoBuffer(buffer,rowsetRowCountArray_); |
| |
| short num = (short) errors_.entries(); |
| short numToPack = num; |
| |
| #ifdef _DEBUG |
| // In the debug build we allow the UDR server to generate a corrupt |
| // packed object. This allows us to test error handling in the |
| // executor. The MXUDR_DEBUG_BUILD variable is always set by the |
| // debug UDR server and we only test it once. We test |
| // MXUDR_CORRUPT_DIAGS_REPLY every time we come here in the UDR |
| // server. |
| static NABoolean inUdrServer = (getenv("MXUDR_DEBUG_BUILD") != NULL); |
| if (inUdrServer) |
| { |
| char *val = getenv("MXUDR_CORRUPT_DIAGS_REPLY"); |
| if (val && val[0]) |
| { |
| numToPack++; |
| } |
| } |
| #endif |
| |
| size += packIntoBuffer(buffer, numToPack, swapBytes); |
| |
| |
| CollIndex index=0; |
| while (index!= (CollIndex) num) { |
| IpcMessageObjSize temp = |
| (errors_[index])->packDependentObjIntoMessage32(buffer, swapBytes); |
| size += temp; |
| buffer += temp; |
| index++; |
| } |
| num = ( short) warnings_.entries(); |
| size += packIntoBuffer(buffer,num, swapBytes); |
| index = 0; |
| while (index!= (CollIndex) num) { |
| IpcMessageObjSize temp = |
| (warnings_[index])->packDependentObjIntoMessage32(buffer, swapBytes); |
| size += temp; |
| buffer += temp; |
| index++; |
| } |
| |
| // Pack the fillers part too |
| size += packStrIntoBuffer(buffer, fillers_, sizeof(fillers_)); |
| |
| return size; |
| } |
| |
| NABoolean ComDiagsArea::checkObj(IpcMessageObjType objType, |
| IpcMessageObjVersion objVersion, |
| NABoolean sameEndianness, |
| IpcMessageObjSize objSize, |
| IpcConstMessageBufferPtr buffer) const |
| { |
| // NOTE: changes to any of the following methods also require |
| // corresponding changes in the others: |
| // - packedLength() |
| // - packObjIntoMessage() |
| // - unpackObj() |
| // - checkObj() |
| |
| const IpcConstMessageBufferPtr lastByte = buffer + objSize - 1; |
| |
| if (!checkBaseClass(objType, objVersion, sameEndianness, objSize, buffer)) |
| return FALSE; |
| |
| if (!checkBuffer(buffer, sizeof(areMore_), lastByte)) |
| return FALSE; |
| |
| Int32 lengthLimit = 0; |
| if (!checkAndUnpackBuffer(buffer, sizeof(lengthLimit), |
| (char *) &lengthLimit, lastByte)) |
| return FALSE; |
| if (!sameEndianness) |
| swapFourBytes(lengthLimit); |
| |
| if (!checkBuffer(buffer, |
| sizeof(rowCount_) |
| + sizeof(avgStreamWaitTime_) |
| + sizeof(cost_) |
| + sizeof(theSQLFunction_) |
| + sizeof(maxDiagsId_) |
| + sizeof(flags_) |
| , lastByte)) |
| return FALSE; |
| |
| short extraFieldsLen = 0; |
| if (!checkAndUnpackBuffer(buffer, sizeof(extraFieldsLen), |
| (char *) &extraFieldsLen, lastByte)) |
| return FALSE; |
| if (!sameEndianness) |
| swapTwoBytes(extraFieldsLen); |
| |
| // from NEO/Coyote releases extraFieldsLen should include |
| // sizeof(rowsetRowCountArray_). There is no unpacking |
| // to be done here as this data member is NULL at this point. |
| if (!checkBuffer(buffer, extraFieldsLen, lastByte)) |
| return FALSE; |
| |
| short i; |
| short numErrors = 0; |
| short numWarnings = 0; |
| DiagsCondition cond; |
| |
| // Error conditions |
| if (!checkAndUnpackBuffer(buffer, sizeof(numErrors), |
| (char *) &numErrors, lastByte)) |
| return FALSE; |
| if (!sameEndianness) |
| swapTwoBytes(numErrors); |
| |
| for (i = 0; i < numErrors; i++) |
| if (!cond.checkDependentObj(buffer, sameEndianness)) |
| return FALSE; |
| |
| // Warning conditions |
| if (!checkAndUnpackBuffer(buffer, sizeof(numWarnings), |
| (char *) &numWarnings, lastByte)) |
| return FALSE; |
| if (!sameEndianness) |
| swapTwoBytes(numWarnings); |
| |
| for (i = 0; i < numWarnings; i++) |
| if (!cond.checkDependentObj(buffer, sameEndianness)) |
| return FALSE; |
| |
| if ((numErrors + numWarnings) > lengthLimit) |
| { |
| ipcIntegrityCheckEpilogue(FALSE); |
| return FALSE; |
| } |
| |
| // Check fillers_ part |
| if (!checkBuffer(buffer, sizeof(fillers_), lastByte)) |
| return FALSE; |
| |
| return TRUE; |
| } |
| |
| // Accessors for Basic Info |
| // |
| // This returns the sum of the number of |
| // elements in errors_ and warnings_. |
| |
| Lng32 ComDiagsArea::getNumber () const |
| { |
| return errors_.entries() + warnings_.entries(); |
| } |
| |
| Lng32 ComDiagsArea::getNumber (DgSqlCode::ErrorOrWarning type) const |
| { |
| switch (type) { |
| case DgSqlCode::ERROR_: return errors_.entries(); |
| case DgSqlCode::WARNING_: return warnings_.entries(); |
| default: return -1; |
| } |
| } |
| |
| |
| NABoolean ComDiagsArea::areMore () const |
| { |
| return (areMore_ != ComCondition::NO_MORE); |
| } |
| |
| NABoolean ComDiagsArea::canAcceptMoreErrors () const |
| { |
| return (areMore_ != ComCondition::MORE_ERRORS); |
| } |
| |
| |
| Int64 ComDiagsArea::getRowCount () const |
| { |
| return rowCount_; |
| } |
| |
| void ComDiagsArea::addRowCount (Int64 newRowCount) |
| { |
| rowCount_ += newRowCount; |
| } |
| |
| void ComDiagsArea::setRowCount (Int64 newRowCount) |
| { |
| rowCount_ = newRowCount; |
| } |
| |
| ComDiagBigInt ComDiagsArea::getAvgStreamWaitTime () const |
| { |
| return avgStreamWaitTime_; |
| } |
| |
| void ComDiagsArea::setAvgStreamWaitTime (ComDiagBigInt avgStreamWaitTime ) |
| { |
| avgStreamWaitTime_ = avgStreamWaitTime; |
| } |
| |
| double ComDiagsArea::getCost () const |
| { |
| return cost_; |
| } |
| |
| void ComDiagsArea::setCost (double newCost) |
| { |
| cost_ = newCost; |
| } |
| |
| // |
| // setAllSqlID |
| // |
| // Traverse through the conditions from the latest to the earliest and |
| // set any unknown sql ids. Stop at the first one that is already set |
| // since we've already seen it in a past execution. (This functions |
| // the same way as setAllRowNumber.) |
| // |
| |
| void ComDiagsArea::setAllSqlID (char *sqlID) |
| { |
| if (!sqlID) return; |
| |
| Lng32 errorCount = getNumber(DgSqlCode::ERROR_); |
| Int32 i = 0; |
| for(i=0; i < errorCount; i++) { |
| ComCondition* errCond = getErrorEntry(errorCount-i); |
| if (errCond->getSqlID() == NULL) |
| errCond->setSqlID(sqlID); |
| else |
| break ; |
| } |
| Lng32 warnCount = getNumber(DgSqlCode::WARNING_); |
| for(i=0; i < warnCount; i++) { |
| ComCondition* warnCond = getWarningEntry(warnCount-i); |
| if (warnCond->getSqlID() == NULL) |
| warnCond->setSqlID(sqlID); |
| else |
| break ; |
| } |
| } |
| |
| void ComDiagsArea::setAllRowNumber (Lng32 rowNum, DgSqlCode::ErrorOrWarning errOrWarn) |
| { |
| if (errOrWarn != DgSqlCode::WARNING_) |
| { |
| Lng32 errorCount = getNumber(DgSqlCode::ERROR_); |
| for(Int32 i=0; i < errorCount; i++) { |
| ComCondition* errCond = getErrorEntry(errorCount-i); |
| if (errCond->getRowNumber() < 0) |
| errCond->setRowNumber(rowNum); |
| else |
| break ; |
| } |
| } |
| else |
| { |
| Lng32 warnCount = getNumber(DgSqlCode::WARNING_); |
| for(Int32 i=0; i < warnCount; i++) { |
| ComCondition* warnCond = getWarningEntry(warnCount-i); |
| if (warnCond->getRowNumber() < 0) |
| warnCond->setRowNumber(rowNum); |
| else |
| break ; |
| } |
| } |
| } |
| |
| |
| Lng32 ComDiagsArea::getNextRowNumber (Lng32 indexValue) const |
| { |
| Lng32 errorCount = getNumber(DgSqlCode::ERROR_); |
| Lng32 nextRowNumber = ComCondition::INVALID_ROWNUMBER; |
| |
| for(Int32 i=0; i < errorCount; i++) { |
| ComCondition* errCond = ((ComDiagsArea *) this)->getErrorEntry(i+1); |
| if ((errCond->getRowNumber() != ComCondition::INVALID_ROWNUMBER) && |
| (errCond->getRowNumber() >= indexValue)) { |
| if ((nextRowNumber == ComCondition::INVALID_ROWNUMBER) || |
| (errCond->getRowNumber() < nextRowNumber)) { |
| nextRowNumber = errCond->getRowNumber(); |
| } |
| } |
| } |
| return nextRowNumber ; |
| } |
| |
| |
| NABoolean ComDiagsArea::hasValidRowsetRowCountArray () const |
| { |
| return (rowsetRowCountArray_ != NULL); |
| } |
| |
| |
| Lng32 ComDiagsArea::numEntriesInRowsetRowCountArray () const |
| { |
| if (rowsetRowCountArray_) |
| return (Lng32) rowsetRowCountArray_->entries(); |
| else |
| return 0; |
| } |
| |
| void ComDiagsArea::insertIntoRowsetRowCountArray (Lng32 index, Int64 value, |
| Lng32 arraySize, CollHeap* heapPtr) |
| { |
| if (rowsetRowCountArray_ == NULL) |
| { |
| if (heapPtr) |
| rowsetRowCountArray_ = new (heapPtr) NAArray<Int64>(heapPtr,arraySize); |
| else |
| rowsetRowCountArray_ = new (collHeapPtr_) NAArray<Int64>(collHeapPtr_, arraySize); |
| } |
| // index is assumed to be zero based. It is also assumed to be non-negative |
| // it is OK if index is > arraySize, though this should |
| // not happen as arraySize is expected to be maximum rowset size |
| rowsetRowCountArray_->insertAt((CollIndex)index, value); |
| } |
| |
| Int64 ComDiagsArea::getValueFromRowsetRowCountArray (Lng32 index) const |
| { |
| if ((rowsetRowCountArray_ == NULL) || |
| (index < 0) || |
| (!((rowsetRowCountArray_->used((CollIndex) index))))) { |
| return -1; |
| } |
| |
| return (*rowsetRowCountArray_)[(CollIndex) index]; |
| } |
| |
| |
| // The Function Name |
| // |
| // Now we provide implementation for the functions that get and set |
| // the ``function name.'' |
| |
| void ComDiagsArea::setFunction(FunctionEnum newFunction) |
| { |
| theSQLFunction_=newFunction; |
| } |
| |
| ComDiagsArea::FunctionEnum ComDiagsArea::getFunction() const |
| { |
| return (ComDiagsArea::FunctionEnum) theSQLFunction_; |
| } |
| |
| // For the purpose of returning a function name, depending |
| // on the value of theSQLFunction_, we shall declare an |
| // array static (or private) to this source file. This |
| // array has entries, one each, giving a char* that |
| // is the name of the SQL function represented by each of the |
| // FunctionEnum values. |
| // |
| // WARNING: The entries in this array must correspond |
| // with the definitions of the members of FunctionEnum. |
| |
| static const char *const functionNames[ComDiagsArea::MAX_FUNCTION_ENUM] = { |
| "NULL_FUNCTION", |
| "ALLOCATE_CURSOR", |
| "ALLOCATE_DESCRIPTOR", |
| "ALTER_DOMAIN", |
| "ALTER_TABLE", |
| "CREATE_ASSERTION", |
| "CREATE_CHARACTER_SET", |
| "CLOSE_CURSOR", |
| "CREATE_COLLATION", |
| "COMMIT_WORK", |
| "CONNECT", |
| "DEALLOCATE_DESCRIPTOR", |
| "DEALLOCATE_PREPARE", |
| "DELETE_CURSOR", |
| "DELETE_WHERE", |
| "DESCRIBE", |
| "SELECT", |
| "DISCONNECT", |
| "CREATE_DOMAIN", |
| "DROP_ASSERTION", |
| "DROP_CHARACTER_SET", |
| "DROP_COLLATION", |
| "DROP_DOMAIN", |
| "DROP_SCHEMA", |
| "DROP_TABLE", |
| "DROP_TRANSLATION", |
| "DROP_VIEW", |
| "DYNAMIC_CLOSE", |
| "DYNAMIC_DELETE_CURSOR", |
| "DYNAMIC_FETCH", |
| "DYNAMIC_OPEN", |
| "DYNAMIC_UPDATE_CURSOR", |
| "EXECUTE_IMMEDIATE", |
| "EXECUTE", |
| "FETCH", |
| "GET_DESCRIPTOR", |
| "GET_DIAGNOSTICS", |
| "GRANT", |
| "INSERT", |
| "OPEN", |
| "PREPARE", |
| "REVOKE", |
| "ROLLBACK_WORK", |
| "CREATE_SCHEMA", |
| "SET_CATALOG", |
| "SET_CONNECTION", |
| "SET_CONSTRAINT", |
| "SET_DESCRIPTOR", |
| "SET_TIME_ZONE", |
| "SET_NAMES", |
| "SET_SCHEMA", |
| "SET_TRANSACTION", |
| "SET_SESSION_AUTHORIZATION", |
| "CREATE_TABLE", |
| "CREATE_TRANSLATION", |
| "UPDATE_CURSOR", |
| "UPDATE_WHERE", |
| "CREATE_VIEW" |
| }; |
| |
| |
| const char * ComDiagsArea::getFunctionName () const |
| { |
| return functionNames[theSQLFunction_]; |
| } |
| |
| // Class DiagsCondition Implementation |
| // ...is very simple indeed. A very simple constructor |
| // and destructor, and some get/get methods for the diagsId_. |
| |
| ComDiagsArea::DiagsCondition::DiagsCondition (CollHeap* ptr) : |
| ComCondition(ptr) |
| { } |
| |
| ComDiagsArea::DiagsCondition::DiagsCondition () : |
| ComCondition() |
| { } |
| |
| ComDiagsArea::DiagsCondition::~DiagsCondition () |
| { |
| } |
| |
| // And for the set/get methods: |
| |
| |
| void ComDiagsArea::DiagsCondition::setDiagsId(Lng32 newDiagsId) |
| { |
| diagsId_ = newDiagsId; |
| } |
| |
| Lng32 ComDiagsArea::DiagsCondition::getDiagsId () const |
| { |
| return diagsId_; |
| } |
| |
| |
| // Finally, the IPC methods: |
| |
| IpcMessageObjSize ComDiagsArea::DiagsCondition::packedLength () |
| { |
| // NOTE: changes to any of the following methods also require |
| // corresponding changes in the others: |
| // - packedLength() |
| // - packObjIntoMessage() |
| // - unpackObj() |
| // - checkObj() |
| |
| return ComCondition::packedLength()+sizeof(diagsId_); |
| } |
| |
| IpcMessageObjSize ComDiagsArea::DiagsCondition::packedLength32() |
| { |
| return ComCondition::packedLength32()+sizeof(diagsId_); |
| } |
| |
| IpcMessageObjSize ComDiagsArea::DiagsCondition::packObjIntoMessage ( |
| IpcMessageBufferPtr buffer) |
| { |
| return packObjIntoMessage(buffer, FALSE); |
| } |
| // To pack a DiagsCondition object, you just pack the |
| // the base class --- a ComCondition object --- and then pack in the |
| // diagsId_ member. Easy, no? |
| |
| IpcMessageObjSize ComDiagsArea::DiagsCondition::packObjIntoMessage ( |
| IpcMessageBufferPtr buffer, NABoolean swapBytes) |
| { |
| // NOTE: changes to any of the following methods also require |
| // corresponding changes in the others: |
| // - packedLength() |
| // - packObjIntoMessage() |
| // - unpackObj() |
| // - checkObj() |
| |
| IpcMessageObjSize size = ComCondition::packObjIntoMessage(buffer, swapBytes); |
| buffer += size; |
| size += packIntoBuffer(buffer,diagsId_, swapBytes); |
| return size; |
| } |
| |
| IpcMessageObjSize ComDiagsArea::DiagsCondition::packObjIntoMessage32 ( |
| IpcMessageBufferPtr buffer) |
| { |
| return packObjIntoMessage32(buffer, FALSE); |
| } |
| IpcMessageObjSize ComDiagsArea::DiagsCondition::packObjIntoMessage32 ( |
| IpcMessageBufferPtr buffer, NABoolean swapBytes) |
| { |
| // NOTE: changes to any of the following methods also require |
| // corresponding changes in the others: |
| // - packedLength32() |
| // - packObjIntoMessage32() |
| // - unpackObj() |
| // - checkObj() |
| |
| IpcMessageObjSize size = ComCondition::packObjIntoMessage32(buffer, swapBytes); |
| buffer += size; |
| size += packIntoBuffer(buffer,diagsId_, swapBytes); |
| return size; |
| } |
| |
| void ComDiagsArea::DiagsCondition::unpackObj(IpcMessageObjType objType, |
| IpcMessageObjVersion objVersion, |
| NABoolean sameEndianness, |
| IpcMessageObjSize objSize, |
| IpcConstMessageBufferPtr buffer) |
| { |
| // NOTE: changes to any of the following methods also require |
| // corresponding changes in the others: |
| // - packedLength() |
| // - packObjIntoMessage() |
| // - unpackObj() |
| // - checkObj() |
| |
| ComCondition::unpackObj(objType,objVersion,sameEndianness, |
| objSize,buffer); |
| buffer += objSize - sizeof(diagsId_); |
| unpackBuffer(buffer,diagsId_); |
| } |
| |
| void ComDiagsArea::DiagsCondition::unpackObj32(IpcMessageObjType objType, |
| IpcMessageObjVersion objVersion, |
| NABoolean sameEndianness, |
| IpcMessageObjSize objSize, |
| IpcConstMessageBufferPtr buffer) |
| { |
| // NOTE: changes to any of the following methods also require |
| // corresponding changes in the others: |
| // - packedLength() |
| // - packObjIntoMessage() |
| // - unpackObj() |
| // - checkObj() |
| |
| ComCondition::unpackObj32(objType,objVersion,sameEndianness, |
| objSize,buffer); |
| buffer += objSize - sizeof(diagsId_); |
| unpackBuffer(buffer,diagsId_); |
| } |
| |
| NABoolean |
| ComDiagsArea::DiagsCondition::checkObj(IpcMessageObjType t, |
| IpcMessageObjVersion v, |
| NABoolean sameEndianness, |
| IpcMessageObjSize objSize, |
| IpcConstMessageBufferPtr buffer) const |
| { |
| // NOTE: changes to any of the following methods also require |
| // corresponding changes in the others: |
| // - packedLength() |
| // - packObjIntoMessage() |
| // - unpackObj() |
| // - checkObj() |
| |
| const IpcConstMessageBufferPtr lastByte = buffer + objSize - 1; |
| |
| if (!ComCondition::checkObj(t, v, sameEndianness, objSize, buffer)) |
| return FALSE; |
| |
| if (!checkBuffer(buffer, sizeof(diagsId_), lastByte)) |
| return FALSE; |
| |
| return TRUE; |
| } |
| |
| // Condition Addition |
| // The code in this section is the implementation for the ComDiagsArea |
| // members that allow the user to create and insert ComCondition |
| // objects. |
| // |
| // To create a new ComCondition we allocate a new DiagsCondition |
| // object on the proper heap. |
| // |
| // Note that the first condition's diagsId will be 1 (not 0). |
| // |
| |
| ComCondition * ComDiagsArea::makeNewCondition() |
| { |
| assert(newCondition_==NULL); |
| newCondition_ = DiagsCondition::allocate(collHeapPtr_); |
| assert(newCondition_ != NULL); |
| newCondition_->setDiagsId(++maxDiagsId_); // PREincrement |
| newCondition_->setConditionNumber(newCondition_->getDiagsId()); |
| return newCondition_; |
| } |
| |
| // All that this chunk's function must do is to free |
| // the current DiagsCondition object using the proper heap. |
| // |
| |
| void ComDiagsArea::discardNewCondition() |
| { |
| assert(newCondition_ != NULL); |
| newCondition_->deAllocate(); |
| newCondition_ = NULL; |
| maxDiagsId_--; |
| } |
| |
| void ComDiagsArea::insertNewWarning() |
| { |
| warnings_.insert(newCondition_); |
| } |
| |
| void ComDiagsArea::insertNewEODWarning() |
| { |
| warnings_.insert(newCondition_); |
| } |
| |
| void ComDiagsArea::insertNewError() |
| { |
| |
| errors_.insert(newCondition_); |
| // for non-atomic inserts, if any error is inserted after NonFatalErrorSeen flag |
| // is set, then we want to unset the flag so that mainSQLCODE does not return 30022. |
| if (getNonFatalErrorSeen()) |
| setNonFatalErrorSeen(FALSE); |
| } |
| |
| // What we do here is: |
| // Make sure that newCondition_ is not NULL. |
| // If *newCondition_ is for SQLCODE of zero, assert a failure. |
| // If *newCondition_ is for a positive SQLCODE, add it to warnings_. |
| // Otherwise, *newCondition_ is for a negative SQLCODE, and |
| // add it to errors_. |
| // Set *newCondition_ to NULL. |
| |
| void ComDiagsArea::acceptNewCondition() |
| { |
| assert(newCondition_!=NULL); |
| assert(newCondition_->getSQLCODE()!=0); |
| if (newCondition_->getSQLCODE() < 0) |
| insertNewError(); |
| else if (newCondition_->getSQLCODE() == 100) |
| insertNewEODWarning(); |
| else |
| insertNewWarning(); |
| |
| newCondition_=NULL; |
| enforceLengthLimit(); |
| } |
| |
| // Access to sequence of DiagsCondition (ComCondition plus diagsId sequencenum) |
| // |
| // This operator makes it look like ComDiagsAreas are indexed 1..getNumber() |
| // while the internal errors_/warnings_ lists are indexed from 0..entries()-1. |
| // |
| // This function used to return all errors entries before all warnings, |
| // regardless of their actual arrival sequence; this was motivated by the |
| // desire to be able to output completed conditions by severity. |
| // Unfortunately, this led to problems when in the midst of assembling a |
| // *new* (not yet complete) condition when previous conditions were an |
| // interleaved mixture of warnings and errors: the current condition's |
| // DgBase parameters are assigned to the comDiags[comDiags.getNumber()] |
| // condition, which would not necessarily be the current condition, |
| // but the last warning in the area. |
| // |
| // Now, this function returns entries by arrival sequence, |
| // *even if this means a warning is returned (to be output) before an error*. |
| // (Contrast this behavior to mainSQLCode().) |
| // |
| |
| ComCondition &ComDiagsArea::operator[] (Lng32 index) const |
| { |
| CollIndex numErrors = errors_.entries(); |
| CollIndex numWarnings = warnings_.entries(); |
| assert(index > 0); |
| assert((CollIndex)index <= numErrors + numWarnings); |
| index--; // convert to 0 based |
| // If only one of the lists is populated, fast lookup of index'th condition. |
| if (numErrors == 0) |
| return *warnings_[index]; |
| else if (numWarnings == 0) |
| return *errors_[index]; |
| |
| // diagsId is unique among all conditions |
| // the conditions in errors_[] warnings_[] are sorted on diags Id |
| // respectively, because conditions are created with a incrementing |
| // diags Id counter and appended to the array. |
| // sometimes, the conditions are removed, so their assigned diags Id is no |
| // more continuous. This is why we need to find the right condition |
| // by searching through the two arrays, relying on the diags Id in |
| // the conditions as the order. |
| CollIndex errorIdx = 0; |
| CollIndex warnIdx = 0; |
| Lng32 pos = 0; |
| |
| while(pos < index){ |
| if(errorIdx == numErrors) |
| warnIdx++; |
| else if(warnIdx == numWarnings) |
| errorIdx++; |
| else{ |
| if(errors_[errorIdx]->getDiagsId() < |
| warnings_[warnIdx]->getDiagsId()) |
| errorIdx++; |
| else if(errors_[errorIdx]->getDiagsId() > |
| warnings_[warnIdx]->getDiagsId()) |
| warnIdx++; |
| else { |
| //assert("duplicated diagsId" == 0); |
| //return *errors_[0]; |
| warnIdx++; |
| } |
| } |
| pos++; |
| } |
| |
| if(errorIdx == numErrors) |
| return *warnings_[warnIdx]; |
| else if(warnIdx == numWarnings) |
| return *errors_[errorIdx]; |
| else{ |
| if(errors_[errorIdx]->getDiagsId() < |
| warnings_[warnIdx]->getDiagsId()) |
| return *errors_[errorIdx]; |
| else if(errors_[errorIdx]->getDiagsId() > |
| warnings_[warnIdx]->getDiagsId()) |
| return *warnings_[warnIdx]; |
| else { |
| //assert("duplicated diagsId" == 0); |
| //return *errors_[0]; |
| return *warnings_[warnIdx]; |
| } |
| } |
| } |
| |
| // the following 2 methods retrieve the warning/error ComCondition at |
| // warnings_[index] or errors_[index] |
| // index ranges from 1..getNumber(DgSqlCode::WARNING_ or ERROR_) |
| // MARIA |
| ComCondition* ComDiagsArea::getWarningEntry(Lng32 index) { |
| assert((warnings_.entries() >= (CollIndex)index) && (index > 0)); |
| return warnings_[--index]; |
| } |
| |
| ComCondition* ComDiagsArea::getErrorEntry(Lng32 index) { |
| assert((errors_.entries() >= (CollIndex)index) && (index > 0)); |
| return errors_[--index]; |
| } |
| |
| ComCondition* ComDiagsArea::findCondition(Lng32 sqlCode, Lng32 *entryNumber) |
| { |
| if (sqlCode == 0) |
| return NULL; |
| |
| ComCondition * c = NULL; |
| CollIndex i = 0; |
| |
| if (sqlCode > 0) |
| { |
| for (i = 0; i < warnings_.entries(); ++i) |
| if (warnings_[i]->getSQLCODE() == sqlCode) |
| { |
| c = warnings_[i]; |
| if (entryNumber != NULL) |
| *entryNumber = i; |
| break; |
| } |
| return c; |
| } |
| |
| // sqlCode < 0 |
| |
| for (i = 0; i < errors_.entries(); ++i) |
| if (errors_[i]->getSQLCODE() == sqlCode) |
| { |
| c = errors_[i]; |
| if (entryNumber != NULL) |
| *entryNumber = i; |
| break; |
| } |
| return c; |
| } |
| |
| |
| |
| // The clearConditionsOnly method just deletes and clears each element of |
| // both sequences (errors_ and warnings_), and resets the maxDiagsId_. |
| |
| void ComDiagsArea::clearConditionsOnly() |
| { |
| DiagsCondition *ptr; |
| while (errors_.getFirst(ptr)) ptr->deAllocate(); |
| while (warnings_.getFirst(ptr)) ptr->deAllocate(); |
| maxDiagsId_ = 0; |
| } |
| |
| // The clear method just deletes and clears each element of |
| // both sequences (errors_ and warnings_) and additionally sets things |
| // like areMore_ to false (NO_MORE). |
| |
| void ComDiagsArea::clear() |
| { |
| clearConditionsOnly(); |
| areMore_=ComCondition::NO_MORE; |
| flags_ = 0; |
| rowCount_ = 0; |
| avgStreamWaitTime_ = -1; |
| cost_ = 0.0; |
| if (rowsetRowCountArray_ != NULL) { |
| rowsetRowCountArray_->deallocate(); |
| rowsetRowCountArray_ = NULL; |
| } |
| |
| } |
| |
| void ComDiagsArea::clearErrorConditionsOnly() |
| { |
| DiagsCondition *ptr; |
| while (errors_.getFirst(ptr)) |
| { |
| ptr->deAllocate(); |
| --maxDiagsId_; |
| } |
| } |
| |
| void ComDiagsArea::clearWarnings() |
| { |
| DiagsCondition *ptr; |
| while (warnings_.getFirst(ptr)) |
| { |
| ptr->deAllocate(); |
| --maxDiagsId_; |
| } |
| } |
| |
| // Returnes the SQLSTATE value of the last SIGNAL statement. |
| // Assumes the SIGNAL condition is the highest priority error. |
| const char *ComDiagsArea::getSignalSQLSTATE() const |
| { |
| if (errors_.entries() > 0) { |
| ComCondition *signal = errors_[0]; |
| |
| if (signal->getSQLCODE() == -ComDiags_SignalSQLCODE) |
| return signal->getOptionalString(0); |
| } |
| return NULL; |
| } |
| |
| // The code for mainSQLCODE is rather straightforward |
| // (see the .h file for a specification). |
| // This value is what GET DIAGNOSTICS CONDITION_NUMBER=1 should return |
| // (all other conditionNumber's are implementation-dependent, so can be random). |
| |
| Lng32 ComDiagsArea::mainSQLCODE() const |
| { |
| if (errors_.entries() > 0) { |
| if (containsError(-EXE_CANCELED)) |
| return -EXE_CANCELED; |
| else if (errors_[0]->getSQLCODE() == -EXE_INTERNALLY_GENERATED_COMMAND && errors_.entries() > 1) |
| return errors_[1]->getSQLCODE(); |
| else if (errors_[errors_.entries()-1]->getSQLCODE() == -EXE_NONATOMIC_FAILURE_LIMIT_EXCEEDED) |
| return -EXE_NONATOMIC_FAILURE_LIMIT_EXCEEDED; |
| else if (getNonFatalErrorSeen()) { |
| if (containsWarning(EXE_NONFATAL_ERROR_SEEN)) |
| return EXE_NONFATAL_ERROR_SEEN; |
| else |
| return EXE_NONFATAL_ERROR_ON_ALL_ROWS; |
| } |
| else |
| return errors_[0]->getSQLCODE(); |
| } |
| else if (warnings_.entries() > 1 && warnings_[0]->getSQLCODE() == EXE_INTERNALLY_GENERATED_COMMAND) |
| return warnings_[1]->getSQLCODE(); |
| else if (warnings_.entries() > 0) |
| return warnings_[0]->getSQLCODE(); |
| else |
| return 0L; |
| } |
| |
| // Negation of ComConditions |
| // |
| // Negation of a condition in a ComDiagsArea is somewhat tricky, |
| // and definitely possible. Here's the algorithm we implement: |
| // |
| // Assert that the index is in range. |
| // |
| // Assert that the ComCondition, c, referenced by index |
| // is not locked yet. |
| // |
| // Remove c from the list (errors, warnings) that it is currently |
| // resident in. |
| // |
| // Negate the value of the SQLCODE member of c. |
| // |
| // Insert c into the other list (warnings,errors) than the one |
| // from which it came. Do the insertion preserving the ascending |
| // ordering of the list based on the DiagsId as a key. |
| // |
| // It is the insertion into the ordered list that is the trickiest part --- |
| // but definitely possible. |
| |
| void ComDiagsArea::negateCondition(CollIndex index) |
| { |
| CollIndex numErrorEntries = errors_.entries(); |
| CollIndex numWarningEntries = warnings_.entries(); |
| assert(numErrorEntries+numWarningEntries != 0);//index invalid if this fails |
| assert(index < numErrorEntries+numWarningEntries); |
| NABoolean sourceIsWarning = |
| (numErrorEntries==0 || (index > numErrorEntries-1)); |
| LIST(DiagsCondition*) &source = sourceIsWarning ? warnings_ : errors_; |
| LIST(DiagsCondition*) &dest = sourceIsWarning ? errors_ : warnings_; |
| if (sourceIsWarning) index -= numErrorEntries; |
| |
| // We declare ptr and do a lookup, and then a removeAt to |
| // extract the pointer to the ComCondition in question from |
| // the source list. |
| // |
| |
| DiagsCondition *ptr = source[index]; |
| |
| NABoolean removed = source.removeAt(index); |
| assert(removed); |
| |
| assert(ptr); |
| ptr->isLocked_ = FALSE; |
| ptr->theSQLCODE_ = -ptr->theSQLCODE_; |
| |
| // We presume/know that dest is ordered in an ascending order |
| // by DiagsId. We want to add ptr to dest preserving this ordering. |
| // |
| // We can use a loop to determine an index such that an insertion will |
| // preserve ordering. Then, we simply insert. |
| // |
| // Fortunately (for us in this chunk) the insertAt of NAList |
| // does indeed ``slide down'' all members of the list that |
| // are beyond the insertion point. |
| // |
| // When the loop terminates, we want that all of the elements |
| // of dest which have a DiagsId less than the DiagsId of |
| // *ptr are before the place where insertionPoint points. |
| // Note that no two DiagsConditions should have the same DiagsId |
| // value, if they are resident in the same ComDiagsArea. |
| |
| CollIndex insertionPoint = 0; |
| while (insertionPoint != dest.entries() && |
| dest[insertionPoint]->getDiagsId() < ptr->getDiagsId()) |
| insertionPoint++; |
| dest.insertAt(insertionPoint,ptr); |
| } |
| |
| // Merging of ComDiagsAreas |
| // See the header file for the specification for what this |
| // function does. |
| // |
| // Steps |
| // ===== |
| // Assert that the function enums are the same for this and source. |
| // |
| // Copy conditions from source into this object in source insertion sequence, |
| // using the [] operator. |
| // |
| // Add source's rowCount_ to this rowCount_. |
| // |
| // Replace avgStreamWaitTime_ with source's, if valid. |
| |
| void ComDiagsArea::mergeAfter(const ComDiagsArea& source) |
| { |
| Lng32 nfMark = -1; |
| if (this == &source) return; |
| |
| // if NAR errors are flowing up the tree avoid merging them if |
| // they are the same. |
| if (((source.mainSQLCODE() == EXE_NONFATAL_ERROR_SEEN) && |
| (mainSQLCODE() == EXE_NONFATAL_ERROR_SEEN)) || |
| ((source.mainSQLCODE() == EXE_NONFATAL_ERROR_ON_ALL_ROWS) && |
| (mainSQLCODE() == EXE_NONFATAL_ERROR_ON_ALL_ROWS))) |
| { |
| if ((source.getNumber() <= getNumber())) |
| return ; |
| else |
| nfMark = ((ComDiagsArea *)&source)->markDupNFConditions(); |
| } |
| |
| assert( newCondition_ == NULL ); |
| |
| // I, (Bill), am commenting this out because with our current |
| // interfaces between subcomponents of the architecture it is |
| // not always desirable to perform a gratuitous SQL-FUNCTION change |
| // just to keep this assert from failing. Conceptually, however, |
| // it makes sense to me that merging two diags areas only should |
| // work if they apply to the same SQL-FUNCTION. :-) |
| // |
| // assert( theSQLFunction_ == source.theSQLFunction_); |
| |
| // if lengthLimit of source is greater than that of target |
| // then the target lengthLimit is assigned that of the source. |
| // Note that NO_LIMIT_ON_ERROR_CONDITIONS |
| // is the largest value lengthLimit can have, even though this enum = -1. |
| if (source.lengthLimit_ == ComCondition::NO_LIMIT_ON_ERROR_CONDITIONS) { |
| lengthLimit_ = ComCondition::NO_LIMIT_ON_ERROR_CONDITIONS; |
| } |
| else if ((lengthLimit_ != ComCondition::NO_LIMIT_ON_ERROR_CONDITIONS) && |
| (source.lengthLimit_ > lengthLimit_)) { |
| lengthLimit_ = source.lengthLimit_ ; |
| } |
| |
| // changed to preserve insertion order of the conditions |
| |
| for (Int32 index = (((nfMark != -1) ? (nfMark+1):1)); index <= source.getNumber(); index++) |
| { |
| ComCondition * newCondition = this->makeNewCondition(); |
| |
| *newCondition = source[index]; |
| this->acceptNewCondition(); |
| } |
| |
| rowCount_ += source.rowCount_; |
| |
| if (source.avgStreamWaitTime_ != -1) |
| avgStreamWaitTime_ = source.avgStreamWaitTime_ ; |
| |
| if (areMore_ == ComCondition::NO_MORE) |
| areMore_ = source.areMore_; |
| |
| enforceLengthLimit(); |
| |
| flags_ = source.flags_; |
| |
| assert((rowsetRowCountArray_ == NULL) || (source.rowsetRowCountArray_ == NULL)); |
| if (source.rowsetRowCountArray_) { |
| rowsetRowCountArray_ = new (collHeapPtr_) |
| NAArray<Int64>(*(source.rowsetRowCountArray_), collHeapPtr_); |
| } |
| |
| } |
| |
| // |
| // Helper routine to copy a zero-terminated string to |
| // particular heap. |
| // |
| /* |
| static char *copyStringMember(char* src, CollHeap *heap) |
| { |
| if (src==NULL) return src; |
| |
| char *copy; |
| unsigned buffsize = str_len(src) + 1; |
| |
| copy = (char*) heap->allocateMemory(buffsize); |
| assert(copy!=NULL); |
| |
| str_cpy(copy,src,buffsize); |
| copy[buffsize-1]=0; |
| |
| return copy; |
| } |
| */ |
| |
| ComDiagsArea::DiagsCondition* ComDiagsArea::DiagsCondition::copy() |
| { |
| DiagsCondition *diagsCond = DiagsCondition::allocate(collHeapPtr_); |
| assert(diagsCond!=NULL); |
| |
| *diagsCond = *this; |
| |
| return diagsCond; |
| } |
| |
| ComDiagsArea* ComDiagsArea::copy() |
| { |
| ComDiagsArea* diagsArea = ComDiagsArea::allocate(collHeapPtr_); |
| assert(diagsArea!=NULL); |
| |
| diagsArea->collHeapPtr_ = collHeapPtr_; |
| diagsArea->newCondition_ = newCondition_; |
| diagsArea->areMore_ = areMore_; |
| diagsArea->rowCount_ = rowCount_; |
| diagsArea->avgStreamWaitTime_ = avgStreamWaitTime_; |
| diagsArea->cost_ = cost_; |
| diagsArea->theSQLFunction_ = theSQLFunction_; |
| diagsArea->maxDiagsId_ = maxDiagsId_; |
| diagsArea->flags_ = flags_; |
| |
| CollIndex i = 0; |
| for (i=0; i < warnings_.entries(); i++) |
| diagsArea->warnings_.insert(warnings_[i]->copy()); |
| |
| for (i=0; i < errors_.entries(); i++) |
| diagsArea->errors_.insert(errors_[i]->copy()); |
| |
| if (rowsetRowCountArray_) { |
| diagsArea->rowsetRowCountArray_ = new (collHeapPtr_) |
| NAArray<Int64>(*(rowsetRowCountArray_), collHeapPtr_); |
| } |
| else |
| diagsArea->rowsetRowCountArray_ = NULL; |
| |
| |
| return diagsArea; |
| } |
| |
| |
| |
| |
| |
| // Marking and Rewinding |
| // |
| // The marking function can actually do what it is really supposed to: |
| // just return the value of the maxDiagsId_ member function. |
| // In the case that there is a current newCondition_ object (i.e., |
| // that pointer is not NULL) then the returned value should be |
| // maxDiagsId_ - 1. |
| |
| Lng32 ComDiagsArea::mark() const |
| { |
| if (newCondition_ == NULL) |
| return maxDiagsId_; |
| else |
| return maxDiagsId_-1; |
| } |
| |
| // It iterates over the two linked lists, |
| // and deletes the tail portions that are ComConditioins |
| // with diags-id values greater |
| // than the given mark value. |
| // |
| // Alternative: Under the category of ``road not taken'' |
| // we have the following idea. Have a data member of ComDiagsArea |
| // that is a stack of markValues, where the top is the most recently |
| // obtained mark. When rewind is called, it checks the stack |
| // to see if the stack contains the given mark value. If the the mark value |
| // is found to be valid (by being on the stack) then |
| // the stack is popped to just below the given mark value, and |
| // the deletion is performed. Otherwise (and this is the big reason |
| // for having the stack in any case) we assertion fail since the mark |
| // is invalid. |
| // |
| // One more twist on this scheme that might be a further improvement |
| // would be to make the mark value an index into the sequence which |
| // is the stack. |
| // |
| |
| void ComDiagsArea::rewind(Lng32 markValue, NABoolean decId) |
| { |
| CollIndex maxError = errors_.entries()-1; |
| while (maxError != -1 && errors_[maxError]->getDiagsId() > markValue) { |
| errors_[maxError]->deAllocate(); |
| NABoolean removed = errors_.removeAt(maxError--); |
| assert(removed); |
| if (decId) --maxDiagsId_; // This is the merged line |
| } |
| CollIndex maxWarning = warnings_.entries()-1; |
| while (maxWarning != -1 && warnings_[maxWarning]->getDiagsId() > markValue){ |
| warnings_[maxWarning]->deAllocate(); |
| NABoolean removed = warnings_.removeAt(maxWarning--); |
| assert(removed); |
| if (decId) --maxDiagsId_; |
| } |
| } |
| |
| // The algorithm for this function is two steps: |
| // 1) if the destPtr validly does not point to *this, then append/copy |
| // the to-be-discarded ComConditions from this to *destPtr, |
| // preserving order (and not reversing it, which would be easy to do). |
| // 2) perform the rewind of "this," discarding certain ComCondition objects. |
| // |
| // For step 1 we use a pair of for loops, the first for errors and the |
| // second for warnings. Not that it should matter, but this WILL result |
| // in the ComCondition objects of *destPtr having a different chronological |
| // ordering than the ComConditions have originally in *this. However, |
| // that should be of no consequence since, to those outside a ComDiagsArea, |
| // the ComConditions are always ordered by priority, with all errors before |
| // all warnings. |
| |
| void ComDiagsArea::rewindAndMergeIfDifferent(Lng32 markValue, |
| ComDiagsArea *destPtr) |
| { |
| if (destPtr != NULL && destPtr != this) { |
| CollIndex i; |
| for (i=0; i!=errors_.entries();i++) |
| if (errors_[i]->getDiagsId() > markValue) { |
| // copy/append errors_[i] to destPtr->errors_ |
| |
| DiagsCondition *newPtr = |
| DiagsCondition::allocate(destPtr->collHeapPtr_); |
| |
| *newPtr = *(errors_[i]); |
| newPtr->setDiagsId(++destPtr->maxDiagsId_); |
| destPtr->errors_.insert(newPtr); |
| } |
| for (i=0; i!=warnings_.entries();i++) |
| if (warnings_[i]->getDiagsId() > markValue) { |
| // copy/append warnings_[i] to destPtr->warnings_ |
| DiagsCondition *newPtr = |
| DiagsCondition::allocate(destPtr->collHeapPtr_); |
| |
| *newPtr = *(warnings_[i]); |
| newPtr->setDiagsId(++destPtr->maxDiagsId_); |
| destPtr->warnings_.insert(newPtr); |
| } |
| rewind(markValue); |
| } |
| } |
| |
| void ComDiagsArea::deleteWarning(Lng32 entryNumber) { |
| warnings_[entryNumber]->deAllocate(); |
| NABoolean removed = warnings_.removeAt(entryNumber); |
| assert(removed); |
| --maxDiagsId_; |
| } |
| |
| |
| void ComDiagsArea::deleteError(Lng32 entryNumber) { |
| errors_[entryNumber]->deAllocate(); |
| NABoolean removed = errors_.removeAt(entryNumber); |
| assert(removed); |
| --maxDiagsId_; |
| } |
| |
| ComCondition * ComDiagsArea::removeError(Lng32 entryNumber) { |
| ComCondition * errCond = getErrorEntry(entryNumber+1); |
| NABoolean removed = errors_.removeAt(entryNumber); |
| assert(removed); |
| return errCond ; |
| } |
| |
| |
| void ComCondition::destroyMe() |
| { |
| this -> ~ComCondition(); |
| } |
| |
| void ComDiagsArea::destroyMe() |
| { |
| this -> ~ComDiagsArea(); |
| } |
| |
| void ComDiagsArea::DiagsCondition::destroyMe() |
| { |
| this -> DiagsCondition::~DiagsCondition(); |
| } |
| |
| ComDiagsArea::DiagsCondition & |
| ComDiagsArea::DiagsCondition::operator= (const ComDiagsArea::DiagsCondition&d) |
| { |
| ComCondition::operator=(d); |
| diagsId_ = d.diagsId_; |
| return *this; |
| } |
| |
| void ComDiagsArea::removeFinalCondition100() |
| { |
| // Might not have a SQL_EOF condition, because these |
| // are not used on NT. |
| |
| if (warnings_.entries() == 0 ) |
| { |
| return; |
| } |
| |
| const CollIndex i = warnings_.entries() - 1; |
| DiagsCondition *w100 = warnings_[i]; |
| if ((w100->getDiagsId() != maxDiagsId_ ) || |
| (w100->getSQLCODE() != 100)) |
| { |
| return; |
| } |
| |
| w100->deAllocate(); |
| warnings_.removeAt(i); |
| --maxDiagsId_; |
| return; |
| } |
| |
| void ComDiagsArea::removeLastErrorCondition() |
| { |
| // Might not have a SQL_EOF condition, because these |
| // are not used on NT. |
| |
| if (errors_.entries() == 0 ) |
| { |
| return; |
| } |
| |
| const CollIndex i = errors_.entries() - 1; |
| DiagsCondition *errCond = errors_[i]; |
| if (errCond->getDiagsId() != maxDiagsId_ ) |
| { |
| return; |
| } |
| |
| deleteError((Lng32) i); |
| return; |
| } |
| |
| |
| /////////////////////////////////////////////////////////////// |
| // returns TRUE, if any ComCondition in the diagsArea contains |
| // error SQLCode. |
| // returns FALSE, otherwise. |
| /////////////////////////////////////////////////////////////// |
| NABoolean ComDiagsArea::contains(Lng32 SQLCode) const |
| { |
| |
| return containsError(SQLCode) || containsWarning(SQLCode); |
| |
| } // end of ComDiagsArea::contains |
| |
| NABoolean ComDiagsArea::containsError(Lng32 SQLCode) const |
| { |
| for ( CollIndex i=0; i < errors_.entries(); i++ ) |
| { |
| if ( errors_[i]->getSQLCODE() == SQLCode ) |
| { |
| return TRUE; |
| } |
| } |
| return FALSE; |
| } |
| |
| NABoolean ComDiagsArea::containsWarning(Lng32 SQLCode) const |
| { |
| return containsWarning(0, SQLCode); |
| } |
| |
| // Check if warnings_ contains SQLCODE within the range [begin, warnings_.entries()). |
| // Note begin is 0-based. |
| NABoolean ComDiagsArea::containsWarning(CollIndex begin, Lng32 SQLCode) const |
| { |
| for ( CollIndex i=begin; i<warnings_.entries(); i++ ) |
| { |
| if ( warnings_[i]->getSQLCODE() == SQLCode ) |
| { |
| return TRUE; |
| } |
| } |
| return FALSE; |
| } |
| |
| // returns TRUE, if diagsArea contains the fileName for error SQLCode. |
| // returns FALSE, otherwise. |
| NABoolean ComDiagsArea::containsForFile(Lng32 SqlCd, const char * fileName) |
| { |
| ComDiagsArea* DA = ComDiagsArea::copy(); |
| if (!(*DA).contains(SqlCd)) |
| return FALSE; |
| |
| |
| NABoolean fileNameExists = FALSE; |
| |
| //Loop through Diagnostic area to check if extFileSetName is |
| //already present. |
| for (Lng32 j = 1 ; ((j <= (*DA).getNumber()) && (!(fileNameExists))); j++) |
| { |
| if( ((*DA)[j].getSQLCODE() == SqlCd) && |
| ((strcmp(fileName, ((*DA)[j].getTableName()))) == 0) ) |
| { |
| fileNameExists = TRUE; |
| } |
| } |
| return fileNameExists; |
| } |
| |
| //returnIndex returns the index number of a given SQLCODE in this diagsarea |
| //If the given SQLCODE is not found in the diagsarea then NULL_COLL_INDEX is returned. |
| //The index is zero based. The index number for warnings is obtained by |
| //incrementing the array position of the particular SQLCODE by the total |
| //number of errors in this diagsarea. The CollIndex value returned is in a form suitable |
| //to be used by a method like ComDiagsArea::negateCondition(CollIndex ), if it is |
| //not equal to NULL_COLL_INDEX. |
| CollIndex ComDiagsArea::returnIndex(Lng32 SQLCode) const |
| { |
| CollIndex i; |
| for ( i=0; i < errors_.entries(); i++ ) |
| { |
| if ( errors_[i]->getSQLCODE() == SQLCode ) |
| { |
| return i; |
| } |
| } |
| |
| for ( i = 0; i < warnings_.entries(); i++ ) |
| { |
| if ( warnings_[i]->getSQLCODE() == SQLCode ) |
| { |
| return i + errors_.entries(); |
| } |
| } |
| return NULL_COLL_INDEX ; |
| } // end of ComDiagsArea::returnIndex |
| |
| |
| |
| |
| void ComDiagsArea::removeLastNonFatalCondition() |
| { |
| if (warnings_.entries() == 0 ) |
| { |
| return; |
| } |
| |
| const CollIndex i = warnings_.entries() - 1; |
| DiagsCondition *wNF = warnings_[i]; |
| |
| if ((wNF->getDiagsId() != maxDiagsId_ ) || |
| ((wNF->getSQLCODE() != EXE_NONFATAL_ERROR_SEEN) && |
| (wNF->getSQLCODE() != EXE_NONFATAL_ERROR_ON_ALL_ROWS)) |
| ) |
| { |
| return; |
| } |
| |
| wNF->deAllocate(); |
| warnings_.removeAt(i); |
| --maxDiagsId_; |
| setNonFatalErrorSeen(FALSE); |
| return; |
| } |
| |
| Lng32 ComDiagsArea::markDupNFConditions() |
| { |
| CollIndex lnfw = 0; |
| DiagsCondition *warningMark = NULL; |
| |
| if ((lnfw = returnIndex(EXE_NONFATAL_ERROR_ON_ALL_ROWS)) != NULL_COLL_INDEX) |
| warningMark = warnings_[lnfw-errors_.entries()]; |
| else |
| if ((lnfw=returnIndex(EXE_NONFATAL_ERROR_SEEN)) != NULL_COLL_INDEX) |
| warningMark= warnings_[lnfw-errors_.entries()]; |
| |
| if(warningMark) |
| return warningMark->getDiagsId(); |
| else |
| return -1; |
| |
| |
| } |
| // ----------------------------------------------------------------------- |
| // ComDiagsTranslator::translateDiagsArea |
| // A driver for the translation of individual conditions in a diags area |
| // ----------------------------------------------------------------------- |
| |
| void ComDiagsTranslator::translateDiagsArea |
| ( ComDiagsArea &diags, |
| const NABoolean twoPass) |
| { |
| Int32 index; |
| |
| if (twoPass) |
| { |
| // First, run through the individual conditions and call the virtual |
| // condition analyzer method, to allow our caller to figure out |
| // what's in the diags area before translating conditions. |
| firstError_ = TRUE; |
| beforeAnalyze(); |
| for (index = 1; index <= diags.getNumber(); index++) |
| { |
| analyzeCondition (diags[index]); |
| firstError_ = FALSE; |
| } |
| } |
| |
| ComDiagsArea * localDiags = diags.copy(); |
| diags.clearConditionsOnly (); |
| firstError_ = TRUE; |
| beforeTranslate(); |
| for (index = 1; index <= localDiags->getNumber(); index++) |
| { |
| // Run through the individual conditions, call the |
| // virtual condition translation method for each condition |
| ComCondition &condition = (*localDiags)[index]; |
| if (!translateCondition (diags, condition)) |
| { |
| // the condition translator method didn't translate the condition, |
| // copy it unchanged |
| ComCondition * newCondition = diags.makeNewCondition(); |
| *newCondition = condition; |
| diags.acceptNewCondition(); |
| } |
| firstError_ = FALSE; |
| } |
| afterTranslate(); |
| // deallocate the copy |
| localDiags->deAllocate(); |
| } |
| |
| |
| // ----------------------------------------------------------------------- |
| // ComDiagsTranslator::analyzeCondition |
| // Don't implement - derived classes that want to use this one |
| // must provide it themselves |
| // ----------------------------------------------------------------------- |
| |
| void ComDiagsTranslator::analyzeCondition (const ComCondition &cond) |
| { assert(0); } |
| |
| |
| // ----------------------------------------------------------------------- |
| // Virtual methods, to be called before the first condition is processed. |
| // Derived classes that want to know about this can redefine. |
| // ----------------------------------------------------------------------- |
| |
| void ComDiagsTranslator::beforeAnalyze (void) {}; |
| void ComDiagsTranslator::beforeTranslate (void) {}; |
| |
| // ----------------------------------------------------------------------- |
| // Virtual method, to be called after the last condition is processed. |
| // Derived classes that want to know about this can redefine. |
| // Note that there is no "afterAnalyze" since that would be identical to |
| // "beforeTranslate". |
| // ----------------------------------------------------------------------- |
| |
| void ComDiagsTranslator::afterTranslate (void) {}; |
| |
| |