blob: 8a79d915b172eb08709f900e731b6749fa7d8715 [file] [log] [blame]
/* -*-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 );
SQLEXP_LIB_FUNC
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;
}
NA_EIDPROC
SQLEXP_LIB_FUNC
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);
}
NA_EIDPROC
SQLEXP_LIB_FUNC
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);
}
NA_EIDPROC
SQLEXP_LIB_FUNC
ComDiagsArea *ExRaiseSqlWarning(CollHeap* heap, ComDiagsArea** diagsArea,
ExeErrorCode err, ComCondition** cond)
{
return ExAddCondition(heap, diagsArea, (Lng32) err, cond, NULL, NULL, NULL);
}
NA_EIDPROC
SQLEXP_LIB_FUNC
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;
}
NA_EIDPROC
SQLEXP_LIB_FUNC
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;
}
NA_EIDPROC
SQLEXP_LIB_FUNC
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.
NA_EIDPROC
SQLEXP_LIB_FUNC
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.
NA_EIDPROC
SQLEXP_LIB_FUNC
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.
NA_EIDPROC
SQLEXP_LIB_FUNC
ComDiagsArea *ExRaiseDetailSqlError(CollHeap* heap,
ComDiagsArea** diagsArea,
ExeErrorCode err,
char *src,
Int32 srcLength,
Int16 srcType,
Int32 srcScale,
Int16 tgtType,
UInt32 flags,
Int32 tgtLength,
Int32 tgtScale)
{
//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 BYTES,%s",
getDatatypeAsString(tgtType, false),
tgtLength,
// 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)
{
//clear out buffer first
memset(out,0,outLen);
outLen = (outLen / 2) -1 ;
if(inLen < outLen) outLen = inLen;
char hex[3];
for(int i = 0; i < outLen; i++)
{
sprintf(hex, "%02x", in[i]);
strcat(out,hex);
}
return out;
}