LmResult LmRoutineCppObj::dealloc(ComDiagsArea *diagsArea) { LmResult result = LM_OK; delete invocationInfo_; invocationInfo_ = NULL; for (CollIndex i=0; i<planInfos_.getUsedLength(); i++) if (planInfos_.used(i)) delete planInfos_[i]; planInfos_.clear(); if (paramRow_) { NADELETEBASIC(paramRow_, collHeap()); paramRow_ = NULL; } if (inputRows_) { for (int i=0; i<numInputTables_; i++) if (inputRows_[i]) NADELETEBASIC((inputRows_[i]), collHeap()); NADELETEBASIC(inputRows_, collHeap()); inputRows_ = NULL; } if (outputRow_) { // actually allocated buffer started where the wall starts NADELETEBASIC((outputRow_ - WALL_STRING_LEN), collHeap()); outputRow_ = NULL; } try { // delete the interface object, the virtual destructor may call user code delete interfaceObj_; } catch (tmudr::UDRException e) { *diagsArea << DgSqlCode(-LME_UDR_METHOD_ERROR) << DgString0("destructor") << DgString1(getNameForDiags()) << DgString2(e.getMessage().c_str()); result = LM_ERR; } catch (...) { *diagsArea << DgSqlCode(-LME_UDR_METHOD_ERROR) << DgString0("destructor") << DgString1(getNameForDiags()) << DgString2("General exception."); result = LM_ERR; } interfaceObj_ = NULL; return result; }
LmHandle loadDll( const char *containerName, const char *externalPath, LmHandle extLoader, ComUInt32 *containerSize, ComDiagsArea *da, NAMemory *heap) { #ifdef LMCOMMON_CANNOT_CALL_DLOPEN *da << DgSqlCode(-LME_INTERNAL_ERROR) << DgString0(": dlopen() is not supported"); *da << DgSqlCode(-LME_DLL_CONT_NOT_FOUND) << DgString0(containerName) << DgString1(externalPath); return NULL; #else char *libraryName = NULL; if (str_len(externalPath) == 0) externalPath = "."; libraryName = new (heap) char[str_len(externalPath) + str_len(containerName) + 2]; sprintf(libraryName, "%s/%s", externalPath, containerName); // TBD: For now, set container size to 0. Need to see how to get // the actual size if (containerSize) *containerSize = 0; // extLoader is an object of LmCLoader class. It's not used to // load the library. We can simply load the DLL. LmHandle container = NULL; const char *operation = "dlopen"; container = (LmHandle) dlopen(libraryName, RTLD_NOW | RTLD_GLOBAL); LM_DEBUG3("%s(%s) returned 0x%08x\n", operation, libraryName, container); if (container == NULL) { *da << DgSqlCode(-LME_DLL_CONT_NOT_FOUND) << DgString0(containerName) << DgString1(externalPath); addDllErrors(*da, operation, FALSE); } NADELETEBASIC(libraryName, heap); return container; #endif // LMCOMMON_CANNOT_CALL_DLOPEN }
void addDllErrors(ComDiagsArea &diags, const char *operation, NABoolean isWarningOnly) { Int32 errorCode = 0; Int32 errorDetail = 0; char *errorString = (char *)""; #ifndef LMCOMMON_CANNOT_CALL_DLOPEN // dlresultcode() is not applicable to Linux errorString = dlerror(); #endif // Remove trailing period and linefeed characters from the message // string ComUInt32 msglen = 0; while (errorString && (msglen = strlen(errorString)) > 0) { ComUInt32 idx = msglen - 1; if (errorString[idx] == '\n' || errorString[idx] == '\r' || errorString[idx] == '.') errorString[idx] = 0; else break; } diags << DgSqlCode((isWarningOnly ? LME_DLFCN_ERROR : -LME_DLFCN_ERROR)) << DgString0(operation) << DgInt0(errorCode) << DgInt1(errorDetail) << DgString1(errorString); }
// match a terminal symbol t void ExtQualModuleNames::match(tokenType t) { if (nextToken() == t) { // matches t. all is OK. currentTokenCode_ = scanner(); // get next token } else { *mxCUMptr << FAIL << DgSqlCode(-2212) << DgString0(tokenString(t)) << DgString1(currentTokenString()); } }
LmResult LmRoutineCppObj::validateWall(char *userBuf, int userBufLen, ComDiagsArea *da, const char *bufferName) { if (memcmp(userBuf - WALL_STRING_LEN, WALL_STRING, WALL_STRING_LEN) != 0) { if (da) *da << DgSqlCode(LME_BUFFER_OVERWRITE) << DgString0(invocationInfo_->getUDRName().data()) << DgString1(bufferName) << DgString2("beginning"); else throw tmudr::UDRException( 38900, "UDR %s overwrote space before its %s buffer", invocationInfo_->getUDRName().data(), bufferName); } if (memcmp(userBuf + userBufLen, WALL_STRING, WALL_STRING_LEN) != 0) { if (da) *da << DgSqlCode(LME_BUFFER_OVERWRITE) << DgString0(invocationInfo_->getUDRName().data()) << DgString1(bufferName) << DgString2("end"); else throw tmudr::UDRException( 38900, "UDR %s overwrote space after its %s buffer", invocationInfo_->getUDRName().data(), bufferName); } return LM_OK; }
void ExFastExtractTcb::updateWorkATPDiagsArea(const char *file, int line, const char *msg) { ComDiagsArea *da = workAtp_->getDiagsArea(); if(!da) { da = ComDiagsArea::allocate(getHeap()); workAtp_->setDiagsArea(da); } *da << DgSqlCode(-1001) << DgString0(file) << DgInt0(line) << DgString1(msg); }
// LCOV_EXCL_START :cnu Int32 ValidateAnsiList::validate( const char *value, const NADefaults *nad, Int32 attrEnum, Int32 errOrWarn, float *) const { // Validate using a copy of "*value" char tempStr[1000]; // max length of ATTR_VALUE if ( strlen(value) >= 1000 ) return FALSE; // just in case if ( strlen(value) == 0 ) return TRUE; // empty string ATTR_VALUE is OK strcpy(tempStr, value); // prepare to extract the partitions/tokens from the default string const char *token, *sep = " ,:" ; token = strtok( tempStr, sep ); // iterate thru list of volume names; return false iff any name is invalid // (Also an appropriate error/warning would be issued.) while ( token != NULL ) { NAString tokenObj(token); Int32 countPeriods = 0, inBetween = 0; NABoolean anyError = tokenObj.isNull() ; // check three part ANSI name for (Int32 i = 0; !anyError && i < (Int32)tokenObj.length() ; i++ ) { if ( ComSqlText.isDigit(token[i]) || ComSqlText.isSimpleLatinLetter(token[i]) ) inBetween++; else { if ( ComSqlText.getPeriod() == token[i] && // it is a period countPeriods++ < 2 ) { if ( inBetween == 0 ) anyError = TRUE; // no CATALOG or SCHEMA else inBetween = 0 ; // start counting the next ( SCHEMA or NAME ) } else anyError = TRUE; } } if ( countPeriods != 2 || inBetween == 0 ) anyError = TRUE; if ( anyError ) { if (errOrWarn) *CmpCommon::diags() << DgSqlCode(ERRWARN(2055)) << DgString0(token) << DgString1("INVALID QUALIFIED NAME"); return FALSE; } token = strtok( NULL, sep ); } return TRUE; }
// validate parameter for MV_AGE Int32 ValidateMVAge::validate( const char *value, const NADefaults *nad, Int32 attrEnum, Int32 errOrWarn, float *alreadyHaveFloat ) const { Int32 isOK = FALSE; float number=0; char textChars[20]; if (strlen(value) < 15) { if (sscanf(value, "%f %s", &number, textChars) == 2) { const NAString text(textChars); if (!text.compareTo("Seconds", NAString::ignoreCase)) { isOK = TRUE; } else if (!text.compareTo("Minutes", NAString::ignoreCase)) { isOK = TRUE; } else if (!text.compareTo("Hours", NAString::ignoreCase)) { isOK = TRUE; } else if (!text.compareTo("Days", NAString::ignoreCase)) { isOK = TRUE; } } } if (!isOK) { if (errOrWarn) *CmpCommon::diags() << DgSqlCode(ERRWARN(2055)) << DgString0(value) << DgString1(nad->lookupAttrName(attrEnum, errOrWarn)); } return isOK; }
Int32 ValidateRoleNameList::validate( const char *value, const NADefaults *nad, Int32 attrEnum, Int32 errOrWarn, float *) const { // Validate a list of role names. Based on ValidateAnsiList // List format: comma separated list of role names which use either . or _ // example: "role.user1", "ROLE.user2", "role_user3" // SeaQuest example: DB__Root, DB__Services, db_role12, db_user3 // Validate using a copy of "*value" char tempStr[1000]; // max length of ATTR_VALUE if ( strlen(value) >= 1000 ) return FALSE; // just in case if ( strlen(value) == 0 ) return TRUE; // empty string ATTR_VALUE is OK strcpy(tempStr, value); // prepare to extract the role names/tokens from the default string const char *token, *sep = " ," ; token = strtok( tempStr, sep ); // iterate thru list of role names; return false iff any name is invalid // (Also an appropriate error/warning would be issued.) while ( token != NULL ) { NAString tokenObj(token); Lng32 sqlcode = ToInternalIdentifier(tokenObj, TRUE /*upCase*/, FALSE /*acceptCircumflex*/, 0 /*toInternalIdentifierFlags*/); if (sqlcode && ABS(sqlcode) != 3128) { // 3004 A delimited identifier must contain at least one character. // 3118 Identifier too long. // 3127 Illegal character in identifier $0~string0. // 3128 $1~string1 is a reserved word. if (errOrWarn) *CmpCommon::diags() << DgSqlCode(ERRWARN(2055)) << DgString0(token) << DgString1("INVALID AUTHORIZATION IDENTIFIER"); } token = strtok( NULL, sep ); } return TRUE; }
// validate OVERRIDE_SCHEMA FROM_SCHEMA:TO_SCHEMA setting // format validation for xxx:yyy Int32 ValidateOverrideSchema::validate( const char *value, const NADefaults *nad, Int32 attrEnum, Int32 errOrWarn, float *flt ) const { NABoolean ok = TRUE; Int32 len = strlen(value); if (len == 0) // empty is ok return ok; NAString fromSchema, toSchema; extractOverrideSchemas(value, fromSchema, toSchema); if ( (fromSchema.isNull()) || (toSchema.isNull()) ) ok = FALSE; else { ComSchemaName targetSchema(toSchema); if (!targetSchema.isValid()) ok = FALSE; else if (fromSchema!="*") // reserve * for wildcard operation { ComSchemaName sourceSchema(fromSchema); if (!sourceSchema.isValid()) ok = FALSE; } } if (!ok && errOrWarn) *CmpCommon::diags() << DgSqlCode(ERRWARN(2055)) << DgString0(value) << DgString1(nad->lookupAttrName(attrEnum, errOrWarn)); return ok; }
// validate REPLICATE_IO_VERSION setting // setting may be schema or catalog.schema Int32 ValidateReplIoVersion::validate( const char *value, const NADefaults *nad, Int32 attrEnum, Int32 errOrWarn, float *alreadyHaveFloat ) const { Int32 isValid = FALSE; float flt; Int32 min; if (alreadyHaveFloat) flt = *alreadyHaveFloat; else { isValid = nad->validateFloat(value, flt, attrEnum, SilentIfSYSTEM); if (isValid == SilentIfSYSTEM) return SilentIfSYSTEM; } if (alreadyHaveFloat || isValid) { if (Get_SqlParser_Flags(INTERNAL_QUERY_FROM_EXEUTIL)) min = 1; else min = min_; if (flt >= min && flt <= max_) return TRUE; // valid } if (alreadyHaveFloat) *alreadyHaveFloat = (float)min_; if (errOrWarn) *CmpCommon::diags() << DgSqlCode(ERRWARN(2055)) << DgString0(value) << DgString1(nad->lookupAttrName(attrEnum, errOrWarn)); return FALSE; }
// validate PUBLIC_SCHEMA_NAME setting // setting may be schema or catalog.schema Int32 ValidatePublicSchema::validate( const char *value, const NADefaults *nad, Int32 attrEnum, Int32 errOrWarn, float *flt ) const { NABoolean ok = TRUE; Int32 len = strlen(value); if (len == 0) // empty is ok return ok; ComSchemaName pubSchema(value); if (!pubSchema.isValid()) ok = FALSE; if (!ok && errOrWarn) *CmpCommon::diags() << DgSqlCode(ERRWARN(2055)) << DgString0(value) << DgString1(nad->lookupAttrName(attrEnum, errOrWarn)); return ok; }
Int32 ValidateCollationList::validate(const char *value, const NADefaults *nad, Int32 attrEnum, Int32 errOrWarn, float *) const { if (errOrWarn) { CMPASSERT(nad && attrEnum); errOrWarn = +1; // warnings only (else silent) } // Cast away constness on various private members which are really implicit // arguments (the validate method by itself vs. from insertIntoCDB). ValidateCollationList *ncThis = (ValidateCollationList *)this; #ifndef NDEBUG if (getenv("NCHAR_DEBUG")) ncThis->formatRetry_ = TRUE; #endif // If cdb is NULL, we are validating only; if nonNULL, we are inserting. CollationDB *cdb = ncThis->cdb_; const ComMPLoc *defaultMPLoc = NULL; const SchemaName *defaultSchema = NULL; if (cdb) { CMPASSERT(sdb_); defaultMPLoc = &SqlParser_MPLOC; defaultSchema = &sdb_->getDefaultSchema(); } // Make our own copy of the value string data, // on which we can safely cast away const-ness for the loop, // which chops the list up into individual names by replacing // (in place, i.e. w/o additional copying) // each semicolon with a string-terminating nul. NAString collNAS(value); char *collList = (char *)collNAS.data(); while (*collList) { // SYNTAX OF THE MP_COLLATIONS LIST: // // The list may look like any of these: // '' (empty) // 'collname' // 'c1; sv.c2; $v.sv.c3; \s.$v.sv.c4' // 'c1; sv.c2; $v.sv.c3; \s.$v.sv.c4;' // ' = c1; =sv.c2;=$v.sv.c3;\s.$v.sv.c4;' // We also ignore pathologies like // ' ' or '=========;;;;;===; ; = = == =; ; ; ' // // The '=' flags the following collation name as one that has a 1:1 mapping, // i.e. its CPRULES.CHARACTERISTICS == 'O', // i.e. in Rel1 it allows only equality comparisons // (SQL '=', '<>', DISTINCT, GROUP BY), // although no other operations // (other predicates, ordering, MIN/MAX, partitioning) // would be disallowed -- the column wouldn't even be updatable, // but it could be at least read and appear in some limited other places. // // The absence of a '=' means the collation's CHARACTERISTICS == 'N', // and in Rel1 we cannot support *any* comparisons, predicates, MIN/MAX, // ordering, partitioning, on it -- // it's basically just a name attached to a column, // but the intent was to allow the column to be at least readable. // // See ReadTableDef and NATable to see if MP COLLATEd column support // is or is not currently being enabled. // Find the next semicolon separator outside of delim-ident quotes, // or find end of string. // Set collStr to be the fragment up to (excluding) the semicolon or zero; // set collList to be the rest of itself (after the semicolon). // // LCOV_EXCL_START :mp char *s = collList; for (NABoolean quoted = FALSE; *s; s++) { if (*s == '"') quoted = !quoted; else if (*s == ';' && !quoted) break; } char sep = *s; // sep is either ';' or '\0' *s = '\0'; NAString collStr(collList); collList = sep ? ++s : s; // get past ';' OR stay on final '\0' CollationInfo::CollationFlags flags = CollationInfo::ALL_CMP_ILLEGAL; TrimNAStringSpace(collStr); // remove leading/trailing blanks size_t i = 0, n = collStr.length(); while (i < n) if (collStr[i] == '=' || collStr[i] == ' ') i++; // get past leading '=' (and blanks) else break; if (i) { // an '=' was seen, EQ_NE_CMP is LEGAL flags = CollationInfo::ORDERED_CMP_ILLEGAL; collStr.remove(0, i); } if (!collStr.isNull()) { NABoolean ok = FALSE; NABoolean nsk = formatNSK_; NABoolean retry = formatRetry_; retry_as_other_format: if (nsk) { ComMPLoc collMP(collStr, ComMPLoc::FILE); if (collMP.isValid(ComMPLoc::FILE)) { ok = TRUE; if (cdb) { ncThis->lastCoInserted_ = cdb->insert(collMP, defaultMPLoc, flags); } } } else { ComObjectName collMX(collStr); if (collMX.isValid()) { ok = TRUE; if (cdb) { QualifiedName collQN(collMX); ncThis->lastCoInserted_ = cdb->insert(collQN, defaultSchema, flags); } } } if (ok) ncThis->cntCoParsed_++; if (!ok && retry) { retry = FALSE; // Retry only once, nsk = !nsk; // using the other name format. goto retry_as_other_format; } if (!ok && errOrWarn) *CmpCommon::diags() << DgSqlCode(ERRWARN(2055)) << DgString0(collStr) << DgString1(nad->lookupAttrName(attrEnum, errOrWarn)); // LCOV_EXCL_STOP } // !collStr.isNull() } // while return TRUE; // warnings only; all is valid }
Int32 ValidateNumericRange::validate( const char *value, const NADefaults *nad, Int32 attrEnum, Int32 errOrWarn, float *alreadyHaveFloat) const { Int32 isValid = FALSE, rangeOK = FALSE, multipleOK = FALSE; float flt; if (alreadyHaveFloat) flt = *alreadyHaveFloat; else { isValid = nad->validateFloat(value, flt, attrEnum, SilentIfSYSTEM); if (isValid == SilentIfSYSTEM) return SilentIfSYSTEM; } if (alreadyHaveFloat || isValid) { rangeOK = (min_ <= flt && flt <= max_); if (rangeOK) { multipleOK = (multiple_ == 0 || ((ULng32)flt) % multiple_ == 0); if (multipleOK) { return TRUE; // valid } } } if (alreadyHaveFloat) *alreadyHaveFloat = min_; if (errOrWarn) { *CmpCommon::diags() << DgSqlCode(ERRWARN(2055)) << DgString0(value) << DgString1(nad->lookupAttrName(attrEnum, errOrWarn)); if (!rangeOK) { char minbuf[50], maxbuf[50]; if (type_ == VALID_INT) { sprintf(minbuf, "%d", (Lng32)min_); // A fudge factor of 64 is added for NT/Yos/Neo to include // the precision lost. The value printed is 2147483520, // while values are accepted till 2147483584. sprintf(maxbuf, "%d", (Lng32)max_+64); } else if (type_ == VALID_UINT) { sprintf(minbuf, "%u", (ULng32)min_); if (max_ == 2147483520) sprintf(maxbuf, "%u", (ULng32)max_+64); else sprintf(maxbuf, "%u", (ULng32)max_); } else { sprintf(minbuf, "%g", min_); sprintf(maxbuf, "%g", max_); } switch (attrEnum) { case HIVE_INSERT_ERROR_MODE: { sprintf(minbuf, "%u", 0); sprintf(maxbuf, "%u", 3); } break; default: { // do nothing } } NAString range = NAString("[") + minbuf + "," + maxbuf + "]"; *CmpCommon::diags() << DgSqlCode(ERRWARN(2056)) << DgString0(range); } if (multiple_ && !multipleOK) #pragma nowarn(1506) // warning elimination *CmpCommon::diags() << DgSqlCode(ERRWARN(2057)) << DgInt0(multiple_); #pragma warn(1506) // warning elimination } return FALSE; // not valid }
Int32 ValidatePOSTableSizes::validate(const char *value, const NADefaults *nad, Int32 attrEnum, Int32 errOrWarn, float *) const { char tempStr[1000]; // max length of ATTR_VALUE if ( strlen(value) == 0 ) return TRUE; // empty string ATTR_VALUE is OK if ( strlen(value) > 1000 ) { *CmpCommon::diags() << DgSqlCode(ERRWARN(2055)) << DgString0(value) << DgString1(nad->lookupAttrName(attrEnum, errOrWarn)); return FALSE; } strcpy(tempStr, value); const char *token, *sep = " ,"; token = strtok(tempStr, sep); float initialSize = -1; float maxSize = -1; ValidateUInt uint; if (token != NULL) { // check if the first value is an unsigned int if (!uint.validate(token, nad, attrEnum, -1)) return FALSE; else { sscanf(token, "%g", &initialSize); token = strtok(NULL, sep); if (token != NULL) { // check if the second value is an unsigned int if (!uint.validate(token, nad, attrEnum, -1)) return FALSE; else { // if there is a third value or max table size is smaller than // initial table size raise an error sscanf(token, "%g", &maxSize); token = strtok(NULL, sep); if (token != NULL || maxSize < initialSize) { *CmpCommon::diags() << DgSqlCode(ERRWARN(2055)) << DgString0(value) << DgString1(nad->lookupAttrName(attrEnum, errOrWarn)); if (maxSize < initialSize) { *CmpCommon::diags() << DgSqlCode(ERRWARN(2077)) << DgInt0((Lng32)maxSize) << DgInt1((Lng32)initialSize); } return FALSE; } } } } } else { *CmpCommon::diags() << DgSqlCode(ERRWARN(2055)) << DgString0(value) << DgString1(nad->lookupAttrName(attrEnum, errOrWarn)); return FALSE; } return TRUE; }
LmResult LmRoutineCppObj::invokeRoutineMethod( /* IN */ tmudr::UDRInvocationInfo::CallPhase phase, /* IN */ const char *serializedInvocationInfo, /* IN */ Int32 invocationInfoLen, /* OUT */ Int32 *invocationInfoLenOut, /* IN */ const char *serializedPlanInfo, /* IN */ Int32 planInfoLen, /* IN */ Int32 planNum, /* OUT */ Int32 *planInfoLenOut, /* IN */ char *inputParamRow, /* IN */ Int32 inputParamRowLen, /* OUT */ char *outputRow, /* IN */ Int32 outputRowLen, /* IN/OUT */ ComDiagsArea *da) { LmResult result = LM_OK; // initialize out parameters *invocationInfoLenOut = 0; *planInfoLenOut = 0; // some parameter checks if (invocationInfoLen <= 0 && invocationInfo_ == NULL) { // we need to have an Invocation info *da << DgSqlCode(-LME_OBJECT_INTERFACE_ERROR) << DgString0(getNameForDiags()) << DgString1(tmudr::UDRInvocationInfo::callPhaseToString( tmudr::UDRInvocationInfo::COMPILER_INITIAL_CALL)) << DgString2("LmRoutineCppObj::invokeRoutineMethod()") << DgString3("Missing UDRInvocationInfo"); } try { if (invocationInfoLen > 0) { if (invocationInfo_ == NULL) invocationInfo_ = new tmudr::UDRInvocationInfo; // unpack the invocation info invocationInfo_->deserializeObj(serializedInvocationInfo, invocationInfoLen); } if (planInfoLen > 0) { if (!planInfos_.used(planNum)) planInfos_.insertAt(planNum, new tmudr::UDRPlanInfo(invocationInfo_, planNum)); // unpack the invocation info planInfos_[planNum]->deserializeObj(serializedPlanInfo, planInfoLen); } // some parameter checks if (inputParamRowLen < inputParamRowLen_) return LM_ERR; // test to do for scalar UDFs // if (outputRowLen < invocationInfo_->out().getRecordLength()) // return LM_ERR; if (inputParamRow && inputParamRowLen_ > 0) // copy parameter row memcpy(invocationInfo_->par().getRowPtr(), inputParamRow, inputParamRowLen_); invocationInfo_->callPhase_ = phase; switch (phase) { case tmudr::UDRInvocationInfo::COMPILER_INITIAL_CALL: if (invocationInfo_->getDebugFlags() & tmudr::UDRInvocationInfo::PRINT_INVOCATION_INFO_INITIAL) invocationInfo_->print(); if (invocationInfo_->getDebugFlags() & tmudr::UDRInvocationInfo::DEBUG_INITIAL_COMPILE_TIME_LOOP) if (invocationInfo_->getSessionUser() == ComUser::getRootUserName()) interfaceObj_->debugLoop(); else if (da) *da << DgSqlCode(1260); // warning, only root user can debug interfaceObj_->describeParamsAndColumns(*invocationInfo_); break; case tmudr::UDRInvocationInfo::COMPILER_DATAFLOW_CALL: interfaceObj_->describeDataflowAndPredicates(*invocationInfo_); break; case tmudr::UDRInvocationInfo::COMPILER_CONSTRAINTS_CALL: interfaceObj_->describeConstraints(*invocationInfo_); break; case tmudr::UDRInvocationInfo::COMPILER_STATISTICS_CALL: interfaceObj_->describeStatistics(*invocationInfo_); break; case tmudr::UDRInvocationInfo::COMPILER_DOP_CALL: interfaceObj_->describeDesiredDegreeOfParallelism( *invocationInfo_, *planInfos_[planNum]); break; case tmudr::UDRInvocationInfo::COMPILER_PLAN_CALL: interfaceObj_->describePlanProperties(*invocationInfo_, *planInfos_[planNum]); break; case tmudr::UDRInvocationInfo::COMPILER_COMPLETION_CALL: interfaceObj_->completeDescription(*invocationInfo_, *planInfos_[planNum]); if (invocationInfo_->getDebugFlags() & tmudr::UDRInvocationInfo::PRINT_INVOCATION_INFO_END_COMPILE) { invocationInfo_->print(); printf("\n"); for (CollIndex i=0; i<planInfos_.getUsedLength(); i++) if (planInfos_.used(i)) { if (i == planNum) printf("++++++++++ Chosen plan: ++++++++++\n"); else printf("-------- Plan not chosen: --------\n"); planInfos_[i]->print(); } } break; case tmudr::UDRInvocationInfo::RUNTIME_WORK_CALL: { if (invocationInfo_->getDebugFlags() & tmudr::UDRInvocationInfo::PRINT_INVOCATION_INFO_AT_RUN_TIME) { invocationInfo_->print(); planInfos_[planNum]->print(); } if ((invocationInfo_->getDebugFlags() & tmudr::UDRInvocationInfo::DEBUG_INITIAL_RUN_TIME_LOOP_ALL) || (invocationInfo_->getDebugFlags() & tmudr::UDRInvocationInfo::DEBUG_INITIAL_RUN_TIME_LOOP_ONE && invocationInfo_->getMyInstanceNum() == 0)) interfaceObj_->debugLoop(); interfaceObj_->processData(*invocationInfo_, *planInfos_[planNum]); if (result == LM_OK) { if (invocationInfo_->getDebugFlags() & tmudr::UDRInvocationInfo::TRACE_ROWS) printf("(%d) Emitting EOD\n", invocationInfo_->getMyInstanceNum()); // call emitRow to indicate EOD, something the // C interface would do inside the UDF SQLUDR_Q_STATE qstate = SQLUDR_Q_EOD; (*interfaceObj_->emitRowPtr_)( invocationInfo_->out().getRowPtr(), 0, &qstate); } } break; default: *da << DgSqlCode(-11111) << DgString0("Invalid call phase in LmRoutineCppObj::invokeRoutineMethod()"); result = LM_ERR; break; } // return length of updated invocation and plan info for // compile-time phases if (invocationInfo_ && phase < tmudr::UDRInvocationInfo::RUNTIME_WORK_CALL) { *invocationInfoLenOut = invocationInfo_->serializedLength(); if (planInfos_.used(planNum)) *planInfoLenOut = planInfos_[planNum]->serializedLength(); } } catch (tmudr::UDRException e) { // Check the returned SQLSTATE value and raise appropriate // SQL code. Valid SQLSTATE values begin with "38" except "38000" const char *sqlState = e.getSQLState(); if ((strncmp(sqlState, "38", 2) == 0) && (strncmp(sqlState, "38000", 5) != 0)) { *da << DgSqlCode(-LME_CUSTOM_ERROR) << DgString0(e.getMessage().c_str()) << DgString1(sqlState); *da << DgCustomSQLState(sqlState); } else { *da << DgSqlCode(-LME_UDF_ERROR) << DgString0(invocationInfo_->getUDRName().c_str()) << DgString1(sqlState) << DgString2(e.getMessage().c_str()); } result = LM_ERR; } catch (...) { *da << DgSqlCode(-LME_OBJECT_INTERFACE_ERROR) << DgString0(getNameForDiags()) << DgString1(invocationInfo_->callPhaseToString(phase)) << DgString2("LmRoutineCppObj::invokeRoutineMethod()") << DgString3("general exception"); result = LM_ERR; } invocationInfo_->callPhase_ = tmudr::UDRInvocationInfo::UNKNOWN_CALL_PHASE; return result; }
LmResult LmLanguageManagerC::getRoutine( ComUInt32 numSqlParam, LmParameter parameters[], ComUInt32 numTableInfo, LmTableInfo tableInfo[], LmParameter *returnValue, ComRoutineParamStyle paramStyle, ComRoutineTransactionAttributes transactionAttrs, ComRoutineSQLAccess sqlAccessMode, const char *parentQid, ComUInt32 inputRowLen, ComUInt32 outputRowLen, const char *sqlName, const char *externalName, const char *routineSig, const char *containerName, const char *externalPath, const char *librarySqlName, const char *currentUserName, const char *sessionUserName, ComRoutineExternalSecurity externalSecurity, Int32 routineOwnerId, LmRoutine **handle, LmHandle getNextRowPtr, LmHandle emitRowPtr, ComUInt32 maxResultSets, ComDiagsArea *diagsArea) { *handle = NULL; LmContainer *container = NULL; LmResult result = LM_OK; ComDiagsArea *da = (diagsArea != NULL) ? diagsArea : diagsArea_; // Get the requested container from the CM. result = contManager_->getContainer(containerName, externalPath, &container, da); if (result == LM_ERR) return LM_ERR; // Get a handle to the requested routine LmHandle routinePtr = NULL; routinePtr = getRoutinePtr(container->getHandle(), externalName); const char *operation = "dlsym"; if (routinePtr == NULL) { char *libraryName = new (collHeap()) char[str_len(externalPath) + str_len(containerName) + 2]; sprintf(libraryName, "%s/%s", externalPath, containerName); *da << DgSqlCode(-LME_DLL_METHOD_NOT_FOUND) << DgString0(externalName) << DgString1(libraryName); addDllErrors(*da, operation, FALSE); NADELETEBASIC(libraryName, collHeap()); return LM_ERR; } // allocate an LM handle for the external method. LmRoutine *routineHandle = NULL; if (paramStyle == COM_STYLE_SQL) { routineHandle = new (collHeap()) LmRoutineCSql(sqlName, externalName, librarySqlName, numSqlParam, (char *)routineSig, maxResultSets, transactionAttrs, sqlAccessMode, externalSecurity, routineOwnerId, parentQid, inputRowLen, outputRowLen, currentUserName, sessionUserName, parameters, this, routinePtr, container, da); } else if (paramStyle == COM_STYLE_SQLROW) { routineHandle = new (collHeap()) LmRoutineCSqlRow(sqlName, externalName, librarySqlName, numSqlParam, (char *)routineSig, maxResultSets, transactionAttrs, sqlAccessMode, externalSecurity, routineOwnerId, parentQid, inputRowLen, outputRowLen, currentUserName, sessionUserName, parameters, this, routinePtr, container, da); } else if (paramStyle == COM_STYLE_TM) { routineHandle = new (collHeap()) LmRoutineCSqlRowTM(sqlName, externalName, librarySqlName, numSqlParam, numTableInfo, tableInfo, (char *)routineSig, maxResultSets, transactionAttrs, sqlAccessMode, externalSecurity, routineOwnerId, parentQid, inputRowLen, outputRowLen, currentUserName, sessionUserName, parameters, this, routinePtr, getNextRowPtr, emitRowPtr, container, da); } else { // XXX LM_ASSERT(0); char *paramStyleMsg = new (collHeap()) char[100]; sprintf(paramStyleMsg, "Unknown ParameterStyle(%d)", paramStyle); *da << DgSqlCode(-LME_VALIDATION_FAILED) << DgString0(externalName) << DgString1(paramStyleMsg); addDllErrors(*da, operation, FALSE); } // Verify the handle. if (routineHandle == NULL) { // DiagsArea is already filled if (container) contManager_->putContainer(container); return LM_ERR; } else { *handle = routineHandle; return LM_OK; } }
LmResult LmRoutineCppObj::getRoutineInvocationInfo( /* IN/OUT */ char *serializedInvocationInfo, /* IN */ Int32 invocationInfoMaxLen, /* OUT */ Int32 *invocationInfoLenOut, /* IN/OUT */ char *serializedPlanInfo, /* IN */ Int32 planInfoMaxLen, /* IN */ Int32 planNum, /* OUT */ Int32 *planInfoLenOut, /* IN/OUT */ ComDiagsArea *da) { LmResult result = LM_OK; // Retrieve updated invocation and plan info. // The invokeRoutineMethod provided the required buffer // space, so there is no excuse for having insufficient // buffer when calling this, and doing so will raise // an exception in the try block below. try { if (invocationInfo_ && invocationInfoMaxLen > 0) { char *tempiibuf = serializedInvocationInfo; int tempiilen = invocationInfoMaxLen; *invocationInfoLenOut = invocationInfo_->serialize( tempiibuf, tempiilen); } else *invocationInfoLenOut = 0; if (planInfos_.used(planNum) && planInfoMaxLen > 0) { char *temppibuf = serializedPlanInfo; int temppilen = planInfoMaxLen; *planInfoLenOut = planInfos_[planNum]->serialize( temppibuf, temppilen); } else *planInfoLenOut = 0; } catch (tmudr::UDRException e) { // this UDRException is generated by Trafodion code and // it is an internal error to fail serializing the structs, // even though the user might have caused it by corrupting // these structs *da << DgSqlCode(-LME_OBJECT_INTERFACE_ERROR) << DgString0(getNameForDiags()) << DgString1(invocationInfo_->callPhaseToString(invocationInfo_->getCallPhase())) << DgString2("LmRoutineCppObj::getRoutineInvocationInfo()") << DgString3(e.getMessage().c_str()); result = LM_ERR; } catch (...) { *da << DgSqlCode(-LME_OBJECT_INTERFACE_ERROR) << DgString0(getNameForDiags()) << DgString1(invocationInfo_->callPhaseToString(invocationInfo_->getCallPhase())) << DgString2("LmRoutineCppObj::getRoutineInvocationInfo()") << DgString3("general exception"); result = LM_ERR; } return result; }
// print MDFWriter errors to cout void SQLJFile::printMDFWriterErrors(char *errFileName) { char args[1024], EorW[10]; Int32 errNum; FILE *errFile = fopen(errFileName, "r"); if (errFile) { // accommodate case of MDFWriter dumping more entries into its errFile // than can fit into the fixed-size diags area. Do this by feeding // and then dumping diags one entry at a time. ComDiagsArea *myDiags = ComDiagsArea::allocate(mxCUMptr->heap()); while (fscanf(errFile, "%s %d ", EorW, &errNum) != EOF) { size_t sLen = 0; if (fgets(args, 1024, errFile) == NULL) { // fgets got EOF or an error args[0] = 0; // empty string *mxCUMptr << FAIL; } else { // fgets got something sLen = strlen(args); // chop off terminating newline if (args[sLen-1] == '\n') { args[sLen-1] = 0; } if (sLen >= 1023) { // diagnostic msg is too long // toss rest of line Int32 nxtCh; do { nxtCh = fgetc(errFile); } while (nxtCh != '\n' && nxtCh != EOF); } } if (!myDiags) { // no diags *mxCUMptr << FAIL; if (sLen >= 1023) { // diagnostic msg is too long cerr << "Diagnostic message is over 1023 characters long." << endl; } // echo error file entry to cerr cerr << EorW << " " << errNum << " " << args << endl; } else { if (sLen >= 1023) { // diagnostic msg is too long *mxCUMptr << WARNING; *myDiags << DgSqlCode(2237); } switch (errNum) { case 2224: case 2225: case 2226: *mxCUMptr << FAIL; *myDiags << DgSqlCode(-errNum); break; case 2227: case 2228: case 2230: *mxCUMptr << FAIL; *myDiags << DgSqlCode(-errNum) << DgString0(args); break; case 2229: *mxCUMptr << ERROR; *myDiags << DgSqlCode(-errNum) << DgString0(args); break; default: *mxCUMptr << (EorW[0]=='E' ? ERROR : (EorW[0]=='W' ? WARNING : FAIL)); *myDiags << DgSqlCode(-2231) << DgInt0(errNum) << DgString0(EorW) << DgString1(args); break; } // end switch NADumpDiags(cerr, myDiags, TRUE); myDiags->clear(); } // end if } // end while if (myDiags) { myDiags->decrRefCount(); } fclose(errFile); } else { *mxCUMptr << FAIL << DgSqlCode(-2218) << DgString0(errFileName); } // clean up temporary file (MDFWriter errors) remove(errFileName); }
// static helper function to generate one list of disks // (returns an array of ExScratchDiskDrive objects) static ExScratchDiskDrive * genScratchDriveList(const NAString &def, Lng32 &numDrives, Generator *generator, const char *defName) { ExScratchDiskDrive *result = NULL; // temporary // numDrives = 0; // return result; // end temporary const char *str = def.data(); if (!*str) { numDrives = 0; return result; // fast return if empty NADefaults val } // --------------------------------------------------------------------- // Convert the strings into a temporary list of ExScratchDiskDrive // objects (temporary because we want to make the final list a // contiguous array) // --------------------------------------------------------------------- LIST(ExScratchDiskDrive *) tempList; CollHeap *heap = generator->wHeap(); Space *space = generator->getSpace(); // --------------------------------------------------------------------- // process the NT default // --------------------------------------------------------------------- while (str && *str) { Lng32 nodeNum; char *driveLetter = new(heap) char[2]; driveLetter[1] = 0; if (ValidateDiskListNT::getNextDriveLetterAndAdvance( str,nodeNum,driveLetter[0])) { // syntax error in default, issue a warning (not an error) *CmpCommon::diags() << DgSqlCode(2055) << DgString0(def) << DgString1(defName); // don't continue after a syntax error str = NULL; } else { tempList.insert(new(heap) ExScratchDiskDrive( driveLetter, 1, // Thanks to Bill Gates nodeNum)); } NADELETEBASIC(driveLetter, heap); driveLetter = NULL; } // --------------------------------------------------------------------- // Calculate total generated space needed and allocate it // --------------------------------------------------------------------- #pragma nowarn(1506) // warning elimination numDrives = tempList.entries(); #pragma warn(1506) // warning elimination Lng32 allClusterNamesLen = 0; Lng32 allDiskNamesLen = 0; char *generatedClusterNames = NULL; char *generatedDiskNames = NULL; Int32 i=0; for (; i<numDrives; i++) { allClusterNamesLen += tempList[i]->getClusterNameLength()+1; allDiskNamesLen += str_len(tempList[i]->getDiskName())+1; } if (numDrives >0) { result = new(space) ExScratchDiskDrive[numDrives]; generatedClusterNames = new(space) char[allClusterNamesLen]; generatedDiskNames = new(space) char[allDiskNamesLen]; } // --------------------------------------------------------------------- // Loop over the temporary list and copy it into the generated space // --------------------------------------------------------------------- for (i=0; i<numDrives; i++) { ExScratchDiskDrive *src = tempList[i]; Lng32 clusterNameLen = src->getClusterNameLength(); Lng32 diskNameLen = src->getDiskNameLength(); if (clusterNameLen) { str_cpy_all(generatedClusterNames, src->getClusterName(), clusterNameLen); generatedClusterNames[clusterNameLen] = 0; result[i].setClusterName(generatedClusterNames); generatedClusterNames += clusterNameLen+1; } else { result[i].setClusterName(NULL); } result[i].setClusterNameLength(clusterNameLen); result[i].setClusterNumber(src->getClusterNumber()); result[i].setNodeNumber(src->getNodeNumber()); str_cpy_all(generatedDiskNames, src->getDiskName(), diskNameLen); generatedDiskNames[diskNameLen] = 0; result[i].setDiskName(generatedDiskNames); result[i].setDiskNameLength(diskNameLen); generatedDiskNames += diskNameLen+1; } return result; }
NABoolean CmpSqlSession::validateVolatileQualifiedName(QualifiedName &inName) { if (NOT Get_SqlParser_Flags(ALLOW_VOLATILE_SCHEMA_IN_TABLE_NAME)) { if (NOT inName.getCatalogName().isNull()) { // cannot be a 3-part name *CmpCommon::diags() << DgSqlCode(-4192); return FALSE; } if (NOT inName.getSchemaName().isNull()) { // validate that the schemaName part is the currentUserName if (inName.getSchemaName() != externalUserName_) { *CmpCommon::diags() << DgSqlCode(-4191) << DgString0(inName.getSchemaName()) << DgString1(externalUserName_); return FALSE; } } } else { // Volatile schema name is allowed. // Make sure that it is a valid volatile 3 part name. if ((NOT inName.getCatalogName().isNull()) && (NOT inName.getSchemaName().isNull())) { // move to a temp to upcase ComSchemaName csn(inName.getSchemaName()); ULng32 len = MINOF(strlen(csn.getSchemaNamePartAsAnsiString().data()), strlen(COM_VOLATILE_SCHEMA_PREFIX)); NAString upSch(csn.getSchemaNamePartAsAnsiString().data()); upSch.toUpper(); if ((len < strlen(COM_VOLATILE_SCHEMA_PREFIX)) || (strncmp(upSch.data(), COM_VOLATILE_SCHEMA_PREFIX, len) != 0)) { *CmpCommon::diags() << DgSqlCode(-4192); return FALSE; } } else if (NOT inName.getSchemaName().isNull()) { // 2 part name // validate that the schemaName part is the currentUserName if (inName.getSchemaName() != externalUserName_) { *CmpCommon::diags() << DgSqlCode(-4191) << DgString0(inName.getSchemaName()) << DgString1(externalUserName_); return FALSE; } } } return TRUE; }
// static helper function to generate one list of disks // (returns an array of ExScratchDiskDrive objects) static ExScratchDiskDrive * genScratchDisks(const NAString &def, Lng32 &numDirs, Generator *generator, const char *defName) { ExScratchDiskDrive *result = NULL; // temporary // numDrives = 0; // return result; // end temporary const char *str = def.data(); if (!str || str[0]=='\0') { numDirs = 0; return result; // fast return if empty NADefaults val } // --------------------------------------------------------------------- // Convert the strings into a temporary list of ExScratchDiskDrive // objects (temporary because we want to make the final list a // contiguous array) // --------------------------------------------------------------------- CollHeap *heap = generator->wHeap(); Space *space = generator->getSpace(); LIST(ExScratchDiskDrive *) tempList(heap); struct stat st; Lng32 nodeNum; char *token,*saveptr = NULL; //save the pointer to this since token will keep changing. char *sep = (char *)":"; token = strtok_r((char *)str,sep,&saveptr); while (token != NULL) { //validate the directory if ((stat(token,&st) != 0 ) && !S_ISDIR(st.st_mode) ) //&& (numDirs > MAX_SCRATCH_LOCATIONS)) { // syntax error in default, issue a warning (not an error) *CmpCommon::diags() << DgSqlCode(2055) << DgString0(def) << DgString1(defName); // don't continue after a syntax error str = NULL; } else { tempList.insert(new(heap) ExScratchDiskDrive( token, strlen(token) )); } token = strtok_r(NULL,sep,&saveptr); } token = NULL; // --------------------------------------------------------------------- // Calculate total generated space needed and allocate it // --------------------------------------------------------------------- numDirs = tempList.entries(); Lng32 allDirNamesLen = 0; char *generatedDirNames = NULL; Int32 i=0; for (; i<numDirs; i++) { allDirNamesLen += str_len(tempList[i]->getDirName())+1; } if (numDirs >0) { result = new(space) ExScratchDiskDrive[numDirs]; generatedDirNames = new(space) char[allDirNamesLen]; } // --------------------------------------------------------------------- // Loop over the temporary list and copy it into the generated space // --------------------------------------------------------------------- for (i=0; i<numDirs; i++) { ExScratchDiskDrive *src = tempList[i]; Lng32 dirNameLen = src->getDirNameLength(); str_cpy_all(generatedDirNames, src->getDirName(), dirNameLen); generatedDirNames[dirNameLen] = 0; result[i].setDirName(generatedDirNames); result[i].setDirNameLength(dirNameLen); generatedDirNames += dirNameLen+1; } return result; }
ExprNode * ElemDDLPartitionSystem::bindNode(BindWA * /*pBindWA*/) { // // location // ComLocationName defaultLocName; // empty object if (getLocationName().isNull()) // // location clause not specified (only allowed for primary partition) // guardianLocation_ = defaultLocName.getGuardianFullyQualifiedName(); else // LOCATION clause was specified { ComLocationName locName; // empty object switch (getLocationNameType()) { case ElemDDLLocation::LOCATION_GUARDIAN_NAME : locName.copy(getLocationName(), ComLocationName::GUARDIAN_LOCATION_NAME_FORMAT); if (NOT locName.isValid()) { // Illegal location name format. *SqlParser_Diags << DgSqlCode(-3061) << DgString0(getLocationName()); guardianLocation_ = defaultLocName.getGuardianFullyQualifiedName(); } else // valid location guardianLocation_ = locName.getGuardianFullyQualifiedName(); break; case ElemDDLLocation::LOCATION_OSS_NAME : locName.copy(getLocationName(), ComLocationName::OSS_LOCATION_NAME_FORMAT); if (NOT locName.isValid()) { // Illegal location name format. *SqlParser_Diags << DgSqlCode(-3061) << DgString0(getLocationName()); guardianLocation_ = defaultLocName.getGuardianFullyQualifiedName(); } else // valid location guardianLocation_ = locName.getGuardianFullyQualifiedName(); break; #if 0 // // Currently we do not handle this case // The grammar productions don't accept this syntax. // So comment out the following code for now. // case ElemDDLLocation::LOCATION_ENVIRONMENT_VARIABLE : { NAString envVarName(getLocationName()); // // if the specified OSS environment variable has the // dollar sign prefix, removes it. // if (envVarName[(size_t) 0] EQU '$') // NT_PORT FIX SK 07/15/96 { envVarName = envVarName(1/*startpos*/, envVarName.length() - 1); } const char * pEnvVarValue = getenv((const char *)envVarName); NAString locationName; if (pEnvVarValue NEQ NULL) { locationName = pEnvVarValue; } if (locationName.isNull()) { guardianLocation_ = defaultLocName. getGuardianFullyQualifiedName(); } else { guardianLocationName = locationName; if (guardianLocationName.isValid()) { guardianLocation_ = (guardianLocationName. getGuardianFullyQualifiedName()); } else { ossLocationName = locationName; if (ossLocationName.isValid()) { guardianLocation_ = (ossLocationName. getGuardianFullyQualifiedName()); } else { // OSS environment variable $1~string1 contains illegal // location name $0~string0. *SqlParser_Diags << DgSqlCode(-3061) << DgString0(locationName) << DgString1(envVarName) ; } } } } break; #endif // 0 default : NAAbort("ElemDDLPartition.C", __LINE__, "internal logic error"); break; } } markAsBound(); return this; }
ExWorkProcRetcode ExCancelTcb::work() { ExMasterStmtGlobals *masterGlobals = getGlobals()->castToExExeStmtGlobals()->castToExMasterStmtGlobals(); CliGlobals *cliGlobals = masterGlobals->getCliGlobals(); while ((qparent_.down->isEmpty() == FALSE) && (qparent_.up->isFull() == FALSE)) { ex_queue_entry *pentry_down = qparent_.down->getHeadEntry(); switch (step_) { case NOT_STARTED: { if (pentry_down->downState.request == ex_queue::GET_NOMORE) step_ = DONE; else { retryCount_ = 0; // Priv checking is done during compilation. To support // REVOKE, prevent a prepared CANCEL/SUSPEND/ACTIVATE // that was compiled more than 1 second ago from executing // by raising the 8734 error to force an AQR. Int64 microSecondsSinceCompile = NA_JulianTimestamp() - masterGlobals->getStatement()->getCompileEndTime(); if (microSecondsSinceCompile > 1000*1000) { ComDiagsArea *diagsArea = ComDiagsArea::allocate(getGlobals()->getDefaultHeap()); *diagsArea << DgSqlCode(-CLI_INVALID_QUERY_PRIVS); reportError(diagsArea); step_ = DONE; break; } // Figure out which MXSSMP broker to use. if (cancelTdb().getAction() == ComTdbCancel::CancelByPname) { int nid = -1; int rc = msg_mon_get_process_info(cancelTdb().getCancelPname(), &nid, &pid_); switch (rc) { case XZFIL_ERR_OK: cpu_ = (short) nid; break; case XZFIL_ERR_NOTFOUND: case XZFIL_ERR_BADNAME: case XZFIL_ERR_NOSUCHDEV: { ComDiagsArea *diagsArea = ComDiagsArea::allocate(getGlobals()->getDefaultHeap()); *diagsArea << DgSqlCode(-EXE_CANCEL_PROCESS_NOT_FOUND); *diagsArea << DgString0(cancelTdb().getCancelPname()); reportError(diagsArea); step_ = DONE; break; } default: { char buf[200]; str_sprintf(buf, "Unexpected error %d returned from " "msg_mon_get_process_info", rc); ex_assert(0, buf); } } if (step_ != NOT_STARTED) break; } else if (cancelTdb().getAction() == ComTdbCancel::CancelByNidPid) { cpu_ = (short) cancelTdb().getCancelNid(); pid_ = cancelTdb().getCancelPid(); // check that process exists, if not report error. char processName[MS_MON_MAX_PROCESS_NAME]; int rc = msg_mon_get_process_name(cpu_, pid_, processName); if (XZFIL_ERR_OK == rc) ; // good. nid & pid are valid. else { if ((XZFIL_ERR_NOTFOUND != rc) && (XZFIL_ERR_BADNAME != rc) && (XZFIL_ERR_NOSUCHDEV != rc)) { // Log rc in case it needs investigation later. char buf[200]; str_sprintf(buf, "Unexpected error %d returned from " "msg_mon_get_process_name", rc); SQLMXLoggingArea::logExecRtInfo(__FILE__, __LINE__, buf, 0); } char nid_pid_str[32]; str_sprintf(nid_pid_str, "%d, %d", cpu_, pid_); ComDiagsArea *diagsArea = ComDiagsArea::allocate(getGlobals()->getDefaultHeap()); *diagsArea << DgSqlCode(-EXE_CANCEL_PROCESS_NOT_FOUND); *diagsArea << DgString0(nid_pid_str); reportError(diagsArea); step_ = DONE; break; } } else { char * qid = cancelTdb().qid_; Lng32 qid_len = str_len(qid); // This static method is defined in SqlStats.cpp. It side-effects // the nodeName and cpu_ according to the input qid. if (getMasterCpu( qid, qid_len, nodeName_, sizeof(nodeName_) - 1, cpu_) == -1) { ComDiagsArea *diagsArea = ComDiagsArea::allocate(getGlobals()->getDefaultHeap()); *diagsArea << DgSqlCode(-EXE_RTS_INVALID_QID); reportError(diagsArea); step_ = DONE; break; } } // Testpoints for hard to reproduce problems: bool fakeError8028 = false; fakeError8028 = (getenv("HP_FAKE_ERROR_8028") != NULL); if ((cliGlobals->getCbServerClass() == NULL) || fakeError8028) { ComDiagsArea *diagsArea = ComDiagsArea::allocate(getGlobals()->getDefaultHeap()); *diagsArea << DgSqlCode(-EXE_CANCEL_PROCESS_NOT_FOUND); *diagsArea << DgString0("$ZSM000"); reportError(diagsArea); step_ = DONE; break; } ComDiagsArea *diagsArea = NULL; bool fakeError2024 = false; fakeError2024 = (getenv("HP_FAKE_ERROR_2024") != NULL); if (fakeError2024) { cbServer_ = NULL; diagsArea = ComDiagsArea::allocate(getGlobals()->getDefaultHeap()); if (getenv("HP_FAKE_ERROR_8142")) { *diagsArea << DgSqlCode(-8142); *diagsArea << DgString0(__FILE__); *diagsArea << DgString1("cbServer_ is NULL"); } else *diagsArea << DgSqlCode(-2024); } else cbServer_ = cliGlobals->getCbServerClass()->allocateServerProcess( &diagsArea, cliGlobals->getEnvironment()->getHeap(), nodeName_, cpu_, IPC_PRIORITY_DONT_CARE, FALSE, // usesTransactions TRUE, // waitedCreation 2 // maxNowaitRequests -- cancel+(1 extra). ); if (cbServer_ == NULL || cbServer_->getControlConnection() == NULL) { ex_assert(diagsArea != NULL, "allocateServerProcess failed, but no diags"); // look for SQLCode 2024 // "*** ERROR[2024] Server Process $0~string0 // is not running or could not be created. Operating System // Error $1~int0 was returned." // Remap to cancel-specfic error 8028. if (diagsArea->contains(-2024) && cancelTdb().actionIsCancel()) { diagsArea->deleteError(diagsArea->returnIndex(-2024)); reportError(diagsArea, true, EXE_CANCEL_PROCESS_NOT_FOUND, nodeName_, cpu_); } else reportError(diagsArea); step_ = DONE; break; } // the reportError method was not called -- see break above. if (diagsArea != NULL) diagsArea->decrRefCount(); //Create the stream on the IpcHeap, since we don't dispose // of it immediately. We just add it to the list of completed // messages in the IpcEnv, and it is disposed of later. cancelStream_ = new (cliGlobals->getIpcHeap()) CancelMsgStream(cliGlobals->getEnvironment(), this); cancelStream_->addRecipient(cbServer_->getControlConnection()); } step_ = SEND_MESSAGE; break; } // end case NOT_STARTED #pragma warning (disable : 4291) case SEND_MESSAGE: { RtsHandle rtsHandle = (RtsHandle) this; if (cancelTdb().actionIsCancel()) { Int64 cancelStartTime = JULIANTIMESTAMP(); Lng32 firstEscalationInterval = cliGlobals->currContext()-> getSessionDefaults()->getCancelEscalationInterval(); Lng32 secondEscalationInterval = cliGlobals->currContext()-> getSessionDefaults()->getCancelEscalationMxosrvrInterval(); NABoolean cancelEscalationSaveabend = cliGlobals->currContext()-> getSessionDefaults()->getCancelEscalationSaveabend(); bool cancelLogging = (TRUE == cliGlobals->currContext()-> getSessionDefaults()->getCancelLogging()); CancelQueryRequest *cancelMsg = new (cliGlobals->getIpcHeap()) CancelQueryRequest(rtsHandle, cliGlobals->getIpcHeap(), cancelStartTime, firstEscalationInterval, secondEscalationInterval, cancelEscalationSaveabend, cancelTdb().getCommentText(), str_len(cancelTdb().getCommentText()), cancelLogging, cancelTdb().action_ != ComTdbCancel::CancelByQid, pid_, cancelTdb().getCancelPidBlockThreshold()); #pragma warning (default : 4291) *cancelStream_ << *cancelMsg; cancelMsg->decrRefCount(); } else if (ComTdbCancel::Suspend == cancelTdb().action_) { bool suspendLogging = (TRUE == cliGlobals->currContext()-> getSessionDefaults()->getSuspendLogging()); #pragma warning (disable : 4291) SuspendQueryRequest * suspendMsg = new (cliGlobals->getIpcHeap()) SuspendQueryRequest(rtsHandle, cliGlobals->getIpcHeap(), ComTdbCancel::Force == cancelTdb().forced_, suspendLogging); #pragma warning (default : 4291) *cancelStream_ << *suspendMsg; suspendMsg->decrRefCount(); } else { ex_assert( ComTdbCancel::Activate == cancelTdb().action_, "invalid action for ExCancelTcb"); bool suspendLogging = (TRUE == cliGlobals->currContext()-> getSessionDefaults()->getSuspendLogging()); #pragma warning (disable : 4291) ActivateQueryRequest * activateMsg = new (cliGlobals->getIpcHeap()) ActivateQueryRequest(rtsHandle, cliGlobals->getIpcHeap(), suspendLogging); #pragma warning (default : 4291) *cancelStream_ << *activateMsg; activateMsg->decrRefCount(); } if ((cancelTdb().getAction() != ComTdbCancel::CancelByPname) && (cancelTdb().getAction() != ComTdbCancel::CancelByNidPid)) { char * qid = cancelTdb().qid_; Lng32 qid_len = str_len(qid); #pragma warning (disable : 4291) RtsQueryId *rtsQueryId = new (cliGlobals->getIpcHeap()) RtsQueryId( cliGlobals->getIpcHeap(), qid, qid_len); #pragma warning (default : 4291) *cancelStream_ << *rtsQueryId; rtsQueryId->decrRefCount(); } // send a no-wait request to the cancel broker. cancelStream_->send(FALSE); step_ = GET_REPLY; // Come back when I/O completes. return WORK_OK; break; } // end case SEND_MESSAGE case GET_REPLY: { // Handle general IPC error. bool fakeError201 = false; fakeError201 = (getenv("HP_FAKE_ERROR_201") != NULL); if ((cbServer_->getControlConnection()->getErrorInfo() != 0) || fakeError201) { ComDiagsArea *diagsArea = ComDiagsArea::allocate(getGlobals()->getDefaultHeap()); cbServer_->getControlConnection()-> populateDiagsArea( diagsArea, getGlobals()->getDefaultHeap()); if (fakeError201) { *diagsArea << DgSqlCode(-2034) << DgInt0(201) << DgString0("I say") << DgString1("control broker"); } if (diagsArea->contains(-8921)) { // Should not get timeout error 8921. Get a core-file // of the SSMP and this process too so that this can be // debugged. cbServer_->getControlConnection()-> dumpAndStopOtherEnd(true, false); genLinuxCorefile("Unexpected timeout error"); } reportError(diagsArea); step_ = DONE; break; } // See if stream has the reply yet. if (!cancelStream_->moreObjects()) return WORK_OK; #pragma warning (disable : 4291) ControlQueryReply *reply = new (cliGlobals->getIpcHeap()) ControlQueryReply(INVALID_RTS_HANDLE, cliGlobals->getIpcHeap()); #pragma warning (default : 4291) *cancelStream_ >> *reply; if (reply->didAttemptControl()) { // yeaah! cancelStream_->clearAllObjects(); } else { if (cancelStream_->moreObjects() && cancelStream_->getNextObjType() == IPC_SQL_DIAG_AREA) { ComDiagsArea *diagsArea = ComDiagsArea::allocate(getGlobals()->getDefaultHeap()); *cancelStream_ >> *diagsArea; cancelStream_->clearAllObjects(); if ( retryQidNotActive_ && (diagsArea->mainSQLCODE() == -EXE_SUSPEND_QID_NOT_ACTIVE) && (++retryCount_ <= 60)) { SQLMXLoggingArea::logExecRtInfo(__FILE__, __LINE__, "Retrying error 8672.", 0); DELAY(500); diagsArea->decrRefCount(); step_ = SEND_MESSAGE; break; } reportError(diagsArea); } else ex_assert(0, "Control failed, but no diagnostics."); } step_ = DONE; break; } case DONE: { if (cancelStream_) { cancelStream_->addToCompletedList(); cancelStream_ = NULL; } if (cbServer_) { cbServer_->release(); cbServer_ = NULL; } ex_queue_entry * up_entry = qparent_.up->getTailEntry(); up_entry->copyAtp(pentry_down); up_entry->upState.parentIndex = pentry_down->downState.parentIndex; up_entry->upState.downIndex = qparent_.down->getHeadIndex(); up_entry->upState.setMatchNo(1); up_entry->upState.status = ex_queue::Q_NO_DATA; qparent_.up->insert(); qparent_.down->removeHead(); step_ = NOT_STARTED; break; } default: ex_assert( 0, "Unknown step_."); }
// // Set private data members corresponding to the SG options // specified in a file option or load option phrases in a SG // clause. This method also looks for duplicate phrases. // void ElemDDLSGOptions::setSGOpt(ElemDDLNode * pSGOpt) { switch(pSGOpt->getOperatorType()) { case ELM_SG_OPT_START_VALUE_ELEM : if (isStartValueSpec_) { // cout << "*** Error *** Duplicate options in sg option list. if (ieType_ == SG_INTERNAL) *SqlParser_Diags << DgSqlCode(-3427) << DgString0("START WITH") << DgString1("IDENTITY column"); else *SqlParser_Diags << DgSqlCode(-3427) << DgString0("START WITH") << DgString1("sequence generator"); } isStartValueSpec_ = TRUE; startValue_ = pSGOpt->castToElemDDLSGOptionStartValue()->getValue(); break; case ELM_SG_OPT_INCREMENT_ELEM : if (isIncrementSpec_) { // cout << "*** Error *** Duplicate options in sg option list. if (ieType_ == SG_INTERNAL) *SqlParser_Diags << DgSqlCode(-3427) << DgString0("INCREMENT BY") << DgString1("IDENTITY column"); else *SqlParser_Diags << DgSqlCode(-3427) << DgString0("INCREMENT BY") << DgString1("sequence generator"); } isIncrementSpec_ = TRUE; increment_ = pSGOpt->castToElemDDLSGOptionIncrement()->getValue(); break; case ELM_SG_OPT_MIN_VALUE_ELEM : if (isMinValueSpec_) { // cout << "*** Error *** Duplicate options in sg option list. if (ieType_ == SG_INTERNAL) *SqlParser_Diags << DgSqlCode(-3427) << DgString0("MINVALUE") << DgString1("IDENTITY column"); else *SqlParser_Diags << DgSqlCode(-3427) << DgString0("MINVALUE") << DgString1("sequence generator"); } isMinValueSpec_ = TRUE; minValue_ = pSGOpt->castToElemDDLSGOptionMinValue()->getValue(); isNoMinValue_ = pSGOpt->castToElemDDLSGOptionMinValue()->isNoMinValue(); break; case ELM_SG_OPT_MAX_VALUE_ELEM : if (isMaxValueSpec_) { // cout << "*** Error *** Duplicate options in sg option list. if (ieType_ == SG_INTERNAL) *SqlParser_Diags << DgSqlCode(-3427) << DgString0("MAXVALUE") << DgString1("IDENTITY column"); else *SqlParser_Diags << DgSqlCode(-3427) << DgString0("MAXVALUE") << DgString1("sequence generator"); } isMaxValueSpec_ = TRUE; maxValue_ = pSGOpt->castToElemDDLSGOptionMaxValue()->getValue(); isNoMaxValue_ = pSGOpt->castToElemDDLSGOptionMaxValue()->isNoMaxValue(); break; case ELM_SG_OPT_CYCLE_OPTION_ELEM : if (isCycleSpec_) { // cout << "*** Error *** Duplicate options in sg option list. if (ieType_ == SG_INTERNAL) *SqlParser_Diags << DgSqlCode(-3427) << DgString0("CYCLE") << DgString1("IDENTITY column"); else *SqlParser_Diags << DgSqlCode(-3427) << DgString0("CYCLE") << DgString1("sequence generator"); } isCycleSpec_ = TRUE; cycle_ = pSGOpt->castToElemDDLSGOptionCycleOption()->getValue(); break; case ELM_SG_OPT_CACHE_OPTION_ELEM : if (isCacheSpec_) { // cout << "*** Error *** Duplicate options in sg option list. if (ieType_ == SG_INTERNAL) *SqlParser_Diags << DgSqlCode(-3427) << DgString0("CACHE") << DgString1("IDENTITY column"); else *SqlParser_Diags << DgSqlCode(-3427) << DgString0("CACHE") << DgString1("sequence generator"); } isCacheSpec_ = TRUE; cache_ = pSGOpt->castToElemDDLSGOptionCacheOption()->getCacheSize(); isNoCache_ = pSGOpt->castToElemDDLSGOptionCacheOption()->isNoCache(); break; case ELM_SG_OPT_DATATYPE_ELEM : if (isDatatypeSpec_) { // cout << "*** Error *** Duplicate options in sg option list. if (ieType_ == SG_INTERNAL) *SqlParser_Diags << DgSqlCode(-3427) << DgString0("DATATYPE") << DgString1("IDENTITY column"); else *SqlParser_Diags << DgSqlCode(-3427) << DgString0("DATATYPE") << DgString1("sequence generator"); } isDatatypeSpec_ = TRUE; fsDataType_ = pSGOpt->castToElemDDLSGOptionDatatype()->getDatatype(); break; case ELM_SG_OPT_RESET_OPTION_ELEM : if (isResetSpec_) { // cout << "*** Error *** Duplicate options in sg option list. if (ieType_ == SG_INTERNAL) *SqlParser_Diags << DgSqlCode(-3427) << DgString0("RESET") << DgString1("IDENTITY column"); else *SqlParser_Diags << DgSqlCode(-3427) << DgString0("RESET") << DgString1("sequence generator"); } isResetSpec_ = TRUE; reset_ = TRUE; break; default : ABORT("internal logic error"); break; } } // ElemDDLSGOptions::setSGOpt()
// queryType: 0, create sequence. 1, alter sequence. 2, IDENTITY col. short ElemDDLSGOptions::validate(short queryType) { char queryTypeStr[40]; if (queryType == 0) strcpy(queryTypeStr, "CREATE SEQUENCE"); else if (queryType == 1) strcpy(queryTypeStr, "ALTER SEQUENCE"); else strcpy(queryTypeStr, "IDENTITY column"); Int64 minValue = 0; Int64 startValue = 0; Int64 increment = 0; Int64 maxValue = LONG_MAX - 1; NAString dtStr; if (fsDataType_ != COM_UNKNOWN_FSDT) { switch (fsDataType_) { case COM_UNSIGNED_BIN16_FSDT: maxValue = USHRT_MAX; dtStr = COM_SMALLINT_UNSIGNED_SDT_LIT; break; case COM_UNSIGNED_BIN32_FSDT: maxValue = UINT_MAX; dtStr = COM_INTEGER_UNSIGNED_SDT_LIT; break; case COM_SIGNED_BIN64_FSDT: maxValue = LONG_MAX - 1; dtStr = COM_LARGEINT_SIGNED_SDT_LIT; break; default: *CmpCommon::diags() << DgSqlCode(-1510); return -1; } } if (queryType == 1) // alter { if ((isMinValueSpecified()|| isStartValueSpecified())) { *CmpCommon::diags() << DgSqlCode(-1592) << (isMinValueSpecified() ? DgString0("MINVALUE") : DgString0("START WITH")) << DgString1(queryTypeStr); return -1; } minValue = getMinValue(); startValue = getStartValue(); increment = getIncrement(); if (isMaxValueSpecified() && (NOT isNoMaxValue())) { if ((fsDataType_ != COM_UNKNOWN_FSDT) && (getMaxValue() > maxValue)) { *CmpCommon::diags() << DgSqlCode(-1576) << DgString0("MAXVALUE") << DgString1(dtStr); return -1; } } maxValue = getMaxValue(); } // alter else { if (isResetSpecified()) { *CmpCommon::diags() << DgSqlCode(-1592) << DgString0("RESET") << DgString1(queryTypeStr); return -1; } minValue = ((isMinValueSpecified() && (NOT isNoMinValue())) ? getMinValue() : 1LL); startValue = (isStartValueSpecified() ? getStartValue() : minValue); increment = (isIncrementSpecified() ? getIncrement() : 1LL); } //else if (isMaxValueSpecified() && (NOT isNoMaxValue())) { if ((fsDataType_ != COM_UNKNOWN_FSDT) && (getMaxValue() > maxValue)) { *CmpCommon::diags() << DgSqlCode(-1576) << DgString0("MAXVALUE") << DgString1(dtStr); return -1; } maxValue = getMaxValue(); } if (minValue == 0) { *CmpCommon::diags() << DgSqlCode(-1571) << DgString0("MINVALUE") << DgString1(queryTypeStr); return -1; } if (minValue < 0) { *CmpCommon::diags() << DgSqlCode(-1572) << DgString0("MINVALUE") << DgString1(queryTypeStr); return -1; } if (maxValue == 0) { *CmpCommon::diags() << DgSqlCode(-1571) << DgString0("MAXVALUE") << DgString1(queryTypeStr); return -1; } if (maxValue < 0) { *CmpCommon::diags() << DgSqlCode(-1572) << DgString0("MAXVALUE") << DgString1(queryTypeStr); return -1; } if (increment == 0) { *CmpCommon::diags() << DgSqlCode(-1571) << DgString0("INCREMENT BY") << DgString1(queryTypeStr); return -1; } if (increment < 0) { *CmpCommon::diags() << DgSqlCode(-1572) << DgString0("INCREMENT BY") << DgString1(queryTypeStr); return -1; } if (startValue < 0) { *CmpCommon::diags() << DgSqlCode(-1572) << DgString0("START WITH") << DgString1(queryTypeStr); return -1; } if (maxValue <= minValue) { *CmpCommon::diags() << DgSqlCode(-1570) << DgString0(queryTypeStr); return -1; } if (startValue > maxValue) { *CmpCommon::diags() << DgSqlCode(-1573) << DgString0(queryTypeStr); return -1; } if (startValue < minValue) { *CmpCommon::diags() << DgSqlCode(-1573) << DgString0(queryTypeStr); return -1; } if (increment > (maxValue - minValue)) { *CmpCommon::diags() << DgSqlCode(-1575) << DgString0(queryTypeStr); return -1; } Int64 cache = 0; Int64 minVal = MAXOF(startValue, minValue); Int64 rangeOfVals = (maxValue-minVal)/increment + 1; if (isCacheSpecified()) cache = getCache(); else cache = MINOF(rangeOfVals, 25); if (NOT isNoCache()) { if ((cache <= 1) || (cache > rangeOfVals)) { *CmpCommon::diags() << DgSqlCode(-1577) << DgString0(queryTypeStr); return -1; } } cache = MINOF(rangeOfVals, cache); setStartValue(startValue); setIncrement(increment); setMinValue(minValue); setMaxValue(maxValue); if (NOT isCacheSpecified()) setCache(cache); return 0; }
void ParDDLLikeOptsCreateTable::setLikeOption(ElemDDLLikeOpt * pLikeOption) { ComASSERT(pLikeOption != NULL); switch (pLikeOption->getOperatorType()) { case ELM_LIKE_OPT_WITHOUT_CONSTRAINTS_ELEM : if (isLikeOptWithoutConstraintsSpec_) { *SqlParser_Diags << DgSqlCode(-3149); // "*** Error *** Duplicate WITHOUT CONSTRAINTS phrases " // << "in LIKE clause" << endl; } ComASSERT(pLikeOption->castToElemDDLLikeOptWithoutConstraints() != NULL); isLikeOptWithoutConstraints_ = TRUE; isLikeOptWithoutConstraintsSpec_ = TRUE; break; case ELM_LIKE_OPT_WITH_HEADINGS_ELEM : if (isLikeOptWithHeadingsSpec_) { *SqlParser_Diags << DgSqlCode(-3150); // cout << "*** Error *** Duplicate WITH HEADING phrases " // << "in LIKE clause" << endl; } ComASSERT(pLikeOption->castToElemDDLLikeOptWithHeadings() != NULL); isLikeOptWithHeadings_ = TRUE; isLikeOptWithHeadingsSpec_ = TRUE; break; case ELM_LIKE_OPT_WITH_HORIZONTAL_PARTITIONS_ELEM : if (isLikeOptWithHorizontalPartitionsSpec_) { *SqlParser_Diags << DgSqlCode(-3151); //cout << "*** Error *** Duplicate WITH HORIZONTAL PARTITIONS phrases " // << "in LIKE clause" << endl; } ComASSERT(pLikeOption->castToElemDDLLikeOptWithHorizontalPartitions() != NULL); isLikeOptWithHorizontalPartitions_ = TRUE; isLikeOptWithHorizontalPartitionsSpec_ = TRUE; break; case ELM_LIKE_OPT_WITHOUT_SALT_ELEM : if (isLikeOptWithoutSaltSpec_) { // ERROR[3152] Duplicate WITHOUT SALT phrases were specified // in LIKE clause in CREATE TABLE statement. *SqlParser_Diags << DgSqlCode(-3152) << DgString0("SALT"); } if (isLikeOptSaltClauseSpec_) { // ERROR[3154] The WITHOUT SALT clause is not allowed with the SALT clause. *SqlParser_Diags << DgSqlCode(-3154) << DgString0("WITHOUT SALT") << DgString1("SALT"); } ComASSERT(pLikeOption->castToElemDDLLikeOptWithoutSalt() != NULL); isLikeOptWithoutSalt_ = TRUE; isLikeOptWithoutSaltSpec_ = TRUE; break; case ELM_LIKE_OPT_SALT_CLAUSE_ELEM: { // braces needed since we declare some variables in this case if (isLikeOptSaltClauseSpec_) { // ERROR[3183] Duplicate SALT clauses were specified. *SqlParser_Diags << DgSqlCode(-3183) << DgString0("SALT"); } if (isLikeOptWithoutSaltSpec_) { // ERROR[3154] The WITHOUT SALT clause is not allowed with the SALT clause. *SqlParser_Diags << DgSqlCode(-3154) << DgString0("WITHOUT SALT") << DgString1("SALT"); } ComASSERT(pLikeOption->castToElemDDLLikeSaltClause() != NULL); isLikeOptSaltClauseSpec_ = TRUE; isLikeOptSaltClause_ = new (PARSERHEAP()) NAString(); ElemDDLLikeSaltClause * saltClauseWrapper = pLikeOption->castToElemDDLLikeSaltClause(); const ElemDDLSaltOptionsClause * saltOptions = saltClauseWrapper->getSaltClause(); saltOptions->unparseIt(*isLikeOptSaltClause_ /* side-effected */); isLikeOptWithoutSalt_ = TRUE; // suppresses any SALT clause from the source table } break; case ELM_LIKE_OPT_WITHOUT_DIVISION_ELEM : if (isLikeOptWithoutDivisionSpec_) { // ERROR[3152] Duplicate WITHOUT DIVISION phrases were specified // in LIKE clause in CREATE TABLE statement. *SqlParser_Diags << DgSqlCode(-3152) << DgString0("DIVISION"); } ComASSERT(pLikeOption->castToElemDDLLikeOptWithoutDivision() != NULL); isLikeOptWithoutDivision_ = TRUE; isLikeOptWithoutDivisionSpec_ = TRUE; break; case ELM_LIKE_OPT_LIMIT_COLUMN_LENGTH: { if (isLikeOptLimitColumnLengthSpec_) { // ERROR[3152] Duplicate LIMIT COLUMN LENGTH phrases were specified // in LIKE clause in CREATE TABLE statement. *SqlParser_Diags << DgSqlCode(-3152) << DgString0("LIMIT COLUMN LENGTH"); } ComASSERT(pLikeOption->castToElemDDLLikeLimitColumnLength() != NULL); ElemDDLLikeLimitColumnLength * limitColumnLength = pLikeOption->castToElemDDLLikeLimitColumnLength(); isLikeOptColumnLengthLimit_ = limitColumnLength->getColumnLengthLimit(); isLikeOptLimitColumnLengthSpec_ = TRUE; } break; case ELM_LIKE_OPT_WITHOUT_ROW_FORMAT_ELEM : if (isLikeOptWithoutRowFormatSpec_) { // ERROR[3152] Duplicate WITHOUT ROW FORMAT phrases were specified // in LIKE clause in CREATE TABLE statement. *SqlParser_Diags << DgSqlCode(-3152) << DgString0("ROW FORMAT"); } ComASSERT(pLikeOption->castToElemDDLLikeOptWithoutRowFormat() != NULL); isLikeOptWithoutRowFormat_ = TRUE; isLikeOptWithoutRowFormatSpec_ = TRUE; break; default : NAAbort("ParDDLLikeOpts.C", __LINE__, "internal logic error"); break; } } // ParDDLLikeOptsCreateTable::setLikeOption()
void EspNewIncomingConnectionStream::actOnReceive(IpcConnection *connection) { // check for OS errors if (getState() == ERROR_STATE) { ex_assert(FALSE,"Error while receiving first message from client"); } // check for protocol errors bool willPassTheAssertion = (getType() == IPC_MSG_SQLESP_DATA_REQUEST OR getType() == IPC_MSG_SQLESP_CANCEL_REQUEST) AND getVersion() == CurrEspRequestMessageVersion AND moreObjects(); if (!willPassTheAssertion) { char *doCatchBugCRx = getenv("ESP_BUGCATCHER_CR_NONUMBER"); if (!doCatchBugCRx || *doCatchBugCRx != '0') { connection->dumpAndStopOtherEnd(true, false); environment_->getControlConnection()-> castToGuaReceiveControlConnection()-> getConnection()->dumpAndStopOtherEnd(true, false); } } ex_assert((getType() == IPC_MSG_SQLESP_DATA_REQUEST OR getType() == IPC_MSG_SQLESP_CANCEL_REQUEST) AND getVersion() == CurrEspRequestMessageVersion AND moreObjects(), "Invalid first message from client"); // take a look at the type of the first object in the message IpcMessageObjType nextObjType = getNextObjType(); switch (nextObjType) { case ESP_OPEN_HDR: case ESP_LATE_CANCEL_HDR: { ExFragKey key; Lng32 remoteInstNum; NABoolean isParallelExtract = false; // peek at the message header to see for whom it is if (nextObjType == ESP_OPEN_HDR) { ExEspOpenReqHeader reqHdr((NAMemory *) NULL); *this >> reqHdr; key = reqHdr.key_; remoteInstNum = reqHdr.myInstanceNum_; if (reqHdr.getOpenType() == ExEspOpenReqHeader::PARALLEL_EXTRACT) { isParallelExtract = true; } } else { // note that the late cancel request may or may not // arrive as the first request (only in the former case // will we reach here) ExEspLateCancelReqHeader reqHdr((NAMemory *) NULL); *this >> reqHdr; key = reqHdr.key_; remoteInstNum = reqHdr.myInstanceNum_; } if (!isParallelExtract) { ExFragInstanceHandle handle = espFragInstanceDir_->findHandle(key); if (handle != NullFragInstanceHandle) { // the send bottom node # myInstanceNum of this downloaded fragment // is the true recipient of this open request ex_split_bottom_tcb * receivingTcb = espFragInstanceDir_->getTopTcb(handle); ex_send_bottom_tcb *receivingSendTcb = receivingTcb->getSendNode(remoteInstNum); // Check the connection for a co-located client, and if so, // tell the split bottom, because it may prefer this send // bottom when using skew buster uniform distribution. if (espFragInstanceDir_-> getEnvironment()-> getMyOwnProcessId(IPC_DOM_GUA_PHANDLE).match( connection->getOtherEnd().getNodeName(), connection->getOtherEnd().getCpuNum())) receivingTcb->setLocalSendBottom(remoteInstNum); // Portability note for the code above: we pass IPC_DOM_GUA_PHANDLE // for IpcEnvironment::getMyOwnProcessId, even though that method // can be called with the default param (IpcNetworkDomain // IPC_DOM_INVALID). In fact it would probably be better // to call the object without specifying the IpcNetworkDomain so // that it can decide for itself what domain it is using. // But there is a problem with the Windows implementation // of IpcEnvironment::getMyOwnProcessId, it seems to assume // that its domain is IPC_DOM_INTERNET and so this will // cause the botch of an assertion that its control connection // (which is type EspGuaControlConnection) can be cast to a // SockControlConnection. When this problem is fixed, the // IPC_DOM_GUA_PHANDLE param above can be removed. Also, // when this code is ported to run it a domain other than // "guardian", it will be necessary to fix this and to // fix IpcEnvironment::getMyOwnProcessId to work properly on // windows. receivingSendTcb->setClient(connection); receivingSendTcb->routeMsg(*this); } else { connection->dumpAndStopOtherEnd(true, false); ex_assert(FALSE,"entry not found, set diagnostics area and reply"); } } // normal case, not parallel extract else { // The OPEN request is from a parallel extract consumer. The // incoming request contains a user ID which we will compare // against the current user ID for this ESP. // NOTE: The user ID for the extract security check is // currently sent and compared as a C string. On Linux it is // possible to send and compare integers which would lead to // simpler code. The code to send/compare strings is still // used because it works on all platforms. char errorStr[150]; // check if next msg is of securityInfo type. ex_assert(moreObjects(), "expected object not received"); ex_assert(getNextObjType() == ESP_SECURITY_INFO, "received message for unknown message type"); // unpack security info ExMsgSecurityInfo secInfo(environment_->getHeap()); *this >> secInfo; // Get the auth ID of this ESP in text form and compare it // to the auth ID that arrived in the message. Skip this // step in the debug build if an environment variable is // set. NABoolean doAuthIdCheck = TRUE; Int32 status = 0; #ifdef _DEBUG const char *envvar = getenv("NO_EXTRACT_AUTHID_CHECK"); if (envvar && envvar[0]) doAuthIdCheck = FALSE; #endif if (doAuthIdCheck) { // Get user ID from ExMsgSecurityInfo -> (secUserID) // the user ID is the integer value made into a string // Convert it back into its integer value short userIDLen = (short) str_len(secInfo.getAuthID()); Int32 secUserID = str_atoi(secInfo.getAuthID(), userIDLen); // Get the current user ID Int32 curUserID = ComUser::getSessionUser(); // Report an error if the user ID is not valid if (curUserID == NA_UserIdDefault || secUserID == NA_UserIdDefault) { str_cpy_c(errorStr, "Producer ESP could not authenticate the consumer, " "no valid current user."); status = -1; } // Make sure user id passed in ExMsgSecurityInfo matches // the user id associated with the current session #if defined(_DEBUG) NABoolean doDebug = (getenv("DBUSER_DEBUG") ? TRUE : FALSE); if (doDebug) printf("[DBUSER:%d] ESP extract user ID: " "local [%d], msg [%d]\n", (int) getpid(), curUserID, secUserID); #endif // Compare user ID, Report an error, if comparison fails if (curUserID != secUserID) { str_cpy_c(errorStr, "Producer ESP could not authenticate the consumer, " "user named passed in ExMsgSecurityInfo is not the " "current user"); status = -1; } } // if (doAuthIdCheck) // get the split bottom TCB that matches the securityKey ex_split_bottom_tcb *receivingTcb = NULL; if (status == 0) { receivingTcb = espFragInstanceDir_->getExtractTop(secInfo.getSecurityKey()); if (receivingTcb == NULL) { str_cpy_c(errorStr, "Producer ESP could not locate extract node"); status = -1; } } // get the sendBottom TCB if not already connected to a client ex_send_bottom_tcb *receivingSendTcb = NULL; if (status == 0) { receivingSendTcb = receivingTcb->getConsumerSendBottom(); if (receivingSendTcb == NULL) { str_cpy_c(errorStr, "Producer ESP already connected to a client"); status = -1; } } // send the error message to the consumer if (status != 0) { clearAllObjects(); setType(IPC_MSG_SQLESP_DATA_REPLY); NAMemory *heap = environment_->getHeap(); IpcMessageObj* baseObj = new(heap)IpcMessageObj(IPC_SQL_DIAG_AREA, CurrEspReplyMessageVersion); *this << *baseObj; // prepare proper error message char phandle[100]; MyGuaProcessHandle myHandle; myHandle.toAscii(phandle, 100); ComDiagsArea *diags = ComDiagsArea::allocate(heap); *diags << DgSqlCode(-EXE_PARALLEL_EXTRACT_OPEN_ERROR) << DgString0(phandle) << DgString1(errorStr); *this << *diags; diags->decrRefCount(); send(TRUE /* TRUE indicates waited */); } // if everything okay, then make the connection if (status == 0) { receivingSendTcb->setClient(connection); receivingSendTcb->routeMsg(*this); } } // parallel extract case } // open or cancel header
LmResult LmRoutineCSql::invokeRoutine(void *inputRow, void *outputRow, ComDiagsArea *da) { ComUInt32 argc = numSqlParam_; ComUInt32 i = 0; short *udrInd = (short *) ind_.getBuffer(); // Code handles UDF functions with upto 32 parameters. LM_ASSERT1(argc <= 32, "Parameters more than 32 are not allowed."); // We can return early if the caller is requesting a FINAL call but // not FINAL is necessary because the INITIAL call was never made if (callType_ == SQLUDR_CALLTYPE_FINAL && !finalCallRequired_) return LM_OK; ComUInt32 numIn = 0; ComUInt32 numOut = 0; // Build the argument vector if (callType_ != SQLUDR_CALLTYPE_FINAL) { for (i = 0; i < argc; i++) { LmParameter &p = lmParams_[i]; LM_ASSERT1(p.direction() != COM_INOUT_COLUMN, "INOUT parameters are not supported for C routines"); if (p.isIn()) { numIn++; // Set the input null indicator NABoolean nullVal = p.isNullInput((char *) inputRow); udrInd[i] = (nullVal ? SQLUDR_NULL : SQLUDR_NOTNULL); // Make a copy of the input value if (! nullVal) { char *inData = ((char *) inputRow) + p.inDataOffset(); char *inCopy = data_[i]; ComUInt32 inBytes = p.inSize(); switch (p.fsType()) { case COM_FCHAR_FSDT: { // CHAR(N) CHARACTER SET ISO88591 memcpy(inCopy, inData, inBytes); inCopy[inBytes] = 0; } break; case COM_FCHAR_DBL_FSDT: { // CHAR(N) CHARACTER SET UCS2 memcpy(inCopy, inData, inBytes); inCopy[inBytes] = 0; inCopy[inBytes + 1] = 0; } break; case COM_VCHAR_FSDT: case COM_VCHAR_DBL_FSDT: { // VARCHAR(N) CHARACTER SET ISO88591 // VARCHAR(N) CHARACTER SET UCS2 SQLUDR_VC_STRUCT *vc = (SQLUDR_VC_STRUCT *) inCopy; ComUInt32 inDataLen = p.actualInDataSize(inputRow); memcpy(&(vc->length), &inDataLen, 4); memcpy(vc->data, inData, inDataLen); } break; case COM_SIGNED_BIN16_FSDT: case COM_UNSIGNED_BIN16_FSDT: { // SMALLINT [UNSIGNED] // NUMERIC 0 <= precision <= 4 memcpy(inCopy, inData, 2); } break; case COM_SIGNED_BIN32_FSDT: case COM_UNSIGNED_BIN32_FSDT: case COM_FLOAT32_FSDT: { // INTEGER [UNSIGNED] // REAL // NUMERIC 5 <= precision <= 9 memcpy(inCopy, inData, 4); } break; case COM_SIGNED_BIN64_FSDT: case COM_FLOAT64_FSDT: { // LARGEINT // FLOAT // DOUBLE PRECISION // NUMERIC 10 <= precision <= 18 memcpy(inCopy, inData, 8); } break; case COM_SIGNED_DECIMAL_FSDT: case COM_UNSIGNED_DECIMAL_FSDT: case COM_DATETIME_FSDT: case COM_SIGNED_NUM_BIG_FSDT: case COM_UNSIGNED_NUM_BIG_FSDT: { // DECIMAL [UNSIGNED] // DATE, TIME, TIMESTAMP // NUMERIC precision > 18 memcpy(inCopy, inData, inBytes); inCopy[inBytes] = '\0'; } break; default: { char msg[256]; sprintf(msg, "Unknown parameter type: %d", p.fsType()); LM_ASSERT1(0, msg); } break; } // switch (p.fsType()) } // if not null } // if (isInput) else { numOut++; // Set the output null indicator udrInd[i] = SQLUDR_NOTNULL; // Initialize the output buffer char *outData = (char *)outputRow + p.outDataOffset(); char *outCopy = data_[i]; ComUInt32 outBytes = p.outSize(); switch (p.fsType()) { case COM_FCHAR_FSDT: { // CHAR(N) CHARACTER SET ISO88591 memset(outCopy, ' ', outBytes); outCopy[outBytes] = 0; } break; case COM_FCHAR_DBL_FSDT: { // CHAR(N) CHARACTER SET UCS2 NAWchar *wOutCopy = (NAWchar *) outCopy; ComUInt32 outChars = outBytes / sizeof(NAWchar); wc_str_pad(wOutCopy, outChars); // pads with space by default wOutCopy[outChars] = 0; } break; case COM_VCHAR_FSDT: case COM_VCHAR_DBL_FSDT: { // VARCHAR(N) CHARACTER SET ISO88591 // VARCHAR(N) CHARACTER SET UCS2 SQLUDR_VC_STRUCT *vc = (SQLUDR_VC_STRUCT *) outCopy; vc->length = outBytes; memset(vc->data, 0, outBytes); } break; case COM_SIGNED_BIN16_FSDT: case COM_UNSIGNED_BIN16_FSDT: { // SMALLINT [UNSIGNED] // NUMERIC 0 <= precision <= 4 memset(outCopy, 0, 2); } break; case COM_SIGNED_BIN32_FSDT: case COM_UNSIGNED_BIN32_FSDT: case COM_FLOAT32_FSDT: { // INTEGER [UNSIGNED] // REAL // NUMERIC 5 <= precision <= 9 memset(outCopy, 0, 4); } break; case COM_SIGNED_BIN64_FSDT: case COM_FLOAT64_FSDT: { // LARGEINT // FLOAT // DOUBLE PRECISION // NUMERIC 10 <= precision <= 18 memset(outCopy, 0, 8); } break; case COM_SIGNED_DECIMAL_FSDT: case COM_UNSIGNED_DECIMAL_FSDT: case COM_DATETIME_FSDT: case COM_SIGNED_NUM_BIG_FSDT: case COM_UNSIGNED_NUM_BIG_FSDT: { // DECIMAL [UNSIGNED] // DATE, TIME, TIMESTAMP // NUMERIC precision > 18 memset(outCopy, ' ', outBytes); outCopy[outBytes] = 0; } break; default: { char msg[256]; sprintf(msg, "Unknown parameter type value: %d", p.fsType()); LM_ASSERT1(0, msg); } break; } // switch (p.fsType()) } // if (isInput) else ... } // for each parameter } // if this is not a FINAL call else { // This is a FINAL call. Set all null indicators to SQLUDR_NULL // and zero out data buffers. for (i = 0; i < argc; i++) { udrInd[i] = SQLUDR_NULL; LmCBuffer &cBuf = cBuf_[i]; cBuf.set(0); } } // Initialize SQLSTATE to all '0' characters and add a null terminator str_pad(sqlState_, SQLUDR_SQLSTATE_SIZE - 1, '0'); sqlState_[SQLUDR_SQLSTATE_SIZE - 1] = 0; // Initialize SQL text to all zero bytes str_pad(msgText_, SQLUDR_MSGTEXT_SIZE, '\0'); // Now we can call the routine body... ComSInt32 rc = SQLUDR_INVOKE(routine_, argc, data_, udrInd, sqlState_, msgText_, callType_, stateArea_, udrInfo_); // Set the call type for the next invocation to NORMAL if this is // an INITIAL call if (callType_ == SQLUDR_CALLTYPE_INITIAL) { callType_ = SQLUDR_CALLTYPE_NORMAL; finalCallRequired_ = TRUE; } else if (callType_ == SQLUDR_CALLTYPE_FINAL) { // We are done if this is a FINAL call finalCallRequired_ = FALSE; return LM_OK; } LmResult lmResult = LM_OK; if (rc != SQLUDR_ERROR) { // Copy data and null indicator to caller's output buffers for (i = numIn; i < argc && lmResult == LM_OK; i++) { LmParameter &p = lmParams_[i]; NABoolean isOutput = (p.direction() == COM_OUTPUT_COLUMN ? TRUE : FALSE); if (isOutput) { // Look at the returned null indicator. Raise an error if the // routine returned an invalid null indicator. NABoolean isNull = TRUE; switch(udrInd[i]) { case SQLUDR_NOTNULL: isNull = FALSE; break; case SQLUDR_NULL: break; default: { *da << DgSqlCode(-LME_UDF_INVALID_DATA) << DgString0(getNameForDiags()) << DgInt0((Lng32) i + 1) << DgString1("Invalid null indicator"); lmResult = LM_ERR; } break; } // Write the null indicator into the output row if (lmResult == LM_OK) p.setNullOutput((char *) outputRow, isNull); // If value is not NULL, set data. if (lmResult == LM_OK && !isNull) { char *outData = ((char *)outputRow) + p.outDataOffset(); char *outCopy = data_[i]; ComUInt32 outBytes = p.outSize(); switch (p.fsType()) { case COM_FCHAR_FSDT: case COM_FCHAR_DBL_FSDT: { // CHAR(N) CHARACTER SET ISO88591 // CHAR(N) CHARACTER SET UCS2 p.setOutChar(outputRow, outCopy, outBytes); } break; case COM_VCHAR_FSDT: case COM_VCHAR_DBL_FSDT: { // VARCHAR(N) CHARACTER SET ISO88591 // VARCHAR(N) CHARACTER SET UCS2 SQLUDR_VC_STRUCT *vc = (SQLUDR_VC_STRUCT *) outCopy; if (vc->length > outBytes) { char msg[100]; sprintf(msg, "VARCHAR length should not exceed %d", outBytes); *da << DgSqlCode(-LME_UDF_INVALID_DATA) << DgString0(getNameForDiags()) << DgInt0((Lng32) i + 1) << DgString1(msg); lmResult = LM_ERR; } else { p.setOutChar(outputRow, vc->data, vc->length); } } break; case COM_SIGNED_BIN16_FSDT: case COM_UNSIGNED_BIN16_FSDT: { // SMALLINT [UNSIGNED] // NUMERIC 0 <= precision <= 4 memcpy(outData, outCopy, 2); } break; case COM_SIGNED_BIN32_FSDT: case COM_UNSIGNED_BIN32_FSDT: case COM_FLOAT32_FSDT: { // INTEGER [UNSIGNED] // REAL // NUMERIC 5 <= precision <= 9 memcpy(outData, outCopy, 4); } break; case COM_SIGNED_BIN64_FSDT: case COM_FLOAT64_FSDT: { // LARGEINT // FLOAT // DOUBLE PRECISION // NUMERIC 10 <= precision <= 18 memcpy(outData, outCopy, 8); } break; case COM_SIGNED_DECIMAL_FSDT: case COM_UNSIGNED_DECIMAL_FSDT: case COM_DATETIME_FSDT: case COM_SIGNED_NUM_BIG_FSDT: case COM_UNSIGNED_NUM_BIG_FSDT: { // DECIMAL [UNSIGNED] // DATE, TIME, TIMESTAMP // NUMERIC precision > 18 p.setOutChar(outputRow, outCopy, outBytes); } break; default: { char msg[256]; sprintf(msg, "Unknown parameter type value: %d", p.fsType()); LM_ASSERT1(0, msg); } break; } // switch (p.fsType()) } // if (lmResult == LM_OK && !isNull) } // if (isOutput) } // for each LmParameter } // if (rc != SQLUDR_ERROR) if (lmResult == LM_OK && rc != SQLUDR_SUCCESS) { sqlState_[SQLUDR_SQLSTATE_SIZE - 1] = 0; lmResult = processReturnStatus(rc, da); } return lmResult; } // LmRoutineCSql::invokeRoutine
void CmpSeabaseDDL::createSeabaseRoutine( StmtDDLCreateRoutine * createRoutineNode, NAString &currCatName, NAString &currSchName) { Lng32 retcode = 0; ComObjectName routineName(createRoutineNode->getRoutineName()); ComAnsiNamePart currCatAnsiName(currCatName); ComAnsiNamePart currSchAnsiName(currSchName); routineName.applyDefaults(currCatAnsiName, currSchAnsiName); const NAString catalogNamePart = routineName.getCatalogNamePartAsAnsiString(); const NAString schemaNamePart = routineName.getSchemaNamePartAsAnsiString(TRUE); const NAString objectNamePart = routineName.getObjectNamePartAsAnsiString(TRUE); const NAString extRoutineName = routineName.getExternalName(TRUE); ComRoutineType rType = createRoutineNode->getRoutineType(); ComRoutineLanguage language = createRoutineNode->getLanguageType(); ComRoutineParamStyle ddlStyle = createRoutineNode->getParamStyle(); ComRoutineParamStyle style = ddlStyle; NABoolean isJava = (language == COM_LANGUAGE_JAVA); // Check to see if user has the authority to create the routine ExeCliInterface cliInterface(STMTHEAP, NULL, NULL, CmpCommon::context()->sqlSession()->getParentQid()); Int32 objectOwnerID = SUPER_USER; Int32 schemaOwnerID = SUPER_USER; ComSchemaClass schemaClass; retcode = verifyDDLCreateOperationAuthorized(&cliInterface, SQLOperation::CREATE_ROUTINE, catalogNamePart, schemaNamePart, schemaClass, objectOwnerID, schemaOwnerID); if (retcode != 0) { handleDDLCreateAuthorizationError(retcode,catalogNamePart,schemaNamePart); return; } ExpHbaseInterface * ehi = NULL; ehi = allocEHI(); if (ehi == NULL) { processReturn(); return; } retcode = existsInSeabaseMDTable(&cliInterface, catalogNamePart, schemaNamePart, objectNamePart, COM_USER_DEFINED_ROUTINE_OBJECT, TRUE, FALSE); if (retcode < 0) { deallocEHI(ehi); processReturn(); return; } if (retcode == 1) // already exists { *CmpCommon::diags() << DgSqlCode(-1390) << DgString0(extRoutineName); deallocEHI(ehi); processReturn(); return; } ComObjectName libName(createRoutineNode-> getLibraryName().getQualifiedNameAsAnsiString()); libName.applyDefaults(currCatAnsiName, currSchAnsiName); NAString libCatNamePart = libName.getCatalogNamePartAsAnsiString(); NAString libSchNamePart = libName.getSchemaNamePartAsAnsiString(TRUE); NAString libObjNamePart = libName.getObjectNamePartAsAnsiString(TRUE); const NAString extLibraryName = libName.getExternalName(TRUE); char externalPath[512] ; Lng32 cliRC = 0; // this call needs to change Int64 libUID = getObjectUID(&cliInterface, libCatNamePart, libSchNamePart, libObjNamePart, COM_LIBRARY_OBJECT_LIT); if (libUID < 0) { processReturn(); return; } if (libUID == 0) // does not exist { *CmpCommon::diags() << DgSqlCode(-1361) << DgString0(extLibraryName); deallocEHI(ehi); processReturn(); return; } // read the library path name from the LIBRARIES metadata table char * buf = new(STMTHEAP) char[200]; str_sprintf(buf, "select library_filename from %s.\"%s\".%s" " where library_uid = %Ld for read uncommitted access", getSystemCatalog(), SEABASE_MD_SCHEMA, SEABASE_LIBRARIES, libUID); cliRC = cliInterface.fetchRowsPrologue(buf, TRUE/*no exec*/); if (cliRC < 0) { cliInterface.retrieveSQLDiagnostics(CmpCommon::diags()); deallocEHI(ehi); processReturn(); return; } cliRC = cliInterface.clearExecFetchClose(NULL, 0); if (cliRC < 0) { cliInterface.retrieveSQLDiagnostics(CmpCommon::diags()); deallocEHI(ehi); processReturn(); return; } if (cliRC == 100) // did not find the row { *CmpCommon::diags() << DgSqlCode(-1231) << DgString0(extRoutineName); deallocEHI(ehi); processReturn(); return; } char * ptr = NULL; Lng32 len = 0; cliInterface.getPtrAndLen(1, ptr, len); str_cpy_all(externalPath, ptr, len); externalPath[len] = '\0'; // determine language and parameter styles based on the library // type, unless already specified if (!createRoutineNode->isLanguageTypeSpecified()) { NAString extPath(externalPath); size_t lastDot = extPath.last('.'); NAString libSuffix; if (lastDot != NA_NPOS) libSuffix = extPath(lastDot,extPath.length()-lastDot); libSuffix.toUpper(); if (libSuffix == ".JAR") { isJava = TRUE; language = COM_LANGUAGE_JAVA; } else if (libSuffix == ".SO" || libSuffix == ".DLL") { // a known C/C++ library, set // language and parameter style below } else { // language not specified and library name // is inconclusive, issue an error *CmpCommon::diags() << DgSqlCode( -3284 ) << DgString0( externalPath ); processReturn(); } } // set parameter style and also language, if not already // specified, based on routine type and type of library if (isJava) { // library is a jar file if (rType == COM_PROCEDURE_TYPE) // Java stored procedures use the older Java style style = COM_STYLE_JAVA_CALL; else // Java UDFs use the newer Java object style style = COM_STYLE_JAVA_OBJ; } else { // assume the library is a DLL with C or C++ code if (rType == COM_TABLE_UDF_TYPE && (language == COM_LANGUAGE_CPP || !createRoutineNode->isLanguageTypeSpecified())) { // Table UDFs (TMUDFs) default to the C++ interface language = COM_LANGUAGE_CPP; style = COM_STYLE_CPP_OBJ; } else if (rType == COM_SCALAR_UDF_TYPE && (language == COM_LANGUAGE_C || !createRoutineNode->isLanguageTypeSpecified())) { // scalar UDFs default to C and SQL parameter style language = COM_LANGUAGE_C; style = COM_STYLE_SQL; } else { // some invalid combination of routine type, language and // library type *CmpCommon::diags() << DgSqlCode(-3286); processReturn(); return; } } // C/C++ DLL if (createRoutineNode->isParamStyleSpecified() && ddlStyle != style) { // An unsupported PARAMETER STYLE was specified *CmpCommon::diags() << DgSqlCode(-3280); processReturn(); return; } NAString externalName; if (language == COM_LANGUAGE_JAVA && style == COM_STYLE_JAVA_CALL) { // the external name is a Java method signature externalName = createRoutineNode->getJavaClassName(); externalName += "." ; externalName += createRoutineNode->getJavaMethodName(); } else // the external name is a C/C++ entry point or a // Java class name externalName = createRoutineNode->getExternalName(); // Verify that current user has authority to create the routine // User must be DB__ROOT or have privileges if (isAuthorizationEnabled() && !ComUser::isRootUserID()) { // For now, go get privileges directly. If we ever cache routines, then // make sure privileges are stored in the cache. NAString privMgrMDLoc; CONCAT_CATSCH(privMgrMDLoc, getSystemCatalog(), SEABASE_PRIVMGR_SCHEMA); PrivMgrCommands privInterface(privMgrMDLoc.data(), CmpCommon::diags()); PrivMgrUserPrivs privs; PrivStatus retcode = privInterface.getPrivileges(libUID, COM_LIBRARY_OBJECT, ComUser::getCurrentUser(), privs); if (retcode != STATUS_GOOD) { if (CmpCommon::diags()->getNumber(DgSqlCode::ERROR_) == 0) SEABASEDDL_INTERNAL_ERROR("checking routine privilege"); processReturn(); return; } // Requester must have USAGE privilege on the library NABoolean hasPriv = TRUE; if ( !privs.hasUsagePriv() ) { *CmpCommon::diags() << DgSqlCode( -4481 ) << DgString0( "USAGE" ) << DgString1( extLibraryName.data()); processReturn(); return; } } ElemDDLParamDefArray &routineParamArray = createRoutineNode->getParamArray(); Lng32 numParams = routineParamArray.entries(); if ((createRoutineNode->getRoutineType() == COM_SCALAR_UDF_TYPE) && (numParams > 32)) { *CmpCommon::diags() << DgSqlCode( -1550 ) << DgString0( extRoutineName ) << DgInt0( numParams ); deallocEHI(ehi); processReturn(); return; } #define MAX_SIGNATURE_LENGTH 8193 // Allocate buffer for generated signature char sigBuf[MAX_SIGNATURE_LENGTH]; sigBuf[0] = '\0'; if (style == COM_STYLE_JAVA_CALL) { // validate routine for Java call based on signature Lng32 numJavaParam = 0; ComFSDataType *paramType = new ComFSDataType[numParams]; ComUInt32 *subType = new ComUInt32 [numParams]; ComColumnDirection *direction = new ComColumnDirection[numParams]; NAType *genericType; // Gather the param attributes for LM from the paramDefArray previously // populated and from the routineparamList generated from paramDefArray. for (CollIndex i = 0; (Int32)i < numParams; i++) { paramType[i] = (ComFSDataType)routineParamArray[i]->getParamDataType()->getFSDatatype(); subType[i] = 0; // default // Set subType for special cases detected by LM switch ( paramType[i] ) { case COM_SIGNED_BIN16_FSDT : case COM_SIGNED_BIN32_FSDT : case COM_SIGNED_BIN64_FSDT : case COM_UNSIGNED_BIN16_FSDT : case COM_UNSIGNED_BIN32_FSDT : case COM_UNSIGNED_BPINT_FSDT : { genericType = routineParamArray[i]->getParamDataType() ; if (genericType->getTypeName() == LiteralNumeric) subType[i] = genericType->getPrecision(); else subType[i] = 0 ; break; } case COM_DATETIME_FSDT : { genericType = routineParamArray[i]->getParamDataType() ; DatetimeType & datetimeType = (DatetimeType &) *genericType; if (datetimeType.getSimpleTypeName() EQU "DATE") subType[i] = 1 ; else if (datetimeType.getSimpleTypeName() EQU "TIME") subType[i] = 2; else if (datetimeType.getSimpleTypeName() EQU "TIMESTAMP") subType[i] = 3; } } // end switch paramType[i] direction[i] = (ComColumnDirection) routineParamArray[i]->getParamDirection(); } // If the syntax specified a signature, pass that to LanguageManager. NAString specifiedSig( createRoutineNode->getJavaSignature() ); char* optionalSig; if ( specifiedSig.length() == 0 ) optionalSig = NULL; else optionalSig = (char *)specifiedSig.data(); ComBoolean isJavaMain = ((str_cmp_ne(createRoutineNode->getJavaMethodName(), "main") == 0) ? TRUE : FALSE); LmResult createSigResult; LmJavaSignature *lmSignature = new (STMTHEAP) LmJavaSignature(NULL, STMTHEAP); createSigResult = lmSignature->createSig(paramType, subType, direction, numParams, COM_UNKNOWN_FSDT, 0, createRoutineNode->getMaxResults(), optionalSig, isJavaMain, sigBuf, MAX_SIGNATURE_LENGTH, CmpCommon::diags()); NADELETE(lmSignature, LmJavaSignature, STMTHEAP); delete [] paramType; delete [] subType; delete [] direction; // Lm returned error. Lm fills diags area, so no need to worry about diags. if (createSigResult == LM_ERR) { *CmpCommon::diags() << DgSqlCode(-1231) << DgString0(extRoutineName); deallocEHI(ehi); processReturn(); return; } numJavaParam = (isJavaMain ? 1 : numParams); if (validateRoutine(&cliInterface, createRoutineNode->getJavaClassName(), createRoutineNode->getJavaMethodName(), externalPath, sigBuf, numJavaParam, createRoutineNode->getMaxResults(), optionalSig)) { *CmpCommon::diags() << DgSqlCode(-1231) << DgString0(extRoutineName); deallocEHI(ehi); processReturn(); return; } } else if (style == COM_STYLE_JAVA_OBJ || style == COM_STYLE_CPP_OBJ) { // validate existence of the C++ or Java class in the library Int32 routineHandle = NullCliRoutineHandle; NAString externalPrefix(externalPath); NAString externalNameForValidation(externalName); NAString containerName; if (language == COM_LANGUAGE_C || language == COM_LANGUAGE_CPP) { // separate the actual DLL name from the prefix char separator = '/'; size_t separatorPos = externalPrefix.last(separator); if (separatorPos != NA_NPOS) { containerName = externalPrefix(separatorPos+1, externalPrefix.length()-separatorPos-1); externalPrefix.remove(separatorPos, externalPrefix.length()-separatorPos); } else { // assume the entire string is a local name containerName = externalPrefix; externalPrefix = "."; } } else { // For Java, the way the language manager works is that the // external path is the fully qualified name of the jar and // the container is the class name (external name). We load // the container (the class) by searching in the path (the // jar). The external name is the method name, which in this // case is the constructor of the class, <init>. // leave externalPrevix unchanged, fully qualified jar file containerName = externalName; externalNameForValidation = "<init>"; } // use a CLI call to validate that the library contains the routine if (cliInterface.getRoutine( NULL, // No InvocationInfo specified in this step 0, NULL, 0, (Int32) language, (Int32) style, externalNameForValidation.data(), containerName.data(), externalPrefix.data(), extLibraryName.data(), &routineHandle, CmpCommon::diags()) != LME_ROUTINE_VALIDATED) { if (routineHandle != NullCliRoutineHandle) cliInterface.putRoutine(routineHandle, CmpCommon::diags()); CMPASSERT(CmpCommon::diags()->mainSQLCODE() < 0); processReturn(); return; } cliInterface.putRoutine(routineHandle, CmpCommon::diags()); } ComTdbVirtTableColumnInfo * colInfoArray = (ComTdbVirtTableColumnInfo*) new(STMTHEAP) ComTdbVirtTableColumnInfo[numParams]; if (buildColInfoArray(&routineParamArray, colInfoArray)) { processReturn(); return; } ComTdbVirtTableTableInfo * tableInfo = new(STMTHEAP) ComTdbVirtTableTableInfo[1]; tableInfo->tableName = NULL, tableInfo->createTime = 0; tableInfo->redefTime = 0; tableInfo->objUID = 0; tableInfo->objOwnerID = objectOwnerID; tableInfo->schemaOwnerID = schemaOwnerID; tableInfo->isAudited = 1; tableInfo->validDef = 1; tableInfo->hbaseCreateOptions = NULL; tableInfo->numSaltPartns = 0; tableInfo->rowFormat = COM_UNKNOWN_FORMAT_TYPE; tableInfo->objectFlags = 0; Int64 objUID = -1; if (updateSeabaseMDTable(&cliInterface, catalogNamePart, schemaNamePart, objectNamePart, COM_USER_DEFINED_ROUTINE_OBJECT, "N", tableInfo, numParams, colInfoArray, 0, NULL, 0, NULL, objUID)) { deallocEHI(ehi); processReturn(); return; } if (objUID == -1) { deallocEHI(ehi); processReturn(); return; } NAString udrType; getRoutineTypeLit(createRoutineNode->getRoutineType(), udrType); NAString languageType; getLanguageTypeLit(language, languageType); NAString sqlAccess; getSqlAccessLit(createRoutineNode->getSqlAccess(), sqlAccess); NAString paramStyle; getParamStyleLit(style, paramStyle); NAString transactionAttributes; getTransAttributesLit(createRoutineNode->getTransactionAttributes(), transactionAttributes); NAString parallelism; getParallelismLit(createRoutineNode->getParallelism(), parallelism); NAString externalSecurity; getExternalSecurityLit(createRoutineNode->getExternalSecurity(), externalSecurity); NAString executionMode; getExecutionModeLit(createRoutineNode->getExecutionMode(), executionMode); char * query = new(STMTHEAP) char[2000+MAX_SIGNATURE_LENGTH]; str_sprintf(query, "insert into %s.\"%s\".%s values (%Ld, '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', %d, %d, '%s', '%s', '%s', '%s', '%s', %Ld, '%s' )", getSystemCatalog(), SEABASE_MD_SCHEMA, SEABASE_ROUTINES, objUID, udrType.data(), languageType.data(), createRoutineNode->isDeterministic() ? "Y" : "N" , sqlAccess.data(), createRoutineNode->isCallOnNull() ? "Y" : "N" , createRoutineNode->isIsolate() ? "Y" : "N" , paramStyle.data(), transactionAttributes.data(), createRoutineNode->getMaxResults(), createRoutineNode->getStateAreaSize(), externalName.data(), parallelism.data(), createRoutineNode->getUserVersion().data(), externalSecurity.data(), executionMode.data(), libUID, sigBuf); cliRC = cliInterface.executeImmediate(query); NADELETEBASIC(query, STMTHEAP); if (cliRC < 0) { cliInterface.retrieveSQLDiagnostics(CmpCommon::diags()); processReturn(); return; } char * query1 = new(STMTHEAP) char[1000]; str_sprintf(query1, "insert into %s.\"%s\".%s values (%Ld, %Ld)", getSystemCatalog(), SEABASE_MD_SCHEMA, SEABASE_LIBRARIES_USAGE, libUID, objUID); cliRC = cliInterface.executeImmediate(query1); NADELETEBASIC(query1, STMTHEAP); if (cliRC < 0) { cliInterface.retrieveSQLDiagnostics(CmpCommon::diags()); processReturn(); return; } // hope to remove this call soon by setting the valid flag to Y sooner if (updateObjectValidDef(&cliInterface, catalogNamePart, schemaNamePart, objectNamePart, COM_USER_DEFINED_ROUTINE_OBJECT_LIT, "Y")) { deallocEHI(ehi); processReturn(); return; } processReturn(); return; }