| /* -*-C++-*- |
| **************************************************************************** |
| * |
| * File: ExpError.cpp (previously part of /executor/ex_error.cpp) |
| * Description: |
| * |
| * Created: 5/6/98 |
| * Language: C++ |
| * |
| * |
| // @@@ START COPYRIGHT @@@ |
| // |
| // Licensed to the Apache Software Foundation (ASF) under one |
| // or more contributor license agreements. See the NOTICE file |
| // distributed with this work for additional information |
| // regarding copyright ownership. The ASF licenses this file |
| // to you under the Apache License, Version 2.0 (the |
| // "License"); you may not use this file except in compliance |
| // with the License. You may obtain a copy of the License at |
| // |
| // http://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, |
| // software distributed under the License is distributed on an |
| // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| // KIND, either express or implied. See the License for the |
| // specific language governing permissions and limitations |
| // under the License. |
| // |
| // @@@ END COPYRIGHT @@@ |
| * |
| **************************************************************************** |
| */ |
| |
| #include "Platform.h" |
| |
| |
| #include "ExpError.h" |
| #include "str.h" |
| #include "ComDiags.h" |
| #include "exp_clause_derived.h" |
| |
| // Single allocation of buf is split up to be used for opstrings, |
| // formatting. |
| // |-----buf------------------------------------|---opstrings[]---------------|--FORMATTING--| |
| // |--(numAModes * VALUE_TYPE_LEN) + INSTR_LEN--|--(numAModes * OPVALUE_LEN)--|--FORMATTING--] |
| // |--(numAModes * VALUE_TYPE_LEN) + INSTR_LEN--+--(numAModes * OPVALUE_LEN)--+--FORMATTING--] |
| |
| // above equation deduced to: |
| // ==[(numAModes * (VALUE_TYPE_LEN + OPVALUE_LEN)) + INSTR_LEN + FORMATTING] |
| #define OPVALUE_LEN 200 // operand value length |
| #define OPTYPE_LEN 100 // operand type length |
| #define VALUE_TYPE_LEN OPTYPE_LEN + OPVALUE_LEN |
| #define INSTR_LEN 200 // Instruction,operation,formatting length |
| #define FORMATTING 200 // For formatting detailed error string |
| |
| |
| class PCIType; |
| extern char * exClauseGetText(OperatorTypeEnum ote); |
| extern char * getDatatypeAsString( Int32 Datatype, NABoolean extFormat ); |
| |
| ComDiagsArea *ExAddCondition(CollHeap* heap, ComDiagsArea** diagsArea, |
| Lng32 err, ComCondition** newCond, |
| Lng32 * intParam1, |
| Lng32 * intParam2, |
| Lng32 * intParam3, |
| const char * stringParam1, |
| const char * stringParam2, |
| const char * stringParam3) |
| { |
| // |
| // This version of ExRaiseSqlError is used by the expressions code. In |
| // addition to having slightly different parameters, it differs from the |
| // above version in that it puts an error condition in the supplied |
| // ComDiagsArea rather than in a copy. |
| // |
| // If the caller didn't pass in the address of a pointer to the |
| // ComDiagsArea, there's no point in creating an error condition since the |
| // caller won't receive it. Normally this should never happen, but right |
| // now it may occur until all the error processing code is in place. |
| // |
| if (diagsArea == NULL) |
| return NULL; |
| // |
| // The caller did pass in the address of a pointer to the ComDiagsArea. If |
| // the pointer is NULL, we need to allocate the ComDiagsArea and put its |
| // address in the pointer. Otherwise, we will put the error condition in |
| // the ComDiagsArea that was supplied. |
| // |
| if (*diagsArea == NULL) { |
| // |
| // If the heap is NULL, we can't allocate the ComDiagsArea. This should |
| // never happen. |
| // |
| if (heap == NULL) |
| return NULL; |
| *diagsArea = ComDiagsArea::allocate(heap); |
| } |
| |
| ComDiagsArea *da = *diagsArea; |
| ComCondition *cond = da->makeNewCondition(); |
| cond->setSQLCODE(err); |
| |
| if (intParam1) |
| cond->setOptionalInteger(0, *intParam1); |
| if (intParam2) |
| cond->setOptionalInteger(1, *intParam2); |
| if (intParam3) |
| cond->setOptionalInteger(2, *intParam3); |
| if (stringParam1) |
| cond->setOptionalString(0, stringParam1); |
| if (stringParam2) |
| cond->setOptionalString(1, stringParam2); |
| if (stringParam3) |
| cond->setOptionalString(2, stringParam3); |
| |
| da->acceptNewCondition(); |
| |
| if (newCond) |
| *newCond = cond; |
| |
| return *diagsArea; |
| } |
| |
| ComDiagsArea *ExRaiseSqlError(CollHeap* heap, ComDiagsArea** diagsArea, |
| ExeErrorCode err, ComCondition** cond, |
| Lng32 * intParam1, |
| Lng32 * intParam2, |
| Lng32 * intParam3, |
| const char * stringParam1, |
| const char * stringParam2, |
| const char * stringParam3) |
| { |
| return ExAddCondition(heap, diagsArea, - (Lng32) err, cond, |
| intParam1, intParam2, intParam3, |
| stringParam1, stringParam2, stringParam3); |
| } |
| |
| ComDiagsArea *ExRaiseSqlError(CollHeap* heap, ComDiagsArea** diagsArea, |
| Lng32 err, |
| Lng32 * intParam1, |
| Lng32 * intParam2, |
| Lng32 * intParam3, |
| const char * stringParam1, |
| const char * stringParam2, |
| const char * stringParam3) |
| { |
| return ExAddCondition(heap, diagsArea, err, NULL, |
| intParam1, intParam2, intParam3, |
| stringParam1, stringParam2, stringParam3); |
| } |
| |
| ComDiagsArea *ExRaiseSqlWarning(CollHeap* heap, ComDiagsArea** diagsArea, |
| ExeErrorCode err, ComCondition** cond, |
| Lng32 * intParam1, |
| Lng32 * intParam2, |
| Lng32 * intParam3, |
| const char * stringParam1, |
| const char * stringParam2, |
| const char * stringParam3) |
| { |
| return ExAddCondition(heap, diagsArea, (Lng32) err, cond, |
| intParam1, intParam2, intParam3, |
| stringParam1, stringParam2, stringParam3); |
| } |
| ComDiagsArea *ExRaiseSqlWarning(CollHeap* heap, ComDiagsArea** diagsArea, |
| ExeErrorCode err, ComCondition** cond) |
| { |
| return ExAddCondition(heap, diagsArea, (Lng32) err, cond, NULL, NULL, NULL); |
| } |
| |
| ComDiagsArea *ExRaiseFunctionSqlError(CollHeap* heap, |
| ComDiagsArea** diagsArea, |
| ExeErrorCode err, |
| NABoolean derivedFunction, |
| OperatorTypeEnum origOperType, |
| ComCondition** cond) |
| { |
| ExRaiseSqlError(heap, diagsArea, err); |
| |
| if (derivedFunction) |
| { |
| **diagsArea << DgSqlCode(-EXE_MAPPED_FUNCTION_ERROR); |
| **diagsArea << DgString0(exClauseGetText(origOperType)); |
| } |
| return *diagsArea; |
| } |
| |
| Int32 convertToHexAscii(char *src, Int32 srcLength, char *result, |
| Int32 maxResultSize) |
| { |
| const char HexArray[16] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', |
| 'A', 'B', 'C', 'D', 'E', 'F'}; |
| |
| if( src == NULL || result == NULL || srcLength<=0 || maxResultSize <= 0) |
| return 1; |
| //Each byte = 2 chars to represent hex + '0x'+'\0'. |
| if( ((srcLength * 2) + 3) > maxResultSize) |
| return 1; |
| |
| char *srcTemp = src; |
| Int32 upper4bits, lower4bits; |
| result[0] = '0'; |
| result[1] = 'x'; |
| char *resultTemp = &result[2]; |
| |
| //Since source length may be a odd value, it is not possible to |
| //convert between little or big endian. We just convert the |
| //memory into hex and put it in the string. |
| for( Int32 i = 0; i < srcLength; i++ ) |
| { |
| lower4bits = (*srcTemp) & 0x0F; |
| upper4bits = (*srcTemp) & 0xF0; |
| upper4bits>>= 4; |
| resultTemp[2 * i] = HexArray[upper4bits]; |
| resultTemp[(2 * i) + 1 ] = HexArray[lower4bits]; |
| srcTemp++; |
| } |
| result[(srcLength * 2)+2] = '\0'; |
| return 0; |
| } |
| |
| |
| void ExConvertErrorToString(CollHeap* heap, |
| ComDiagsArea** diagsArea, |
| char *src, |
| Int32 srcLength, |
| Int16 srcType, |
| Int32 srcScale, |
| char *result, |
| Int32 maxResultSize |
| ) |
| { |
| ex_expr::exp_return_type retCode = ex_expr::EXPR_OK; |
| |
| Int32 vcharLen = 0; |
| Int32 counter; |
| Int32 errorMark = ComDiagsArea::INVALID_MARK_VALUE; |
| Int32 warningMark = ComDiagsArea::INVALID_MARK_VALUE; |
| Int32 errorMark1; |
| Int32 warningMark1; |
| |
| |
| if(*diagsArea){ |
| errorMark = (*diagsArea)->getNumber(DgSqlCode::ERROR_); |
| warningMark = (*diagsArea)->getNumber(DgSqlCode::WARNING_); |
| } |
| |
| retCode = convDoIt( src, |
| srcLength, //source length |
| srcType, //source type |
| 0, //source precision |
| srcScale, //source scale |
| result, //target |
| maxResultSize, //targetlength |
| REC_BYTE_V_ASCII, //target type |
| 0, //target precision |
| SQLCHARSETCODE_UTF8, //target scale |
| (char*)&vcharLen, //vcharlength |
| sizeof(vcharLen), //vchar length size |
| heap, |
| diagsArea, |
| CONV_UNKNOWN, |
| 0, |
| CONV_CONTROL_LOOPING | CONV_ALLOW_INVALID_CODE_VALUE); |
| |
| //Before proceeding, delete any errors and warnings that may have |
| //been introduced by convDoIt from above. |
| if(*diagsArea){ |
| errorMark1 = (*diagsArea)->getNumber(DgSqlCode::ERROR_); |
| warningMark1 = (*diagsArea)->getNumber(DgSqlCode::WARNING_); |
| counter = errorMark1 - errorMark; |
| while(counter){ |
| (*diagsArea)->deleteError(errorMark1 - counter); |
| counter--; |
| } |
| counter = warningMark1 - warningMark; |
| while(counter){ |
| (*diagsArea)->deleteWarning(warningMark1 - counter); |
| counter--; |
| } |
| } |
| |
| if (retCode == ex_expr::EXPR_OK ){ |
| // need to zero terminate the result buffer to printf error string |
| if (vcharLen < maxResultSize - 1) |
| result[vcharLen] = '\0'; |
| else |
| result[maxResultSize - 1] = '\0'; |
| return; |
| } |
| |
| //Once we reach this point, all we can do is just dump the source memory. |
| if(convertToHexAscii(src, srcLength, result, maxResultSize) == 0 ){ |
| return; |
| } |
| |
| // Once we reach this point, there is nothing we can do much. |
| // Attempt to display "-E" indicating error, else NULL. |
| if(maxResultSize >=3){ |
| result[0] = '-'; |
| result[1] = 'E'; |
| result[2] = '\0'; |
| } |
| else |
| result[0] = '\0'; |
| return; |
| } |
| |
| //Detailed error support for pcode expression evaluation. |
| ComDiagsArea *ExRaiseDetailSqlError(CollHeap* heap, |
| ComDiagsArea** diagsArea, |
| ExeErrorCode err, |
| Int32 pciInst, |
| char *op1, |
| char *op2, |
| char *op3) |
| { |
| if (diagsArea == NULL) |
| return NULL; |
| |
| if (*diagsArea == NULL){ |
| |
| if (heap == NULL) |
| return NULL; |
| *diagsArea = ComDiagsArea::allocate(heap); |
| } |
| |
| PCIT::Operation operation; |
| PCIT::AddressingMode am[6]; |
| Int32 numAModes; |
| Int32 rangeInst = PCode::isInstructionRangeType((PCIT::Instruction)pciInst)? 1: 0; |
| |
| if(PCode::getOpCodeMapElements( pciInst, operation, am, numAModes ) ){ |
| |
| ExRaiseSqlError(heap, diagsArea, err); |
| return *diagsArea; |
| } |
| |
| // Single allocation of buf is split up to be used for opstrings, |
| // formatting. See defines at beginning of this header file |
| // for details. |
| char *buf = new (heap) |
| char[(numAModes * (VALUE_TYPE_LEN + OPVALUE_LEN)) + INSTR_LEN + FORMATTING]; |
| |
| if( !buf ){ |
| ExRaiseSqlError(heap, diagsArea, err); |
| return *diagsArea; |
| } |
| char *opStrings = &buf[(numAModes * VALUE_TYPE_LEN) + INSTR_LEN ]; |
| char *buf1 = // assign FORMATTING part of address. |
| &buf[(numAModes * (VALUE_TYPE_LEN + OPVALUE_LEN)) + INSTR_LEN]; |
| |
| switch( numAModes ){ |
| case 1: |
| ExConvertErrorToString(heap, |
| diagsArea, |
| op1, |
| PCIT::getOperandLengthForAddressingMode(am[0]), |
| PCIT::getDataTypeForMemoryAddressingMode(am[0]), |
| 0, |
| (char*)&opStrings[0], |
| OPVALUE_LEN); |
| |
| //construct a formated string and assign to diags area |
| **diagsArea << DgSqlCode(-err); |
| |
| if(rangeInst){ |
| str_sprintf( buf, " Source Value:%s not within limits of Target Type:%s(%s).", |
| &opStrings[0], |
| getDatatypeAsString(PCIT::getDataTypeForMemoryAddressingMode(am[0]),true), |
| PCIT::addressingModeString(am[0])); |
| } |
| else{ |
| str_sprintf( buf, " Operand Type:%s(%s) Operand Value:%s.", |
| getDatatypeAsString(PCIT::getDataTypeForMemoryAddressingMode(am[0]),true), |
| PCIT::addressingModeString(am[0]), &opStrings[0]); |
| } |
| |
| str_sprintf( buf1, " Instruction:%s Operation:%s.", |
| PCIT::instructionString((PCIT::Instruction)pciInst), |
| PCIT::operationString(operation)); |
| str_cat(buf, buf1, buf); |
| **diagsArea<<DgString0(buf); |
| |
| break; |
| |
| case 3: |
| case 4: |
| //since we are only interested in left and right operands, just overright |
| //am modes to be processed by case 2 below. |
| am[0] = am[1]; |
| am[1] = am[2]; |
| |
| //do not break here. Flow down to case 2. |
| case 2: |
| ExConvertErrorToString(heap, |
| diagsArea, |
| op1, |
| PCIT::getOperandLengthForAddressingMode(am[0]), |
| PCIT::getDataTypeForMemoryAddressingMode(am[0]), |
| 0, |
| (char*)&opStrings[0], |
| OPVALUE_LEN); |
| |
| ExConvertErrorToString(heap, |
| diagsArea, |
| op2, |
| PCIT::getOperandLengthForAddressingMode(am[1]), |
| PCIT::getDataTypeForMemoryAddressingMode(am[1]), |
| 0, |
| (char*)&opStrings[OPVALUE_LEN], |
| OPVALUE_LEN); |
| |
| //construct a formated string and assign to diags area |
| **diagsArea << DgSqlCode(-err); |
| str_sprintf( buf, " %s Type:%s(%s) %s Value:%s", |
| rangeInst? "Source":"Operand1", |
| getDatatypeAsString(PCIT::getDataTypeForMemoryAddressingMode(am[0]),true), |
| PCIT::addressingModeString(am[0]), |
| rangeInst? "Source":"Operand1", &opStrings[0]); |
| str_sprintf( buf1, " %s Type:%s(%s)%s%s Value:%s.", |
| rangeInst? "Target":"Operand2", |
| getDatatypeAsString(PCIT::getDataTypeForMemoryAddressingMode(am[1]),true), |
| PCIT::addressingModeString(am[1]), |
| rangeInst? (opStrings[OPVALUE_LEN] == '-' ? " Min ": " Max "):" ", |
| rangeInst? "Target":"Operand2", &opStrings[OPVALUE_LEN]); |
| str_cat(buf, buf1, buf); |
| str_sprintf( buf1, " Instruction:%s Operation:%s.", |
| PCIT::instructionString((PCIT::Instruction)pciInst), |
| PCIT::operationString(operation)); |
| str_cat(buf, buf1, buf); |
| **diagsArea<<DgString0(buf); |
| break; |
| |
| //Needs to be enhanced for other types. Just dump what ever we have. |
| default: |
| ExRaiseSqlError(heap, diagsArea, err); |
| }; |
| |
| NADELETEBASICARRAY(buf, (heap)); |
| return *diagsArea; |
| } |
| |
| //Detailed error support for clause expression evaluation. |
| ComDiagsArea *ExRaiseDetailSqlError(CollHeap* heap, |
| ComDiagsArea** diagsArea, |
| ExeErrorCode err, |
| ex_clause *clause, |
| char *op_data[]) |
| { |
| if (diagsArea == NULL) |
| return NULL; |
| |
| if (*diagsArea == NULL){ |
| |
| if (heap == NULL) |
| return NULL; |
| *diagsArea = ComDiagsArea::allocate(heap); |
| } |
| |
| Int16 numOperands = clause->getNumOperands(); |
| Attributes *op; |
| Int16 i; |
| |
| // Single allocation of buf is split up to be used for opstrings, |
| // formatting. See defines at beginning of this header file |
| // for details. |
| char *buf = new (heap) |
| char[(numOperands * (VALUE_TYPE_LEN + OPVALUE_LEN)) + INSTR_LEN + FORMATTING]; |
| |
| if( !buf ){ |
| ExRaiseSqlError(heap, diagsArea, err); |
| return *diagsArea; |
| } |
| char *opStrings = &buf[(numOperands * VALUE_TYPE_LEN) + INSTR_LEN ]; |
| // assign FORMATTING part of address. |
| char *buf1 = &buf[(numOperands * (VALUE_TYPE_LEN + OPVALUE_LEN)) + INSTR_LEN]; |
| |
| for (i = 1; i < numOperands; i++){ |
| op = clause->getOperand(i); |
| ExConvertErrorToString(heap, |
| diagsArea, |
| (char*)op_data[i], |
| op->getLength(), |
| op->getDatatype(), |
| op->getScale(), |
| (char*)&opStrings[(i-1)*OPVALUE_LEN], |
| OPVALUE_LEN); |
| |
| } |
| |
| //initialize buf before entering the loop. |
| buf[0] = '\0'; |
| |
| for(i = 1; i< numOperands; i++){ |
| op = clause->getOperand(i); |
| str_sprintf(buf1, " Operand%d Type:%s(%s) Operand%d Value:%s",i, |
| getDatatypeAsString(op->getDatatype(), true), |
| getDatatypeAsString(op->getDatatype(), false), |
| i, |
| &opStrings[(i-1)*OPVALUE_LEN]); |
| str_cat(buf, buf1, buf); |
| } |
| if(numOperands) |
| { |
| str_sprintf(buf1,"."); |
| str_cat(buf, buf1, buf); |
| } |
| str_sprintf(buf1, " Clause Type:%d Clause number:%d Operation:%s.", |
| clause->getType(), clause->clauseNum(), |
| exClauseGetText(clause->getOperType())); |
| str_cat(buf, buf1, buf); |
| |
| **diagsArea << DgSqlCode(-err); |
| **diagsArea<<DgString0(buf); |
| |
| NADELETEBASICARRAY(buf, (heap)); |
| return *diagsArea; |
| } |
| |
| |
| //Detailed error support for conversions, especially for use in convdoit. |
| ComDiagsArea *ExRaiseDetailSqlError(CollHeap* heap, |
| ComDiagsArea** diagsArea, |
| ExeErrorCode err, |
| char *src, |
| Int32 srcLength, |
| Int16 srcType, |
| Int32 srcScale, |
| Int16 tgtType, |
| UInt32 flags, |
| Int32 tgtLength, |
| Int32 tgtScale, |
| Int32 tgtPrecision) |
| { |
| //if looping situation, no need to proceed further, return back. |
| if(flags & CONV_CONTROL_LOOPING) |
| return NULL; |
| |
| NABoolean intermediate; |
| |
| if( flags & CONV_INTERMEDIATE_CONVERSION ) |
| intermediate = TRUE; |
| else |
| intermediate = FALSE; |
| |
| if (diagsArea == NULL) |
| return NULL; |
| |
| if (*diagsArea == NULL){ |
| |
| if (heap == NULL) |
| return NULL; |
| *diagsArea = ComDiagsArea::allocate(heap); |
| } |
| |
| //Allocate buf once, for formatting and opstring[1]. |
| // |--------formatting--------|--opstring[1]------| |
| char *buf = new (heap) char[FORMATTING+ OPVALUE_LEN] ; |
| if( !buf ){ |
| ExRaiseSqlError(heap, diagsArea, err); |
| return *diagsArea; |
| } |
| char *opString = &buf[FORMATTING]; |
| |
| ExConvertErrorToString(heap, |
| diagsArea, |
| src, |
| srcLength, |
| srcType, |
| srcScale, |
| opString, |
| OPVALUE_LEN); |
| |
| char srcDatatypeDetail[200]; |
| if ((DFS2REC::isAnyCharacter(srcType)) && |
| (srcLength >= 0) && |
| (srcScale > 0)) |
| str_sprintf(srcDatatypeDetail, "%s,%d BYTES,%s", |
| getDatatypeAsString(srcType, false), |
| // srcLength/CharInfo::bytesPerChar((CharInfo::CharSet)srcScale), |
| srcLength, |
| (srcScale == CharInfo::ISO88591 ? "ISO88591" : "UTF8")); |
| else |
| strcpy(srcDatatypeDetail, getDatatypeAsString(srcType, false)); |
| |
| char tgtDatatypeDetail[200]; |
| if ((DFS2REC::isAnyCharacter(tgtType)) && |
| (tgtLength >= 0) && |
| (tgtScale > 0)) |
| str_sprintf(tgtDatatypeDetail, "%s,%d %s,%s", |
| getDatatypeAsString(tgtType, false), |
| tgtPrecision ? tgtPrecision : tgtLength, |
| tgtPrecision ? "CHARS" : "BYTES", |
| // tgtLength/CharInfo::bytesPerChar((CharInfo::CharSet)tgtScale), |
| (tgtScale == CharInfo::ISO88591 ? "ISO88591" : "UTF8")); |
| else |
| strcpy(tgtDatatypeDetail, getDatatypeAsString(tgtType, false)); |
| |
| str_sprintf(buf, |
| " %s of Source Type:%s(%s) Source Value:%s to Target Type:%s(%s).", |
| intermediate? "Intermediate conversion" : "Conversion", |
| getDatatypeAsString(srcType, true), |
| srcDatatypeDetail, |
| opString, |
| getDatatypeAsString(tgtType,true), |
| tgtDatatypeDetail); |
| |
| **diagsArea << DgSqlCode(-err); |
| **diagsArea<<DgString0(buf); |
| |
| NADELETEBASICARRAY(buf, (heap)); |
| return *diagsArea; |
| } |
| |
| ////////////////////////////////////////////////////////////////// |
| //// |
| //// A helper function to show buffer in HEX |
| //// |
| //// /////////////////////////////////////////////////////////////// |
| |
| char *stringToHex(char * out, Int32 outLen, char * in, Int32 inLen) |
| { |
| |
| Int32 hexLen = (outLen / 2) -1 ; |
| if (inLen < hexLen) |
| hexLen = inLen; |
| if (hexLen < 0) |
| hexLen = 0; |
| if (outLen > 0) |
| out[0] = '\0'; |
| char hex[3]; |
| for(int i = 0; i < hexLen; i++) |
| { |
| snprintf(hex, sizeof(hex), "%02x", (unsigned char)in[i]); |
| strcat(out,hex); |
| } |
| return out; |
| } |
| |