// paramName must be passed in WITHOUT leading '$' (ERRORPARAM_BEGINMARK). // paramName returns stripped of any internal '~' (ERRORPARAM_TYPESEP) and the // chars either preceding it or following it, if paramName is at all valid. // E.g., "0~string0" returns as "0" if positional but "string0" if named; // "int0~1" returns as "1" if pos but "int0" if named; // "2" returns as "2" either way; // "b" returns as "b" either way (if pos, function result is -1, invalid); // "intx~y" returns as "y" if pos (and function result is -1, invalid) // but "intx~y" if named (with a successful result, and the ComDiagsMsg.C // caller will reject it as not matching a string table lookup and then // display the entire bogus name). // Function returns -1 for invalid paramName, // 0 for valid NAMED_PARAM, // n>=0 for valid POSITIONAL_PARAM (n = the position, 0th, 1st, 2nd, ...) // // Why do we need to do this? Well, we have two kinds of messages -- // ComDiagsMsg.C ComCondition ones with named params, and // ErrorMessage.C ErrorMessage ones with positional. // The positional params need to have position numbers so that messages can // be translated (I18N of text often requires reordering params). // Tagging each param with both name and position info means that the same // msg code can be used from anywhere (either ComDiags or E'Msg), // i.e. we can share messages and not have a confusing welter of nearly // identical ones. // Lng32 FixupMessageParam(NAWchar *paramName, MsgParamType paramType) { ComASSERT(paramName); if (!*paramName) return -1; // invalid (empty) paramName NAWchar *p; NAWchar* sep = NAWstrchr(paramName, ERRORPARAM_TYPESEP); NABoolean begend = sep ? (sep == paramName || sep[1] == NAWchar('\0')) : FALSE; switch (paramType) { case NAMED_PARAM: if (begend) return 0; // "~x" and "9~" `legal' names if (sep) if (isdigit(*paramName)) NAWstrcpy(paramName, ++sep); // "9~x" -> "x" else if (isdigit(sep[1])) *sep = NAWchar('\0'); // "x~9" -> "x" //else {} // "x~y" `legal' return 0; // (Dubious legal names will be // flagged by our caller.) case POSITIONAL_PARAM: if (begend) return -1; // "~x" and "9~" invalid nums if (!isdigit(*paramName)) if (!sep) return -1; // "x" invalid num else NAWstrcpy(paramName, ++sep); // "x~9" -> "9" else if (sep) *sep = NAWchar('\0'); // "9~x" -> "9" //else {} // "9" valid for (p=paramName; *p; p++) if (!isdigit(*p)) return -1; // "9x" invalid num Lng32 pos; NAWsscanf(paramName, WIDE_("%d"), &pos); return pos; default: return -1; // invalid (unknown paramType) } } // FixupMessageParam
void ErrorMessage::insertParams(NAError * errcb) { if (errcb->getErrParamCount() > 0) { // Note that we allocate twice the size for tmp, in order to forestall // array overrun problems (i.e. memory corruption) NAWchar tmp[MSG_BUF_SIZE * 2]; NAWchar paramName[MSG_BUF_SIZE]; NAWchar paramVal[MSG_BUF_SIZE]; // regular char, not TCHAR Int32 paramLen; Lng32 paramPos; Int32 tmpLen = 0; Int32 truncation = FALSE; #pragma nowarn(1506) // warning elimination Int32 msgBufOrigLen = NAWstrlen(msgBuf_); #pragma warn(1506) // warning elimination for (Int32 i = 0; i < msgBufOrigLen; i++) { if (msgBuf_[i] == ERRORPARAM_BEGINMARK) { // Get the formal parameter name, excluding the leading '$' mark NAWchar *p = paramName; while (++i < msgBufOrigLen && (isalnum(msgBuf_[i]) || msgBuf_[i] == ERRORPARAM_TYPESEP)) *p++ = msgBuf_[i]; *p = NAWchar('\0'); i--; // let's not lose a character! paramPos = FixupMessageParam(paramName, POSITIONAL_PARAM); if (paramPos >= 0) { paramVal[0] = NAWchar('\0'); // default is empty param NAErrorParam * param = errcb->getNAErrorParam(paramPos); if (param) switch (param->getNAErrorParamType()) { case NAErrorParam::NAERROR_PARAM_TYPE_INTEGER: NAWsprintf(paramVal,WIDE_("%d"),param->getIntegerNAErrorParam()); break; case NAErrorParam::NAERROR_PARAM_TYPE_CHAR_STRING: NAWsprintf(paramVal,WIDE_("%s"),param->getStringNAErrorParam()); break; } #pragma nowarn(1506) // warning elimination paramLen = NAWstrlen(paramVal); #pragma warn(1506) // warning elimination NAWstrncpy(&tmp[tmpLen], paramVal, paramLen); } else // invalid formal param (e.g. "$ab" "$9~" "$~9" "$9x") { tmp[tmpLen++] = ERRORPARAM_BEGINMARK; #pragma nowarn(1506) // warning elimination paramLen = NAWstrlen(paramName); #pragma warn(1506) // warning elimination NAWstrncpy(&tmp[tmpLen], paramName, paramLen); } tmpLen += paramLen; } else { tmp[tmpLen++] = msgBuf_[i]; } // If necessary, truncate the message and exit loop early. // The -1 is for the terminating '\0' below the loop. if (tmpLen > MSG_BUF_SIZE - 1) { tmpLen = MSG_BUF_SIZE - 1; truncation = TRUE; break; } } // for // Indicate truncation by overwriting last three characters with '...' if (truncation) tmp[tmpLen-3] = tmp[tmpLen-2] = tmp[tmpLen-1] = NAWchar('.'); NAWstrncpy(msgBuf_, tmp, tmpLen); msgBuf_[tmpLen] = NAWchar('\0'); } } // ErrorMessage::insertParams()
////////////////////////////////////////////// // Begin ERROR //////////////////////////////////////////////// short Error::process(SqlciEnv * sqlci_env) { NAWchar *error_msg; Int32 codeE, codeW; char stateE[10], stateW[10]; NABoolean msgNotFound; ostringstream omsg; #define GETERRORMESS(in, out, typ) GetErrorMessage(in, (NAWchar *&)out, typ) codeW = ABS(atoi(get_argument())); // >= 0, i.e. warning codeE = -codeW; // <= 0, i.e. error // These calls must be done before any of the GETERRORMESS(), // as they all use (overwrite) the same static buffer in GetErrorMessage.cpp. ComSQLSTATE(codeE, stateE); ComSQLSTATE(codeW, stateW); msgNotFound = GETERRORMESS(codeE, error_msg, ERROR_TEXT); if (type == ENVCMD_) { if (msgNotFound) { error_msg[0] = NAWchar('\n'); error_msg[1] = NAWchar('\0'); } else { // Extract the {braces-enclosed version string} // that msgfileVrsn.ksh (called by GenErrComp.bat) // has put into this ENVCMD_ message. NAWchar *v = NAWstrchr(error_msg, NAWchar(']')); if (v) error_msg = v; v = NAWstrchr(error_msg, NAWchar('{')); if (v) error_msg = v; v = NAWstrchr(error_msg, NAWchar('}')); if (v++ && *v == NAWchar('.')) *v = NAWchar(' '); } NAWriteConsole(error_msg, omsg, FALSE); } else if (!msgNotFound || codeE == 0) // SQL "success", special case { omsg << "\n*** SQLSTATE (Err): " << stateE << " SQLSTATE (Warn): " << stateW; omsg << endl; NAWriteConsole(error_msg,omsg, TRUE); } else { // Msg not found. ComDiagsArea diags; diags << DgSqlCode(codeW); NADumpDiags(omsg, &diags, TRUE/*newline*/); } #if 0 // CAUSE/EFFECT/RECOVERY text not implemented yet! if (!msgNotFound && type == DETAIL_) { GETERRORMESS(codeE, error_msg, CAUSE_TEXT); NAWriteConsole(error_msg,omsg, TRUE); GETERRORMESS(codeE, error_msg, EFFECT_TEXT); NAWriteConsole(error_msg,omsg, TRUE); GETERRORMESS(codeE, error_msg, RECOVERY_TEXT); NAWriteConsole(error_msg,omsg, TRUE); } #endif // 0 // CAUSE/EFFECT/RECOVERY text not implemented yet! omsg << ends; // to tack on a null-terminator sqlci_env->get_logfile()->WriteAllWithoutEOL(omsg.str().c_str()); return 0; }
void ErrorMessage::printErrorMessage(NAError * errcb) { NAWchar* tmp = msgBuf_; // This is always a positive number (but make sure of it!) NAErrorCode erc_abs = errcb->getErrCode(); if (erc_abs < 0) erc_abs = -erc_abs; // A warning is positive, an error negative -- // GetErrorMessage generates the proper text for each. NAErrorCode erc_signed = (errcb->getErrType() == NAError::NAERROR_WARNING) ? erc_abs : -erc_abs; NABoolean msgNotFound = GetErrorMessage(erc_signed, tmp); NABoolean forceParamSubst = msgNotFound && errcb->getErrParamCount() > 0; /* // if tmp was assigned to a different (e.g. a static) string, we need to copy // its contents into this msgBuf_ so that insertParams overwrites our copy // and not the original. */ NAWstrcpy(msgBuf_, tmp); if (forceParamSubst) { // msgBuf_ will contain a suitable msg-not-found message, so now we just // append substitution parameters to at least make debugging easier. // // This mirrors what ComCondition::getMessageText does. NAWstrcat(msgBuf_, WIDE_(" $0 $1 $2 $3 $4 $5 $6 $7 $8 $9")); //dbg: NAWstrcat(msgBuf_, WIDE_(" $ $$ $ab $9 $~ $~~ $~0 $0~ $~a $a~ $0x $0x~int0 $int0~x # $0~int0 $int0~0 $0 $00 $0$0")); //dbg: NAWstrcat(msgBuf_, WIDE_(" $Int0~0$int0~1 $0~Int0$1~int0 #")); //dbg: NAWstrcat(msgBuf_, WIDE_(" $Int0~0$int0~0 $0~Int0$0~int0 #")); //dbg: NAWstrcat(msgBuf_, WIDE_(" $Int0~0$0~int0 $0~Int0$int0~0 #")); } ErrorMessageOverflowCheckW(msgBuf_, MSG_BUF_SIZE); insertParams(errcb); if (forceParamSubst) { // remove trailing blanks and unsubstituted substitution marks #pragma nowarn(1506) // warning elimination Int32 tmpLen = NAWstrlen(msgBuf_); #pragma warn(1506) // warning elimination while (--tmpLen >= 0 && (msgBuf_[tmpLen] == NAWchar(' ') || msgBuf_[tmpLen] == NAWchar('\t') || msgBuf_[tmpLen] == ERRORPARAM_BEGINMARK)) ; msgBuf_[++tmpLen] = NAWchar('\0'); } char msgBuf8bit[2*MSG_BUF_SIZE]; UnicodeStringToLocale(CharInfo::ISO88591, msgBuf_, MSG_BUF_SIZE, msgBuf8bit, 2*MSG_BUF_SIZE); printf("%s\n", msgBuf8bit); fflush(stdout); } // ErrorMessage::printErrorMessage()
Lng32 FormatRow(const HSColumnStruct *srcDesc, const char *src, HSDataBuffer &target) { const Lng32 REC_INTERVAL = REC_MIN_INTERVAL; Lng32 retcode = 0; const Lng32 workBufLen = 4096; NAWchar workBuf[workBufLen]; Lng32 type = srcDesc->datatype; NAWString wStr; //The input source buffer will always be in the following form and will //contain unicode format. We need to separate the buffer accordingly. // |-------|--------------| // SRC -->| LEN | DATA | // |-------|--------------| short inDataLen; memcpy((char*)&inDataLen, src, sizeof(short)); const NAWchar *inData = (NAWchar*)(src + sizeof(short)); if (DFS2REC::isInterval(type)) type = REC_INTERVAL; if (DFS2REC::isAnyCharacter(type)) { wStr = WIDE_("'"); for (short i = 0; i < inDataLen/sizeof(NAWchar); i++) { if (inData[i] == NAWchar('\0')) wStr += NAWchar('\1'); /* convert x00 to x01 */ else { wStr += inData[i]; if (inData[i] == NAWchar('\'')) wStr.append(WIDE_("'")); } } wStr.append(WIDE_("'")); target = wStr.data(); } else { switch (type) { case REC_DATETIME: { switch (srcDesc->precision) { case REC_DTCODE_DATE: { wStr = WIDE_("DATE '"); wStr.append(inData, inDataLen/sizeof(NAWchar)); wStr.append(WIDE_("'")); break; } case REC_DTCODE_TIME: { wStr = WIDE_("TIME '"); wStr.append(inData, inDataLen/sizeof(NAWchar)); wStr.append(WIDE_("'")); break; } case REC_DTCODE_TIMESTAMP: { wStr = WIDE_("TIMESTAMP '"); wStr.append(inData, inDataLen/sizeof(NAWchar)); wStr.append(WIDE_("'")); break; } // Here begin a number of cases that are only possible with MP datetime types. // LCOV_EXCL_START :mp case REC_DTCODE_YEAR: { wStr = WIDE_("DATETIME '"); wStr.append(inData, inDataLen/sizeof(NAWchar)); wStr.append(WIDE_("' YEAR")); break; } case REC_DTCODE_YEAR_MONTH: { wStr = WIDE_("DATETIME '"); wStr.append(inData, inDataLen/sizeof(NAWchar)); wStr.append(WIDE_("' YEAR TO MONTH")); break; } case REC_DTCODE_YEAR_HOUR: { wStr = WIDE_("DATETIME '"); wStr.append(inData, inDataLen/sizeof(NAWchar)); wStr.append(WIDE_("' YEAR TO HOUR")); break; } case REC_DTCODE_YEAR_MINUTE: { wStr = WIDE_("DATETIME '"); wStr.append(inData, inDataLen/sizeof(NAWchar)); wStr.append(WIDE_("' YEAR TO MINUTE")); break; } case REC_DTCODE_MONTH: { wStr = WIDE_("DATETIME '"); wStr.append(inData, inDataLen/sizeof(NAWchar)); wStr.append(WIDE_("' MONTH")); break; } case REC_DTCODE_MONTH_DAY: { wStr = WIDE_("DATETIME '"); wStr.append(inData, inDataLen/sizeof(NAWchar)); wStr.append(WIDE_("' MONTH TO DAY")); break; } case REC_DTCODE_MONTH_HOUR: { wStr = WIDE_("DATETIME '"); wStr.append(inData, inDataLen/sizeof(NAWchar)); wStr.append(WIDE_("' MONTH TO HOUR")); break; } case REC_DTCODE_MONTH_MINUTE: { wStr = WIDE_("DATETIME '"); wStr.append(inData, inDataLen/sizeof(NAWchar)); wStr.append(WIDE_("' MONTH TO MINUTE")); break; } case REC_DTCODE_MONTH_SECOND: { wStr = WIDE_("DATETIME '"); wStr.append(inData, inDataLen/sizeof(NAWchar)); if (srcDesc->scale == 0) wStr.append(WIDE_("' MONTH TO SECOND")); else { wStr.append(WIDE_("' MONTH TO ")); wStr.append(appendFraction(srcDesc->scale)); } break; } case REC_DTCODE_DAY: { wStr = WIDE_("DATETIME '"); wStr.append(inData, inDataLen/sizeof(NAWchar)); wStr.append(WIDE_("' DAY")); break; } case REC_DTCODE_DAY_HOUR: { wStr = WIDE_("DATETIME '"); wStr.append(inData, inDataLen/sizeof(NAWchar)); wStr.append(WIDE_("' DAY TO HOUR")); break; } case REC_DTCODE_DAY_MINUTE: { wStr = WIDE_("DATETIME '"); wStr.append(inData, inDataLen/sizeof(NAWchar)); wStr.append(WIDE_("' DAY TO MINUTE")); break; } case REC_DTCODE_DAY_SECOND: { wStr = WIDE_("DATETIME '"); wStr.append(inData, inDataLen/sizeof(NAWchar)); if (srcDesc->scale == 0) wStr.append(WIDE_("' DAY TO SECOND")); else { wStr.append(WIDE_("' DAY TO ")); wStr.append(appendFraction(srcDesc->scale)); } break; } case REC_DTCODE_HOUR: { wStr = WIDE_("DATETIME '"); wStr.append(inData, inDataLen/sizeof(NAWchar)); wStr.append(WIDE_("' HOUR")); break; } case REC_DTCODE_HOUR_MINUTE: { wStr = WIDE_("DATETIME '"); wStr.append(inData, inDataLen/sizeof(NAWchar)); wStr.append(WIDE_("' HOUR TO MINUTE")); break; } case REC_DTCODE_MINUTE: { wStr = WIDE_("DATETIME '"); wStr.append(inData, inDataLen/sizeof(NAWchar)); wStr.append(WIDE_("' MINUTE")); break; } case REC_DTCODE_MINUTE_SECOND: { wStr = WIDE_("DATETIME '"); wStr.append(inData, inDataLen/sizeof(NAWchar)); if (srcDesc->scale == 0) wStr.append(WIDE_("' MINUTE TO SECOND")); else { wStr.append(WIDE_("' MINUTE TO ")); wStr.append(appendFraction(srcDesc->scale)); } break; } case REC_DTCODE_SECOND: { wStr = WIDE_("DATETIME '"); wStr.append(inData, inDataLen/sizeof(NAWchar)); if (srcDesc->scale == 0) wStr.append(WIDE_("' SECOND")); else { wStr.append(WIDE_("' SECOND TO ")); wStr.append(appendFraction(srcDesc->scale)); } break; } // LCOV_EXCL_STOP // LCOV_EXCL_START :rfi default: { HS_ASSERT(FALSE); break; } // LCOV_EXCL_STOP } target = wStr.data(); break; } case REC_INTERVAL: { //The INTERVAL may contain spaces and the negative sign //in front of the number. //We must capture the sign, but do not copy the extra character. Int32 spaceLen = 0; NABoolean signPresent = FALSE; spaceLen = wcsspn(inData, L" "); if (inData[spaceLen] == L'-') { signPresent = TRUE; wStr = WIDE_("INTERVAL -'"); } else wStr = WIDE_("INTERVAL '"); for (short i=0; i < spaceLen; i++) wStr.append(L" "); wStr.append( (inData+((signPresent) ? 1 : 0)+spaceLen), (inDataLen/sizeof(NAWchar)-((signPresent) ? 1 : 0)-spaceLen)); wStr.append(WIDE_("'")); switch (srcDesc->datatype) { case REC_INT_YEAR: { na_wsprintf(workBuf, WIDE_("%s YEAR(%d)"), wStr.data(), srcDesc->precision); break; } case REC_INT_YEAR_MONTH: { na_wsprintf(workBuf, WIDE_("%s YEAR(%d) TO MONTH"), wStr.data(), srcDesc->precision); break; } case REC_INT_MONTH: { na_wsprintf(workBuf, WIDE_("%s MONTH(%d)"), wStr.data(), srcDesc->precision); break; } case REC_INT_DAY: { na_wsprintf(workBuf, WIDE_("%s DAY(%d)"), wStr.data(), srcDesc->precision); break; } case REC_INT_DAY_HOUR: { na_wsprintf(workBuf, WIDE_("%s DAY(%d) TO HOUR"), wStr.data(), srcDesc->precision); break; } case REC_INT_DAY_MINUTE: { na_wsprintf(workBuf, WIDE_("%s DAY(%d) TO MINUTE"), wStr.data(), srcDesc->precision); break; } case REC_INT_DAY_SECOND: { na_wsprintf(workBuf, WIDE_("%s DAY(%d) TO SECOND(%d)"), wStr.data(), srcDesc->precision, srcDesc->scale); break; } case REC_INT_HOUR: { na_wsprintf(workBuf, WIDE_("%s HOUR(%d)"), wStr.data(), srcDesc->precision); break; } case REC_INT_HOUR_MINUTE: { na_wsprintf(workBuf, WIDE_("%s HOUR(%d) TO MINUTE"), wStr.data(), srcDesc->precision); break; } case REC_INT_HOUR_SECOND: { na_wsprintf(workBuf, WIDE_("%s HOUR(%d) TO SECOND(%d)"), wStr.data(), srcDesc->precision, srcDesc->scale); break; } case REC_INT_MINUTE: { na_wsprintf(workBuf, WIDE_("%s MINUTE(%d)"), wStr.data(), srcDesc->precision); break; } case REC_INT_MINUTE_SECOND: { na_wsprintf(workBuf, WIDE_("%s MINUTE(%d) TO SECOND(%d)"), wStr.data(), srcDesc->precision, srcDesc->scale); break; } case REC_INT_SECOND: { na_wsprintf(workBuf, WIDE_("%s SECOND(%d, %d)"), wStr.data(), srcDesc->precision, srcDesc->scale); break; } // LCOV_EXCL_START :rfi default: { HS_ASSERT(FALSE); break; } // LCOV_EXCL_STOP } target = workBuf; break; } default: { wStr.replace(0, wStr.length(), inData, inDataLen/sizeof(NAWchar)); target = wStr.data(); break; } } } return retcode; }