blob: 00fbcc4da6e872d48e9dec3d9aba0e653d582241 [file] [log] [blame]
/**********************************************************************
// @@@ START COPYRIGHT @@@
//
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
//
// @@@ END COPYRIGHT @@@
**********************************************************************/
/* -*-C++-*-
*****************************************************************************
*
* File: exp_eval.cpp
* Description: Expression evaluator, makes operands accessible, calls
* NULL processing methods and/or evaluation methods on clauses
*
* Created: 7/10/95
* Language: C++
*
*
*
*
*****************************************************************************
*/
#include "Platform.h"
#include "exp_stdh.h"
#include "ExpAtp.h"
#include "exp_clause_derived.h"
#include "ExpPCode.h"
#include "exp_function.h"
#include "ComSysUtils.h"
#include "exp_bignum.h"
#include "BigNumHelper.h"
#include "ExpPCodeOptimizations.h"
#include "unicode_char_set.h"
#include "wstr.h"
#include <unistd.h>
#include <sys/mman.h>
#include "exp_ovfl_ptal.h"
#include "exp_ieee.h"
double MathConvReal64ToReal64(double op1, Int16 * ov);
#include <float.h> /* nolist */
#include <limits.h> /* nolist */
// 3 bit left circular shift op1, and xor with op2.
// Both op1 and op2 are UInt32.
#define EXP_SHIFT_XOR(op1, op2) \
( ( ((op1) << 3) | ((op1) >> 29) ) ^ (op2) )
// Clear the sign bit and toggle one other bit accordingly.
// result is UInt32
#define EXP_CLEAR_SIGNBIT(result) \
( ((result) & 0x80000000) ? ((result) ^ 0x80000002) : (result) )
void setVCLength(char * VCLen, Int32 VCLenSize, UInt32 value);
// --------------------------------------------------------------------
// Generate 31 bit hash value by
// multiplication, shift, and xor for every 4 byte.
// --------------------------------------------------------------------
UInt32 FastHash(char *data, Int32 length)
{
// FastHash should be removed someday
assert( 0 /* "FastHash should not be used!" */ );
// scramble factors.
#define MULT_FACTOR 0x97
#define SCRAMBLE_0 MULT_FACTOR
#define SCRAMBLE_1 0x2d5
#define SCRAMBLE_2 0x1d
#define SCRAMBLE_3 0x2ec3
UInt32 result;
if (length == 4)
{
// Keep this logic in sync with case PCIT::HASH_MBIN32U_MBIN32_IBIN32S
// in ex_expr_base::evalPCode.
return *(UInt32 *)data;
}
else if (length == 2)
{
// Keep this logic in sync with case PCIT::HASH_MBIN32U_MBIN16_IBIN32S
// in ex_expr_base::evalPCode.
return (UInt32) (*(UInt16 *)data);
}
register UInt32 *source = (UInt32 *)data;
register UInt32 z;
if (length == 8)
{
#ifdef NA_LITTLE_ENDIAN
z = *source * MULT_FACTOR;
result = source[1] * SCRAMBLE_1;
#else
z = source[1] * MULT_FACTOR;
result = *source * SCRAMBLE_1;
#endif
result = EXP_SHIFT_XOR(result, z);
return EXP_CLEAR_SIGNBIT(result);
}
result = 0;
while (length >= 4)
{ // longer than 4 bytes and not 8 bytes
z = (*source++) * SCRAMBLE_0;
result = EXP_SHIFT_XOR(result, z);
length -= 4;
if (length < 4) break;
z = (*source++) * SCRAMBLE_1;
result = EXP_SHIFT_XOR(result, z);
length -= 4;
if (length < 4) break;
z = (*source++) * SCRAMBLE_2;
result = EXP_SHIFT_XOR(result, z);
length -= 4;
if (length < 4) break;
z = (*source++) * SCRAMBLE_3;
result = EXP_SHIFT_XOR(result, z);
length -= 4;
}
if (length == 0)
return EXP_CLEAR_SIGNBIT(result);
// Copy the remaining 1, 2, or 3 bytes to a Int32.
if (length == 1)
z = *((unsigned char *)source);
else {
z = *((UInt16 *)source);
if (length == 3)
z = (z << 8) + ((unsigned char *)source)[2];
}
z *= MULT_FACTOR;
result = EXP_SHIFT_XOR(result, z);
return EXP_CLEAR_SIGNBIT(result);
}
// This static array is used when a default value is not null and the
// attribute data format is SQLMX_ALIGNED_FORMAT.
// The default value is stored in SQLMX_FORMAT always and thus there
// is an impedence mismatch between the default value format and the
// disk format it is to be used for.
// This array is 16 bytes long and can accomodate 64 added columns
// that do have a default value.
// If the added column has no default or a default of null, then this
// the nulldata pointer is set to NULL and this static array is not used.
//
static const Int32 nullBitmapData[] = { 0, 0, 0, 0 };
ex_expr::exp_return_type getDefaultValueForAddedColumn(
UInt32 field_num, // field number whose default value is to be
// computed. Zero based.
ExpTupleDesc * td, // describes this row
Attributes * op,
char ** opdata,
char ** nulldata,
char ** varlendata,
CollHeap * heap,
ComDiagsArea **diagsArea)
{
char * defaultValue = td->getAttr((Int16)field_num)->getDefaultValue();
Attributes::DefaultClass dc =
td->getAttr((Int16)field_num)->getDefaultClass();
//
// Default values are stored in the packed SQLMX_FORMAT.
// This may be a different format than the attribute tuple data format.
if ((dc == Attributes::NO_DEFAULT) ||
((dc == Attributes::DEFAULT_NULL) &&
(op->getNullFlag() == 0)))
{
ExRaiseSqlError(heap, diagsArea, EXE_DEFAULT_VALUE_ERROR);
return ex_expr::EXPR_ERROR;
}
if (op->getNullFlag())
{
*nulldata = defaultValue;
if (dc == Attributes::DEFAULT_NULL)
*nulldata = NULL;
else if ( op->isSQLMXAlignedFormat() )
{
if ( ExpTupleDesc::isNullValue( defaultValue,
op->getNullBitIndex(),
ExpTupleDesc::SQLMX_FORMAT ) )
*nulldata = NULL;
else
*nulldata = (char *)nullBitmapData;
}
// Can't use the attribute field since the attribute describes the
// disk field and not the default value itself.
// op->getNullIndicatorLength();
defaultValue += ExpTupleDesc::NULL_INDICATOR_LENGTH;
}
if (op->getVCIndicatorLength() > 0)
*varlendata = defaultValue;
*opdata = defaultValue + op->getVCIndicatorLength();
return ex_expr::EXPR_OK;
}
/////////////////////////////////////////////////////////
// Computes the address of the field_num field. This
// field follows one (or more) varchar fields in a row
// with old format. This is true only for tables created
// in SQL/MP. In this format, all fields
// are stored next to each other in packed format(varchar
// fields are stored without blank padding).
/////////////////////////////////////////////////////////
void computeDataPtr(char * start_data_ptr, // start of data row
Int32 field_num, // field number whose address is to be
// computed. Zero based.
ExpTupleDesc * td, // describes this row
char ** opdata,
char ** nulldata,
char ** varlendata)
{
if (! start_data_ptr)
{
if (nulldata)
*nulldata = 0;
return;
}
AttributesPtr * op = td->attrs();
char * data_ptr = start_data_ptr;
for (Int32 i = 0; i < field_num; i++, op++)
{
data_ptr += ((*op)->getNullFlag() ?
(*op)->getNullIndicatorLength() : 0);
data_ptr += (*op)->getVCIndicatorLength() +
(*op)->getLength(data_ptr);
}
if (((*op)->getNullFlag()) && (nulldata))
*nulldata = data_ptr;
if (((*op)->getVCIndicatorLength() > 0) && (varlendata))
*varlendata = data_ptr + (*op)->getNullIndicatorLength();
if (opdata)
*opdata = data_ptr + (*op)->getNullIndicatorLength() +
(*op)->getVCIndicatorLength();
}
// Evaluate one or more clauses from an expression
// -- Helper for PCode abstract machine
//
ex_expr::exp_return_type ex_expr::evalClauses(ex_clause *clause,
atp_struct *atp1,
atp_struct *atp2,
Int32 datalen,
UInt32 *rowLen,
Int16 *lastFldIndex,
char * fetchedDataPtr) {
atp_struct *atps[] = {atp1, atp2};
// a consecutive regions of ex_clause objects (actually subclasses of
// ex_clause objects), linked by pointers
// allocated space on the stack for pointers to point to null indicator,
// var len indicator and actual data. There could be a maximum of
// MAX_OPERANDS with the first operand of each group being the result.
// The array contains first MAX_OPERANDS entries for null indicators,
// the next MAX_OPERANDS for vclen and the last ones for actual data.
char *op_data[ex_clause::MAX_OPERANDS * 3];
// allocated space for temporary, aligned operands on the stack
// (assuming that we have no more than 4 operands and that no operand
// using the temp space is longer than 64 bytes).
// Using buffer of type Int64 so it starts on an 8-byte aligned offset.
Int64 temp_buffer[ex_clause::MAX_OPERANDS][ex_clause::MAX_TEMP_OPERAND_LEN/sizeof(Int64)];
ex_expr::exp_return_type retcode = ex_expr::EXPR_OK;
// these next 8 locals are for SQLMX tuple format only
UInt32 varOffset = ExpOffsetMax,
voaOffset = 0,
offset = 0,
ff;
Int16 varIndLen;
Int16 nullIndLen;
NABoolean nullable = FALSE;
Attributes *currAttr = NULL;
Attributes *prevAttr = NULL;
NABoolean setLastFldIndex = FALSE;
NABoolean varOpFound = FALSE;
ExpTupleDesc *tuppDesc;
ex_expr::exp_mode mode = ex_expr::exp_UNKNOWN;
// ---------------------------------------------------------------------
// Loop over clauses of the expression
// ---------------------------------------------------------------------
while (clause)
{
// an array of pointers to Attributes data structures, describing
// the data types of the operands of this expression (op[0] points
// to the result type)
register AttributesPtr* op = clause->getOperand();
// pointer to the null indicator data for current operand
register char ** nulldata = &op_data[0];
// pointer to the varlen indicator for current operand
register char ** vardata = &op_data[ex_clause::MAX_OPERANDS];
// pointer to data for current operand
register char ** opdata = &op_data[2 * ex_clause::MAX_OPERANDS];
// a pointer to the actual result buffer of the expression (used in
// case the result is calculated in the temp buffer)
char * result_data = NULL;
// initialize the op_data array to all nulls
// for *every* clause!
str_pad((char*)op_data, sizeof(op_data), '\0');
// reset the variable operand
currAttr = NULL;
// for each operand, incrementing i, op, and opdata
Int16 numOperands = clause->getNumOperands();
for (Int16 i = 0; i < numOperands;
i++, op++, opdata++, nulldata++, vardata++)
{
// -------------------------------------------------------------
// get pointer to operand from its ATP, ATPIndex, and offset
// value
// -------------------------------------------------------------
const UInt16 atpix = (*op)->getAtpIndex();
const UInt16 atpnum = (*op)->getAtp();
if((atpix < 2) && (NOT atps[0]->getTupp(atpix).isAllocated()))
{
if(!getFixupConstsAndTemps())
{
char *base;
if(atpix == 0) base = getConstantsArea();
else if(atpnum == 0) base = getTempsArea();
else base = getPersistentArea();
*opdata = base + (*op)->getOffset();
*nulldata = base + (*op)->getNullIndOffset();
*vardata = base + (*op)->getVCLenIndOffset();
}
else
{
*opdata = (char*)((long)((*op)->getOffset()));
*nulldata = (char*)((long)((*op)->getNullIndOffset()));
*vardata = (char*)((long)((*op)->getVCLenIndOffset()));
}
}
else
{
mode = (i == 0 ? exp_WRITE : exp_READ);
// all other ATPIndex values indicate to use tupp
// specified by ATPIndex from the ATP specifed in atp
register atp_struct *atp;
// which atp is to be used?
atp = atps[atpnum];
tuppDesc = atp->getCriDesc()->getTupleDescriptor(atpix);
register char * dataPtr =
(atp->getTupp(atpix)).getDataPointer();
switch( (*op)->getTupleFormat() )
{
case ExpTupleDesc::SQLMX_KEY_FORMAT:
case ExpTupleDesc::PACKED_FORMAT:
{
// if this is a special field (either a field following
// a varchar field, or a missing field), then compute
// its address or value.
// If offset is ExpOffsetMax, then this field follows a
// varchar field.
// If the offset for a non-varchar field is >= the
// datalen of this record, then this is a missing
// field.
// For a varchar field, if the offset is equal to the
// datalen, then this varchar field either is a null
// value or has a length of zero.
// A varchar field is missing if its offset is > datalen.
if (((*op)->isAddedCol()) &&
(((*op)->getOffset() == ExpOffsetMax) ||
((datalen > 0) &&
((((*op)->getVCIndicatorLength() > 0) &&
((*op)->getOffset() > (UInt32)datalen)) ||
(((*op)->getVCIndicatorLength() <= 0) &&
((*op)->getOffset() >= (UInt32)datalen))))))
{
NABoolean defValNeeded = FALSE;
if ((*op)->getOffset() == ExpOffsetMax)
{
// Offset is max value thus read the field number
// from the relative offset field.
// This signifies that this field follows one or
// more varchar fields.
// True for SQL/MP tables only.
// Needs special logic to compute the actual
// address of this field.
computeDataPtr(dataPtr,
(Int32)(*op)->getRelOffset(),
tuppDesc,
&(*opdata),
&(*nulldata),
&(*vardata));
if ((mode == exp_WRITE) && (rowLen))
{
currAttr = *op;
varOffset = (*opdata - dataPtr);
}
// if *opdata is == the end, but vardata is set
// then the variable field is length 0 so no
// default needed
if ((datalen > 0 ) &&
((*opdata > (dataPtr + datalen)) ||
((*opdata == (dataPtr + datalen)) &&
(*vardata == NULL))))
defValNeeded = TRUE;
}
else
defValNeeded = TRUE;
if ((defValNeeded) && (mode == exp_READ))
{
ComDiagsArea *diagsArea = atp1->getDiagsArea();
retcode =
getDefaultValueForAddedColumn((*op)->getDefaultFieldNum(),
tuppDesc,
*op,
&(*opdata),
&(*nulldata),
&(*vardata),
getHeap(),
&diagsArea);
if (retcode == ex_expr::EXPR_ERROR)
{
if (diagsArea != atp1->getDiagsArea())
atp1->setDiagsArea(diagsArea);
return retcode;
}
}
// ----------------------------------------------
// For SQL/MP tables, evalClauses returns the
// index of the last field in the fetched record.
// This is used by update processing logic to set the
// lastFldixOldrec fld in the ModifiedFieldMap struct,
// for use by DP2 on backout logic. lastFldIndex is set
// to the index of the last column for which a value
// exists in the fetched record.
//----------------------------------------------
if ((lastFldIndex != NULL) &&
(! setLastFldIndex) && // last index not set before
(mode == exp_WRITE) && // result operand
(tuppDesc->addedFieldPresent()))
{
// see if this column is present in the fetched
// row.
char * fetchedOpPtr;
computeDataPtr(fetchedDataPtr,
(Int32)(*op)->getDefaultFieldNum(),
tuppDesc,
&fetchedOpPtr, NULL, NULL);
if (fetchedOpPtr >= (fetchedDataPtr + datalen))
{
// (*op)->getDefaultFieldNum is the index of
// the first missing column.
*lastFldIndex = (Int16)((*op)->getDefaultFieldNum() - 1);
setLastFldIndex = TRUE;
}
}
}
else // not a 'special' attribute
{
if ((mode == exp_WRITE) &&
(rowLen) &&
(*op)->isSQLPackedFormat())
{
varOffset = (*op)->getOffset();
currAttr = *op;
}
if (dataPtr)
{
*opdata = dataPtr + (*op)->getOffset();
if ((*op)->getNullFlag()) // nullable
*nulldata = dataPtr + (*op)->getNullIndOffset();
if ((*op)->getVCIndicatorLength() > 0)
*vardata = dataPtr + (*op)->getVCLenIndOffset();
}
else
{
// missing value. Indicates a null value.
*nulldata = 0;
}
}
} // SQLMX_KEY_FORMAT, PACKED_FORMAT
break;
case ExpTupleDesc::SQLARK_EXPLODED_FORMAT:
{
if (dataPtr)
{
*opdata = dataPtr + (*op)->getOffset();
if ((*op)->getNullFlag()) // nullable
*nulldata = dataPtr + (*op)->getNullIndOffset();
if ((*op)->getVCIndicatorLength() > 0)
*vardata = dataPtr + (*op)->getVCLenIndOffset();
}
else
{
// missing value. Indicates a null value.
*nulldata = 0;
}
}
break;
case ExpTupleDesc::SQLMX_FORMAT:
case ExpTupleDesc::SQLMX_ALIGNED_FORMAT:
{
ExpTupleDesc::TupleDataFormat tdf = (*op)->getTupleFormat();
if (dataPtr)
{
UInt32 nullOff = 0;
NABoolean isAlignedFormat =
(*op)->isSQLMXAlignedFormat();
offset = (*op)->getOffset();
nullable = (*op)->getNullFlag();
nullIndLen = (*op)->getNullIndicatorLength();
varIndLen = (*op)->getVCIndicatorLength();
voaOffset = (*op)->getVoaOffset();
if (mode == exp_WRITE)
{
if (offset == ExpOffsetMax)
{
// all variable length fields after the
// first variable length field have their
// offsets initialized to ExpOffsetMax so
// the actual size of the variable field value
// is used to calculate the offset to be
// written into VOA[i] for this variable field
offset = varOffset;
ExpTupleDesc::setVoaValue(dataPtr,
voaOffset,
offset,
tdf);
if (nullable)
{
nullOff = (isAlignedFormat
? (*op)->getNullIndOffset()
: offset);
*nulldata = dataPtr + nullOff;
offset += nullIndLen;
}
*vardata = dataPtr + offset;
offset += varIndLen;
varOffset = offset;
currAttr = *op;
}
else // offsets computed at compile time
{
if (varIndLen > 0)
{
*vardata = dataPtr + (*op)->getVCLenIndOffset();
varOffset = offset;
currAttr = *op;
varOpFound = TRUE;
}
else if ((! varOpFound) &&
rowLen &&
isAlignedFormat &&
((offset >= varOffset) ||
(varOffset == ExpOffsetMax)))
{
// In aligned format, the fixed fields are
// rearranged and ordered by byte alignment
// and thus offsets are not guaranteed to
// be increasing.
// For variable fields this is not true.
varOffset = offset;
currAttr = *op;
}
// set the VOA entry offset to the start
// of this fields data
ExpTupleDesc::setVoaValue(
dataPtr,
voaOffset,
offset - varIndLen - nullIndLen,
tdf
);
if (nullable)
*nulldata = dataPtr+(*op)->getNullIndOffset();
}
*opdata = dataPtr + offset;
}
else // read mode
{
// set the compile time null indicator offset here
// and it will be reset if added columns present
// or processing a varchar
*nulldata = dataPtr + (*op)->getNullIndOffset();
// if there are added columns, then there exists
// a tuple descriptor
if (tuppDesc != NULL &&
tuppDesc->addedFieldPresent() )
{
ff = ExpTupleDesc::getFirstFixedOffset( dataPtr,
tdf );
if ( Attributes::isDefaultValueNeeded(
(*op),
tuppDesc,
ff,
varIndLen,
voaOffset,
dataPtr,
datalen ) )
{
ComDiagsArea *diagsArea = atp1->getDiagsArea();
// this sets the *nulldata, *opdata, *vardata as needed
retcode =
getDefaultValueForAddedColumn
((*op)->getDefaultFieldNum(),
tuppDesc,
*op,
&(*opdata),
&(*nulldata),
&(*vardata),
getHeap(),
&diagsArea);
if (retcode == ex_expr::EXPR_ERROR)
{
if (diagsArea != atp1->getDiagsArea())
atp1->setDiagsArea(diagsArea);
return retcode;
}
// all pointers are set now
break;
}
else
{ // not an added column needing special attn.
// but there may be other added columns present
// if variable field, then read the offset from
// the data record
if ( varIndLen > 0 )
{
offset = ExpTupleDesc::getVoaOffset(dataPtr,
voaOffset,
tdf);
}
else
{
// use the relative offset in case there are
// added columns in the data row and fields
// have shifted
// Relative is always true based on first
// fixed fields offset.
offset = ff + (*op)->getRelOffset();
}
// For nullable fields, set the nulldata ptr
// and bump the offset value past the null
// indicator bytes.
if (nullable)
{
*nulldata = dataPtr
+ (isAlignedFormat
? ExpAlignedFormat::getBitmapOffset(dataPtr)
: offset);
offset += nullIndLen;
}
} // need defaults or not
} // added col present or not
// No added col present.
// if variable field, read offset from data record
else if ( varIndLen > 0 )
{
offset = ExpTupleDesc::getVoaOffset(dataPtr,
voaOffset,
tdf);
if (nullable)
{
// null indicator does not change for aligned format
// but follows data for MX (packed) format
*nulldata = (dataPtr
+ (isAlignedFormat
? (*op)->getNullIndOffset()
: offset));
offset += nullIndLen;
}
}
// offset now correctly set even if added columns.
// null indicator offset correct set too.
// For variable length fields, set the vardata
// and bump the offset value past the variable
// length bytes.
if (varIndLen > 0)
{
*vardata = dataPtr + offset;
offset += varIndLen;
}
*opdata = dataPtr + offset;
} // else read mode
}
else // missing value (indicates a null value)
*nulldata = 0;
} // SQLMX_FORMAT, SQLMX_ALIGNED_FORMAT
break;
default:
{
ComDiagsArea *diagsArea = atp1->getDiagsArea();
ExRaiseSqlError(getHeap(), &diagsArea, EXE_INTERNAL_ERROR);
if(diagsArea != atp1->getDiagsArea())
atp1->setDiagsArea(diagsArea);
return ex_expr::EXPR_ERROR;
}
} // switch on atp tuple format
} // default atp index case
// -------------------------------------------------------------
// If the operand is nullable, set its data pointer to 0 if
// its NULL indicator is set or set the NULL indicator to 0
// and advance the data pointer to the actual data. Don't do
// this for the first (result) operand at this time.
// -------------------------------------------------------------
if (((*op)->getNullFlag()) && // nullable and
(*nulldata) && // value not missing
(i > 0)) // not result
{
if ( ExpTupleDesc::isNullValue( *nulldata,
(*op)->getNullBitIndex(),
(*op)->getTupleFormat() ) )
{
(*nulldata) = 0;
}
}
} // for
// -----------------------------------------------------------------
// Call the NULL processing method for this clause and, if still
// necessary, evaluate the expression. Note that if the
// processNulls() method can determine the result, it will return
// EXPR_NULL and the evaluation method is not called.
// -----------------------------------------------------------------
ComDiagsArea *diagsArea = atp1->getDiagsArea();
retcode = clause->useProcessNulls()
? clause->processNulls(op_data, getHeap(), &diagsArea)
: ex_expr::EXPR_OK;
if (retcode == ex_expr::EXPR_OK) // do the work
retcode = clause->eval(&op_data[2 * ex_clause::MAX_OPERANDS],
getHeap(),
&diagsArea);
if (retcode == ex_expr::EXPR_OK &&
clause->getOperType()== ITM_CONVERT &&
((ex_conv_clause*)clause)->getLastVOAoffset() >0 &&
((ex_conv_clause*)clause)->getComputedLength() >0 )
{
varOffset = ((ex_conv_clause*)clause)->getComputedLength();
currAttr = *(clause->getOperand());
}
else
// Check if we have an operand that we need to keep track of the length
// as we go. This is a varchar attribute for SQLMX_FORMAT and
// PACKED_FORMAT formats, and all attributes for SQLMX_ALIGNED_FORMAT
// since fixed fields are rearranged.
if ((currAttr && retcode == ex_expr::EXPR_OK) ||
(currAttr &&
(retcode == ex_expr::EXPR_NULL) &&
((currAttr->getTupleFormat() == ExpTupleDesc::PACKED_FORMAT) ||
(currAttr->getTupleFormat() == ExpTupleDesc::SQLMX_ALIGNED_FORMAT))))
{
varOffset += currAttr->getLength(op_data[ex_clause::MAX_OPERANDS]);
// Need the last attribute when we get done to adjust the row length
// for aligned format.
if (currAttr->isSQLMXAlignedFormat())
prevAttr = currAttr;
}
if (diagsArea != atp1->getDiagsArea())
atp1->setDiagsArea(diagsArea);
if (retcode == ex_expr::EXPR_ERROR)
return retcode;
// copy result data into result buffer, if generated in an aligned buffer
if (result_data)
{
str_cpy_all(result_data, (char*)temp_buffer[0],
clause->getOperand(0)->getLength());
}
// advance to the next clause
clause = clause->getNextClause();
} // while
if (rowLen && (varOffset != ExpOffsetMax))
{
currAttr = (currAttr ? currAttr : prevAttr);
if ( currAttr )
ex_clause::evalSetRowLength(currAttr,
atps[currAttr->getAtp()],
rowLen,
varOffset);
else
*rowLen = varOffset;
}
return retcode;
}
static ex_expr::exp_return_type alignAndEval(ex_clause * clause,
char ** op_data,
CollHeap * heap,
ComDiagsArea ** diagsArea)
{
ex_expr::exp_return_type retCode = ex_expr::EXPR_OK;
// -------------------------------------------------------------
// If data alignment is needed, copy the operand into
// the aligned temp_buffer array on the stack. If this is done
// for the result then remember the real result buffer.
// -------------------------------------------------------------
// an array of pointers to Attributes data structures, describing
// the data types of the operands of this expression (op[0] points
// to the result type)
register AttributesPtr* op = clause->getOperand();
// allocated space for temporary, aligned operands on the stack
// (assuming that we have no more than 4 operands and that no operand
// using the temp space is longer than 64 bytes).
// Using buffer of type Int64 so it starts on an 8-byte aligned offset.
Int64 temp_buffer[ex_clause::MAX_OPERANDS][ex_clause::MAX_TEMP_OPERAND_LEN/sizeof(Int64)];
// pointer to data for current operand
register char ** opdata = op_data;
retCode = clause->eval(op_data, heap, diagsArea);
return retCode;
}
// ex_expr::eval
//
// Interprets the expression. If there is no PCODE, evalClauses is used
// to interpret the expression. Otherwise, the PCODE is interpreted using
// a simple stack-based abstract machine.
//
// IN : atp1, atp2 - pointers to tuple arrays
// exHeap - memory allocation
// OUT :
// RETURN : The result of the expression
// EXPR_OK - no errors and no return value from expression
// EXPR_ERROR - expression error
// EXPR_TRUE - the expression returned true
// EXPR_FALSE - the expression returned false
// EXPR_UNKNOWN - the expression returned unknown
// EFFECTS: Executes expression which side effects a tuple or temporary or
// computes a return value. May also change diagnostics area
// of atps on error.
//
// NOTE : When introducing new pcode instructions that involve an
// an operation between signed shorter length operand and
// unsigned longer length operand, then one of the operands
// must be typecasted to Int64 to account for negetive values.
// See case PCIT::LT_MBIN32S_MBIN16S_MBIN32U below for example.
//
// This variable provides 4096 bytes of null indicators.
//
static const Int64 nullData[] = {
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1
};
//
// This table is used when comparing 2 operands. Given the type of comparison
// to perform (1st level index) and an index indicating whether operand1 is
// less than, equal to, or greater than, operand2 (2nd level index), return
// TRUE or FALSE.
//
// Comp codes used in compTable lookup (2nd level index)
//
// if src1 > src2 --> compCode = 2
// if src1 == src2 --> compCode = 1
// if src1 < src2 --> compCode = 0
//
static const Int32 compTable[6][3] = {
/* ITM_EQUAL */ {0, 1, 0},
/* ITM_NOT_EQUAL */ {1, 0, 1},
/* ITM_LESS */ {1, 0, 0},
/* ITM_LESS_EQ */ {1, 1, 0},
/* ITM_GREATER */ {0, 0, 1},
/* ITM_GREATER_EQ */ {0, 1, 1}
};
#define FLT64ASSIGN(tgtptr, srcptr) {*((Int64*)(tgtptr)) = *((Int64*)(srcptr));}
//////////////////////////////////////////////////////////////////////////////
//
// Inlining Routines for PCODE Optimizations
//
// The following evalFast routines were designed to evaluat unique expressions
// identified at compile-time as "inlineable" exprs. Inlined expressions
// do not call evalPCode(). Instead they call one of several evalFast methods.
// The evalPCode() method has a large setup and take-down cost because of its
// need to support all possible PCODE instructions. It additionally has an
// instruction-switching overhead cost. Each evalFast() method is designed to
// evaluate a particular PCODE instruction (or a couple of them).
//
// Below is a set of defines used in each evalFast() method. PCODE_DEF is
// needed to declare the pcode bytestream pointer for each OS target. The
// macro SETUP_EVAL_STK is used to set up the stack-based engine needed to
// evaluate the expression. The stack created assumes that there are no
// more than 2 tuples to be processed.
//
// Also below is the routine setEvalPtr(). This routine is called at fixup
// time to initialize the evalPtr_ function pointer to point to one of the
// many fast eval methods. It defines which PCODE instructions are inlineable.
//
// And lastly we have the set of evalFast methods. The methods are defined as
// "evalFastXXX", where "XXX" is the enum value of the major PCODE instruction
// being processed in this inlineable expression.
//
#define PCODE_DEF(p) PCodeBinary * pCode = p;
#ifdef _DEBUG
#define DBGASSERT(p) assert(p);
#else
#define DBGASSERT(p)
#endif
#define SETUP_EVAL_STK(p, atp1, atp2, e) \
Long stack[6]; \
atp_struct *atps[] = { atp1, atp2 }; \
\
PCODE_DEF(p); /* Define pCode ptr */ \
\
Int32 startOffset = ((Int32)pCode[0] << 1) + 2; /* past 1st opcode */ \
\
stack[1] = (Long)(e->getConstantsArea()); /* Set up constants array */ \
\
stack[4] = (Long)atps[pCode[1]]->getTupp((Lng32)pCode[2]).getDataPointer(); \
if (!stack[4]) { \
DBGASSERT(0); /* don't expect null tuples */ \
stack[4] = (Long)nullData; \
} \
if (startOffset != 4) { \
stack[5] = (Long)atps[pCode[3]]->getTupp((Lng32)pCode[4]).getDataPointer(); \
if (!stack[5]) { \
DBGASSERT(0); /* don't expect null tuples */ \
stack[5] = (Long)nullData; \
} \
} \
\
pCode += (startOffset);
// Define a pointer name directly into the pcode
#define PTR_TO_PCODE(the_type,name,pcode_offset) \
the_type* name = (the_type*)&pCode[pcode_offset] ;
// Define a new pointer name to type ptype, and initialize its value from
// the stack (index from pCode) plus an offset (from the next pCode entry)
#define PTR_DEF_ASSIGN(ptype, name, pcode_offset) \
ptype* name = (ptype*)(stack[pCode[pcode_offset]] + pCode[pcode_offset+1]);
// only the base address, from the stack
#define BASE_PTR_DEF_ASSIGN(the_type, name,pcode_offset) \
the_type* name = (the_type*)stack[pCode[pcode_offset]] ;
// Define a new variable name of the type, and assign it a value from pCode
#define DEF_ASSIGN(the_type, name, pcode_offset) \
the_type name = (the_type) pCode[pcode_offset] ;
// Same as DEF_ASSIGN but handle pointer in pcode binary
#define DEF_ASSIGN_PTR(the_type, name, pcode_offset) \
the_type name = *(the_type *)&(pCode[pcode_offset]) ;
#define MOVE_INSTR(target_type, src_type) \
*((target_type*)(stack[pCode[0]]+pCode[1])) = \
*((src_type*)(stack[pCode[2]]+pCode[3])); \
pCode += 4; \
break;
#define MOVE_CAST_INSTR(target_type, cast_type, src_type) \
*((target_type*)(stack[pCode[0]]+pCode[1])) = \
(cast_type) (*((src_type*)(stack[pCode[2]]+pCode[3]))); \
pCode += 4; \
break;
// The length of PCodeBinary sequence of RANGE_LOW or RANGE_HIGH instruction
#define RANGE_INST_LEN 4
//
// Native Expr Routines at Runtime
//
int dbl_le_cmp (double x, double y) { return x <= y; }
int dbl_ge_cmp (double x, double y) { return x >= y; }
int dbl_lt_cmp (double x, double y) { return x < y; }
int dbl_gt_cmp (double x, double y) { return x > y; }
int dbl_eq_cmp (double x, double y) { return x == y; }
int dbl_ne_cmp (double x, double y) { return x != y; }
ex_expr::exp_return_type reportErr(atp_struct* atp1, ex_expr* expr)
{
ComDiagsArea *diagsArea;
diagsArea = atp1->getDiagsArea();
ExRaiseSqlError(expr->getHeap(), &diagsArea, EXE_INTERNAL_ERROR);
if(diagsArea != atp1->getDiagsArea())
atp1->setDiagsArea(diagsArea);
return ex_expr::EXPR_ERROR;
}
Int32 bignumSub(UInt16* tgt, UInt16* src1, UInt16* src2, Int32 length)
{
NABoolean performAdd = TRUE;
UInt16 carry = 0;
Int32 i;
Int32 length16 = length >> 1;
// Get source sign bits
char src1Sign = BIGN_GET_SIGN(src1, length);
char src2Sign = BIGN_GET_SIGN(src2, length);
char* origSrc1 = (char*)src1;
char* origSrc2 = (char*)src2;
char origSrc1Sign = src1Sign;
char origSrc2Sign = src2Sign;
// Temporarily clear sign bits
BIGN_CLR_SIGN(src1, length);
BIGN_CLR_SIGN(src2, length);
if (TRUE) {
if (src1Sign == src2Sign) {
performAdd = FALSE;
// We want to distribute the SUB operation into the signs of the
// source operand so that everything is normalized as if we were
// just doing an ADD and the source operands carried the sign.
src2Sign = (src2Sign == 0) ? MSB_SET_MSK : 0;
}
}
else {
if (src1Sign != src2Sign)
performAdd = FALSE;
}
if (performAdd)
{
// Add shorts - this is because bignum stored this way.
for (i=0; i < length16; i++) {
UInt32 result = (UInt32)src1[i] + src2[i] + carry;
tgt[i] = (UInt16)(result & 0xffff);
carry = (UInt16)(result >> 16);
}
}
else
{
// Determine which source is bigger
for (i = length16-1; i >= 0; i--) {
// Skip equality
if (src1[i] == src2[i])
continue;
if (src1[i] < src2[i]) {
UInt16* temp = src1; src1 = src2; src2 = temp;
char tempSign = src1Sign; src1Sign = src2Sign; src2Sign = tempSign;
}
break;
}
// Sub shorts - this is because bignum stored this way.
for (i=0; i < length16; i++) {
Int32 result = (Int32)src1[i] - src2[i] + (Int16)carry;
tgt[i] = (UInt16) (result + (Int32)0x10000) & 0xffff;
carry = (result < 0) ? -1 : 0;
}
}
if (origSrc1Sign)
BIGN_SET_SIGN(origSrc1, length);
if (origSrc2Sign)
BIGN_SET_SIGN(origSrc2, length);
// Set target sign - will always be src1Sign, regardless of ADD/SUB
if (src1Sign) {
BIGN_SET_SIGN(tgt, length);
} else {
BIGN_CLR_SIGN(tgt, length);
}
// Report overflow
return (carry != 0);
}
//
// Method used to initialize the evalPtr_ function pointer. If the expression
// isn't marked for inlining, then evalPtr_ should be set to NULL. Also, fast
// moves (strcpy) are evaluated directly by evalFast4().
//
void ex_expr_base::setEvalPtr( NABoolean isSamePrimary ) {
static void* nativeGlobTable[] = {
(void*)(&nullData), // JIT_GLOB_NULL_TABLE = 0
(void*)(&randomHashValues), // JIT_GLOB_RANDOM_HASH_VALS_TABLE = 4
(void*)(&charStringCompareWithPad), // JIT_GLOB_COMPARE_WITH_PAD_FUNC = 8
(void*)(&str_cmp), // JIT_GLOB_STRCMP_FUNC = 12
(void*)(&str_cpy), // JIT_GLOB_STRCPY_FUNC = 16
(void*)(&dbl_le_cmp), // JIT_GLOB_DBL_LE_CMP_FUNC = 20
(void*)(&dbl_ge_cmp), // JIT_GLOB_DBL_GE_CMP_FUNC = 24
(void*)(&dbl_lt_cmp), // JIT_GLOB_DBL_LT_CMP_FUNC = 28
(void*)(&dbl_gt_cmp), // JIT_GLOB_DBL_GT_CMP_FUNC = 32
(void*)(&dbl_eq_cmp), // JIT_GLOB_DBL_EQ_CMP_FUNC = 36
(void*)(&dbl_ne_cmp), // JIT_GLOB_DBL_NE_CMP_FUNC = 40
(void*)(&reportErr), // JIT_GLOB_REPORT_ERROR = 44
(void*)(&bignumSub) // JIT_GLOB_BIG_SUB_FUNC = 48
};
PCodeBinary *pCode = getPCodeBinary();
if (getPCodeNative()) {
// evalPtr_ may have been previously set (send-top tcbs, for example,
// share the same expr), then we can't initialize it again, since the
// offset into the constants area where the native code resides is lost.
// To tell if evalPtr_ hasn't been initialized yet, we check to see if it
// still has a valid offset value within the constant's area.
NABoolean doMProtect = FALSE ;
if ((evalPtrOff_ >= 0) && (evalPtrOff_ <= getConstsLength())) {
evalPtr_ = (evalPtrType)((Long)getConstantsArea() + (Long)evalPtr_);
doMProtect = TRUE ;
}
else if ( ! isSamePrimary )
doMProtect = TRUE ;
if ( doMProtect ) {
// Now give execute privilege to the page containing evalPtr_. This will
// have the side effect of giving other bytes in this page (not related
// to native expr) execute privilege, so there may be a security risk
// here. Also note, this only needs to be done on Linux.
//
// NOTE: We could do a better job tightening the upper boundary for
// which memory pages are executable, but it would require knowing the
// length of the native expression and we don't currently keep that
// info.
//
void* pageStart = (void*)((Long)evalPtr_ & ~(getpagesize() - 1));
Int32 lenToAllow = (getConstantsArea() + getConstsLength()) - (char *)pageStart;
Int32 err = mprotect(pageStart, lenToAllow,
PROT_READ | PROT_WRITE | PROT_EXEC);
// If error occurred, do not go through with opt
if (err != 0) {
assert(FALSE);
evalPtr_ = NULL;
return;
}
}
// Redefine pCode to point to the static function lookup table that can be
// used at runtime.
setPCodeBinary((PCodeBinary*)nativeGlobTable);
return;
}
if (!getPCodeMoveFastpath() || (pCode == NULL)) {
evalPtr_ = NULL;
return;
}
Int32 length = *(Int32*)(pCode++);
pCode += (2 * length);
switch(pCode[0]) {
// Comparisons
case PCIT::EQ_MBIN32S_MBIN16S_MBIN16S:
evalPtr_ = &ex_expr::evalFast33;
break;
case PCIT::EQ_MBIN32S_MBIN32S_MBIN32S:
evalPtr_ = &ex_expr::evalFast36;
break;
case PCIT::EQ_MBIN32S_MBIN16U_MBIN16U:
evalPtr_ = &ex_expr::evalFast37;
break;
case PCIT::EQ_MBIN32S_MBIN32U_MBIN32U:
evalPtr_ = &ex_expr::evalFast40;
break;
case PCIT::EQ_MBIN32S_MASCII_MASCII:
evalPtr_ = &ex_expr::evalFast117;
break;
case PCIT::LT_MBIN32S_MASCII_MASCII:
evalPtr_ = &ex_expr::evalFast130;
break;
case PCIT::LE_MBIN32S_MASCII_MASCII:
evalPtr_ = &ex_expr::evalFast131;
break;
case PCIT::GT_MBIN32S_MASCII_MASCII:
evalPtr_ = &ex_expr::evalFast132;
break;
case PCIT::GE_MBIN32S_MASCII_MASCII:
evalPtr_ = &ex_expr::evalFast133;
break;
case PCIT::EQ_MBIN32S_MBIN64S_MBIN64S:
evalPtr_ = &ex_expr::evalFast162;
break;
case PCIT::NULL_TEST_MBIN32S_MATTR5_IBIN32S_IBIN32S:
evalPtr_ = &ex_expr::evalFast262;
break;
case PCIT::COMP_MBIN32S_MASCII_MASCII_IBIN32S_IBIN32S_IBIN32S:
evalPtr_ = &ex_expr::evalFast275;
break;
// Hash
case PCIT::HASH_MBIN32U_MPTR32_IBIN32S_IBIN32S:
evalPtr_ = &ex_expr::evalFast94;
break;
case PCIT::HASH_MBIN32U_MBIN32_IBIN32S_IBIN32S:
evalPtr_ = &ex_expr::evalFast170;
break;
case PCIT::HASH_MBIN32U_MBIN16_IBIN32S_IBIN32S:
evalPtr_ = &ex_expr::evalFast171;
break;
case PCIT::HASH_MBIN32U_MBIN64_IBIN32S_IBIN32S:
evalPtr_ = &ex_expr::evalFast173;
break;
case PCIT::HASH2_DISTRIB:
evalPtr_ = &ex_expr::evalFast223;
break;
// Moves
case PCIT::MOVE_MBIN32U_MBIN32U:
evalPtr_ = &ex_expr::evalFast202;
break;
case PCIT::MOVE_MBIN64S_MBIN64S:
evalPtr_ = &ex_expr::evalFast203;
break;
default:
evalPtr_ = NULL;
}
}
// Moves
ex_expr::exp_return_type
ex_expr_base::evalFast4(PCodeBinary* p, atp_struct *atp1, atp_struct *atp2,ex_expr* e)
{
SETUP_EVAL_STK(p, atp1, atp2, e);
#pragma refaligned 8 pCode
PTR_DEF_ASSIGN(char,x,0);
PTR_DEF_ASSIGN(char,y,2);
str_cpy_all(x, y, pCode[4]);
return ex_expr::EXPR_OK;
}
ex_expr::exp_return_type
ex_expr_base::evalFast202(PCodeBinary* p,atp_struct *atp1,atp_struct *atp2,ex_expr* e)
{
SETUP_EVAL_STK(p, atp1, atp2, e);
#pragma refaligned 8 pCode
PTR_DEF_ASSIGN(Int32,x,0);
PTR_DEF_ASSIGN(Int32,y,2);
*x = *y;
return ex_expr::EXPR_OK;
}
ex_expr::exp_return_type
ex_expr_base::evalFast203(PCodeBinary* p,atp_struct *atp1,atp_struct *atp2,ex_expr* e)
{
SETUP_EVAL_STK(p, atp1, atp2, e);
#pragma refaligned 8 pCode
PTR_DEF_ASSIGN(Int64,x,0);
PTR_DEF_ASSIGN(Int64,y,2);
*x = *y;
return ex_expr::EXPR_OK;
}
// Hash
ex_expr::exp_return_type
ex_expr_base::evalFast94(PCodeBinary* p, atp_struct *atp1,atp_struct *atp2,ex_expr* e)
{
SETUP_EVAL_STK(p, atp1, atp2, e);
#pragma refaligned 8 pCode
PTR_DEF_ASSIGN(UInt32,x,0);
PTR_DEF_ASSIGN(char,y,2);
*x = ExHDPHash::hash(y, pCode[4], pCode[5]);
return ex_expr::EXPR_OK;
}
ex_expr::exp_return_type
ex_expr_base::evalFast170(PCodeBinary* p,atp_struct *atp1,atp_struct *atp2,ex_expr* e)
{
SETUP_EVAL_STK(p, atp1, atp2, e);
#pragma refaligned 8 pCode
PTR_DEF_ASSIGN(UInt32,x,0);
PTR_DEF_ASSIGN(char,y,2);
*x = ExHDPHash::hash4(y, pCode[4]);
return ex_expr::EXPR_OK;
}
ex_expr::exp_return_type
ex_expr_base::evalFast171(PCodeBinary* p,atp_struct *atp1,atp_struct *atp2,ex_expr* e)
{
SETUP_EVAL_STK(p, atp1, atp2, e);
#pragma refaligned 8 pCode
PTR_DEF_ASSIGN(UInt32,x,0);
PTR_DEF_ASSIGN(char,y,2);
*x = ExHDPHash::hash2(y, pCode[4]);
return ex_expr::EXPR_OK;
}
ex_expr::exp_return_type
ex_expr_base::evalFast173(PCodeBinary* p,atp_struct *atp1,atp_struct *atp2,ex_expr* e)
{
SETUP_EVAL_STK(p, atp1, atp2, e);
#pragma refaligned 8 pCode
PTR_DEF_ASSIGN(UInt32,x,0);
PTR_DEF_ASSIGN(char,y,2);
*x = ExHDPHash::hash8(y, pCode[4]);
return ex_expr::EXPR_OK;
}
ex_expr::exp_return_type
ex_expr_base::evalFast223(PCodeBinary* p,atp_struct *atp1,atp_struct *atp2,ex_expr* e)
{
SETUP_EVAL_STK(p, atp1, atp2, e);
#pragma refaligned 8 pCode
PTR_DEF_ASSIGN(UInt32,x,0);
PTR_DEF_ASSIGN(UInt32,y,2);
PTR_DEF_ASSIGN(UInt32,z,4);
*x = (UInt32)(((Int64)(*y) * (Int64)(*z)) >> 32);
return ex_expr::EXPR_OK;
}
// Comparisons
ex_expr::exp_return_type
ex_expr_base::evalFast33(PCodeBinary* p, atp_struct *atp1,atp_struct *atp2,ex_expr* e)
{
SETUP_EVAL_STK(p, atp1, atp2, e);
#pragma refaligned 8 pCode
PTR_DEF_ASSIGN(Int16,x,2);
PTR_DEF_ASSIGN(Int16,y,4);
return (*x == *y) ? ex_expr::EXPR_TRUE : ex_expr::EXPR_FALSE;
}
ex_expr::exp_return_type
ex_expr_base::evalFast36(PCodeBinary* p, atp_struct *atp1,atp_struct *atp2,ex_expr* e)
{
SETUP_EVAL_STK(p, atp1, atp2, e);
#pragma refaligned 8 pCode
PTR_DEF_ASSIGN(Int32,x,2);
PTR_DEF_ASSIGN(Int32,y,4);
return (*x == *y) ? ex_expr::EXPR_TRUE : ex_expr::EXPR_FALSE;
}
ex_expr::exp_return_type
ex_expr_base::evalFast37(PCodeBinary* p, atp_struct *atp1,atp_struct *atp2,ex_expr* e)
{
SETUP_EVAL_STK(p, atp1, atp2, e);
#pragma refaligned 8 pCode
PTR_DEF_ASSIGN(UInt16, x,2);
PTR_DEF_ASSIGN(UInt16, y,4);
return (*x == *y) ? ex_expr::EXPR_TRUE : ex_expr::EXPR_FALSE;
}
ex_expr::exp_return_type
ex_expr_base::evalFast40(PCodeBinary* p, atp_struct *atp1,atp_struct *atp2,ex_expr* e)
{
SETUP_EVAL_STK(p, atp1, atp2, e);
#pragma refaligned 8 pCode
PTR_DEF_ASSIGN(UInt32,x,2);
PTR_DEF_ASSIGN(UInt32,y,4);
return (*x == *y) ? ex_expr::EXPR_TRUE : ex_expr::EXPR_FALSE;
}
ex_expr::exp_return_type
ex_expr_base::evalFast117(PCodeBinary* p,atp_struct *atp1,atp_struct *atp2,ex_expr* e)
{
SETUP_EVAL_STK(p, atp1, atp2, e);
#pragma refaligned 8 pCode
PTR_DEF_ASSIGN(unsigned char, x,2);
PTR_DEF_ASSIGN(unsigned char,y,4);
if (x[0] != y[0])
return ex_expr::EXPR_FALSE;
return (memcmp(x, y, pCode[6])==0) ? ex_expr::EXPR_TRUE : ex_expr::EXPR_FALSE;
}
ex_expr::exp_return_type
ex_expr_base::evalFast130(PCodeBinary* p,atp_struct *atp1,atp_struct *atp2,ex_expr* e)
{
SETUP_EVAL_STK(p, atp1, atp2, e);
#pragma refaligned 8 pCode
PTR_DEF_ASSIGN(unsigned char,x,2);
PTR_DEF_ASSIGN(unsigned char,y,4);
if (x[0] > y[0])
return ex_expr::EXPR_FALSE;
return (memcmp(x, y, pCode[6])<0) ? ex_expr::EXPR_TRUE : ex_expr::EXPR_FALSE;
}
ex_expr::exp_return_type
ex_expr_base::evalFast131(PCodeBinary* p,atp_struct *atp1,atp_struct *atp2,ex_expr* e)
{
SETUP_EVAL_STK(p, atp1, atp2, e);
#pragma refaligned 8 pCode
PTR_DEF_ASSIGN(unsigned char,x,2);
PTR_DEF_ASSIGN(unsigned char,y,4);
if (x[0] > y[0])
return ex_expr::EXPR_FALSE;
return (memcmp(x, y, pCode[6])<=0) ? ex_expr::EXPR_TRUE : ex_expr::EXPR_FALSE;
}
ex_expr::exp_return_type
ex_expr_base::evalFast132(PCodeBinary* p,atp_struct *atp1,atp_struct *atp2,ex_expr* e)
{
SETUP_EVAL_STK(p, atp1, atp2, e);
#pragma refaligned 8 pCode
PTR_DEF_ASSIGN(unsigned char,x,2);
PTR_DEF_ASSIGN(unsigned char,y,4);
if (x[0] < y[0])
return ex_expr::EXPR_FALSE;
return (memcmp(x, y, pCode[6])>0) ? ex_expr::EXPR_TRUE : ex_expr::EXPR_FALSE;
}
ex_expr::exp_return_type
ex_expr_base::evalFast133(PCodeBinary* p,atp_struct *atp1,atp_struct *atp2,ex_expr* e)
{
SETUP_EVAL_STK(p, atp1, atp2, e);
#pragma refaligned 8 pCode
PTR_DEF_ASSIGN(unsigned char,x,2);
PTR_DEF_ASSIGN(unsigned char,y,4);
if (x[0] < y[0])
return ex_expr::EXPR_FALSE;
return (memcmp(x, y, pCode[6])>=0) ? ex_expr::EXPR_TRUE : ex_expr::EXPR_FALSE;
}
ex_expr::exp_return_type
ex_expr_base::evalFast162(PCodeBinary* p,atp_struct *atp1,atp_struct *atp2,ex_expr* e)
{
SETUP_EVAL_STK(p, atp1, atp2, e);
#pragma refaligned 8 pCode
PTR_DEF_ASSIGN(Int64,x,2);
PTR_DEF_ASSIGN(Int64,y,4);
return (*x == *y) ? ex_expr::EXPR_TRUE : ex_expr::EXPR_FALSE;
}
ex_expr::exp_return_type
ex_expr_base::evalFast262(PCodeBinary* p,atp_struct *atp1,atp_struct *atp2,ex_expr* e)
{
SETUP_EVAL_STK(p, atp1, atp2, e);
#pragma refaligned 8 pCode
UInt32 pCode3 = (pCode[7] == 1) ? *((Int32*)(stack[pCode[2]] + pCode[4]))
: pCode[3];
NABoolean isNullCheck = (pCode[8] != 0);
NABoolean srcNull = ExpTupleDesc::isNullValue(
(char*)(stack[pCode[2]]+pCode3),
(Int16)pCode[6],
(ExpTupleDesc::TupleDataFormat)pCode[5]);
if (srcNull && isNullCheck)
return ex_expr::EXPR_TRUE;
if (!srcNull && !isNullCheck)
return ex_expr::EXPR_TRUE;
return ex_expr::EXPR_FALSE;
}
ex_expr::exp_return_type
ex_expr_base::evalFast275(PCodeBinary* p,atp_struct *atp1,atp_struct *atp2,ex_expr* e)
{
SETUP_EVAL_STK(p, atp1, atp2, e);
#pragma refaligned 8 pCode
Int32 compCode;
const Int32* table;
#pragma refaligned 8 table
// Set table pointer to appropriate position based on operation
table = &(compTable[pCode[8] - ITM_EQUAL][1]);
// "x" is the smaller string, "y" is the bigger one
PTR_DEF_ASSIGN(unsigned char,x,2);
PTR_DEF_ASSIGN(unsigned char,y,4);
// Quick first byte compare
if (x[0] == y[0]) {
DEF_ASSIGN(Int32,len1,6);
DEF_ASSIGN(Int32,len2,7);
//Int32 len1 = pCode[6];
//Int32 len2 = pCode[7];
compCode = memcmp(x, y, len1);
// Fix compCode to -1, 0, or 1
if (compCode != 0) {
compCode = (compCode < 0) ? -1 : 1;
}
// If strings are equal so far and lengths are different, compare more
else if (len1 != len2) {
for (Int32 i=len1; i < len2; i++) {
if (y[i] == ' ')
continue;
compCode = (' ' < y[i]) ? -1 : 1;
break;
}
}
}
else
compCode = (x[0] < y[0]) ? -1 : 1;
return (table[compCode] ? ex_expr::EXPR_TRUE : ex_expr::EXPR_FALSE);
}
/////////////////////////////////////////////////////////////////////////////
ex_expr::exp_return_type ex_expr::evalPCodeAligned(PCodeBinary* pCode32,
atp_struct *atp1,
atp_struct *atp2,
ULng32 *rowLen)
{
return ex_expr::EXPR_ERROR;
}
// Guidelines for pcodes involving varchar source and/or varchar targets
//
// PCodes involving varchars have to support these row formats:
// Packed format, exploded format and aligned format.
//
// A Varchar operand should be defined as MATTR5 with the pcode values
// in the following order: (atp, atpindex, offset, voaOffset, length, comboLen)
// where comboLen is a 4 byte integer whose first byte represents length of
// nullIndicator and second byte represents length of VCIndicator, in bytes.
//
// Note that there is no nullbitmap index in the above notation because pcodes
// related to null checking will use a shorter version than MATTR5 and
// will have nullbitmap index as a pcode value.
//
// If there is a need to check whether the operand is a varchar or not,
// check the value of VCIndLen.
//
// If there is a need to check whether the target is disk format or not,
// check the value of VoaOffset.
//
// Steps in which varchar pcodes should be evaluated for source operands:
// ---------------------------------------------------------------------
//
// 1. Define a ptr to the start of the source row
// char *src = (char *)stack[pCode[2]];
//
// 2. Get the nullIndicator and VCIndicator lengths from the combo pcode
// Int32 comboLen = pCode[6];
// char* comboPtr = (char*)&comboLen;
// Int16 srcNullIndLen = (Int16)comboPtr[0];
// Int16 srcVCIndLen = (Int16)comboPtr[1];
//
//2a. Optionally, check if it is a varchar
// if (srcVCIndLen > 0)
//
// 3. Call inline function getVarOffset() to get the offset to the the beginning
// of the varchar, i.e, to the offset of VCIndLen. Increment source to that offset.
// src += ExpTupleDesc::getVarOffset(src,
// pCode[3], // offset
// pCode[4], // voaOff
// srcVCIndLen, // vcIndLen
// srcNullIndLen // nullIndLen
// );
// If the supplied offset is valid (exploded format or first varchar), this
// function would simply subtract the vcIndLen and return the new offset.
// If it is an indirect varchar, the offset will not be valid, the actual offset
// will be obtained from the voaOffset and optionally nullIndLen will be added.
//
// 4. Get the actual length of the varchar by calling inline function getVarLength()
// and increment the source to that offset.
// srcLen = ExpTupleDesc::getVarLength(src, srcVCIndLen);
// srcStr += srcVCIndLen;
//
// 5. If the operand was not a varchar, use the offset and length given at compile time.
// srcStr += pCode[3];
// srcLen = pCode[5];
//
// src points to the start of the actual varchar data,
// srcLen has the actual length of the varchar.
//
// Steps in which varchar pcodes should be evaluated for target operands.
// ---------------------------------------------------------------------
//
// 1. If target operand is a varchar, call getTgtVarOffset() to compute
// the target offset. For non-disk format, it would just return
// offset - vcIndLen. For disk format, it will compute the offset
// based on loop variable. This function would also update the VOA entry.
// tgt += ExpTupleDesc::getTgtVarOffset( tgt,
// tgtOffset,
// tgtVoaOffset,
// tgtVCIndLen,
// tgtNullIndLen,
// varOffset,
// len0
// );
//
// 2. Update the varchar length at the varchar offset and increment the tgt pointer.
// if (tgtVCIndLen > 0)
// {
// ExpTupleDesc::setVarLength(tgt, len0, tgtVCIndLen);
// tgt += tgtVCIndLen;
// }
//
// 3. Do the desired operation.
// if (len0 > 0)
// str_cpy_all(tgt, &src[start], len0);
ex_expr::exp_return_type ex_expr::evalPCode(PCodeBinary* pCode32,
atp_struct *atp1,
atp_struct *atp2,
Lng32 datalen,
ULng32 *rowLen)
{
ComDiagsArea *diagsArea;
PCodeBinary * pCode = pCode32;
// Declarations for clause variables used in some cases of the
// switch statement below. Declared here to make the compiler happy.
//
ex_clause *clause;
ex_branch_clause *branchClause;
// The return code is OK unless something happens to change it.
//
ex_expr::exp_return_type retCode = ex_expr::EXPR_OK;
// Should runtime optimizations be performed
//
NABoolean enableRuntimeOpts = FALSE;
// The stack used by the evaluator and a stack pointer
//
char *opData[3 * ex_clause::MAX_OPERANDS];
char **opDataData = &opData[2 * ex_clause::MAX_OPERANDS];
// stack contains addresses
Long stack[258];
// The first N entries in the stack are reserved for pointers to
// the base addresses for the tuple data that is accessed by the
// PCODE instructions. During PCODE generation the accessed ATPs
// and indexes are recorded and preprended along with a count
// to the PCODE instruction sequence.
//
atp_struct *atps[] = { atp1, atp2 };
// Use Long for stack
stack[1] = (Long)(castToExExpr()->getMyConstantsArea());
stack[2] = (Long)(castToExExpr()->getTempsArea());
stack[3] = (Long)(castToExExpr()->getMyPersistentArea());
Long lengthPlus4 = *(pCode) + 4;
// Move past length. Note, this was done before in conjunction with the
// previous assignment, but because of a bug in the compiler which prevents
// the refaligned pragma to be recognized in such cases, I separated the two
// statements -
pCode++;
for(Long i=4; i<lengthPlus4; i++) {
stack[i] = (Long)atps[pCode[0]]->getTupp((Lng32)pCode[1]).getDataPointer();
// A null (C++ NULL) tuple data pointer indicates that the tuple
// value is null (SQL NULL). This special case is handled here
// rather than requiring every PCODE load/move instruction to
// understand this case.
//
// Basically, the null tuple address is changed to point to 4096 bytes
// of null data (from a variable above). Thus, the PCODE instructions
// will unsuspectingly load/move this null data instead of the
// non-existent null data from the tuple.
//
// Caveats -- null pointer errors may be masked and moves are limited
// to 4096 bytes (size of null data array).
//
if(!stack[i]) {
// Should remove this whole check when we are confident that we
// will no longer see any null tuples
DBGASSERT(0); /* don't expect null tuples */
stack[i] = (Long)nullData;
}
pCode += 2;
}
Int16 ov; // overflow indicator
double flt64_1;
double flt64_2;
// current max variable field offset
// incremented everytime a variable field in disk format is evaluated
Int32 varOffset = 0;
// Keep track of write of varchars to aligned rows. VOA values should always be increasing.
Int32 lastVoaOffset = 0;
PCodeBinary * pCodeOpcPtr;
while(1) {
PCodeBinary pCodeOpc;
pCodeOpcPtr = pCode;
pCodeOpc = *pCodeOpcPtr;
pCode++;
/**
*** The large switch statement below results in a mis-predicted indirect
*** branch every time we iterate through the loop. This cost is severe.
*** Since we know that one of the instructions has to be an END, we can
*** directly check for that at the beginning of each iteration. The
*** conditional branch will always be dynamically predicted as not taken.
*** When we do end up taking the branch, the target address will have
*** already been calculated, and all that would happen would be 3 inserted
*** pipeline bubbles. Compare that to the 13+ cycles we lose each time
*** from the mis-predicted branch.
**/
if (pCodeOpc == PCIT::RETURN) {
if (enableRuntimeOpts) {
PCodeCfg* cfg = new(heap_) PCodeCfg(this, NULL, NULL, heap_, NULL);
cfg->runtimeOptimize();
NADELETE(cfg, PCodeCfg, heap_);
}
return retCode;
}
switch(pCodeOpc) {
case PCIT::OPDATA_MBIN16U_IBIN32S:
case PCIT::OPDATA_MPTR32_IBIN32S:
case PCIT::OPDATA_MPTR32_IBIN32S_IBIN32S:
case PCIT::OPDATA_MATTR5_IBIN32S:
{
// Loop through all opdata instructions and then fall-through to
// eval instruction. Note, the assumption is that opdata/eval instruction
// sequences are contiguous - no intermediate instruction can exist
// within this sequence.
do {
PTR_DEF_ASSIGN(char,src,0);
if (pCodeOpc == PCIT::OPDATA_MPTR32_IBIN32S_IBIN32S)
{
// If the operand is NULL, leave 0 on the stack, otherwise a non-zero.
NABoolean valueNull = ExpAlignedFormat::isNullValue((char *)src,
(Int16)pCode[2]);
opData[pCode[3]] = (char *)((long)(valueNull ? 0 : 1));
pCodeOpc = pCode[4];
pCode += 5;
}
else if (pCodeOpc == PCIT::OPDATA_MATTR5_IBIN32S)
{
// Set up the data pointer and vclen pointer (this one instruction
// does both) for an indirect varchar field in aligned row format.
//
BASE_PTR_DEF_ASSIGN(char, dataPtr, 0);
DEF_ASSIGN(Int32,comboLen,4);
char* comboPtr = (char*)&comboLen;
Int16 nullIndLen = (Int16)comboPtr[0];
Int16 vcIndLen = (Int16)comboPtr[1];
DEF_ASSIGN(Int32,vcLoc,5);
Int32 dataLoc = vcLoc + ex_clause::MAX_OPERANDS;
// If this is the first operand it is a write.
// So set the VOA entry for this varchar.
if(vcLoc == ex_clause::MAX_OPERANDS) {
DEF_ASSIGN(Int32,tgtVoaOffset,2);
// VOA offsets should always be used in order.
if(tgtVoaOffset > 0) {
assert(tgtVoaOffset > lastVoaOffset);
lastVoaOffset = tgtVoaOffset;
}
ExpTupleDesc::setVoaValue(dataPtr, tgtVoaOffset, varOffset, vcIndLen);
dataPtr = dataPtr + varOffset;
} else {
// Otherwise, get the offset from the VOA entry.
DEF_ASSIGN(UInt32, offset, 1 );
DEF_ASSIGN(UInt32, voaOffset, 2 );
dataPtr += ExpTupleDesc::getVarOffset(dataPtr,
offset,
voaOffset,
vcIndLen, // vcIndLen
nullIndLen // nullIndLen
);
}
// Update the VCLen pointer and the data pointer of
// the opData array.
opData[vcLoc] = dataPtr;
opData[dataLoc] = dataPtr + vcIndLen;
pCodeOpc = pCode[6];
pCode += 7;
}
else
{
if (pCodeOpc == PCIT::OPDATA_MBIN16U_IBIN32S)
src = (char*)(*((UInt16*)src) == 0);
opData[pCode[2]] = src;
pCodeOpc = pCode[3];
pCode += 4;
}
} while (pCodeOpc != PCIT::CLAUSE_EVAL);
//
// Do NOT break here...
// OPDATA and CLAUSE_EVAL go together
}
case PCIT::CLAUSE_EVAL:
// on 64-bit platform, pCode[0] and pCode[1] store the clause ptr
// and pCode[2] is check null indicator, while on 32-bit platform
// pCode[0] alone stores the clause ptr. Use PCODEBINARIES_PER_PTR to
// handle these differences.
clause = (ex_clause*)*(Long*)&(pCode[0]);
diagsArea = atp1->getDiagsArea();
if(!(pCode[PCODEBINARIES_PER_PTR] && clause->processNulls(opData)))
retCode = alignAndEval(clause, opDataData, getHeap(), &diagsArea);
if (diagsArea != atp1->getDiagsArea())
atp1->setDiagsArea(diagsArea);
if(retCode == ex_expr::EXPR_ERROR)
return retCode;
pCode += 1 + PCODEBINARIES_PER_PTR;
break;
case PCIT::HASHCOMB_BULK_MBIN32U:
{
UInt32 i, combRes = 0;
UInt32 hashVals[PCodeCfg::MAX_HASHCOMB_BULK_OPERANDS];
UInt32 numOfOps = ((UInt32)pCode[0] - 4) >> 2;
UInt32 count = numOfOps;
PTR_DEF_ASSIGN(UInt32,tgt,1);
pCode += 3; // Move to first operand
// Hash all source operands
do {
DEF_ASSIGN(Int32,len1,2);
DEF_ASSIGN(Int32,len2,6);
DEF_ASSIGN(Int32,pos1,3);
DEF_ASSIGN(Int32,pos2,7);
PTR_DEF_ASSIGN(unsigned char,src1,0);
PTR_DEF_ASSIGN(unsigned char,src2,4);
UInt64 result = ExHDPHash::hashP(src1, src2, len1, len2);
UInt32 h1 = (len1 == 0) ? *((UInt32*)src1) : (UInt32)(result >> 32);
UInt32 h2 = (len2 == 0) ? *((UInt32*)src2)
: (UInt32)(result & 0xFFFFFFFF);
hashVals[pos1] = h1;
hashVals[pos2] = h2;
count -= 2;
pCode += 8;
} while (count > 1);
if (count) {
PTR_DEF_ASSIGN(char,src1,0);
hashVals[pCode[3]] = (pCode[2] == 0) ? *((UInt32*)src1)
: ExHDPHash::hash(src1, ExHDPHash::NO_FLAGS,
(Int32)pCode[2]);
pCode += 4;
}
// Join all operands (j of them) one at a time;
combRes = hashVals[0];
for (i=1; i < numOfOps; i++)
combRes = ((combRes << 1) | (combRes >> 31)) ^ hashVals[i];
*tgt = combRes;
break;
}
case PCIT::NOT_NULL_BRANCH_BULK:
{
NABoolean isNull = FALSE;
DEF_ASSIGN(Int32,length,0);
length--;
Int32 btgt = length - 1;
if (pCode[1] == 0) {
Int32 i = 3;
Long tgt = stack[pCode[2]];
do {
// Retrieve null bit and check for nullness
isNull = (*((Int16*)(tgt + pCode[i])) != 0);
if (isNull)
break;
// Move to next offset
i++;
} while(i < btgt);
}
else {
Long tgt, i = 2;
do {
tgt = stack[pCode[i]];
// Retrieve null bit and check for nullness
isNull = (*((Int16*)(tgt + pCode[i+1])) != 0);
if (isNull)
break;
// Move to next offset
i += 2;
} while(i < btgt);
}
pCode += (isNull) ? length : pCode[btgt];
break;
}
case PCIT::NULL_BITMAP_BULK:
{
//Int32 i;
NABoolean isNull = FALSE;
DEF_ASSIGN(Int32,length,0);
length--;
Int32 btgt = length - 1;
if (pCode[1] == 0) {
PTR_DEF_ASSIGN(char,nullDataPtr,2);
PTR_TO_PCODE(char, bitmapMaskPtr, 5);
for (Int32 i=0; i < (Int32)pCode[4]; i++) {
isNull = (nullDataPtr[i] & bitmapMaskPtr[i]);
if (isNull)
break;
}
}
else {
for (Int32 i=2; i < btgt; i+=3) {
DEF_ASSIGN(Int32,nbi,i+2);
PTR_DEF_ASSIGN(char,nullDataPtr,i);
isNull = (nbi == -1) ? (*nullDataPtr != 0) :
ExpAlignedFormat::isNullValue(nullDataPtr, (UInt16)nbi);
if (isNull)
break;
}
}
pCode += (isNull) ? length : pCode[btgt];
break;
}
case PCIT::MOVE_BULK:
{
Int32 i;
DEF_ASSIGN(Int32,length,0);
length--;
Long tgtBase = stack[pCode[1]];
Long srcBase = stack[pCode[2]];
for (i=3; i != length; i+=3) {
Long tgt = tgtBase + pCode[i+1];
Long src = srcBase + pCode[i+2];
switch (pCode[i]) {
case PCIT::MOVE_MBIN8_MBIN8_IBIN32S:
str_cpy_all((char*)tgt, (char*)src, (Lng32)pCode[i+3]);
i++;
break;
case PCIT::MOVE_MBIN64S_MBIN64S:
*((Int64*)tgt) = *((Int64*)src);
break;
case PCIT::MOVE_MBIN32U_MBIN32U:
*((UInt32*)tgt) = *((UInt32*)src);
break;
case PCIT::MOVE_MBIN16U_MBIN16U:
*((UInt16*)tgt) = *((UInt16*)src);
break;
case PCIT::MOVE_MBIN16U_IBIN16U:
*((UInt16*)tgt) = (UInt16)pCode[i+2];
break;
case PCIT::MOVE_MBIN32S_IBIN32S:
*((Int32*)tgt) = (Int32)pCode[i+2];
break;
case PCIT::MOVE_MBIN8_MBIN8:
*((char*)tgt) = *((char*)src);
break;
}
}
pCode += length;
break;
}
case PCIT::CLAUSE_BRANCH:
// On 64-bit platform pCode[0] and pCode[1] contain branch pcode stream,
// pCode[2] and pCode[3] store ptr to target clause, while on 32-bit
// platform, only pCode[0] and pCode[1] are used for both.
// Use PCODEBINARIES_PER_PTR to handle both platforms
branchClause = (ex_branch_clause*)*(Long*)&(pCode[PCODEBINARIES_PER_PTR]);
if(branchClause->get_branch_clause() == branchClause->getNextClause())
pCode += (Int64)pCode[0];
else
pCode += PCODEBINARIES_PER_PTR + PCODEBINARIES_PER_PTR;
break;
case PCIT::RETURN_IBIN32S:
{
NABoolean res = (pCode[0] == 1);
if (enableRuntimeOpts) {
PCodeCfg* cfg = new(heap_) PCodeCfg(this, NULL, NULL, heap_, NULL);
cfg->runtimeOptimize();
NADELETE(cfg, PCodeCfg, heap_);
}
return ((res) ? ex_expr::EXPR_TRUE : ex_expr::EXPR_FALSE);
break;
}
case PCIT::MOVE_MBIN32S:
{
PTR_DEF_ASSIGN(Int32,resultPtr,0);
if ( *resultPtr == 1 ) retCode = ex_expr::EXPR_TRUE;
else retCode = ex_expr::EXPR_FALSE;
pCode += 2;
break;
}
case PCIT::MOVE_MBIN32S_IBIN32S:
{
PTR_DEF_ASSIGN(UInt32,tmpUIntPtr,0);
DEF_ASSIGN(UInt32,tmpUInt,2);
* tmpUIntPtr = tmpUInt ;
pCode += 3;
break;
}
case PCIT::MOVE_MBIN16U_IBIN16U:
{
PTR_DEF_ASSIGN(UInt16, tmpUShortPtr,0);
DEF_ASSIGN(UInt16, tmpUShort,2);
* tmpUShortPtr = tmpUShort ;
pCode += 3;
break;
}
case PCIT::MOVE_MBIN8_MBIN8_IBIN32S:
{
PTR_DEF_ASSIGN(char,toPtr,0);
PTR_DEF_ASSIGN(char,fromPtr,2);
DEF_ASSIGN(UInt32,moveLen,4);
str_cpy_all( toPtr, fromPtr, moveLen );
pCode += 5;
break;
}
// fixed length source to fixed length target. Lengths
// are not equal. Currently only supports targetlen > srclen.
case PCIT::MOVE_MASCII_MASCII_IBIN32S_IBIN32S:
{
DEF_ASSIGN(Int32,maxTgtLen, 4);
DEF_ASSIGN(Int32,actualSrcLen, 5);
PTR_DEF_ASSIGN(char,tgt, 0);
PTR_DEF_ASSIGN(char,src, 2);
char* pad = tgt + actualSrcLen;
Int32 padLen = (maxTgtLen - actualSrcLen);
str_cpy_all(tgt, src, actualSrcLen);
// add blankpad
str_pad(pad, padLen, ' ');
pCode += 6;
break;
}
// fixed length source to fixed length target. Lengths
// are not equal. Currently only supports targetlen > srclen.
case PCIT::MOVE_MUNI_MUNI_IBIN32S_IBIN32S:
{
DEF_ASSIGN(Int32,maxTgtLen, 4);
DEF_ASSIGN(Int32,actualSrcLen, 5);
PTR_DEF_ASSIGN(char,tgt, 0);
PTR_DEF_ASSIGN(char,src, 2);
NAWchar* pad = (NAWchar*)(tgt + actualSrcLen);
Int32 padLen = (maxTgtLen - actualSrcLen) >> 1; // Shift for dbl-byte
str_cpy_all(tgt, src, actualSrcLen);
// add blankpad
wc_str_pad(pad, padLen);
pCode += 6;
break;
}
// move varchar source to varchar target
// source or target may be indirect.
case PCIT::MOVE_MATTR5_MATTR5:
{
DEF_ASSIGN(Int32,maxTgtLen, 3);
Int32 srcLen, copyLen;
BASE_PTR_DEF_ASSIGN(char,src, 5);
BASE_PTR_DEF_ASSIGN(char,tgt, 0);
DEF_ASSIGN(Int32,comboLen1, 4);
char* comboPtr1 = (char*)&comboLen1;
Int16 tgtNullIndLen = (Int16)comboPtr1[0];
Int16 tgtVCIndLen = (Int16)comboPtr1[1];
DEF_ASSIGN(Int32,comboLen2, 9);
char* comboPtr2 = (char*)&comboLen2;
Int16 srcNullIndLen = (Int16)comboPtr2[0];
Int16 srcVCIndLen = (Int16)comboPtr2[1];
DEF_ASSIGN(UInt32,srcOffset, 6);
DEF_ASSIGN(UInt32,srcVoaOffset, 7);
src += ExpTupleDesc::getVarOffset(src,
srcOffset,
srcVoaOffset,
srcVCIndLen, // vcIndLen
srcNullIndLen // nullIndLen
);
srcLen = ExpTupleDesc::getVarLength(src, srcVCIndLen);
copyLen = ((maxTgtLen >= srcLen) ? srcLen : maxTgtLen);
src += srcVCIndLen;
DEF_ASSIGN(Int32,tgtOffset, 1);
DEF_ASSIGN(Int32,tgtVoaOffset, 2);
// VOA offsets should always be used in order.
if(tgtVoaOffset > 0) {
assert(tgtVoaOffset > lastVoaOffset);
lastVoaOffset = tgtVoaOffset;
}
tgt += ExpTupleDesc::getTgtVarOffset( tgt,
tgtOffset, // tgt offset
tgtVoaOffset, // tgt voa offset
tgtVCIndLen,
tgtNullIndLen,
varOffset,
copyLen
);
ExpTupleDesc::setVarLength(tgt, copyLen, tgtVCIndLen); // set variable length value
tgt += tgtVCIndLen; // bump past the vc indicator length field
str_cpy_all(tgt, src, copyLen);
pCode += 10;
}
break;
// move varchar source to fixed target
// source may be indirect
case PCIT::MOVE_MASCII_MATTR5_IBIN32S:
{
DEF_ASSIGN(Int32,maxTgtLen, 7);
Int32 srcLen, copyLen, padLen = 0;
PTR_DEF_ASSIGN(char, dst, 0);
BASE_PTR_DEF_ASSIGN(char, src, 2);
DEF_ASSIGN(Int32,comboLen1, 6);
char* comboPtr1 = (char*)&comboLen1;
Int16 srcNullIndLen = (Int16)comboPtr1[0];
Int16 srcVCIndLen = (Int16)comboPtr1[1];
DEF_ASSIGN(UInt32, srcOffset, 3);
DEF_ASSIGN(UInt32, srcVoaOffset, 4);
src += ExpTupleDesc::getVarOffset(src,
srcOffset,
srcVoaOffset,
srcVCIndLen, // vcIndLen
srcNullIndLen // nullIndLen
);
srcLen = ExpTupleDesc::getVarLength(src, srcVCIndLen);
padLen = maxTgtLen - srcLen;
if (padLen > 0) {
copyLen = srcLen;
str_pad(dst + copyLen, padLen, ' ');
} else {
copyLen = maxTgtLen;
}
// Now copy in the value ...
str_cpy_all(dst, src + srcVCIndLen, copyLen);
pCode += 8;
}
break;
// move fixed source to varchar target
// target may be indirect.
case PCIT::MOVE_MATTR5_MASCII_IBIN32S:
{
PTR_DEF_ASSIGN(char, src, 5);
DEF_ASSIGN(Int32, srcLen, 7);
DEF_ASSIGN(Int32, maxTgtLen, 3);
Int32 copyLen = ((maxTgtLen >= srcLen) ? srcLen : maxTgtLen);
DEF_ASSIGN(Int32, comboLen1, 4);
char* comboPtr1 = (char*)&comboLen1;
Int16 tgtNullIndLen = (Int16)comboPtr1[0];
Int16 tgtVCIndLen = (Int16)comboPtr1[1];
BASE_PTR_DEF_ASSIGN(char, tgt, 0);
DEF_ASSIGN(Int32, tgtOffset, 1);
DEF_ASSIGN(Int32,tgtVoaOffset, 2);
// VOA offsets should always be used in order.
if(tgtVoaOffset > 0) {
assert(tgtVoaOffset > lastVoaOffset);
lastVoaOffset = tgtVoaOffset;
}
tgt += ExpTupleDesc::getTgtVarOffset( tgt,
tgtOffset,
tgtVoaOffset,
tgtVCIndLen,
tgtNullIndLen,
varOffset,
copyLen
);
ExpTupleDesc::setVarLength(tgt, copyLen, tgtVCIndLen);
tgt += tgtVCIndLen;
str_cpy_all(tgt, src, copyLen);
pCode += 8;
}
break;
// convert varchar ptr source to Int32 or Int64
case PCIT::CONVVCPTR_MBIN32S_MATTR5_IBIN32S:
case PCIT::CONVVCPTR_MBIN64S_MATTR5_IBIN32S:
{
DEF_ASSIGN(Int32,maxTgtLen, 7);
Int32 srcLen = 0;
PTR_DEF_ASSIGN(char, dst, 0);
BASE_PTR_DEF_ASSIGN(char, src, 2);
DEF_ASSIGN(Int32,comboLen1, 6);
char* comboPtr1 = (char*)&comboLen1;
Int16 srcNullIndLen = (Int16)comboPtr1[0];
Int16 srcVCIndLen = (Int16)comboPtr1[1];
DEF_ASSIGN(UInt32, srcOffset, 3);
DEF_ASSIGN(UInt32, srcVoaOffset, 4);
src += ExpTupleDesc::getVarOffset(src,
srcOffset,
srcVoaOffset,
srcVCIndLen, // vcIndLen
srcNullIndLen // nullIndLen
);
srcLen = ExpTupleDesc::getVarLength(src, srcVCIndLen);
// ptr to source value is stored at src as an Int64.
Int64 ptrVal = *(Int64*)(src + srcVCIndLen);
char * ptrSrc = (char*)ptrVal;
// convert source to target (Int32)
// First try simple conversion. If that returns an error, try complex conversion.
NABoolean neg = FALSE;
if (ptrSrc[0] == '-')
{
neg = TRUE;
ptrSrc++;
srcLen--;
}
Int64 srcNumericVal = str_atoi(ptrSrc, srcLen);
if (srcNumericVal == -1)
{
diagsArea = atp1->getDiagsArea();
ex_expr::exp_return_type er =
convDoIt(ptrSrc, srcLen, REC_BYTE_F_ASCII, 0, 0,
(char*)&srcNumericVal, sizeof(Int64),
(pCodeOpc == PCIT::CONVVCPTR_MBIN64S_MATTR5_IBIN32S
? REC_BIN64_SIGNED : REC_BIN32_SIGNED),
0, 0,
NULL, 0,
heap_, &diagsArea,
CONV_ASCII_BIN64S,
NULL, 0);
if (diagsArea != atp1->getDiagsArea())
atp1->setDiagsArea(diagsArea);
if (er == ex_expr::EXPR_ERROR)
return ex_expr::EXPR_ERROR;
}
if (pCodeOpc == PCIT::CONVVCPTR_MBIN64S_MATTR5_IBIN32S)
{
if (neg)
*(Int64*)dst = -srcNumericVal;
else
*(Int64*)dst = srcNumericVal;
}
else
{
if (neg)
*(Lng32*)dst = -(Int32)srcNumericVal;
else
*(Lng32*)dst = (Int32)srcNumericVal;
}
pCode += 8;
}
break;
// convert varchar ptr source to Flt32
case PCIT::CONVVCPTR_MFLT32_MATTR5_IBIN32S:
{
DEF_ASSIGN(Int32,maxTgtLen, 7);
Int32 srcLen = 0;
PTR_DEF_ASSIGN(char, dst, 0);
BASE_PTR_DEF_ASSIGN(char, src, 2);
DEF_ASSIGN(Int32,comboLen1, 6);
char* comboPtr1 = (char*)&comboLen1;
Int16 srcNullIndLen = (Int16)comboPtr1[0];
Int16 srcVCIndLen = (Int16)comboPtr1[1];
DEF_ASSIGN(UInt32, srcOffset, 3);
DEF_ASSIGN(UInt32, srcVoaOffset, 4);
src += ExpTupleDesc::getVarOffset(src,
srcOffset,
srcVoaOffset,
srcVCIndLen, // vcIndLen
srcNullIndLen // nullIndLen
);
srcLen = ExpTupleDesc::getVarLength(src, srcVCIndLen);
// ptr to source value is stored at src as an Int64.
Int64 ptrVal = *(Int64*)(src + srcVCIndLen);
char * ptrSrc = (char*)ptrVal;
// convert source to target (Flt32).
// First try simple conversion. If that returns an error, try complex conversion.
NABoolean neg = FALSE;
if (ptrSrc[0] == '-')
{
neg = TRUE;
ptrSrc++;
srcLen--;
}
double srcNumericVal = str_ftoi(ptrSrc, srcLen);
if (srcNumericVal == -1)
{
diagsArea = atp1->getDiagsArea();
ex_expr::exp_return_type er =
convDoIt(ptrSrc, srcLen, REC_BYTE_F_ASCII, 0, 0,
(char*)&srcNumericVal, sizeof(double), REC_FLOAT32, 0, 0,
NULL, 0,
heap_, &diagsArea,
CONV_ASCII_FLOAT64,
NULL, 0);
if (diagsArea != atp1->getDiagsArea())
atp1->setDiagsArea(diagsArea);
if (er == ex_expr::EXPR_ERROR)
return ex_expr::EXPR_ERROR;
}
if (neg)
*(float*)dst = - (float)srcNumericVal;
else
*(float*)dst = (float)srcNumericVal;
pCode += 8;
}
break;
// convert varchar ptr source to varchar tgt
case PCIT::CONVVCPTR_MATTR5_MATTR5:
{
DEF_ASSIGN(Int32,maxTgtLen, 3);
Int32 srcLen, copyLen;
BASE_PTR_DEF_ASSIGN(char,src, 5);
BASE_PTR_DEF_ASSIGN(char,tgt, 0);
DEF_ASSIGN(Int32,comboLen1, 4);
char* comboPtr1 = (char*)&comboLen1;
Int16 tgtNullIndLen = (Int16)comboPtr1[0];
Int16 tgtVCIndLen = (Int16)comboPtr1[1];
DEF_ASSIGN(Int32,comboLen2, 9);
char* comboPtr2 = (char*)&comboLen2;
Int16 srcNullIndLen = (Int16)comboPtr2[0];
Int16 srcVCIndLen = (Int16)comboPtr2[1];
DEF_ASSIGN(UInt32,srcOffset, 6);
DEF_ASSIGN(UInt32,srcVoaOffset, 7);
src += ExpTupleDesc::getVarOffset(src,
srcOffset,
srcVoaOffset,
srcVCIndLen, // vcIndLen
srcNullIndLen // nullIndLen
);
srcLen = ExpTupleDesc::getVarLength(src, srcVCIndLen);
copyLen = ((maxTgtLen >= srcLen) ? srcLen : maxTgtLen);
// ptr to source value is stored at src as an Int64.
Int64 ptrVal = *(Int64*)(src + srcVCIndLen);
char * ptrSrc = (char*)ptrVal;
DEF_ASSIGN(Int32,tgtOffset, 1);
DEF_ASSIGN(Int32,tgtVoaOffset, 2);
// VOA offsets should always be used in order.
if(tgtVoaOffset > 0) {
assert(tgtVoaOffset > lastVoaOffset);
lastVoaOffset = tgtVoaOffset;
}
tgt += ExpTupleDesc::getTgtVarOffset( tgt,
tgtOffset, // tgt offset
tgtVoaOffset, // tgt voa offset
tgtVCIndLen,
tgtNullIndLen,
varOffset,
copyLen
);
if (copyLen < srcLen)
{
diagsArea = atp1->getDiagsArea();
ex_expr::exp_return_type er =
convDoIt(ptrSrc, srcLen, REC_BYTE_F_ASCII, 0, 0,
(tgt+tgtVCIndLen), maxTgtLen, REC_BYTE_V_ASCII, 0, 0,
tgt, tgtVCIndLen,
heap_, &diagsArea,
CONV_ASCII_F_V,
NULL, 0);
if (diagsArea != atp1->getDiagsArea())
atp1->setDiagsArea(diagsArea);
if (er == ex_expr::EXPR_ERROR)
return ex_expr::EXPR_ERROR;
}
else
{
ExpTupleDesc::setVarLength(tgt, copyLen, tgtVCIndLen); // set variable length value
tgt += tgtVCIndLen; // bump past the vc indicator length field
str_cpy_all(tgt, ptrSrc, copyLen);
}
pCode += 10;
}
break;
case PCIT::STRLEN_MBIN32U_MATTR5:
case PCIT::STRLEN_MBIN32U_MUNIV:
{
PTR_DEF_ASSIGN(UInt32, tgt, 0);
BASE_PTR_DEF_ASSIGN(char, src, 2);
UInt32 srcLen;
DEF_ASSIGN(Int32, comboLen, 6);
char* comboPtr = (char*)&comboLen;
Int16 srcNullIndLen = (Int16)comboPtr[0];
Int16 srcVCIndLen = (Int16)comboPtr[1];
DEF_ASSIGN(UInt32,srcOffset, 3);
DEF_ASSIGN(UInt32,srcVoaOffset, 4);
src += ExpTupleDesc::getVarOffset(src,
srcOffset,
srcVoaOffset,
srcVCIndLen, // vcIndLen
srcNullIndLen // nullIndLen
);
srcLen = ExpTupleDesc::getVarLength(src, srcVCIndLen);
// Divide length by 2 if we're dealing with a UCS2 string
*tgt = (pCodeOpc == PCIT::STRLEN_MBIN32U_MATTR5)
? srcLen : (srcLen >> 1);
pCode += 7;
break;
}
case PCIT::LIKE_MBIN32S_MATTR5_MATTR5_IBIN32S_IBIN32S:
{
PTR_DEF_ASSIGN(Int32, result, 0);
Int32 retVal = 1;
DEF_ASSIGN(Int32,comboLen1, 6);
DEF_ASSIGN(Int32,comboLen2, 11);
//
// NOTE: Use "unsigned char" in the next 2 lines so that we do not
// get sign extension. That way the 8-bit values pointed at
// can be 0 - 255 rather than only 0 - 127.
//
unsigned char* comboPtr1 = (unsigned char*)&comboLen1;
unsigned char* comboPtr2 = (unsigned char*)&comboLen2;
Int16 srcVCIndLen = (Int16)comboPtr1[1];
Int16 patVCIndLen = (Int16)comboPtr2[1];
Int16 srcNullIndLen = (Int16)comboPtr1[0];
Int16 patNullIndLen = (Int16)comboPtr2[0];
BASE_PTR_DEF_ASSIGN(char,srcStr, 2);
BASE_PTR_DEF_ASSIGN(char,patStr, 7);
DEF_ASSIGN(UInt32,srcOffset, 3);
DEF_ASSIGN(UInt32,srcVoaOffset, 4);
DEF_ASSIGN(UInt32,srcLen, 5);
DEF_ASSIGN(UInt32,patOffset, 8);
DEF_ASSIGN(UInt32,patVoaOffset, 9);
DEF_ASSIGN(UInt32,patLen, 10);
//UInt32 srcLen, patLen;
if (srcVCIndLen > 0)
{
srcStr += ExpTupleDesc::getVarOffset(srcStr,
srcOffset,
srcVoaOffset,
srcVCIndLen,
srcNullIndLen
);
srcLen = ExpTupleDesc::getVarLength(srcStr, srcVCIndLen);
srcStr += srcVCIndLen;
}
else
{
srcStr += srcOffset;
}
if (patVCIndLen > 0)
{
patStr += ExpTupleDesc::getVarOffset(patStr,
patOffset,
patVoaOffset,
patVCIndLen,
patNullIndLen
);
patLen = ExpTupleDesc::getVarLength(patStr, patVCIndLen);
patStr += patVCIndLen;
}
else
{
patStr += patOffset;
}
// Set up pointers to offsets and lengths of all pattern strings
//
// NOTE: Use "unsigned char" so that offsets and lengths can be
// up to 255.
//
PTR_TO_PCODE(unsigned char, pOffPtr, 12);
PTR_TO_PCODE(unsigned char, pLenPtr, 13);
char* tempSrc = srcStr;
Int32 tempSrcLen = srcLen;
Int32 numOfPatterns = comboPtr1[3];
Int32 flags = comboPtr1[2];
Int32 precision = comboPtr2[2];
// ignore trailing filler blanks for UTF-8 arguments with a char limit
if (precision)
tempSrcLen =
srcLen = lightValidateUTF8Str(tempSrc, tempSrcLen, precision, 0);
// Iterate through each pattern string. The length of the pattern string
// can't exceed the remaining length of the source string to search. As
// pattern strings are found, shift up source string (i.e. temp string)
// so that searching can continue with next pattern. Also, we generate
// pcode *only* if there is at least one pattern.
for (Int32 i=0; i < numOfPatterns; i++) {
Int32 pos;
NABoolean fastCheck = FALSE;
char* pat = patStr + pOffPtr[i];
Int32 patLen = pLenPtr[i];
if (patLen > tempSrcLen) {
retVal = 0;
break;
}
// Do a fast check if flags indicate so for head of string
if ((i == 0) && (flags & ex_like_clause_base::LIKE_HEAD))
fastCheck = TRUE;
// If flags indicate a search from tail of string, re-adjust pointers
// so that a fast boundary search can be done with strcmp.
if ((i == numOfPatterns-1) && (flags & ex_like_clause_base::LIKE_TAIL))
{
fastCheck = TRUE;
tempSrc = srcStr + (srcLen - patLen);
tempSrcLen = patLen;
}
// Perform search
pos = ex_function_position::findPosition(pat, patLen, tempSrc,
tempSrcLen, fastCheck);
// If match was not found, return false.
if (pos == 0) {
retVal = 0;
break;
}
// Adjust pointers to source string to begin searching next pattern.
tempSrc += (pos + patLen - 1);
tempSrcLen -= (pos + patLen -1);
}
*result = retVal;
pCode += 14;
break;
}
case PCIT::POS_MBIN32S_MATTR5_MATTR5:
{
PTR_DEF_ASSIGN(Int32, result, 0);
Int32 pos;
DEF_ASSIGN(Int32, comboLen1, 6);
DEF_ASSIGN(Int32, comboLen2, 11);
char* comboPtr1 = (char*)&comboLen1;
char* comboPtr2 = (char*)&comboLen2;
Int16 patVCIndLen = (Int16)comboPtr1[1];
Int16 srcVCIndLen = (Int16)comboPtr2[1];
Int16 patNullIndLen = (Int16)comboPtr1[0];
Int16 srcNullIndLen = (Int16)comboPtr2[0];
BASE_PTR_DEF_ASSIGN(char, patStr, 2);
BASE_PTR_DEF_ASSIGN(char, srcStr, 7);
DEF_ASSIGN(UInt32,patOffset, 3);
DEF_ASSIGN(UInt32,patVoaOffset, 4);
DEF_ASSIGN(UInt32, patLen, 5);
DEF_ASSIGN(UInt32,srcOffset, 8);
DEF_ASSIGN(UInt32,srcVoaOffset, 9);
DEF_ASSIGN(UInt32, srcLen, 10);
if (patVCIndLen > 0)
{
patStr += ExpTupleDesc::getVarOffset(patStr,
patOffset,
patVoaOffset,
patVCIndLen,
patNullIndLen
);
patLen = ExpTupleDesc::getVarLength(patStr, patVCIndLen);
patStr += patVCIndLen;
}
else
{
patStr += patOffset;
}
if (srcVCIndLen > 0)
{
srcStr += ExpTupleDesc::getVarOffset(srcStr,
srcOffset,
srcVoaOffset,
srcVCIndLen,
srcNullIndLen
);
srcLen = ExpTupleDesc::getVarLength(srcStr, srcVCIndLen);
srcStr += srcVCIndLen;
}
else
{
srcStr += srcOffset;
}
// Must check patLen first to ensure functionality correctness
if (patLen == 0)
pos = 1;
else if (srcLen == 0)
pos = 0;
else
pos =
ex_function_position::findPosition(patStr,patLen,srcStr,srcLen,FALSE);
*result = pos;
pCode += 12;
break;
}
case PCIT::CONCAT_MATTR5_MATTR5_MATTR5:
{
DEF_ASSIGN(Int32, comboLen1, 4);
DEF_ASSIGN(Int32, comboLen2, 9);
DEF_ASSIGN(Int32, comboLen3, 14);
char* comboPtr1 = (char*)&comboLen1;
char* comboPtr2 = (char*)&comboLen2;
char* comboPtr3 = (char*)&comboLen3;
Int16 tgtNullIndLen = (Int16)comboPtr1[0];
Int16 tgtVCIndLen = (Int16)comboPtr1[1];
Int16 src1NullIndLen = (Int16)comboPtr2[0];
Int16 src1VCIndLen = (Int16)comboPtr2[1];
Int16 src2NullIndLen = (Int16)comboPtr3[0];
Int16 src2VCIndLen = (Int16)comboPtr3[1];
BASE_PTR_DEF_ASSIGN(char, tgt, 0);
BASE_PTR_DEF_ASSIGN(char, src1, 5);
BASE_PTR_DEF_ASSIGN(char, src2, 10);
DEF_ASSIGN(UInt32,src1Offset, 6);
DEF_ASSIGN(UInt32,src1VoaOffset, 7);
DEF_ASSIGN(UInt32,src1Len, 8);
DEF_ASSIGN(UInt32,src2Offset, 11);
DEF_ASSIGN(UInt32,src2VoaOffset, 12);
DEF_ASSIGN(UInt32,src2Len, 13);
if (src1VCIndLen > 0)
{
src1 += ExpTupleDesc::getVarOffset(src1,
src1Offset,
src1VoaOffset,
src1VCIndLen,
src1NullIndLen
);
src1Len = ExpTupleDesc::getVarLength(src1, src1VCIndLen);
src1 += src1VCIndLen;
}
else
{
src1 += src1Offset;
}
if (src2VCIndLen > 0)
{
src2 += ExpTupleDesc::getVarOffset(src2,
src2Offset,
src2VoaOffset,
src2VCIndLen,
src2NullIndLen
);
src2Len = ExpTupleDesc::getVarLength(src2, src2VCIndLen);
src2 += src2VCIndLen;
}
else
{
src2 += src2Offset;
}
Int32 tgtLen = src1Len + src2Len;
DEF_ASSIGN(Int32, maxTgtLen, 3);
if (tgtLen > maxTgtLen )
goto Error1_;
DEF_ASSIGN(Int32,tgtOffset, 1);
DEF_ASSIGN(Int32,tgtVoaOffset, 2);
if (tgtVCIndLen > 0)
{
// VOA offsets should always be used in order.
if(tgtVoaOffset > 0) {
assert(tgtVoaOffset > lastVoaOffset);
lastVoaOffset = tgtVoaOffset;
}
tgt += ExpTupleDesc::getTgtVarOffset( tgt,
tgtOffset,
tgtVoaOffset,
tgtVCIndLen,
tgtNullIndLen,
varOffset,
tgtLen
);
ExpTupleDesc::setVarLength(tgt, tgtLen, tgtVCIndLen);
tgt += tgtVCIndLen;
}
else
{
tgt += tgtOffset;
}
str_cpy_all(tgt, src1, src1Len);
str_cpy_all(&(tgt[src1Len]), src2, src2Len);
pCode += 15;
break;
}
case PCIT::SUBSTR_MATTR5_MATTR5_MBIN32S_MBIN32S:
{
// SUBSTRING
// Source/target string can be in Exploded or Compressed Internal format.
DEF_ASSIGN(UInt32, comboLen1, 4);
DEF_ASSIGN(UInt32, comboLen2, 9);
char* comboPtr1 = (char*)&comboLen1;
char* comboPtr2 = (char*)&comboLen2;
Int16 tgtNullIndLen = (Int16)comboPtr1[0];
Int16 tgtVCIndLen = (Int16)comboPtr1[1];
Int16 srcNullIndLen = (Int16)comboPtr2[0];
Int16 srcVCIndLen = (Int16)comboPtr2[1];
Int16 numOperands = (Int16)comboPtr2[2];
DEF_ASSIGN(UInt32, srcOffset, 6);
DEF_ASSIGN(UInt32, srcVoaOffset, 7);
DEF_ASSIGN(UInt32, srcMaxLen, 8);
BASE_PTR_DEF_ASSIGN(char, src, 5);
BASE_PTR_DEF_ASSIGN(char, tgt, 0);
if (srcVCIndLen > 0) // is varchar
{
src += ExpTupleDesc::getVarOffset(src,
srcOffset,
srcVoaOffset,
srcVCIndLen,
srcNullIndLen);
srcMaxLen = ExpTupleDesc::getVarLength(src, srcVCIndLen);
src += srcVCIndLen;
}
else
{
src += srcOffset;
}
PTR_DEF_ASSIGN(Int32, startPtr, 10);
PTR_DEF_ASSIGN(Int32, lengthPtr,12);
Int64 start = *startPtr;
Int64 length = *lengthPtr;
Int64 temp = ((numOperands > 0)
? (start + length)
: ((start > (srcMaxLen + 1)) ? start : (srcMaxLen + 1)));
// This error case must be when we have a potential overflow
if (temp < start) {
diagsArea = atp1->getDiagsArea();
ExRaiseSqlError(heap_, &diagsArea, EXE_SUBSTRING_ERROR);
if(diagsArea != atp1->getDiagsArea())
atp1->setDiagsArea(diagsArea);
return ex_expr::EXPR_ERROR;
}
Int32 len0 = 0;
if ((start <= srcMaxLen) && (temp > 0)) {
if (start < 1)
start = 1;
if (temp > (srcMaxLen + 1))
temp = srcMaxLen + 1;
len0 = (Int32)(temp - start);
// The copy length can't be greater than the max target length
DEF_ASSIGN(Int32, maxTgtLen, 3);
if ( len0 > maxTgtLen ) len0 = maxTgtLen ;
}
src += (start - 1);
DEF_ASSIGN(Int32, tgtOffset, 1);
DEF_ASSIGN(Int32, tgtVoaOffset, 2);
// VOA offsets should always be used in order.
if(tgtVoaOffset > 0) {
assert(tgtVoaOffset > lastVoaOffset);
lastVoaOffset = tgtVoaOffset;
}
tgt += ExpTupleDesc::getTgtVarOffset( tgt,
tgtOffset,
tgtVoaOffset,
tgtVCIndLen,
tgtNullIndLen,
varOffset,
len0
);
if (tgtVCIndLen > 0) // if varchar
{
ExpTupleDesc::setVarLength(tgt, len0, tgtVCIndLen);
tgt += tgtVCIndLen;
}
if (len0)
str_cpy_all(tgt, src, len0);
pCode += 14;
break;
}
case PCIT::MOVE_MBIN16S_MBIN8S:
MOVE_INSTR( Int16, Int8 );
case PCIT::MOVE_MBIN16U_MBIN8U:
MOVE_INSTR( UInt16, UInt8 );
case PCIT::MOVE_MBIN16U_MBIN8:
MOVE_INSTR( UInt16, UInt8 );
case PCIT::MOVE_MBIN32S_MBIN8S:
MOVE_INSTR( Int32, Int8 );
case PCIT::MOVE_MBIN32U_MBIN8U:
MOVE_INSTR( UInt32, UInt8 );
case PCIT::MOVE_MBIN64S_MBIN8S:
MOVE_INSTR( Int64, Int8 );
case PCIT::MOVE_MBIN64U_MBIN8U:
MOVE_INSTR( UInt64, UInt8 );
case PCIT::MOVE_MBIN32U_MBIN16U:
MOVE_INSTR( UInt32, UInt16 );
case PCIT::MOVE_MBIN32S_MBIN16U:
MOVE_INSTR( Int32 , UInt16 );
case PCIT::MOVE_MBIN64S_MBIN16U:
MOVE_INSTR( Int64, UInt16 );
case PCIT::MOVE_MBIN32U_MBIN16S:
MOVE_INSTR( UInt32 , Int16 );
case PCIT::MOVE_MBIN32S_MBIN16S:
MOVE_INSTR( Int32 , Int16 );
case PCIT::MOVE_MBIN64S_MBIN16S:
MOVE_INSTR( Int64 , Int16 );
case PCIT::MOVE_MBIN64S_MBIN32U:
MOVE_INSTR( Int64 , UInt32 );
case PCIT::MOVE_MBIN64S_MBIN32S:
MOVE_INSTR( Int64 , Int32 );
case PCIT::MOVE_MBIN8_MBIN8:
MOVE_INSTR( unsigned char , unsigned char );
case PCIT::MOVE_MBIN16U_MBIN16U:
MOVE_INSTR( UInt16 , UInt16 );
case PCIT::MOVE_MBIN32U_MBIN32U:
MOVE_INSTR( UInt32 , UInt32 );
case PCIT::MOVE_MBIN64S_MBIN64S:
MOVE_INSTR( Int64 , Int64 );
case PCIT::MOVE_MBIN64S_MBIN64U:
MOVE_INSTR( Int64 , UInt64 );
case PCIT::MOVE_MBIN64U_MBIN64S:
MOVE_INSTR( UInt64 , Int64 );
case PCIT::MOVE_MBIN64U_MBIN64U:
MOVE_INSTR( UInt64 , UInt64 );
case PCIT::MOVE_MBIN64S_MDECS_IBIN32S:
{
PTR_DEF_ASSIGN(char, src, 2);
PTR_DEF_ASSIGN(Int64, tgt, 0);
if (src[0] & 0200)
{
*tgt = ((src[0] & 0177) - '0');
}
else
{
*tgt = (src[0] - '0');
}
for (Int32 k = 1; k < pCode[4]; k++)
{
*tgt = *tgt * 10 + (src[k] - '0');
}
if (src[0] & 0200)
{
*tgt = -*tgt;
}
pCode += 5;
}
break;
case PCIT::MOVE_MBIN64S_MDECU_IBIN32S:
{
PTR_DEF_ASSIGN(char, src, 2);
PTR_DEF_ASSIGN(Int64, tgt, 0);
*tgt = 0;
for (Int32 k = 0; k < pCode[4]; k++)
{
*tgt = *tgt * 10 + (src[k] - '0');
}
pCode += 5;
}
break;
case PCIT::MOVE_MFLT64_MBIN16S:
MOVE_INSTR( double , short );
case PCIT::MOVE_MFLT64_MBIN32S:
MOVE_INSTR( double , Int32 );
case PCIT::MOVE_MFLT64_MBIN64S:
MOVE_CAST_INSTR( double , double, Int64 );
case PCIT::MOVE_MFLT64_MFLT32:
MOVE_INSTR( double , float );
// Generated by ExHeaderClause ... new in R2.4
case PCIT::HDR_MPTR32_IBIN32S_IBIN32S_IBIN32S_IBIN32S_IBIN32S:
{
BASE_PTR_DEF_ASSIGN(char, data, 0 );
PTR_DEF_ASSIGN(char, hdrStart , 0 );
// Clear the header area
str_pad(hdrStart, pCode[2], '\0');
// Set the first fixed offset
if ( pCode[4] == sizeof(Int16) )
*((UInt16 *)hdrStart) = (UInt16)pCode[3];
else
*((Int32 *)hdrStart) = (Int32)pCode[3];
// Set the bitmap offset if relevant (n/a for SQLMX_FORMAT)
if ( pCode[5] > 0 )
*((Int16 *)(data + pCode[6])) = (Int16)pCode[5];
pCode += 7;
break;
}
case PCIT::NULL_MBIN16U:
{
PTR_DEF_ASSIGN(Int16, tmpPtr, 0 );
* tmpPtr = 0x00;
pCode += 2;
break;
}
case PCIT::NULL_BITMAP:
{
PTR_DEF_ASSIGN(char, bitmap, 0 );
DEF_ASSIGN(Int16, bitIdx , 3 );
// for aligned format's null bitmap
switch (pCode[2])
{
case PCIT::NULL_BITMAP_SET:
{
// Either clear a bit or set one ...
if ( pCode[4] )
ExpAlignedFormat::setNullBit( bitmap, bitIdx );
else
ExpAlignedFormat::clearNullBit( bitmap, bitIdx );
pCode += 5;
break;
}
case PCIT::NULL_BITMAP_TEST:
{
assert(0); // this code is not used
// in case this code is to become used: missing below are
// -- return the value from isNullValue()
// -- advance the pCode
// Test a bit to see if it is null or not.
ExpAlignedFormat::isNullValue( bitmap, bitIdx );
break;
}
}
}
break;
case PCIT::NULL_BYTES:
{
// for packed format
DEF_ASSIGN(UInt32, nullIndOffset, 1 );
DEF_ASSIGN(Int16, tmp, 2 );
if (nullIndOffset == ExpOffsetMax)
nullIndOffset = varOffset;
*(Int16 *)(stack[pCode[0]] + nullIndOffset) = tmp;
pCode += 3;
break;
}
case PCIT::NULL_MBIN16U_IBIN16U:
{
PTR_DEF_ASSIGN(Int16, tmpPtr16 , 0);
DEF_ASSIGN(Int16, tmp16, 2 );
* tmpPtr16 = tmp16 ;
pCode += 3;
break;
}
case PCIT::NULL_TEST_MBIN32S_MBIN16U_IBIN32S:
// for packed format
{
PTR_DEF_ASSIGN(Int16, tmpPtr16, 2);
DEF_ASSIGN(Int16, tmp16, 4);
PTR_DEF_ASSIGN(Int32, resultPtr, 0);
* resultPtr = ( *tmpPtr16 == tmp16 ) ? 1 : 0 ;
pCode += 5;
break;
}
case PCIT::NOT_NULL_BRANCH_MBIN16S_IBIN32S:
{
PTR_DEF_ASSIGN(Int16, resultPtr, 0);
// Not sure why we cast to Int64 ?
if( *resultPtr == 0 )
pCode += (Int64)pCode[2];
else
pCode += 3;
}
break;
case PCIT::NOT_NULL_BRANCH_MBIN16S_MBIN16S_IBIN32S:
{
PTR_DEF_ASSIGN(Int16, returnResultPtr, 0);
PTR_DEF_ASSIGN(Int16, resultPtr, 2);
* returnResultPtr = * resultPtr ;
if( *resultPtr == 0 ) pCode += (Int64)pCode[4];
else pCode += 5;
}
break;
case PCIT::NOT_NULL_BRANCH_MBIN32S_MBIN16S_IBIN32S:
{
PTR_DEF_ASSIGN(Int32, returnResultPtr32, 0);
PTR_DEF_ASSIGN(Int16, resultPtr16, 2);
* returnResultPtr32 = * resultPtr16 ;
if( * resultPtr16 == 0 ) pCode += (Int64)pCode[4];
else pCode += 5;
}
break;
// nullBranchHelper - two operands
case PCIT::NOT_NULL_BRANCH_MBIN32S_MBIN32S_MBIN32S_IATTR4_IBIN32S:
// Handles all data formats
// If either source operands are null, then target is null.
// If neither source operands are null, then clear target null indicator.
{
// If NullIndOffset is negative, it indicates that it is an indirect
// varchar in packed format and its positive value gives the voaOffset
// where the actual offset can be found (read 4 bytes from VOA entry).
// For exploded and aligned format the NullIndOffsets will never be
// negative since the null indicator offset is known at compile time.
UInt32 op2NullIndOff =
pCode[3] < 0 ? *((Int32 *)(stack[pCode[2]]+(-pCode[3]))) : pCode[3];
UInt32 op3NullIndOff =
pCode[5] < 0 ? *((Int32 *)(stack[pCode[4]]+(-pCode[5]))) : pCode[5];
// for target operand, if NullIndOffset is negative, use loop variable
// varOffset to get to the next available varchar. This only applies
// to packed format. All other formats will have valid NullIndOffset.
// Note that varOffset is not incremented here. It will be incremented and
// voaOffset will be set when the actual varchar data is written.
UInt32 op1NullIndOff = pCode[1] < 0 ? varOffset : pCode[1];
// Map a group of pcodes to PCodeAttrNull struct.
PCodeAttrNull *attrs = (PCodeAttrNull *)&pCode[6];
NABoolean op2Null =
ExpTupleDesc::isNullValue((char *)stack[pCode[2]] + op2NullIndOff,
(Int16)attrs->op2NullBitIndex_,
(ExpTupleDesc::TupleDataFormat)attrs->fmt_.op2Fmt_);
NABoolean op3Null =
ExpTupleDesc::isNullValue((char *)stack[pCode[4]] + op3NullIndOff,
(Int16)attrs->op3NullBitIndex_,
(ExpTupleDesc::TupleDataFormat)attrs->fmt_.op3Fmt_);
if( op2Null || op3Null ) // either one is null
{
ExpTupleDesc::setNullValue((char*)(stack[pCode[0]] + op1NullIndOff),
(Int16)attrs->op1NullBitIndex_,
(ExpTupleDesc::TupleDataFormat)attrs->fmt_.op1Fmt_);
pCode += attrs->fmt_.size_;
}
else
{
ExpTupleDesc::clearNullValue((char*)(stack[pCode[0]] + op1NullIndOff),
(Int16)attrs->op1NullBitIndex_,
(ExpTupleDesc::TupleDataFormat)attrs->fmt_.op1Fmt_);
pCode += (Int64)pCode[10];
}
}
break;
case PCIT::NOT_NULL_BRANCH_MBIN32S_MBIN32S_IATTR3_IBIN32S:
// nullBranchHelper - one operand
// Handles all data formats
// If source operand is null, then target is null.
// If source operand is not null, then clear target null indicator.
{
// If NullIndOffset is negative, it indicates that it is an indirect
// varchar in packed format and its positive value gives the voaOffset
// where the actual offset can be found (read 4 bytes from VOA entry).
// For exploded and aligned format the NullIndOffsets will never be
// negative since the null indicator offset is known at compile time.
UInt32 op2NullIndOff =
pCode[3] < 0 ? *((Int32 *)(stack[pCode[2]]+(-pCode[3]))) : pCode[3];
// for target operand, if NullIndOffset is negative, use loop variable
// varOffset to get to the next available varchar. This only applies
// to packed format. All other formats will have valid NullIndOffset.
// Note that varOffset is not incremented here. It will be incremented and
// voaOffset will be set when the actual varchar data is written.
UInt32 op1NullIndOff = pCode[1] < 0 ? varOffset : pCode[1];
PCodeAttrNull *attrs = (PCodeAttrNull *)&pCode[4];
NABoolean op2Null =
ExpTupleDesc::isNullValue((char *)stack[pCode[2]] + op2NullIndOff,
(Int16)attrs->op2NullBitIndex_,
(ExpTupleDesc::TupleDataFormat)attrs->fmt_.op2Fmt_);
if( op2Null ) // check to see if operand is null
{
ExpTupleDesc::setNullValue((char*)(stack[pCode[0]] + op1NullIndOff),
(Int16)attrs->op1NullBitIndex_,
(ExpTupleDesc::TupleDataFormat)attrs->fmt_.op1Fmt_);
pCode += attrs->fmt_.size_;
}
else
{
ExpTupleDesc::clearNullValue((char*)(stack[pCode[0]] + op1NullIndOff),
(Int16)attrs->op1NullBitIndex_,
(ExpTupleDesc::TupleDataFormat)attrs->fmt_.op1Fmt_);
pCode += (Int64)pCode[7];
}
}
break;
case PCIT::NOT_NULL_BRANCH_COMP_MBIN32S_MBIN32S_MBIN32S_IATTR4_IBIN32S:
// nullBranchHelperForComp - two operands
{
// If NullIndOffset is negative, it indicates that it is an indirect
// varchar in packed format and its positive value gives the voaOffset
// where the actual offset can be found (read 4 bytes from VOA entry).
// For exploded and aligned format the NullIndOffsets will never be
// negative since the null indicator offset is known at compile time.
UInt32 op2NullIndOff =
pCode[3] < 0 ? *((Int32 *)(stack[pCode[2]]+(-pCode[3]))) : pCode[3];
UInt32 op3NullIndOff =
pCode[5] < 0 ? *((Int32 *)(stack[pCode[4]]+(-pCode[5]))) : pCode[5];
PCodeAttrNull *attrs = (PCodeAttrNull *)&pCode[6];
NABoolean op2Null =
ExpTupleDesc::isNullValue((char*)(stack[pCode[2]] + op2NullIndOff),
(Int16)attrs->op2NullBitIndex_,
(ExpTupleDesc::TupleDataFormat)attrs->fmt_.op2Fmt_);
NABoolean op3Null =
ExpTupleDesc::isNullValue((char*)(stack[pCode[4]] + op3NullIndOff),
(Int16)attrs->op3NullBitIndex_,
(ExpTupleDesc::TupleDataFormat)attrs->fmt_.op3Fmt_);
Int32 rslt = (op2Null || op3Null) ? -1 : 0;
PTR_DEF_ASSIGN(Int32, result, 0 );
* result = rslt ;
if (rslt == 0)
pCode += (Int64)pCode[10];
else
pCode += attrs->fmt_.size_;
}
break;
case PCIT::NOT_NULL_BRANCH_COMP_MBIN32S_MBIN32S_IATTR3_IBIN32S:
// nullBranchHelperForComp - one operand
{
// If NullIndOffset is negative, it indicates that it is an indirect
// varchar in packed format and its positive value gives the voaOffset
// where the actual offset can be found (read 4 bytes from VOA entry).
// For exploded and aligned format the NullIndOffsets will never be
// negative since the null indicator offset is known at compile time.
UInt32 op2NullIndOff =
pCode[3] < 0 ? *((Int32 *)(stack[pCode[2]]+(-pCode[3]))) : pCode[3];
PCodeAttrNull *attrs = (PCodeAttrNull *)&pCode[4];
NABoolean op2Null =
ExpTupleDesc::isNullValue((char*)(stack[pCode[2]] + op2NullIndOff),
(Int16)attrs->op2NullBitIndex_,
(ExpTupleDesc::TupleDataFormat)attrs->fmt_.op2Fmt_);
Int32 rslt = (op2Null) ? -1 : 0;
PTR_DEF_ASSIGN(Int32, result, 0 );
* result = rslt ;
if (rslt == 0)
pCode += (Int64)pCode[7];
else
pCode += attrs->fmt_.size_;
}
break;
case PCIT::NOT_NULL_BRANCH_MBIN32S_MBIN16S_IBIN32S_IBIN32S:
{
PTR_DEF_ASSIGN(Int32, resultPtr32, 0 );
PTR_DEF_ASSIGN(Int16, resultPtr16, 2 );
DEF_ASSIGN(Int32, val32 , 4 );
if( * resultPtr16 == 0 )
pCode += (Int64)pCode[5];
else
{
* resultPtr32 = val32 ;
pCode += 6;
}
}
break;
case PCIT::NOT_NULL_BRANCH_MBIN32S_MBIN16S_MBIN16S_IBIN32S:
{
PTR_DEF_ASSIGN(Int32, ptr32 , 0 );
PTR_DEF_ASSIGN(Int16, ptr16_1, 2 );
PTR_DEF_ASSIGN(Int16, ptr16_2, 4 );
Int16 result = *ptr16_1 | *ptr16_2 ;
* ptr32 = result ;
if(result == 0) pCode += (Int64)pCode[6];
else pCode += 7;
}
break;
case PCIT::NNB_MATTR3_IBIN32S:
// Handles all formats ...
{
PTR_DEF_ASSIGN(char, ptr , 0 );
DEF_ASSIGN(Int16, val, 2);
NABoolean nullp = ExpTupleDesc::isNullValue( ptr, val );
if ( nullp )
{
pCode += 4;
}
else
{
pCode += (Int64)pCode[3];
}
}
break;
case PCIT::NNB_MBIN32S_MATTR3_IBIN32S_IBIN32S:
// Handles all formats ...
// generated by nullBranchHelperForHash
{
PTR_DEF_ASSIGN(Int32, retPtr, 0 );
PTR_DEF_ASSIGN(char, ptr , 2 );
DEF_ASSIGN(Int16, val, 4);
DEF_ASSIGN(Int32, retVal, 5 );
NABoolean nullp = ExpTupleDesc::isNullValue( ptr, val );
if ( nullp )
{
* retPtr = retVal ;
pCode += 7;
}
else
{
pCode += (Int64)pCode[6];
}
}
break;
case PCIT::NNB_SPECIAL_NULLS_MBIN32S_MATTR3_MATTR3_IBIN32S_IBIN32S:
// Supports all data formats.
{
PTR_DEF_ASSIGN(Int32, retPtr, 0 );
PTR_DEF_ASSIGN(char, ptr1 , 2 );
PTR_DEF_ASSIGN(char, ptr2 , 5 );
DEF_ASSIGN(Int16, val1, 4);
DEF_ASSIGN(Int16, val2, 7);
NABoolean op1Null = ExpTupleDesc::isNullValue( ptr1, val1 );
NABoolean op2Null = ExpTupleDesc::isNullValue( ptr2, val2 );
if ( (NOT op1Null) && (NOT op2Null) )
{
* retPtr = 0;
pCode += (Int64)pCode[9];
}
else
{
// only equi case is supported. Could be extended later.
// pCode[8] contains the operator type (ITM_EQUAL for now).
* retPtr = op1Null && op2Null ? 1 : 0;
pCode += 10;
}
}
break;
case PCIT::NOT_NULL_BRANCH_MBIN16S_MBIN16S_MBIN16S_IBIN32S:
{
PTR_DEF_ASSIGN(Int16, ptr16_0, 0);
PTR_DEF_ASSIGN(Int16, ptr16_2, 2);
PTR_DEF_ASSIGN(Int16, ptr16_4, 4);
* ptr16_0 = * ptr16_2 | * ptr16_4 ;
if( * ptr16_0 == 0) pCode += (Int64)pCode[6];
else pCode += 7;
}
break;
case PCIT::NULL_VIOLATION_MPTR32_MPTR32_IPTR_IPTR:
// for aligned format's null bitmap
// Handles 1 or 2 arguments to check if null and raise an error if so.
// Select b, c from TFoo where cast( c as int not null) = 30
// where c is a nullable column this gets pushed to the EID.
{
PTR_DEF_ASSIGN(char, ptr_0, 0);
PTR_DEF_ASSIGN(char, ptr_2, 2);
Attributes *arg1 = (Attributes*)(GetPCodeBinaryAsPtr(pCode, 4));
Attributes *arg2 = (Attributes*)(GetPCodeBinaryAsPtr(pCode, 4 + PCODEBINARIES_PER_PTR));
NABoolean arg1Null =
ExpTupleDesc::isNullValue( ptr_0,
arg1->getNullBitIndex(),
arg1->getTupleFormat() );
NABoolean arg2Null =
( arg2 == 0
? FALSE
: ExpTupleDesc::isNullValue( ptr_2,
arg2->getNullBitIndex(),
arg2->getTupleFormat() ) );
if( arg1Null || arg2Null )
{
// Raise an "assigning a null value to a NOT NULL".
diagsArea = atp1->getDiagsArea();
ExRaiseSqlError(getHeap(), &diagsArea, EXE_ASSIGNING_NULL_TO_NOT_NULL);
if(diagsArea != atp1->getDiagsArea())
atp1->setDiagsArea(diagsArea);
return ex_expr::EXPR_ERROR;
}
pCode += 4 + PCODEBINARIES_PER_PTR + PCODEBINARIES_PER_PTR;
break;
}
case PCIT::UPDATE_ROWLEN3_MATTR5_IBIN32S:
{
{
BASE_PTR_DEF_ASSIGN(char, data, 0);
DEF_ASSIGN(UInt32, offset, 1);
DEF_ASSIGN(Int32, comboLen1, 4);
char* comboPtr1 = (char*)&comboLen1;
Int16 attrNullIndLen = (Int16)comboPtr1[0];
Int16 attrVCIndLen = (Int16)comboPtr1[1];
DEF_ASSIGN(Int32, voaOffset, 2 );
offset = ExpTupleDesc::getVarOffset( data,
offset,
voaOffset,
attrVCIndLen,
attrNullIndLen );
offset += ExpTupleDesc::getVarLength( data + offset,
attrVCIndLen );
offset += attrVCIndLen; // jump past the variable length bytes
varOffset = offset;
if (rowLen != NULL) {
DEF_ASSIGN(Int32, newLen, 5 );
// the last varchar must adjust the overall length out if
// in aligned format
if ( newLen > 0 )
{
offset = ExpAlignedFormat::adjustDataLength(data,
offset,
newLen);
}
*rowLen = offset;
}
}
pCode += 6;
break;
}
case PCIT::COPYVARROW_MBIN8_MBIN8_IBIN32S_IBIN32S_IBIN32S_IBIN32S:
{
{
PTR_DEF_ASSIGN(char, tgtData , 0 );
PTR_DEF_ASSIGN(char, srcData , 2 );
DEF_ASSIGN(UInt32, voaOffset, 4);
DEF_ASSIGN(Int32, comboLen1, 5);
char* comboPtr1 = (char*)&comboLen1;
Int16 attrNullIndLen = (Int16)comboPtr1[0];
Int16 attrVCIndLen = (Int16)comboPtr1[1];
DEF_ASSIGN(Int16, alignment, 6);
DEF_ASSIGN(Int32, rowLength, 7);
UInt32 copyLength = 0;
if (*(Int32*)srcData ==-1 ) //if aliggned format header is 0xFFFFFFFF
{// case of null instantiated row
DBGASSERT(*(Int16*)&srcData[voaOffset] ==-1);
copyLength = (UInt32)rowLength;
}
else
{
copyLength = ExpTupleDesc::getVarOffset(srcData,
UINT_MAX, // offset
voaOffset, // voaEntryOffset
attrVCIndLen,
attrNullIndLen );
copyLength += ExpTupleDesc::getVarLength( srcData + copyLength,
attrVCIndLen );
copyLength += attrVCIndLen; // jump past the variable length bytes
}
DBGASSERT(copyLength > 0 && copyLength <=(UInt32)rowLength);
str_cpy_all(tgtData,srcData,copyLength);
UInt32 newLen = copyLength;
// the last varchar must adjust the overall length out if
// in aligned format. Aligngemne should be ExpAlignedFormat::ALIGNMENT
if ( alignment > 0 )
{
newLen = ExpAlignedFormat::adjustDataLength(tgtData, copyLength, alignment, FALSE) ;
}
if (rowLen != NULL)
{
*rowLen = newLen;
}
}
pCode += 8;
break;
}
case PCIT::ADD_MBIN16S_MBIN16S_MBIN16S:
{
PTR_DEF_ASSIGN(Int16, result, 0);
PTR_DEF_ASSIGN(Int16, operand1, 2);
PTR_DEF_ASSIGN(Int16, operand2, 4);
* result = *operand1 + *operand2 ;
pCode += 6;
break;
}
case PCIT::ADD_MBIN32S_MBIN32S_MBIN32S:
{
PTR_DEF_ASSIGN(Int32, result, 0);
PTR_DEF_ASSIGN(Int32, operand1, 2);
PTR_DEF_ASSIGN(Int32, operand2, 4);
* result = *operand1 + *operand2 ;
pCode += 6;
break;
}
case PCIT::ADD_MBIN64S_MBIN64S_MBIN64S:
{
PTR_DEF_ASSIGN(Int64, result, 0);
PTR_DEF_ASSIGN(Int64, xptr, 2);
PTR_DEF_ASSIGN(Int64, yptr, 4);
#if (!defined _DEBUG)
Int64 x = *xptr, y = *yptr;
Int64 z = x + y;
*result = z;
// Same check C/C++ compiler uses to check for overflow
if ((((UInt64)(~(x ^ y) & (x ^ z))) >> 63) == 0) {
} else {
goto Error1_;
}
#else
* result = EXP_FIXED_OV_ADD( *xptr, *yptr, &ov );
if (ov)
{// overflowed
goto Error1_;
}
#endif
pCode += 6;
break;
}
case PCIT::ADD_MBIN32S_MBIN16S_MBIN16S:
{
PTR_DEF_ASSIGN(Int32, result, 0);
PTR_DEF_ASSIGN(Int16, operand1, 2);
PTR_DEF_ASSIGN(Int16, operand2, 4);
* result = *operand1 + *operand2 ;
pCode += 6;
break;
}
case PCIT::ADD_MBIN32S_MBIN16S_MBIN32S:
{
PTR_DEF_ASSIGN(Int32, result, 0);
PTR_DEF_ASSIGN(Int16, operand1, 2);
PTR_DEF_ASSIGN(Int32, operand2, 4);
* result = *operand1 + *operand2 ;
pCode += 6;
break;
}
case PCIT::ADD_MBIN64S_MBIN32S_MBIN64S:
{
PTR_DEF_ASSIGN(Int64, result, 0);
PTR_DEF_ASSIGN(Int32, xptr32, 2);
PTR_DEF_ASSIGN(Int64, yptr, 4);
#if (!defined _DEBUG)
Int64 x = (Int64) *xptr32 , y = *yptr;
Int64 z = x + y;
*result = z;
// Same check C/C++ compiler uses to check for overflow
if ((((UInt64)(~(x ^ y) & (x ^ z))) >> 63) == 0) {
}
else {
goto Error1_;
}
#else
* result = EXP_FIXED_OV_ADD( *xptr32, *yptr, &ov );
if (ov)
{
goto Error1_;
}
#endif
pCode += 6;
break;
}
case PCIT::SUB_MBIN16S_MBIN16S_MBIN16S:
{
PTR_DEF_ASSIGN(Int16, result, 0);
PTR_DEF_ASSIGN(Int16, operand1, 2);
PTR_DEF_ASSIGN(Int16, operand2, 4);
* result = *operand1 - *operand2 ;
pCode += 6;
break;
}
case PCIT::SUB_MBIN32S_MBIN32S_MBIN32S:
{
PTR_DEF_ASSIGN(Int32, result, 0);
PTR_DEF_ASSIGN(Int32, operand1, 2);
PTR_DEF_ASSIGN(Int32, operand2, 4);
* result = *operand1 - *operand2 ;
pCode += 6;
break;
}
case PCIT::SUB_MBIN64S_MBIN64S_MBIN64S:
{
PTR_DEF_ASSIGN(Int64, result, 0);
PTR_DEF_ASSIGN(Int64, xptr, 2);
PTR_DEF_ASSIGN(Int64, yptr, 4);
#if (!defined _DEBUG)
Int64 x = *xptr, y = *yptr;
Int64 z = x - y;
*result = z;
// Same check C/C++ compiler uses to check for overflow
if ((((UInt64)((x ^ y) & (x ^ z))) >> 63) == 0) {
}
else {
goto Error1_;
}
#else
* result = EXP_FIXED_OV_SUB( *xptr, *yptr, &ov);
if (ov)
{
goto Error1_;
}
#endif
pCode += 6;
break;
}
case PCIT::SUB_MBIN32S_MBIN16S_MBIN16S:
{
PTR_DEF_ASSIGN(Int32, result, 0);
PTR_DEF_ASSIGN(Int16, operand1, 2);
PTR_DEF_ASSIGN(Int16, operand2, 4);
* result = *operand1 - *operand2 ;
pCode += 6;
break;
}
case PCIT::SUB_MBIN32S_MBIN16S_MBIN32S:
{
PTR_DEF_ASSIGN(Int32, result, 0);
PTR_DEF_ASSIGN(Int16, operand1, 2);
PTR_DEF_ASSIGN(Int32, operand2, 4);
* result = *operand1 - *operand2 ;
pCode += 6;
break;
}
case PCIT::SUB_MBIN32S_MBIN32S_MBIN16S:
{
PTR_DEF_ASSIGN(Int32, result, 0);
PTR_DEF_ASSIGN(Int32, operand1, 2);
PTR_DEF_ASSIGN(Int16, operand2, 4);
* result = *operand1 - *operand2 ;
pCode += 6;
break;
}
case PCIT::MUL_MBIN16S_MBIN16S_MBIN16S:
{
PTR_DEF_ASSIGN(Int16, result, 0);
PTR_DEF_ASSIGN(Int16, operand1, 2);
PTR_DEF_ASSIGN(Int16, operand2, 4);
* result = *operand1 * *operand2 ;
pCode += 6;
break;
}
case PCIT::MUL_MBIN32S_MBIN32S_MBIN32S:
{
PTR_DEF_ASSIGN(Int32, result, 0);
PTR_DEF_ASSIGN(Int32, operand1, 2);
PTR_DEF_ASSIGN(Int32, operand2, 4);
* result = *operand1 * *operand2 ;
pCode += 6;
break;
}
case PCIT::MUL_MBIN64S_MBIN16S_MBIN32S:
{
PTR_DEF_ASSIGN(Int64, result, 0);
PTR_DEF_ASSIGN(Int16, operand1, 2);
PTR_DEF_ASSIGN(Int32, operand2, 4);
* result = (Int64) *operand1 * (Int64) *operand2 ;
pCode += 6;
break;
}
case PCIT::MUL_MBIN64S_MBIN32S_MBIN32S:
{
PTR_DEF_ASSIGN(Int64, result, 0);
PTR_DEF_ASSIGN(Int32, operand1, 2);
PTR_DEF_ASSIGN(Int32, operand2, 4);
* result = (Int64) *operand1 * (Int64) *operand2 ;
pCode += 6;
break;
}
case PCIT::MUL_MBIN64S_MBIN64S_MBIN64S:
{
PTR_DEF_ASSIGN(Int64, result, 0);
PTR_DEF_ASSIGN(Int64, xptr, 2);
PTR_DEF_ASSIGN(Int64, yptr, 4);
* result = EXP_FIXED_OV_MUL( *xptr, *yptr, &ov);
if (ov)
{
goto Error1_;
}
pCode += 6;
break;
}
case PCIT::MUL_MBIN32S_MBIN16S_MBIN16S:
{
PTR_DEF_ASSIGN(Int32, result, 0);
PTR_DEF_ASSIGN(Int16, operand1, 2);
PTR_DEF_ASSIGN(Int16, operand2, 4);
* result = *operand1 * *operand2 ;
pCode += 6;
break;
}
case PCIT::MUL_MBIN32S_MBIN16S_MBIN32S:
{
PTR_DEF_ASSIGN(Int32, result, 0);
PTR_DEF_ASSIGN(Int16, operand1, 2);
PTR_DEF_ASSIGN(Int32, operand2, 4);
* result = *operand1 * *operand2 ;
pCode += 6;
break;
}
case PCIT::DIV_MBIN64S_MBIN64S_MBIN64S:
{
PTR_DEF_ASSIGN(Int64, result, 0);
PTR_DEF_ASSIGN(Int64, xptr, 2);
PTR_DEF_ASSIGN(Int64, yptr, 4);
#if (!defined _DEBUG)
Int64 x = *xptr, y = *yptr;
// Same check C/C++ compiler uses to check for overflow
if (y != 0) {
if ((x != 0x8000000000000000LL) || (y != -1)) {
*result = x / y;
}
else {
goto Error1_;
}
}
else {
goto Error1_;
}
#else
if ( *yptr == 0 )
{// div by zero
goto Error1_;
}
* result = EXP_FIXED_OV_DIV( *xptr, *yptr, &ov);
if (ov)
{
goto Error1_;
}
#endif
pCode += 6;
break;
}
case PCIT::DIV_MBIN64S_MBIN64S_MBIN64S_ROUND:
{
PTR_DEF_ASSIGN(Int64, result, 0);
PTR_DEF_ASSIGN(Int64, xptr, 2);
PTR_DEF_ASSIGN(Int64, yptr, 4);
if ( *yptr == 0 )
{// div by zero
goto Error1_;
}
// upscale numerator by 1
NABoolean upscaled;
Int64 temp;
DEF_ASSIGN(Int32, bitmap, 6);
Lng32 roundingMode = (Lng32)(bitmap & 0x77);
NABoolean divToDownscale = ((bitmap & 0x100) != 0);
if (divToDownscale)
{
temp = *yptr / 10;
temp = *xptr / temp;
upscaled = TRUE;
}
else
{
temp = EXP_FIXED_OV_MUL( *xptr,
10, &ov);
if (ov)
{
// couldn't upscale. Use the original value and don't do
// any rounding.
upscaled = FALSE;
temp = * xptr;
}
else
{
upscaled = TRUE;
}
temp = EXP_FIXED_OV_DIV(temp,
*yptr,
&ov);
if (ov)
{
//division by zero
goto Error1_;
}
}
if (upscaled)
{
short nsign = 0; // indicates negative sign when set to 1.
// get the last digit
Lng32 v = (Lng32) (temp % (Int64)10);
if( v < 0 ) v = -v;
if(temp < 0) nsign = 1;
// downscale the result
temp = temp / (Int64)10;
if (roundingMode == 1)
{
// ROUND HALF UP MODE
if (v >= 5)
{
// round up the result by 1
temp = nsign ? temp-1 : temp+1;
}
}
else if (roundingMode == 2)
{
// ROUND HALF EVEN MODE
if (v > 5)
{
// round up the result by 1
temp = nsign ? temp-1 : temp+1;
}
else if (v == 5)
{
// Roundup 'w' only if all the trailing digits following
// 'v' is zero and 'w' is even. If 'w' is odd, irrespective
// of trailing digits following 'v', 'w' is rounded up.
// w is second last digit.
Lng32 w = (Lng32) (temp % (Int64)10);
if ((w & 0x1) != 0)
{
// odd number, round up.
temp = nsign ? temp-1 : temp+1;
}
else
{
// Since 'w' is an even digit, we need to determine if
// all the trailing digits following 'v' is zero.
// If any digit following 'v' is nonzero, then it is
// similar to v > 5.
NABoolean vGT5 = FALSE;
if(!divToDownscale)
{
//Figure out if digits following 'v' is non zero.
Int64 multiplier = 100;//For digit following 'v'.
Int64 temp1;
NABoolean biggerPrecision = FALSE;
while(!vGT5)
{
temp1 = EXP_FIXED_OV_MUL(*xptr, multiplier, &ov);
if (ov)
{
//end of digits.
// When we reach here, temp1 is overflowed over
// Int64. In this rare but possible situation,
// we should try checking
// for additional digits using BigNum datatype.
biggerPrecision = TRUE;
break;
}
temp1 = EXP_FIXED_OV_DIV(temp1, *yptr, &ov);
if (ov)
{
//Something went wrong, lets consider
//it as end of digits.
break;
}
if(temp1 % (Int64)10)
{
vGT5 = TRUE;
break;
}
multiplier = EXP_FIXED_OV_MUL(multiplier, 10, &ov);
if (ov)
{
//end of digits.
break;
}
}
if(biggerPrecision)
{
short rc = 0;
Int64 dividend = *xptr;
Int64 divisor = *yptr;
char *op_data[3];
char result1[100];
char result2[100];
Int64 result3 = 0;
Int64 ten = 10;
SimpleType opST(REC_BIN64_SIGNED, sizeof(Int64), 0, 0,
ExpTupleDesc::SQLMX_FORMAT,
8, 0, 0, 0, Attributes::NO_DEFAULT, 0);
BigNum opBN(16, 38, 0, 0);
while(!vGT5)
{
op_data[0] = result1;
op_data[1] = (char *) &dividend;
op_data[2] = (char *) &multiplier;
rc = EXP_FIXED_BIGN_OV_MUL(&opST,
&opST,
op_data);
if (rc)
{
//end of digits.
break;
}
op_data[0] = result2;
op_data[1] = result1;
op_data[2] = (char *) &divisor;
rc = EXP_FIXED_BIGN_OV_DIV(&opBN,
&opST,
op_data);
if (rc)
{
//Something went wrong, lets consider
//it as end of digits.
break;
}
op_data[0] = result2;
op_data[1] = (char *) &ten;
result3 = EXP_FIXED_BIGN_OV_MOD(&opBN,
&opST,
op_data,
&ov);
if (ov)
{
//end of digits.
break;
}
if(result3)
{
vGT5 = TRUE;
break;
}
multiplier = EXP_FIXED_OV_MUL(multiplier, 10, &ov);
if (ov)
{
//end of digits.
break;
}
}
}
}
else
{
Int64 divisor = 100;//divisor=10 corresponds to v digit.
Int64 temp1;
while(!vGT5)
{
temp1 = *yptr / divisor;
if(!temp1) //reached end of digits.
{
break;
}
temp1 = *xptr / temp1;
if(temp1 % (Int64)10)
{
vGT5 = TRUE;
break;
}
divisor = EXP_FIXED_OV_MUL(divisor, 10, &ov);
if (ov)
{
//end of digits.
break;
}
}
}
if(vGT5)
{
//irrespective of w being even number,
//round up the value;
temp = nsign ? temp-1 : temp+1;
}
}
}
}
}
* result = temp;
pCode += 7;
}
break;
// Sum of two nullable BIN32S. Do the null processing in this case
// and then fall through to the next case to handle the actual
// addition.
//
case PCIT::SUM_MATTR3_MATTR3_IBIN32S_MBIN32S_MBIN32S:
{
PTR_DEF_ASSIGN(char, nv1, 0);
DEF_ASSIGN(Int16, off1, 2);
PTR_DEF_ASSIGN(char, nv2, 3);
DEF_ASSIGN(Int16, off2, 5);
PTR_DEF_ASSIGN(Int32, target, 7);
if ( ExpTupleDesc::isNullValue( nv2, off2 ) )
{
pCode += 11;
break;
}
if ( ExpTupleDesc::isNullValue( nv1, off1 ) )
{
// Clear the target null bytes/bit ...
ExpTupleDesc::clearNullValue( nv1, off1 );
// Now set the target value to 0 so it can be used in the sum ...
* target = 0;
}
pCode += 7;
//
// Do NOT break here...
// The nulls have been processed above, so fall through to do the adding.
// These two cases belong together...
//
// Sum of two BIN32S. Assume that either the operands are not nullable
// or the null processing has been accomplished above. Sum the second
// operand to the first.
//
}
case PCIT::SUM_MBIN32S_MBIN32S:
{
PTR_DEF_ASSIGN(Int32, tgtPtr, 0 );
PTR_DEF_ASSIGN(Int32, operPtr, 2 );
* tgtPtr += *operPtr ;
pCode += 4;
break;
}
// Sum of two nullable BIN64S. Do the null processing in this case
// and then fall through to the next case to handle the actual
// addition.
//
case PCIT::SUM_MATTR3_MATTR3_IBIN32S_MBIN64S_MBIN64S:
{
PTR_DEF_ASSIGN(char, nv2, 3);
DEF_ASSIGN(Int16, off2, 5);
if ( ExpTupleDesc::isNullValue( nv2, off2 ) )
{
pCode += 11;
break;
}
PTR_DEF_ASSIGN(char, nv1, 0);
DEF_ASSIGN(Int16, off1, 2);
PTR_DEF_ASSIGN(Int64, target, 7);
if ( ExpTupleDesc::isNullValue( nv1, off1 ) )
{
// Clear the target null bytes/bit ...
ExpTupleDesc::clearNullValue( nv1, off1 );
// Now set the target value to 0 so it can be used in the sum ...
* target = 0;
}
pCode += 7;
//
// Do NOT break here...
// The nulls have been processed above, so fall through to do the adding.
// These two cases belong together...
//
// Sum of two BIN64S. Assume that either the operands are not nullable
// or the null processing has been accomplished above. Sum the second
// operand to the first. Check the result for overflow.
//
}
case PCIT::SUM_MBIN64S_MBIN64S:
{
PTR_DEF_ASSIGN(Int64, result, 0);
PTR_DEF_ASSIGN(Int64, yptr, 2);
//#if defined NA_YOS && !defined _DEBUG
Int64 y = *yptr;
Int64 x = *result;
Int64 z = x + y;
// Same check C/C++ compiler uses to check for overflow
if ((((UInt64)(~(x ^ y) & (x ^ z))) >> 63) == 0) {
*result = z;
} else {
goto Error1_;
}
pCode += 4;
break;
}
// Sum of a nullable BIN64S and BIN32S. Do the null processing in this
// case and then fall through to the next case to handle the actual
// addition.
//
case PCIT::SUM_MATTR3_MATTR3_IBIN32S_MBIN64S_MBIN32S:
{
PTR_DEF_ASSIGN(char, nv2, 3);
DEF_ASSIGN(Int16, off2, 5);
if ( ExpTupleDesc::isNullValue( nv2, off2 ) )
{
pCode += 11;
break;
}
PTR_DEF_ASSIGN(char, nv1, 0);
DEF_ASSIGN(Int16, off1, 2);
PTR_DEF_ASSIGN(Int64, target, 7);
if ( ExpTupleDesc::isNullValue( nv1, off1 ) )
{
// Clear the target null bytes/bit ...
ExpTupleDesc::clearNullValue( nv1, off1 );
// Now set the target value to 0 so it can be used in the sum ...
* target = 0;
}
pCode += 7;
//
// Do NOT break here...
// The nulls have been processed above, so fall through to do the adding.
// These two cases belong together...
//
// Sum of a BIN64S and BIN32S. Assume that either the operands are not
// nullable or the null processing has been accomplished above. Sum the
// second operand to the first. Check the result for overflow.
//
}
case PCIT::SUM_MBIN64S_MBIN32S:
{
PTR_DEF_ASSIGN(Int64, result, 0 );
PTR_DEF_ASSIGN(Int32, yptr, 2 );
#if (!defined _DEBUG)
Int32 y = *yptr;
Int64 x = *result;
Int64 z = x + (Int64)y;
// Same check C/C++ compiler uses to check for overflow
if ((((UInt64)(~(x ^ y) & (x ^ z))) >> 63) == 0) {
*result = z;
} else {
goto Error1_;
}
#else
Int64 op1 = * result;
Int64 theResult = EXP_FIXED_OV_ADD( op1, (Int64) *yptr, &ov);
if (ov)
{
goto Error1_;
}
* result = theResult;
#endif
pCode += 4;
break;
}
// Sum of two nullable FLT64. Do the null processing in this case
// and then fall through to the next case to handle the actual
// addition.
//
case PCIT::SUM_MATTR3_MATTR3_IBIN32S_MFLT64_MFLT64:
{
PTR_DEF_ASSIGN(char, nv2, 3);
DEF_ASSIGN(Int16, off2, 5);
if ( ExpTupleDesc::isNullValue( nv2, off2 ) )
{
pCode += 11;
break;
}
PTR_DEF_ASSIGN(char, nv1, 0);
DEF_ASSIGN(Int16, off1, 2);
if( ExpTupleDesc::isNullValue( nv1, off1 ) )
{
// Clear the target null bytes/bit ...
ExpTupleDesc::clearNullValue( nv1, off1 );
PTR_DEF_ASSIGN(Int64, target, 7);
// Now set the target value to 0 so it can be used in the sum ...
flt64_1 = 0;
* target = (Int64) flt64_1 ; // why not just use a simple zero ?
}
pCode += 7;
//
// Do NOT break here...
// The nulls have been processed above, so fall through to do the adding.
// These two cases belong together...
//
// Sum of two FLT64 ... assume that either the operands are not nullable
// or the null processing has been accomplished above. Sum the second
// operand to the first. Check the result for overflow.
//
}
case PCIT::SUM_MFLT64_MFLT64:
{
double flt64_0;
FLT64ASSIGN(&flt64_1, (stack[pCode[0]] + pCode[1]));
FLT64ASSIGN(&flt64_2, (stack[pCode[2]] + pCode[3]));
flt64_0 = flt64_1 + flt64_2;
if ((flt64_0 < -DBL_MAX) || (flt64_0 > DBL_MAX) ||
((flt64_0 != 0) && (flt64_0 < DBL_MIN) &&
(flt64_0 > -DBL_MIN)))
{
goto Error1_;
}
FLT64ASSIGN((stack[pCode[0]] + pCode[1]), &flt64_0);
pCode += 4;
break;
}
case PCIT::MINMAX_MBIN8_MBIN8_MBIN32S_IBIN32S:
if (*((Int32*)(stack[pCode[4]]+pCode[5])) == 1) // if TRUE
{
PTR_DEF_ASSIGN(char, target, 0 );
PTR_DEF_ASSIGN(char, source, 2 );
DEF_ASSIGN(Int32, length, 6 );
// make the current value the new min/max value
str_cpy_all( target, source, length );
}
pCode += 7;
break;
// A new PCode for hashing an 8 byte key (pCode[4] is ignored)
case PCIT::HASH_MBIN32U_MBIN64_IBIN32S_IBIN32S:
{
PTR_DEF_ASSIGN(UInt32, hashValuePtr, 0 );
PTR_DEF_ASSIGN(char, eightByteValPtr, 2 );
* hashValuePtr = ExHDPHash::hash8( eightByteValPtr, pCode[4]);
pCode += 6;
break;
}
case PCIT::HASH_MBIN32U_MBIN32_IBIN32S_IBIN32S:
{
PTR_DEF_ASSIGN(UInt32, hashValuePtr, 0 );
PTR_DEF_ASSIGN(char, fourByteValPtr, 2 );
* hashValuePtr = ExHDPHash::hash4( fourByteValPtr, pCode[4]);
pCode += 6;
break;
}
case PCIT::HASH_MBIN32U_MBIN16_IBIN32S_IBIN32S:
{
PTR_DEF_ASSIGN(UInt32, hashValuePtr, 0 );
PTR_DEF_ASSIGN(char, twoByteValPtr, 2 );
* hashValuePtr = ExHDPHash::hash2( twoByteValPtr, pCode[4]);
pCode += 6;
break;
}
case PCIT::HASH_MBIN32U_MPTR32_IBIN32S_IBIN32S:
{
PTR_DEF_ASSIGN(UInt32, hashValuePtr, 0 );
PTR_DEF_ASSIGN(char, dataPtr, 2 );
DEF_ASSIGN(UInt32, flags, 4 );
DEF_ASSIGN(Int32, length, 5 );
* hashValuePtr = ExHDPHash::hash( dataPtr, flags, length );
pCode += 6;
break;
}
// varchar hash function
case PCIT::HASH_MBIN32U_MUNIV:
case PCIT::HASH_MBIN32U_MATTR5:
{
DEF_ASSIGN(UInt32, offset, 3 );
DEF_ASSIGN(UInt32, voaOffset, 4 );
BASE_PTR_DEF_ASSIGN(char, data, 2 );
PTR_DEF_ASSIGN(UInt32, tgt, 0 );
DEF_ASSIGN(UInt32, len, 5 );
DEF_ASSIGN(Int32, comboLen, 6 );
char* comboPtr = (char*)&comboLen;
Int16 attrNullIndLen = (Int16)comboPtr[0];
Int16 attrVCIndLen = (Int16)comboPtr[1];
if (attrVCIndLen > 0) // this check may not be needed
{
offset = ExpTupleDesc::getVarOffset( data,
offset,
voaOffset,
attrVCIndLen,
attrNullIndLen );
len = ExpTupleDesc::getVarLength( data + offset,
attrVCIndLen );
offset += attrVCIndLen;
}
data += offset;
UInt32 flags = ExHDPHash::NO_FLAGS;
if (pCodeOpc == PCIT::HASH_MBIN32U_MUNIV)
{
flags = ExHDPHash::SWAP_TWO;
// skip trailing blanks
NAWchar* wstr = (NAWchar*)data;
len = len >> 1; // Divide len by 2 since unicode strs are dbl-bytes
while ((len > 0) && (wstr[len-1] == unicode_char_set::space_char()))
len--;
len = len << 1; // Shift back to length in bytes
}
else {
// skip trailing blanks
while ((len > 0) && (data[len-1] == ' '))
len--;
}
*tgt = ExHDPHash::hash(data, flags, len);
pCode += 7;
break;
}
case PCIT::FILL_MEM_BYTES:
{
PTR_DEF_ASSIGN(char, str, 0);
DEF_ASSIGN(Int32, length, 2);
DEF_ASSIGN(char, padchar, 3);
// for all fixed length fields
str_pad( str, length, padchar );
pCode += 4;
break;
}
case PCIT::FILL_MEM_BYTES_VARIABLE:
{
DEF_ASSIGN(Int32, comboLen1, 4 );
char* comboPtr1 = (char*)&comboLen1;
Int16 tgtNullIndLen = (Int16)comboPtr1[0];
Int16 tgtVCIndLen = (Int16)comboPtr1[1];
BASE_PTR_DEF_ASSIGN(char, tgt, 0 );
DEF_ASSIGN(Int32, tgtOffset, 1);
DEF_ASSIGN(Int32, tgtVoaOffset, 2);
DEF_ASSIGN(Int32, copyLen, 5);
DEF_ASSIGN(char, padchar, 6);
// VOA offsets should always be used in order.
if(tgtVoaOffset > 0) {
assert(tgtVoaOffset > lastVoaOffset);
lastVoaOffset = tgtVoaOffset;
}
tgt += ExpTupleDesc::getTgtVarOffset( tgt,
tgtOffset, // tgt offset
tgtVoaOffset, // tgt voa offset
tgtVCIndLen,
tgtNullIndLen,
varOffset,
copyLen
);
if (tgtVCIndLen > 0)
{
ExpTupleDesc::setVarLength(tgt, copyLen, tgtVCIndLen); // set variable length value
tgt += tgtVCIndLen;
}
if (copyLen > 0)
str_pad(tgt, copyLen, padchar );
pCode += 7;
break;
}
// EQUAL TO ("=") operations
case PCIT::EQ_MBIN32S_MASCII_MASCII:
// both are fixed chars
{
PTR_DEF_ASSIGN(Lng32, tgt, 0);
PTR_DEF_ASSIGN(unsigned char, src1, 2);
PTR_DEF_ASSIGN(unsigned char, src2, 4);
DEF_ASSIGN(Int32, length, 6);
*tgt = (src1[0] != src2[0]) ? 0 : (memcmp(src1, src2, length) == 0);
pCode += 7;
break;
}
case PCIT::COMP_MBIN32S_MUNI_MUNI_IBIN32S_IBIN32S_IBIN32S:
{
Int32 i;
PTR_DEF_ASSIGN(Lng32, res, 0 );
PTR_DEF_ASSIGN(NAWchar, src1, 2 );
PTR_DEF_ASSIGN(NAWchar, src2, 4 );
DEF_ASSIGN(Int32, src1Len, 6 );
DEF_ASSIGN(Int32, src2Len, 7 );
NABoolean diffLens = (src1Len != src2Len);
const Int32* table = compTable[pCode[8] - ITM_EQUAL];
// src1 is guaranteed to be smaller or equal in length to src2, so use
// its length with memcmp.
Int32 compCode = wc_str_cmp(src1, src2, src1Len) + 1;
if (diffLens && (compCode == 1)) {
NAWchar space = unicode_char_set::space_char();
for (i=src1Len; i < src2Len; i++) {
if (src2[i] == space)
continue;
compCode = (space < src2[i]) ? 0 : 2;
break;
}
}
*res = table[compCode];
pCode += 9;
break;
}
case PCIT::COMP_MBIN32S_MASCII_MASCII_IBIN32S_IBIN32S_IBIN32S:
{
Int32 i, compCode;
PTR_DEF_ASSIGN(Lng32, res, 0 );
PTR_DEF_ASSIGN(unsigned char, src1, 2 );
PTR_DEF_ASSIGN(unsigned char, src2, 4 );
DEF_ASSIGN(Int32, src1Len, 6 );
DEF_ASSIGN(Int32, src2Len, 7 );
NABoolean diffLens = (src1Len != src2Len);
// Set table pointer to appropriate position based on operation
const Int32* table = &(compTable[pCode[8] - ITM_EQUAL][1]);
// Quick first byte compare
if (src1[0] == src2[0]) {
// src1 is guaranteed to be smaller or equal in length to src2, so use
// its length with memcmp.
compCode = memcmp(src1, src2, src1Len);
// Fix compCode to -1, 0, or 1
if (compCode != 0) {
compCode = (compCode < 0) ? -1 : 1;
}
// If strings are equal so far and lengths are different, compare more
else if (diffLens && (compCode == 0)) {
for (i=src1Len; i < src2Len; i++) {
if (src2[i] == ' ')
continue;
compCode = (' ' < src2[i]) ? -1 : 1;
break;
}
}
}
else
compCode = (src1[0] < src2[0]) ? -1 : 1;
*res = table[compCode];
pCode += 9;
break;
}
case PCIT::COMP_MBIN32S_MUNIV_MUNIV_IBIN32S:
case PCIT::COMP_MBIN32S_MATTR5_MATTR5_IBIN32S:
{
PTR_DEF_ASSIGN(Int32, res, 0 );
// Set table pointer to appropriate position based on operation
const Int32* table = &(compTable[pCode[12] - ITM_EQUAL][1]);
UInt32 len1, len2;
Int32 compCode;
BASE_PTR_DEF_ASSIGN(char, src1Data, 2);
BASE_PTR_DEF_ASSIGN(char, src2Data, 7);
PTR_TO_PCODE(char, comboPtr1, 6);
PTR_TO_PCODE(char, comboPtr2, 11);
UInt32 src1VCIndLen = (Int32)comboPtr1[1];
UInt32 src2VCIndLen = (Int32)comboPtr2[1];
DEF_ASSIGN(UInt32, offset1, 3);
DEF_ASSIGN(UInt32, offset2, 8);
if( src1VCIndLen > 0 ) // varchar
{
DEF_ASSIGN(UInt32, voaOffset1, 4);
src1Data += ExpTupleDesc::getVarOffset(src1Data, // atp_
offset1,
voaOffset1,
src1VCIndLen, // vcIndLen
(Int32)comboPtr1[0]); // nullIndLen
len1 = ExpTupleDesc::getVarLength(src1Data, src1VCIndLen);
src1Data += src1VCIndLen;
}
else {
DEF_ASSIGN(UInt32, length1, 5);
src1Data += offset1;
len1 = length1;
}
if ( src2VCIndLen > 0 ) // varchar
{
DEF_ASSIGN(UInt32, voaOffset2, 9);
src2Data += ExpTupleDesc::getVarOffset(src2Data, // atp_
offset2,
voaOffset2,
src2VCIndLen, // vcIndLen
(Int32)comboPtr2[0]); // nullIndLen
len2 = ExpTupleDesc::getVarLength(src2Data, src2VCIndLen);
src2Data += src2VCIndLen;
}
else {
DEF_ASSIGN(UInt32, length2, 10);
src2Data += offset2;
len2 = length2;
}
if (pCodeOpc == PCIT::COMP_MBIN32S_MUNIV_MUNIV_IBIN32S)
{
compCode = wcharStringCompareWithPad(
(NAWchar*)(src1Data), len1 >> 1,
(NAWchar*)(src2Data), len2 >> 1,
unicode_char_set::space_char());
}
else
{
compCode = charStringCompareWithPad(src1Data, len1, src2Data, len2, ' ');
}
*res = table[compCode];
pCode += 13;
break;
}
case PCIT::EQ_MBIN32S_MBIN8S_MBIN8S:
{
PTR_DEF_ASSIGN(Int32, result, 0 );
PTR_DEF_ASSIGN(Int8, x, 2 );
PTR_DEF_ASSIGN(Int8, y, 4 );
*result = (*x == *y);
pCode += 6;
break;
}
case PCIT::NE_MBIN32S_MBIN8S_MBIN8S:
{
PTR_DEF_ASSIGN(Int32, result, 0 );
PTR_DEF_ASSIGN(Int8, x, 2 );
PTR_DEF_ASSIGN(Int8, y, 4 );
*result = (*x != *y);
pCode += 6;
break;
}
case PCIT::LT_MBIN32S_MBIN8S_MBIN8S:
{
PTR_DEF_ASSIGN(Int32, result, 0 );
PTR_DEF_ASSIGN(Int8, x, 2 );
PTR_DEF_ASSIGN(Int8, y, 4 );
*result = (*x < *y);
pCode += 6;
break;
}
case PCIT::GT_MBIN32S_MBIN8S_MBIN8S:
{
PTR_DEF_ASSIGN(Int32, result, 0 );
PTR_DEF_ASSIGN(Int8, x, 2 );
PTR_DEF_ASSIGN(Int8, y, 4 );
*result = (*x > *y);
pCode += 6;
break;
}
case PCIT::LE_MBIN32S_MBIN8S_MBIN8S:
{
PTR_DEF_ASSIGN(Int32, result, 0 );
PTR_DEF_ASSIGN(Int8, x, 2 );
PTR_DEF_ASSIGN(Int8, y, 4 );
*result = (*x <= *y);
pCode += 6;
break;
}
case PCIT::GE_MBIN32S_MBIN8S_MBIN8S:
{
PTR_DEF_ASSIGN(Int32, result, 0 );
PTR_DEF_ASSIGN(Int8, x, 2 );
PTR_DEF_ASSIGN(Int8, y, 4 );
*result = (*x >= *y);
pCode += 6;
break;
}
case PCIT::EQ_MBIN32S_MBIN8U_MBIN8U:
{
PTR_DEF_ASSIGN(Int32, result, 0 );
PTR_DEF_ASSIGN(UInt8, x, 2 );
PTR_DEF_ASSIGN(UInt8, y, 4 );
*result = (*x == *y);
pCode += 6;
break;
}
case PCIT::NE_MBIN32S_MBIN8U_MBIN8U:
{
PTR_DEF_ASSIGN(Int32, result, 0 );
PTR_DEF_ASSIGN(UInt8, x, 2 );
PTR_DEF_ASSIGN(UInt8, y, 4 );
*result = (*x != *y);
pCode += 6;
break;
}
case PCIT::LT_MBIN32S_MBIN8U_MBIN8U:
{
PTR_DEF_ASSIGN(Int32, result, 0 );
PTR_DEF_ASSIGN(UInt8, x, 2 );
PTR_DEF_ASSIGN(UInt8, y, 4 );
*result = (*x < *y);
pCode += 6;
break;
}
case PCIT::GT_MBIN32S_MBIN8U_MBIN8U:
{
PTR_DEF_ASSIGN(Int32, result, 0 );
PTR_DEF_ASSIGN(UInt8, x, 2 );
PTR_DEF_ASSIGN(UInt8, y, 4 );
*result = (*x > *y);
pCode += 6;
break;
}
case PCIT::LE_MBIN32S_MBIN8U_MBIN8U:
{
PTR_DEF_ASSIGN(Int32, result, 0 );
PTR_DEF_ASSIGN(UInt8, x, 2 );
PTR_DEF_ASSIGN(UInt8, y, 4 );
*result = (*x <= *y);
pCode += 6;
break;
}
case PCIT::GE_MBIN32S_MBIN8U_MBIN8U:
{
PTR_DEF_ASSIGN(Int32, result, 0 );
PTR_DEF_ASSIGN(UInt8, x, 2 );
PTR_DEF_ASSIGN(UInt8, y, 4 );
*result = (*x >= *y);
pCode += 6;
break;
}
case PCIT::EQ_MBIN32S_MBIN16U_MBIN16S:
{
PTR_DEF_ASSIGN(Int32, result, 0 );
PTR_DEF_ASSIGN(unsigned short, x, 2 );
PTR_DEF_ASSIGN(short, y, 4 );
*result = (*x == *y);
pCode += 6;
break;
}
case PCIT::EQ_MBIN32S_MBIN16S_MBIN16S:
{
PTR_DEF_ASSIGN(Int32, result, 0 );
PTR_DEF_ASSIGN(short, x, 2 );
PTR_DEF_ASSIGN(short, y, 4 );
*result = (*x == *y);
pCode += 6;
break;
}
case PCIT::EQ_MBIN32S_MBIN16S_MBIN32S:
{
PTR_DEF_ASSIGN(Int32, result, 0 );
PTR_DEF_ASSIGN(short, x, 2 );
PTR_DEF_ASSIGN(Int32, y, 4 );
*result = (*x == *y);
pCode += 6;
break;
}
case PCIT::EQ_MBIN32S_MBIN32S_MBIN32S:
{
PTR_DEF_ASSIGN(Int32, result, 0 );
PTR_DEF_ASSIGN(Int32, x, 2 );
PTR_DEF_ASSIGN(Int32, y, 4 );
*result = (*x == *y);
pCode += 6;
break;
}
case PCIT::EQ_MBIN32S_MBIN16U_MBIN16U:
{
PTR_DEF_ASSIGN(Int32, result, 0 );
PTR_DEF_ASSIGN(unsigned short, x, 2 );
PTR_DEF_ASSIGN(unsigned short, y, 4 );
*result = (*x == *y);
pCode += 6;
break;
}
case PCIT::EQ_MBIN32S_MBIN16U_MBIN32U:
{
PTR_DEF_ASSIGN(Int32, result, 0 );
PTR_DEF_ASSIGN(unsigned short, x, 2 );
PTR_DEF_ASSIGN(UInt32, y, 4 );
*result = (*x == *y);
pCode += 6;
break;
}
case PCIT::EQ_MBIN32S_MBIN32U_MBIN32U:
{
PTR_DEF_ASSIGN(Int32, result, 0 );
PTR_DEF_ASSIGN(UInt32, x, 2 );
PTR_DEF_ASSIGN(UInt32, y, 4 );
*result = (*x == *y);
pCode += 6;
break;
}
case PCIT::EQ_MBIN32S_MBIN16S_MBIN32U:
{
PTR_DEF_ASSIGN(Int32, result, 0 );
PTR_DEF_ASSIGN(short, x, 2 );
PTR_DEF_ASSIGN(UInt32, y, 4 );
//typecast x to Int64 to account for negetive values
*result = ((Int64)*x == *y);
pCode += 6;
break;
}
case PCIT::EQ_MBIN32S_MBIN64S_MBIN64S:
{
PTR_DEF_ASSIGN(Int32, result, 0 );
PTR_DEF_ASSIGN(Int64, x, 2 );
PTR_DEF_ASSIGN(Int64, y, 4 );
*result = (*x == *y);
pCode += 6;
break;
}
// LESS THAN ("<") operations
case PCIT::LT_MBIN32S_MASCII_MASCII: // both are fixed chars
{
PTR_DEF_ASSIGN(Lng32, tgt, 0 );
PTR_DEF_ASSIGN(unsigned char, src1, 2 );
PTR_DEF_ASSIGN(unsigned char, src2, 4 );
*tgt = (src1[0] > src2[0]) ? 0 : (memcmp(src1, src2, pCode[6]) < 0);
pCode += 7;
break;
}
case PCIT::LT_MBIN32S_MBIN16U_MBIN16S:
{
PTR_DEF_ASSIGN(Int32, result, 0 );
PTR_DEF_ASSIGN(unsigned short, x, 2 );
PTR_DEF_ASSIGN(short, y, 4 );
*result = (*x < *y);
pCode += 6;
break;
}
case PCIT::LT_MBIN32S_MBIN16S_MBIN16S:
{
PTR_DEF_ASSIGN(Int32, result, 0 );
PTR_DEF_ASSIGN(short, x, 2 );
PTR_DEF_ASSIGN(short, y, 4 );
*result = (*x < *y);
pCode += 6;
break;
}
case PCIT::LT_MBIN32S_MBIN16S_MBIN32S:
{
PTR_DEF_ASSIGN(Int32, result, 0 );
PTR_DEF_ASSIGN(short, x, 2 );
PTR_DEF_ASSIGN(Int32, y, 4 );
*result = (*x < *y);
pCode += 6;
break;
}
case PCIT::LT_MBIN32S_MBIN32S_MBIN32S:
{
PTR_DEF_ASSIGN(Int32, result, 0 );
PTR_DEF_ASSIGN(Int32, x, 2 );
PTR_DEF_ASSIGN(Int32, y, 4 );
*result = (*x < *y);
pCode += 6;
break;
}
case PCIT::LT_MBIN32S_MBIN16U_MBIN16U:
{
PTR_DEF_ASSIGN(Int32, result, 0 );
PTR_DEF_ASSIGN(unsigned short, x, 2 );
PTR_DEF_ASSIGN(unsigned short, y, 4 );
*result = (*x < *y);
pCode += 6;
break;
}
case PCIT::LT_MBIN32S_MBIN16U_MBIN32U:
{
PTR_DEF_ASSIGN(Int32, result, 0 );
PTR_DEF_ASSIGN(unsigned short, x, 2 );
PTR_DEF_ASSIGN(UInt32, y, 4 );
*result = (*x < *y);
pCode += 6;
break;
}
case PCIT::LT_MBIN32S_MBIN32U_MBIN32U:
{
PTR_DEF_ASSIGN(Int32, result, 0 );
PTR_DEF_ASSIGN(UInt32, x, 2 );
PTR_DEF_ASSIGN(UInt32, y, 4 );
*result = (*x < *y);
pCode += 6;
break;
}
case PCIT::LT_MBIN32S_MBIN16S_MBIN32U:
{
PTR_DEF_ASSIGN(Int32, result, 0 );
PTR_DEF_ASSIGN(short, x, 2 );
PTR_DEF_ASSIGN(UInt32, y, 4 );
//typecast x to Int64 to account for negetive values
*result = ((Int64)*x < *y);
pCode += 6;
break;
}
case PCIT::LT_MBIN32S_MBIN64S_MBIN64S:
{
PTR_DEF_ASSIGN(Int32, result, 0 );
PTR_DEF_ASSIGN(Int64, x, 2 );
PTR_DEF_ASSIGN(Int64, y, 4 );
*result = (*x < *y);
pCode += 6;
break;
}
// GREATER THAN (">") operations
case PCIT::GT_MBIN32S_MASCII_MASCII: // both are fixed chars
{
PTR_DEF_ASSIGN(Lng32, tgt, 0 );
PTR_DEF_ASSIGN(unsigned char, src1, 2 );
PTR_DEF_ASSIGN(unsigned char, src2, 4 );
*tgt = (src1[0] < src2[0]) ? 0 : (memcmp(src1, src2, pCode[6]) > 0);
pCode += 7;
break;
}
case PCIT::GT_MBIN32S_MBIN16U_MBIN16S:
{
PTR_DEF_ASSIGN(Int32, result, 0 );
PTR_DEF_ASSIGN(unsigned short, x, 2 );
PTR_DEF_ASSIGN(short, y, 4 );
*result = (*x > *y);
pCode += 6;
break;
}
case PCIT::GT_MBIN32S_MBIN16S_MBIN16S:
{
PTR_DEF_ASSIGN(Int32, result, 0 );
PTR_DEF_ASSIGN(short, x, 2 );
PTR_DEF_ASSIGN(short, y, 4 );
*result = (*x > *y);
pCode += 6;
break;
}
case PCIT::GT_MBIN32S_MBIN16S_MBIN32S:
{
PTR_DEF_ASSIGN(Int32, result, 0 );
PTR_DEF_ASSIGN(short, x, 2 );
PTR_DEF_ASSIGN(Int32, y, 4 );
*result = (*x > *y);
pCode += 6;
break;
}
case PCIT::GT_MBIN32S_MBIN32S_MBIN32S:
{
PTR_DEF_ASSIGN(Int32, result, 0 );
PTR_DEF_ASSIGN(Int32, x, 2 );
PTR_DEF_ASSIGN(Int32, y, 4 );
*result = (*x > *y);
pCode += 6;
break;
}
case PCIT::GT_MBIN32S_MBIN16U_MBIN16U:
{
PTR_DEF_ASSIGN(Int32, result, 0 );
PTR_DEF_ASSIGN(unsigned short, x, 2 );
PTR_DEF_ASSIGN(unsigned short, y, 4 );
*result = (*x > *y);
pCode += 6;
break;
}
case PCIT::GT_MBIN32S_MBIN16U_MBIN32U:
{
PTR_DEF_ASSIGN(Int32, result, 0 );
PTR_DEF_ASSIGN(unsigned short, x, 2 );
PTR_DEF_ASSIGN(UInt32, y, 4 );
*result = (*x > *y);
pCode += 6;
break;
}
case PCIT::GT_MBIN32S_MBIN32U_MBIN32U:
{
PTR_DEF_ASSIGN(Int32, result, 0 );
PTR_DEF_ASSIGN(UInt32, x, 2 );
PTR_DEF_ASSIGN(UInt32, y, 4 );
*result = (*x > *y);
pCode += 6;
break;
}
case PCIT::GT_MBIN32S_MBIN16S_MBIN32U:
{
PTR_DEF_ASSIGN(Int32, result, 0 );
PTR_DEF_ASSIGN(short, x, 2 );
PTR_DEF_ASSIGN(UInt32, y, 4 );
//typecast x to Int64 to account for negetive values
*result = ((Int64)*x > *y);
pCode += 6;
break;
}
case PCIT::GT_MBIN32S_MBIN64S_MBIN64S:
{
PTR_DEF_ASSIGN(Int32, result, 0 );
PTR_DEF_ASSIGN(Int64, x, 2 );
PTR_DEF_ASSIGN(Int64, y, 4 );
*result = (*x > *y);
pCode += 6;
break;
}
// LESS THAN EQUAL TO("<=") operations
case PCIT::LE_MBIN32S_MASCII_MASCII: // both are fixed chars
{
PTR_DEF_ASSIGN(Lng32, tgt, 0 );
PTR_DEF_ASSIGN(unsigned char, src1, 2 );
PTR_DEF_ASSIGN(unsigned char, src2, 4 );
*tgt = (src1[0] > src2[0]) ? 0 : (memcmp(src1, src2, pCode[6]) <= 0);
pCode += 7;
break;
}
case PCIT::LE_MBIN32S_MBIN16U_MBIN16S:
{
PTR_DEF_ASSIGN(Int32, result, 0 );
PTR_DEF_ASSIGN(unsigned short, x, 2 );
PTR_DEF_ASSIGN(short, y, 4 );
*result = (*x <= *y);
pCode += 6;
break;
}
case PCIT::LE_MBIN32S_MBIN16S_MBIN16S:
{
PTR_DEF_ASSIGN(Int32, result, 0 );
PTR_DEF_ASSIGN(short, x, 2 );
PTR_DEF_ASSIGN(short, y, 4 );
*result = (*x <= *y);
pCode += 6;
break;
}
case PCIT::LE_MBIN32S_MBIN16S_MBIN32S:
{
PTR_DEF_ASSIGN(Int32, result, 0 );
PTR_DEF_ASSIGN(short, x, 2 );
PTR_DEF_ASSIGN(Int32, y, 4 );
*result = (*x <= *y);
pCode += 6;
break;
}
case PCIT::LE_MBIN32S_MBIN32S_MBIN32S:
{
PTR_DEF_ASSIGN(Int32, result, 0 );
PTR_DEF_ASSIGN(Int32, x, 2 );
PTR_DEF_ASSIGN(Int32, y, 4 );
*result = (*x <= *y);
pCode += 6;
break;
}
case PCIT::LE_MBIN32S_MBIN16U_MBIN16U:
{
PTR_DEF_ASSIGN(Int32, result, 0 );
PTR_DEF_ASSIGN(unsigned short, x, 2 );
PTR_DEF_ASSIGN(unsigned short, y, 4 );
*result = (*x <= *y);
pCode += 6;
break;
}
case PCIT::LE_MBIN32S_MBIN16U_MBIN32U:
{
PTR_DEF_ASSIGN(Int32, result, 0 );
PTR_DEF_ASSIGN(unsigned short, x, 2 );
PTR_DEF_ASSIGN(UInt32, y, 4 );
*result = (*x <= *y);
pCode += 6;
break;
}
case PCIT::LE_MBIN32S_MBIN32U_MBIN32U:
{
PTR_DEF_ASSIGN(Int32, result, 0 );
PTR_DEF_ASSIGN(UInt32, x, 2 );
PTR_DEF_ASSIGN(UInt32, y, 4 );
*result = (*x <= *y);
pCode += 6;
break;
}
case PCIT::LE_MBIN32S_MBIN16S_MBIN32U:
{
PTR_DEF_ASSIGN(Int32, result, 0 );
PTR_DEF_ASSIGN(short, x, 2 );
PTR_DEF_ASSIGN(UInt32, y, 4 );
//typecast x to Int64 to account for negetive values
*result = ((Int64)*x <= *y);
pCode += 6;
break;
}
case PCIT::LE_MBIN32S_MBIN64S_MBIN64S:
{
PTR_DEF_ASSIGN(Int32, result, 0 );
PTR_DEF_ASSIGN(Int64, x, 2 );
PTR_DEF_ASSIGN(Int64, y, 4 );
*result = (*x <= *y);
pCode += 6;
break;
}
// GREATER THAN EQUAL TO (">=") operations
case PCIT::GE_MBIN32S_MASCII_MASCII: // both are fixed chars
{
PTR_DEF_ASSIGN(Lng32, tgt, 0 );
PTR_DEF_ASSIGN(unsigned char, src1, 2 );
PTR_DEF_ASSIGN(unsigned char, src2, 4 );
*tgt = (src1[0] < src2[0]) ? 0 : (memcmp(src1, src2, pCode[6]) >= 0);
pCode += 7;
break;
}
case PCIT::GE_MBIN32S_MBIN16U_MBIN16S:
{
PTR_DEF_ASSIGN(Int32, result, 0 );
PTR_DEF_ASSIGN(unsigned short, x, 2 );
PTR_DEF_ASSIGN(short, y, 4 );
*result = (*x >= *y);
pCode += 6;
break;
}
case PCIT::GE_MBIN32S_MBIN16S_MBIN16S:
{
PTR_DEF_ASSIGN(Int32, result, 0 );
PTR_DEF_ASSIGN(short, x, 2 );
PTR_DEF_ASSIGN(short, y, 4 );
*result = (*x >= *y);
pCode += 6;
break;
}
case PCIT::GE_MBIN32S_MBIN16S_MBIN32S:
{
PTR_DEF_ASSIGN(Int32, result, 0 );
PTR_DEF_ASSIGN(short, x, 2 );
PTR_DEF_ASSIGN(Int32, y, 4 );
*result = (*x >= *y);
pCode += 6;
break;
}
case PCIT::GE_MBIN32S_MBIN32S_MBIN32S:
{
PTR_DEF_ASSIGN(Int32, result, 0 );
PTR_DEF_ASSIGN(Int32, x, 2 );
PTR_DEF_ASSIGN(Int32, y, 4 );
*result = (*x >= *y);
pCode += 6;
break;
}
case PCIT::GE_MBIN32S_MBIN16U_MBIN16U:
{
PTR_DEF_ASSIGN(Int32, result, 0 );
PTR_DEF_ASSIGN(unsigned short, x, 2 );
PTR_DEF_ASSIGN(unsigned short, y, 4 );
*result = (*x >= *y);
pCode += 6;
break;
}
case PCIT::GE_MBIN32S_MBIN16U_MBIN32U:
{
PTR_DEF_ASSIGN(Int32, result, 0 );
PTR_DEF_ASSIGN(unsigned short, x, 2 );
PTR_DEF_ASSIGN(UInt32, y, 4 );
*result = (*x >= *y);
pCode += 6;
break;
}
case PCIT::GE_MBIN32S_MBIN32U_MBIN32U:
{
PTR_DEF_ASSIGN(Int32, result, 0 );
PTR_DEF_ASSIGN(UInt32, x, 2 );
PTR_DEF_ASSIGN(UInt32, y, 4 );
*result = (*x >= *y);
pCode += 6;
break;
}
case PCIT::GE_MBIN32S_MBIN16S_MBIN32U:
{
PTR_DEF_ASSIGN(Int32, result, 0 );
PTR_DEF_ASSIGN(short, x, 2 );
PTR_DEF_ASSIGN(UInt32, y, 4 );
//typecast x to Int64 to account for negetive values
*result = ((Int64)*x >= *y);
pCode += 6;
break;
}
case PCIT::GE_MBIN32S_MBIN64S_MBIN64S:
{
PTR_DEF_ASSIGN(Int32, result, 0 );
PTR_DEF_ASSIGN(Int64, x, 2 );
PTR_DEF_ASSIGN(Int64, y, 4 );
*result = (*x >= *y);
pCode += 6;
break;
}
// NOT EQUAL TO ("<>") operations
case PCIT::NE_MBIN32S_MASCII_MASCII: // both are fixed chars
{
PTR_DEF_ASSIGN(Lng32, tgt, 0 );
PTR_DEF_ASSIGN(unsigned char, src1, 2 );
PTR_DEF_ASSIGN(unsigned char, src2, 4 );
*tgt = (src1[0] != src2[0]) ? 1 : (memcmp(src1, src2, pCode[6]) != 0);
pCode += 7;
break;
}
case PCIT::NE_MBIN32S_MBIN64S_MBIN64S:
{
PTR_DEF_ASSIGN(Int32, result, 0 );
PTR_DEF_ASSIGN(Int64, x, 2 );
PTR_DEF_ASSIGN(Int64, y, 4 );
*result = (*x != *y);
pCode += 6;
break;
}
case PCIT::NE_MBIN32S_MBIN16S_MBIN16S:
{
PTR_DEF_ASSIGN(Int32, result, 0 );
PTR_DEF_ASSIGN(short, x, 2 );
PTR_DEF_ASSIGN(short, y, 4 );
*result = (*x != *y);
pCode += 6;
break;
}
// EQUAL TO ZERO operations
case PCIT::ZERO_MBIN32S_MBIN32U:
{
PTR_DEF_ASSIGN(Int32, result, 0 );
PTR_DEF_ASSIGN(UInt32, x, 2 );
*result = (*x == 0);
break;
}
// NOT EQUAL TO ZERO operations
case PCIT::NOTZERO_MBIN32S_MBIN32U:
{
PTR_DEF_ASSIGN(Int32, result, 0 );
PTR_DEF_ASSIGN(UInt32, x, 2 );
*result = (*x != 0);
break;
}
case PCIT::AND_MBIN32S_MBIN32S_MBIN32S:
{
PTR_DEF_ASSIGN(Int32, resultPtr, 0 );
PTR_DEF_ASSIGN(Int32, opAPtr, 2 );
PTR_DEF_ASSIGN(Int32, opBPtr, 4 );
* resultPtr = *opAPtr & *opBPtr ? *opAPtr | *opBPtr : 0 ;
pCode += 6;
}
break;
case PCIT::OR_MBIN32S_MBIN32S_MBIN32S:
{
PTR_DEF_ASSIGN(Int32, resultPtr, 0 );
PTR_DEF_ASSIGN(Int32, opAPtr, 2 );
PTR_DEF_ASSIGN(Int32, opBPtr, 4 );
* resultPtr = *opAPtr == 1 || *opBPtr == 1 ? 1 : *opAPtr | *opBPtr ;
pCode += 6;
}
break;
case PCIT::MOD_MBIN32S_MBIN32S_MBIN32S:
{
PTR_DEF_ASSIGN(Int32, resultPtr, 0 );
PTR_DEF_ASSIGN(Int32, opAPtr, 2 );
PTR_DEF_ASSIGN(Int32, opBPtr, 4 );
* resultPtr = *opAPtr % *opBPtr ;
pCode += 6;
break;
}
case PCIT::MOD_MBIN32U_MBIN32U_MBIN32S:
{
PTR_DEF_ASSIGN(UInt32, resultPtr, 0 );
PTR_DEF_ASSIGN(UInt32, opAPtr, 2 );
PTR_DEF_ASSIGN(Int32, opBPtr, 4 );
* resultPtr = *opAPtr % *opBPtr ;
pCode += 6;
break;
}
case PCIT::HASHCOMB_MBIN32U_MBIN32U_MBIN32U:
{
PTR_DEF_ASSIGN(UInt32, tgtPtr, 0 );
PTR_DEF_ASSIGN(UInt32, src1Ptr, 2 );
PTR_DEF_ASSIGN(UInt32, src2Ptr, 4 );
*tgtPtr = ( *src1Ptr << 1 | *src1Ptr >> 31 ) ^ *src2Ptr;
pCode += 6;
break;
}
case PCIT::ENCODE_MASCII_MBIN8S_IBIN32S:
{
PTR_DEF_ASSIGN(Int8, outputPtr, 0 );
PTR_DEF_ASSIGN(Int8, resultPtr, 2 );
DEF_ASSIGN(Int32, bitwiseNOT, 4 );
Int8 result = *resultPtr;
result ^= 0x80;
if ( bitwiseNOT )
result = ~result;
* outputPtr = result ;
pCode += 5;
}
break;
case PCIT::ENCODE_MASCII_MBIN8U_IBIN32S:
{
PTR_DEF_ASSIGN(Int8, outputPtr, 0 );
PTR_DEF_ASSIGN(Int8, resultPtr, 2 );
DEF_ASSIGN(Int32, bitwiseNOT , 4 );
UInt8 result = *resultPtr;
if ( bitwiseNOT )
result = ~result;
* outputPtr = result ;
pCode += 5;
}
break;
case PCIT::ENCODE_MASCII_MBIN16S_IBIN32S:
{
PTR_DEF_ASSIGN(Int16, outputPtr, 0 );
PTR_DEF_ASSIGN(Int16, resultPtr, 2 );
DEF_ASSIGN(Int32, bitwiseNOT , 4 );
Int16 result = *resultPtr;
result ^= 0x8000;
#ifdef NA_LITTLE_ENDIAN
result = reversebytes((UInt16)result);
#endif // NA_LITTLE_ENDIAN
if ( bitwiseNOT ) result = ~result;
* outputPtr = result ;
pCode += 5;
}
break;
case PCIT::ENCODE_MASCII_MBIN16U_IBIN32S:
{
PTR_DEF_ASSIGN(Int16, outputPtr, 0 );
PTR_DEF_ASSIGN(Int16, resultPtr, 2 );
DEF_ASSIGN(Int32, bitwiseNOT , 4 );
Int16 result = *resultPtr;
#ifdef NA_LITTLE_ENDIAN
result = reversebytes((UInt16)result);
#endif // NA_LITTLE_ENDIAN
if ( bitwiseNOT ) result = ~result;
* outputPtr = result ;
pCode += 5;
}
break;
case PCIT::ENCODE_MASCII_MBIN32S_IBIN32S:
{
PTR_DEF_ASSIGN(Int32, outputPtr, 0 );
PTR_DEF_ASSIGN(Int32, resultPtr, 2 );
DEF_ASSIGN(Int32, bitwiseNOT , 4 );
Int32 result = *resultPtr;
result ^= 0x80000000;
#ifdef NA_LITTLE_ENDIAN
result = reversebytes((UInt32)result);
#endif // NA_LITTLE_ENDIAN
if ( bitwiseNOT ) result = ~result;
* outputPtr = result ;
pCode += 5;
}
break;
case PCIT::ENCODE_MASCII_MBIN32U_IBIN32S:
{
PTR_DEF_ASSIGN(Int32, outputPtr, 0 );
PTR_DEF_ASSIGN(Int32, resultPtr, 2 );
DEF_ASSIGN(Int32, bitwiseNOT , 4 );
Int32 result = *resultPtr;
#ifdef NA_LITTLE_ENDIAN
result = reversebytes((UInt32)result);
#endif // NA_LITTLE_ENDIAN
if ( bitwiseNOT ) result = ~result;
* outputPtr = result ;
pCode += 5;
}
break;
case PCIT::ENCODE_MASCII_MBIN64S_IBIN32S:
{
PTR_DEF_ASSIGN(Int64, outputPtr, 0 );
PTR_DEF_ASSIGN(Int64, resultPtr, 2 );
DEF_ASSIGN(Int32, bitwiseNOT , 4 );
Int64 result = *resultPtr;
result ^= 0x8000000000000000LL;
#ifdef NA_LITTLE_ENDIAN
result = reversebytes(result);
#endif // NA_LITTLE_ENDIAN
if ( bitwiseNOT ) result = ~result;
* outputPtr = result ;
pCode += 5;
}
break;
case PCIT::ENCODE_NXX:
{
PTR_DEF_ASSIGN(char, tgt, 0 );
PTR_DEF_ASSIGN(char, src, 2 );
DEF_ASSIGN(Int32, length, 4 );
DEF_ASSIGN(Int32, desc, 5 );
if ( desc )
{
for (Int32 k = 0; k < length; k++)
tgt[k] = (char)(~(src[k]));
}
else
{
str_cpy_all( tgt, src, length );
}
pCode += 6;
}
break;
case PCIT::ENCODE_DECS:
{
PTR_DEF_ASSIGN(char, tgt, 0 );
PTR_DEF_ASSIGN(char, src, 2 );
DEF_ASSIGN(Int32, length, 4 );
DEF_ASSIGN(Int32, desc, 5 );
if (src[0] & 0200) // negative
{
if ( desc )
{
str_cpy_all(tgt, src, length );
}
else
{
for (Int32 k = 0; k < length; k++)
tgt[k] = (char)(~(src[k]));
}
}
else // positive
{
if ( desc )
{
str_cpy_all(tgt, src, length );
tgt[0] = (char)(~(src[0] | 0200));
for (Int32 k = 1; k < length; k++)
tgt[k] = (char)(~(tgt[k]));
}
else
{
str_cpy_all(tgt, src, length );
tgt[0] |= 0200;
}
}
pCode += 6;
}
break;
case PCIT::DECODE_MASCII_MBIN16S_IBIN32S:
{
PTR_DEF_ASSIGN(Int16, outputPtr, 0 );
PTR_DEF_ASSIGN(Int16, resultPtr, 2 );
DEF_ASSIGN(Int32, bitwiseNOT , 4 );
Int16 result = *resultPtr;
if ( bitwiseNOT ) result = ~result;
#ifdef NA_LITTLE_ENDIAN
result = reversebytes((UInt16)result);
#endif // NA_LITTLE_ENDIAN
result ^= 0x8000;
* outputPtr = result ;
pCode += 5;
}
break;
case PCIT::DECODE_MASCII_MBIN16U_IBIN32S:
{
PTR_DEF_ASSIGN(Int16, outputPtr, 0 );
PTR_DEF_ASSIGN(Int16, resultPtr, 2 );
DEF_ASSIGN(Int32, bitwiseNOT , 4 );
Int16 result = *resultPtr;
if ( bitwiseNOT ) result = ~result;
#ifdef NA_LITTLE_ENDIAN
result = reversebytes((UInt16)result);
#endif // NA_LITTLE_ENDIAN
* outputPtr = result ;
pCode += 5;
}
break;
case PCIT::DECODE_MASCII_MBIN32S_IBIN32S:
{
PTR_DEF_ASSIGN(Int32, outputPtr, 0 );
PTR_DEF_ASSIGN(Int32, resultPtr, 2 );
DEF_ASSIGN(Int32, bitwiseNOT , 4 );
Int32 result = *resultPtr;
if ( bitwiseNOT ) result = ~result;
#ifdef NA_LITTLE_ENDIAN
result = reversebytes((UInt32)result);
#endif // NA_LITTLE_ENDIAN
result ^= 0x80000000;
* outputPtr = result ;
pCode += 5;
}
break;
case PCIT::DECODE_MASCII_MBIN32U_IBIN32S:
{
PTR_DEF_ASSIGN(Int32, outputPtr, 0 );
PTR_DEF_ASSIGN(Int32, resultPtr, 2 );
DEF_ASSIGN(Int32, bitwiseNOT , 4 );
Int32 result = *resultPtr;
if ( bitwiseNOT ) result = ~result;
#ifdef NA_LITTLE_ENDIAN
result = reversebytes((UInt32)result);
#endif // NA_LITTLE_ENDIAN
* outputPtr = result ;
pCode += 5;
}
break;
case PCIT::DECODE_MASCII_MBIN64S_IBIN32S:
{
PTR_DEF_ASSIGN(Int64, outputPtr, 0 );
PTR_DEF_ASSIGN(Int64, resultPtr, 2 );
DEF_ASSIGN(Int32, bitwiseNOT , 4 );
Int64 result = *resultPtr;
if ( bitwiseNOT ) result = ~result;
#ifdef NA_LITTLE_ENDIAN
result = reversebytes(result);
#endif // NA_LITTLE_ENDIAN
result ^= 0x8000000000000000LL;
* outputPtr = result ;
pCode += 5;
}
break;
case PCIT::DECODE_NXX:
{
PTR_DEF_ASSIGN(char, tgt, 0 );
PTR_DEF_ASSIGN(char, src, 2 );
DEF_ASSIGN(Int32, length, 4 );
DEF_ASSIGN(Int32, desc, 5 );
if ( desc )
{
for (Int32 k = 0; k < length; k++)
tgt[k] = (char)(~(src[k]));
}
else
{
str_cpy_all( tgt, src, length );
}
pCode += 6;
}
break;
case PCIT::DECODE_DECS:
{
PTR_DEF_ASSIGN(char, tgt, 0 );
PTR_DEF_ASSIGN(char, src, 2 );
DEF_ASSIGN(Int32, length, 4 );
DEF_ASSIGN(Int32, desc, 5 );
if (desc)
{
for (Int32 k = 0; k < length; k++)
tgt[k] = (char)(~(src[k]));
}
if (NOT(src[0] & 0200))
{
for (Lng32 i = 0; i < length; i++)
tgt[i] = ~src[i];
}
else
{
if (tgt != src)
str_cpy_all(tgt, src, length);
tgt[0] &= ~0200;
}
pCode += 6;
}
break;
case PCIT::BRANCH_INDIRECT_MBIN32S:
{
PTR_DEF_ASSIGN(Int32, srcPtr, 0 );
pCode += (Int64)*srcPtr;
break;
}
case PCIT::BRANCH:
{
DEF_ASSIGN(Int64, branchOffset, 0 );
pCode += branchOffset ;
break;
}
case PCIT::BRANCH_AND:
{
// on 64-bit the first 2 operands are pointers
PTR_DEF_ASSIGN(Int32, tgtPtr, 2 * PCODEBINARIES_PER_PTR );
PTR_DEF_ASSIGN(Int32, srcPtr, 2 + 2 * PCODEBINARIES_PER_PTR );
Int32 src = *srcPtr;
if (src == 0)
{
DEF_ASSIGN_PTR(Int64, branchOffset, 0 );
*tgtPtr = 0;
pCode += branchOffset;
}
else
{
* tgtPtr = src ;
pCode += 4 + PCODEBINARIES_PER_PTR + PCODEBINARIES_PER_PTR;
}
}
break;
case PCIT::BRANCH_AND_CNT:
{
PTR_DEF_ASSIGN(Int32, tgtPtr, 2 );
PTR_DEF_ASSIGN(Int32, srcPtr, 4 );
Int32 src = *srcPtr;
// Increment seen counter
pCode[6]++;
// Enable runtime opts if seen count equals trigger count
enableRuntimeOpts = enableRuntimeOpts | (pCode[6] == pCode[1]);
if (src == 0)
{
DEF_ASSIGN(Int64, branchOffset, 0 );
pCode[7]++; // Increment taken count
* tgtPtr = 0;
pCode += branchOffset;
}
else
{
* tgtPtr = src;
pCode += 8;
}
}
break;
case PCIT::BRANCH_OR:
{
// on 64-bit the first 2 operands are pointers
PTR_DEF_ASSIGN(Int32, tgtPtr, 2 * PCODEBINARIES_PER_PTR );
PTR_DEF_ASSIGN(Int32, srcPtr, 2 + 2 * PCODEBINARIES_PER_PTR );
Int32 src = *srcPtr;
if (src == 1)
{
DEF_ASSIGN_PTR(Int64, branchOffset, 0 );
* tgtPtr = 1;
pCode += branchOffset;
}
else
{
* tgtPtr = src ;
pCode += 4 + 2 * PCODEBINARIES_PER_PTR;
}
}
break;
case PCIT::BRANCH_OR_CNT:
{
PTR_DEF_ASSIGN(Int32, tgtPtr, 2 );
PTR_DEF_ASSIGN(Int32, srcPtr, 4 );
Int32 src = *srcPtr;
// Increment seen counter
pCode[6]++;
// Enable runtime opts if seen count equals trigger count
enableRuntimeOpts = enableRuntimeOpts | (pCode[6] == pCode[1]);
if (src == 1)
{
DEF_ASSIGN(Int64, branchOffset, 0 );
pCode[7]++; // Increment taken count
* tgtPtr = 1;
pCode += branchOffset;
}
else
{
* tgtPtr = src;
pCode += 8;
}
}
break;
case PCIT::RANGE_LOW_S64S64:
{
DEF_ASSIGN(Lng32, op, RANGE_INST_LEN ); // the next op
PTR_DEF_ASSIGN(Int64, valPtr, 0 );
PTR_TO_PCODE(Int64, minvalPtr, 2 );
if ( *valPtr < *minvalPtr )
{
goto Error1_;
}
pCode += RANGE_INST_LEN;
if (op != PCIT::RANGE_HIGH_S64S64) {
break;
}
pCode++;
//
// Do NOT break here...
// The next instruction is a matching RANGE_HIGH
}
case PCIT::RANGE_HIGH_S64S64:
{
PTR_DEF_ASSIGN(Int64, valPtr, 0 );
PTR_TO_PCODE(Int64, maxvalPtr, 2 );
if ( *valPtr > *maxvalPtr )
{
goto Error1_;
}
pCode += RANGE_INST_LEN;
break;
}
case PCIT::RANGE_LOW_S32S64:
{
DEF_ASSIGN(Lng32, op, RANGE_INST_LEN ); // the next op
PTR_DEF_ASSIGN(Int32, valPtr, 0 );
PTR_TO_PCODE(Int64, minvalPtr, 2 );
if ( *valPtr < *minvalPtr )
{
goto Error1_;
}
pCode += RANGE_INST_LEN;
if (op != PCIT::RANGE_HIGH_S32S64) {
break;
}
pCode++;
//
// Do NOT break here...
// The next instruction is a matching RANGE_HIGH
}
case PCIT::RANGE_HIGH_S32S64:
{
PTR_DEF_ASSIGN(Int32, valPtr, 0 );
PTR_TO_PCODE(Int64, maxvalPtr, 2 );
if ( *valPtr > *maxvalPtr )
{
goto Error1_;
}
pCode += RANGE_INST_LEN;
break;
}
case PCIT::RANGE_LOW_U32S64:
{
DEF_ASSIGN(Lng32, op, RANGE_INST_LEN ); // the next op
PTR_DEF_ASSIGN(UInt32, valPtr, 0 );
PTR_TO_PCODE(Int64, minvalPtr, 2 );
if ( *valPtr < *minvalPtr )
{
goto Error1_;
}
pCode += RANGE_INST_LEN;
if (op != PCIT::RANGE_HIGH_U32S64) {
break;
}
pCode++;
//
// Do NOT break here...
// The next instruction is a matching RANGE_HIGH
}
case PCIT::RANGE_HIGH_U32S64:
{
PTR_DEF_ASSIGN(UInt32, valPtr, 0 );
PTR_TO_PCODE(Int64, maxvalPtr, 2 );
if ( *valPtr > *maxvalPtr )
{
goto Error1_;
}
pCode += RANGE_INST_LEN;
break;
}
case PCIT::RANGE_LOW_S8S64:
{
DEF_ASSIGN(Lng32, op, RANGE_INST_LEN ); // the next op
PTR_DEF_ASSIGN(Int8, valPtr, 0 );
PTR_TO_PCODE(Int64, minvalPtr, 2 );
if ( *valPtr < *minvalPtr )
{
goto Error1_;
}
pCode += RANGE_INST_LEN;
if (op != PCIT::RANGE_HIGH_S8S64) {
break;
}
pCode++;
//
// Do NOT break here...
// The next instruction is a matching RANGE_HIGH
}
case PCIT::RANGE_HIGH_S8S64:
{
PTR_DEF_ASSIGN(Int8, valPtr, 0 );
PTR_TO_PCODE(Int64, maxvalPtr, 2 );
if ( *valPtr > *maxvalPtr )
{
goto Error1_;
}
pCode += RANGE_INST_LEN;
break;
}
case PCIT::RANGE_LOW_S16S64:
{
DEF_ASSIGN(Lng32, op, RANGE_INST_LEN ); // the next op
PTR_DEF_ASSIGN(short, valPtr, 0 );
PTR_TO_PCODE(Int64, minvalPtr, 2 );
if ( *valPtr < *minvalPtr )
{
goto Error1_;
}
pCode += RANGE_INST_LEN;
if (op != PCIT::RANGE_HIGH_S16S64) {
break;
}
pCode++;
//
// Do NOT break here...
// The next instruction is a matching RANGE_HIGH
}
case PCIT::RANGE_HIGH_S16S64:
{
PTR_DEF_ASSIGN(short, valPtr, 0 );
PTR_TO_PCODE(Int64, maxvalPtr, 2 );
if ( *valPtr > *maxvalPtr )
{
goto Error1_;
}
pCode += RANGE_INST_LEN;
break;
}
case PCIT::RANGE_LOW_U16S64:
{
DEF_ASSIGN(Lng32, op, RANGE_INST_LEN ); // the next op
PTR_DEF_ASSIGN(unsigned short, valPtr, 0 );
PTR_TO_PCODE(Int64, minvalPtr, 2 );
if ( *valPtr < *minvalPtr )
{
goto Error1_;
}
pCode += RANGE_INST_LEN;
if (op != PCIT::RANGE_HIGH_U16S64) {
break;
}
pCode++;
//
// Do NOT break here...
// The next instruction is a matching RANGE_HIGH
}
case PCIT::RANGE_HIGH_U16S64:
{
PTR_DEF_ASSIGN(unsigned short, valPtr, 0 );
PTR_TO_PCODE(Int64, maxvalPtr, 2 );
if ( *valPtr > *maxvalPtr )
{
goto Error1_;
}
pCode += RANGE_INST_LEN;
break;
}
case PCIT::RANGE_LOW_U8S64:
{
DEF_ASSIGN(Lng32, op, RANGE_INST_LEN ); // the next op
PTR_DEF_ASSIGN(UInt8, valPtr, 0 );
PTR_TO_PCODE(Int64, minvalPtr, 2 );
if ( *valPtr < *minvalPtr )
{
goto Error1_;
}
pCode += RANGE_INST_LEN;
if (op != PCIT::RANGE_HIGH_U8S64) {
break;
}
pCode++;
//
// Do NOT break here...
// The next instruction is a matching RANGE_HIGH
}
case PCIT::RANGE_HIGH_U8S64:
{
PTR_DEF_ASSIGN(UInt8, valPtr, 0 );
PTR_TO_PCODE(Int64, maxvalPtr, 2 );
if ( *valPtr > *maxvalPtr )
{
goto Error1_;
}
pCode += RANGE_INST_LEN;
break;
}
case PCIT::REPLACE_NULL_MATTR3_MBIN32S:
case PCIT::REPLACE_NULL_MATTR3_MBIN32U:
case PCIT::REPLACE_NULL_MATTR3_MBIN16S:
case PCIT::REPLACE_NULL_MATTR3_MBIN16U:
{
PTR_DEF_ASSIGN(char, target, 0 );
PTR_DEF_ASSIGN(char, bitmap, 2 );
DEF_ASSIGN(UInt16, idx, 4 );
char *source;
DEF_ASSIGN(Int32, length , 9 );
if ( ExpTupleDesc::isNullValue( bitmap, idx ) )
{
PTR_DEF_ASSIGN(char, nlres, 7 );
source = nlres;
}
else
{
PTR_DEF_ASSIGN(char, notnlres, 5 );
source = notnlres;
}
str_cpy_all(target, source, length);
pCode += 10;
}
break;
case PCIT::ADD_MFLT64_MFLT64_MFLT64:
{
double flt64_0;
PTR_DEF_ASSIGN(double, result, 0 );
PTR_DEF_ASSIGN(double, op1, 2 );
PTR_DEF_ASSIGN(double, op2, 4 );
flt64_0 = MathReal64Add( *op1, *op2, &ov );
if (ov)
{
goto Error1_; // overflow
}
* result = flt64_0;
pCode += 6;
break;
}
case PCIT::SUB_MFLT64_MFLT64_MFLT64:
{
double flt64_0;
PTR_DEF_ASSIGN(double, result, 0 );
PTR_DEF_ASSIGN(double, op1, 2 );
PTR_DEF_ASSIGN(double, op2, 4 );
flt64_0 = MathReal64Sub( *op1, *op2, &ov );
if (ov) {
goto Error1_;
}
* result = flt64_0;
pCode += 6;
break;
}
case PCIT::MUL_MFLT64_MFLT64_MFLT64:
{
double flt64_0;
PTR_DEF_ASSIGN(double, result, 0 );
PTR_DEF_ASSIGN(double, op1, 2 );
PTR_DEF_ASSIGN(double, op2, 4 );
flt64_0 = MathReal64Mul( *op1, *op2, &ov );
if (ov) {
goto Error1_;
}
* result = flt64_0;
pCode += 6;
break;
}
case PCIT::DIV_MFLT64_MFLT64_MFLT64:
{
double flt64_0;
PTR_DEF_ASSIGN(double, result, 0 );
PTR_DEF_ASSIGN(double, op1, 2 );
PTR_DEF_ASSIGN(double, op2, 4 );
flt64_0 = MathReal64Div( *op1, *op2, &ov );
if (ov) {
goto Error1_;
}
* result = flt64_0;
pCode += 6;
break;
}
case PCIT::NEGATE_MASCII_MASCII:
{
PTR_DEF_ASSIGN(char, result, 0 );
PTR_DEF_ASSIGN(char, op1, 2 );
if (*(Int8*)op1 == 1)
*(Int8*)result = 0;
else
*(Int8*)result = 1;
pCode += 4;
break;
}
case PCIT::RANGE_MFLT64:
{
double flt64_1;
flt64_1 = *((double*)(stack[pCode[0]] + pCode[1]));
// If floating point value is NAN, then return overflow result
if (flt64_1 != flt64_1)
{
goto Error1_;
}
pCode += 2;
break;
}
case PCIT::PROFILE:
getPCodeObject()->profileCounts()[pCode[0]]++;
pCode++;
break;
case PCIT::NE_MBIN32S_MFLT32_MFLT32:
{
// NOT EQUAL TO ("<>") operation
PTR_DEF_ASSIGN(float, fltPtr1, 2 );
PTR_DEF_ASSIGN(float, fltPtr2, 4 );
PTR_DEF_ASSIGN(Int32, result, 0 );
* result = *fltPtr1 != *fltPtr2 ;
pCode += 6;
break;
}
case PCIT::NE_MBIN32S_MFLT64_MFLT64:
{
// NOT EQUAL TO ("<>") operation
PTR_DEF_ASSIGN(double, dblPtr1, 2 );
PTR_DEF_ASSIGN(double, dblPtr2, 4 );
PTR_DEF_ASSIGN(Int32, result, 0 );
* result = *dblPtr1 != *dblPtr2 ;
pCode += 6;
break;
}
case PCIT::GT_MBIN32S_MFLT32_MFLT32:
{
// GREATER THAN (">") operation
PTR_DEF_ASSIGN(float, fltPtr1, 2 );
PTR_DEF_ASSIGN(float, fltPtr2, 4 );
PTR_DEF_ASSIGN(Int32, result, 0 );
* result = *fltPtr1 > *fltPtr2 ;
pCode += 6;
break;
}
case PCIT::GT_MBIN32S_MFLT64_MFLT64:
{
// GREATER THAN (">") operation
PTR_DEF_ASSIGN(double, dblPtr1, 2 );
PTR_DEF_ASSIGN(double, dblPtr2, 4 );
PTR_DEF_ASSIGN(Int32, result, 0 );
* result = *dblPtr1 > *dblPtr2 ;
pCode += 6;
break;
}
case PCIT::GE_MBIN32S_MFLT32_MFLT32:
{
// GREATER THAN OR EQUAL TO (">=") operation
PTR_DEF_ASSIGN(float, fltPtr1, 2 );
PTR_DEF_ASSIGN(float, fltPtr2, 4 );
PTR_DEF_ASSIGN(Int32, result, 0 );
* result = *fltPtr1 >= *fltPtr2 ;
pCode += 6;
break;
}
case PCIT::GE_MBIN32S_MFLT64_MFLT64:
{
// GREATER THAN OR EQUAL TO (">=") operation
PTR_DEF_ASSIGN(double, dblPtr1, 2 );
PTR_DEF_ASSIGN(double, dblPtr2, 4 );
PTR_DEF_ASSIGN(Int32, result, 0 );
* result = *dblPtr1 >= *dblPtr2 ;
pCode += 6;
break;
}
case PCIT::EQ_MBIN32S_MFLT32_MFLT32:
{
// EQUAL TO ("=") operation
PTR_DEF_ASSIGN(float, fltPtr1, 2 );
PTR_DEF_ASSIGN(float, fltPtr2, 4 );
PTR_DEF_ASSIGN(Int32, result, 0 );
* result = *fltPtr1 == *fltPtr2 ;
pCode += 6;
break;
}
case PCIT::EQ_MBIN32S_MFLT64_MFLT64:
{
// EQUAL TO ("=") operation
PTR_DEF_ASSIGN(double, dblPtr1, 2 );
PTR_DEF_ASSIGN(double, dblPtr2, 4 );
PTR_DEF_ASSIGN(Int32, result, 0 );
* result = *dblPtr1 == *dblPtr2 ;
pCode += 6;
break;
}
case PCIT::LE_MBIN32S_MFLT32_MFLT32:
{
// LESS THAN OR EQUAL TO ("<=") operation
PTR_DEF_ASSIGN(float, fltPtr1, 2 );
PTR_DEF_ASSIGN(float, fltPtr2, 4 );
PTR_DEF_ASSIGN(Int32, result, 0 );
* result = *fltPtr1 <= *fltPtr2 ;
pCode += 6;
break;
}
case PCIT::LE_MBIN32S_MFLT64_MFLT64:
{
// LESS THAN OR EQUAL TO ("<=") operation
PTR_DEF_ASSIGN(double, dblPtr1, 2 );
PTR_DEF_ASSIGN(double, dblPtr2, 4 );
PTR_DEF_ASSIGN(Int32, result, 0 );
* result = *dblPtr1 <= *dblPtr2 ;
pCode += 6;
break;
}
case PCIT::LT_MBIN32S_MFLT32_MFLT32:
{
// LESS THAN ("<") operation
PTR_DEF_ASSIGN(float, fltPtr1, 2 );
PTR_DEF_ASSIGN(float, fltPtr2, 4 );
PTR_DEF_ASSIGN(Int32, result, 0 );
* result = *fltPtr1 < *fltPtr2 ;
pCode += 6;
break;
}
case PCIT::LT_MBIN32S_MFLT64_MFLT64:
{
// LESS THAN ("<") operation
PTR_DEF_ASSIGN(double, dblPtr1, 2 );
PTR_DEF_ASSIGN(double, dblPtr2, 4 );
PTR_DEF_ASSIGN(Int32, result, 0 );
* result = *dblPtr1 < *dblPtr2 ;
pCode += 6;
break;
}
case PCIT::NULLIFZERO_MPTR32_MATTR3_MPTR32_IBIN32S:
// copies in value from src to target, then sets / clears null if need be
{
PTR_DEF_ASSIGN(char, tgt, 0 );
PTR_DEF_ASSIGN(char, tgtNull, 2 );
PTR_DEF_ASSIGN(char, src, 5 );
DEF_ASSIGN(Int16, indx, 4 );
DEF_ASSIGN(Int32, srcLen, 7 );
NABoolean resultIsNull = TRUE;
for (Int32 i=0; i < srcLen; i++)
{
tgt[i] = src[i];
if (src[i] != 0) {
resultIsNull = FALSE;
}
}
if (resultIsNull)
ExpTupleDesc::setNullValue(tgtNull, indx);
else
ExpTupleDesc::clearNullValue(tgtNull, indx);
pCode += 8;
break;
}
case PCIT::GENFUNC_PCODE_1:
{
switch (pCode[0])
{
// Obsolete
case ITM_NULLIFZERO:
{
PTR_DEF_ASSIGN(char, tgt, 1 );
PTR_DEF_ASSIGN(char, tgtNull, 3 );
PTR_DEF_ASSIGN(char, src, 6 );
DEF_ASSIGN(Int32, tgtNullIndicatorLen, 5 );
DEF_ASSIGN(Int32, srcLen, 8 );
NABoolean resultIsNull = TRUE;
for (Int32 i = 0; i < srcLen; i++)
{
tgt[i] = src[i];
if (src[i] != 0)
{
resultIsNull = FALSE;
}
}
if (resultIsNull)
str_pad(tgtNull, tgtNullIndicatorLen, '\377');
else
str_pad(tgtNull, tgtNullIndicatorLen, 0);
pCode += 9;
}
break;
case ITM_RANDOMNUM:
{
DEF_ASSIGN(Int32, seed, 8 );
PTR_DEF_ASSIGN(UInt32, resultPtr, 1 );
seed++;
if (seed < 0) // numeric overflow ?
seed = seed + INT_MAX;
if (seed < 1) seed = 1; // in case seed == -1 or zero
* resultPtr = seed;
pCode[8] = seed; // assign temp value back
pCode += 9;
}
break;
default:
goto Error2_;
}
}
break;
case PCIT::GENFUNC_MBIN8_MBIN8_MBIN8_IBIN32S_IBIN32S:
{
switch (pCode[0])
{
case ITM_CONCAT:
{
PTR_DEF_ASSIGN(char, tgt, 1 );
PTR_DEF_ASSIGN(char, op1, 3 );
PTR_DEF_ASSIGN(char, op2, 5 );
DEF_ASSIGN(Int32, length1, 7 );
DEF_ASSIGN(Int32, length2, 8 );
str_cpy_all(tgt, op1, length1);
str_cpy_all(&tgt[length1], op2, length2);
}
pCode += 9;
break;
// bitand, bitor, bitxor done for int32 or Int64 operands
// and result. This has been validated during pcode gen for
// this operation.
case ITM_BITAND:
{
DEF_ASSIGN(Int32, oper, 7 );
if ( oper == REC_BIN32_UNSIGNED )
{
PTR_DEF_ASSIGN(UInt32, result, 1 );
PTR_DEF_ASSIGN(UInt32, op1, 3 );
PTR_DEF_ASSIGN(UInt32, op2, 5 );
* result = *op1 & *op2 ;
}
else if ( oper == REC_BIN32_SIGNED )
{
PTR_DEF_ASSIGN(Int32, result, 1 );
PTR_DEF_ASSIGN(Int32, op1, 3 );
PTR_DEF_ASSIGN(Int32, op2, 5 );
* result = *op1 & *op2 ;
}
else
{
PTR_DEF_ASSIGN(Int64, result, 1 );
PTR_DEF_ASSIGN(Int64, op1, 3 );
PTR_DEF_ASSIGN(Int64, op2, 5 );
* result = *op1 & *op2 ;
}
pCode += 9;
}
break;
case ITM_BITOR:
{
DEF_ASSIGN(Int32, oper, 7 );
if ( oper == REC_BIN32_UNSIGNED )
{
PTR_DEF_ASSIGN(UInt32, result, 1 );
PTR_DEF_ASSIGN(UInt32, op1, 3 );
PTR_DEF_ASSIGN(UInt32, op2, 5 );
* result = *op1 | *op2 ;
}
else if ( oper == REC_BIN32_SIGNED )
{
PTR_DEF_ASSIGN(Int32, result, 1 );
PTR_DEF_ASSIGN(Int32, op1, 3 );
PTR_DEF_ASSIGN(Int32, op2, 5 );
* result = *op1 | *op2 ;
}
else
{
PTR_DEF_ASSIGN(Int64, result, 1 );
PTR_DEF_ASSIGN(Int64, op1, 3 );
PTR_DEF_ASSIGN(Int64, op2, 5 );
* result = *op1 | *op2 ;
}
pCode += 9;
}
break;
case ITM_BITXOR:
{
DEF_ASSIGN(Int32, oper, 7 );
if ( oper == REC_BIN32_UNSIGNED )
{
PTR_DEF_ASSIGN(UInt32, result, 1 );
PTR_DEF_ASSIGN(UInt32, op1, 3 );
PTR_DEF_ASSIGN(UInt32, op2, 5 );
* result = *op1 ^ *op2 ;
}
else if ( oper == REC_BIN32_SIGNED )
{
PTR_DEF_ASSIGN(Int32, result, 1 );
PTR_DEF_ASSIGN(Int32, op1, 3 );
PTR_DEF_ASSIGN(Int32, op2, 5 );
* result = *op1 ^ *op2 ;
}
else
{
PTR_DEF_ASSIGN(Int64, result, 1 );
PTR_DEF_ASSIGN(Int64, op1, 3 );
PTR_DEF_ASSIGN(Int64, op2, 5 );
* result = *op1 ^ *op2 ;
}
pCode += 9;
}
break;
case ITM_BITNOT:
{
DEF_ASSIGN(Int32, oper, 7 );
if ( oper == REC_BIN32_UNSIGNED )
{
PTR_DEF_ASSIGN(UInt32, result, 1 );
PTR_DEF_ASSIGN(UInt32, op1, 3 );
* result = ~ *op1 ;
}
else if ( oper == REC_BIN32_SIGNED )
{
PTR_DEF_ASSIGN(Int32, result, 1 );
PTR_DEF_ASSIGN(Int32, op1, 3 );
* result = ~ *op1 ;
}
else
{
PTR_DEF_ASSIGN(Int64, result, 1 );
PTR_DEF_ASSIGN(Int64, op1, 3 );
* result = ~ *op1 ;
}
pCode += 9;
}
break;
default:
goto Error2_;
}
}
break;
case PCIT::GENFUNC_MATTR5_MATTR5_IBIN32S: // upper, lower, trim
case PCIT::GENFUNC_MATTR5_MATTR5_MBIN32S_IBIN32S: // repeat
{
Int32 srcLen = 0, tgtLen = 0, i = 0;
BASE_PTR_DEF_ASSIGN(char, tgt, 0 );
BASE_PTR_DEF_ASSIGN(char, src, 5 );
DEF_ASSIGN(Int32, tgtOffset, 1 );
DEF_ASSIGN(Int32, tgtVoaOffset, 2 );
// VOA offsets should always be used in order.
if(tgtVoaOffset > 0) {
assert(tgtVoaOffset > lastVoaOffset);
lastVoaOffset = tgtVoaOffset;
}
DEF_ASSIGN(Int32, comboLen1, 4 );
DEF_ASSIGN(Int32, comboLen2, 9 );
char* comboPtr1 = (char*)&comboLen1;
char* comboPtr2 = (char*)&comboLen2;
Int16 tgtNullIndLen = (Int16)comboPtr1[0];
Int16 tgtVCIndLen = (Int16)comboPtr1[1];
Int16 srcNullIndLen = (Int16)comboPtr2[0];
Int16 srcVCIndLen = (Int16)comboPtr2[1];
DEF_ASSIGN(Int32, offset, 6 );
DEF_ASSIGN(Int32, voaOffset, 7 );
src += ExpTupleDesc::getVarOffset(src, // atp_
offset,
voaOffset,
srcVCIndLen, // vcIndLen
srcNullIndLen // nullIndLen
);
if (srcVCIndLen > 0)
{
srcLen = ExpTupleDesc::getVarLength(src, srcVCIndLen);
}
else
{
srcLen = pCode[8];
}
// advance to beginning of data
src += srcVCIndLen;
DEF_ASSIGN(Int32, opRepeat, 12 );
DEF_ASSIGN(Int32, opx, 10 );
Int32 subOpc = (pCodeOpc == PCIT::GENFUNC_MATTR5_MATTR5_MBIN32S_IBIN32S)
? opRepeat : opx ;
switch (subOpc) {
case ITM_UPPER:
case ITM_LOWER:
{
tgt += ExpTupleDesc::getTgtVarOffset( tgt,
tgtOffset,
tgtVoaOffset,
tgtVCIndLen,
tgtNullIndLen,
varOffset,
srcLen
);
if (tgtVCIndLen > 0)
{
ExpTupleDesc::setVarLength(tgt, srcLen, tgtVCIndLen);
tgt += tgtVCIndLen;
}
for (Int32 i = 0; i < srcLen; i++)
tgt[i] = (subOpc==ITM_UPPER) ? TOUPPER(src[i]) : TOLOWER(src[i]);
pCode += 11;
break;
}
case ITM_RTRIM:
case ITM_LTRIM:
case ITM_TRIM:
{
// Find how many leading characters in operand 2 correspond
// to the trim character.
Lng32 len0 = srcLen;
Lng32 start = 0;
if (subOpc == ITM_LTRIM || subOpc == ITM_TRIM)
{
while ((start < srcLen) &&
(src[start] == ' ')
)
{
start++;
len0--;
}
}
// Find how many trailing characters in operand 2 correspond
// to the trim character.
Lng32 end = srcLen;
if (subOpc == ITM_RTRIM || subOpc == ITM_TRIM)
{
while ((end > (start)) &&
(src[end-1] == ' ')
)
{
end--;
len0--;
}
}
tgt += ExpTupleDesc::getTgtVarOffset( tgt,
tgtOffset, // tgt offset
tgtVoaOffset, // tgt voa offset
tgtVCIndLen,
tgtNullIndLen,
varOffset,
len0
);
if (tgtVCIndLen > 0)
{
ExpTupleDesc::setVarLength(tgt, len0, tgtVCIndLen);
tgt += tgtVCIndLen;
}
if (len0 > 0)
str_cpy_all(tgt, &src[start], len0);
pCode += 11;
}
break;
case ITM_REPEAT:
{
PTR_DEF_ASSIGN(Int32, repeatCntPtr, 10 );
Int32 repeatCnt = * repeatCntPtr;
UInt32 totalSize = srcLen * repeatCnt;
DEF_ASSIGN(Int32, maxTargetLen, 3 );
// If len is negative or the total bytes to write exceeds the max
// target len, report an error.
if ((repeatCnt < 0) || (repeatCnt * srcLen > maxTargetLen))
goto Error1_;
tgt += ExpTupleDesc::getTgtVarOffset( tgt,
tgtOffset,
tgtVoaOffset,
tgtVCIndLen,
tgtNullIndLen,
varOffset,
totalSize
);
if (tgtVCIndLen > 0)
{
ExpTupleDesc::setVarLength(tgt, totalSize, tgtVCIndLen);
tgt += tgtVCIndLen;
}
for (i=0; i < repeatCnt; i++) {
str_cpy_all(tgt, src, srcLen);
tgt += srcLen;
}
pCode += 13;
break;
}
}
break;
}
case PCIT::HASH2_DISTRIB:
{
PTR_DEF_ASSIGN(UInt32, resultPtr, 0 );
PTR_DEF_ASSIGN(UInt32, hashValPtr, 2 );
PTR_DEF_ASSIGN(UInt32, numPartsPtr, 4 );
*resultPtr = (UInt32)((Int64)*hashValPtr * (Int64)*numPartsPtr >> 32);
pCode += 6;
}
break;
case PCIT::OFFSET_IPTR_IPTR_MBIN32S_MBIN64S_MBIN64S:
{
PTR_DEF_ASSIGN(Int32, indexPtr, 2 * PCODEBINARIES_PER_PTR);
Int32 index = * indexPtr;
// Lookup the indexed row in the history buffer. Compute pointers
// to the attribute data, null indicator, and varchar indicator.
//
Int64 *srcData = NULL;
{
char *(*getRow)(void*,Int32,NABoolean,Lng32,Int32&);
Int32 rc;
getRow = (char *(*)(void*,Int32,NABoolean,Lng32,Int32&) )
GetPCodeBinaryAsPtr(pCode, 0);
char *row = (*(getRow))((void *) GetPCodeBinaryAsPtr(pCode, PCODEBINARIES_PER_PTR),
index, TRUE, 0, rc);
if(rc)
{
diagsArea = atp1->getDiagsArea();
ExRaiseSqlError(heap_, &diagsArea, EXE_HISTORY_BUFFER_TOO_SMALL);
if(diagsArea != atp1->getDiagsArea())
atp1->setDiagsArea(diagsArea);
return ex_expr::EXPR_ERROR;
}
if(row)
{
srcData = (Int64 *)(row + pCode[5 + 2 * PCODEBINARIES_PER_PTR]);
}
}
PTR_DEF_ASSIGN(Int64, dstData, 2 + 2 * PCODEBINARIES_PER_PTR);
*dstData = (srcData ? *srcData : 0);
pCode += 6 + 2 * PCODEBINARIES_PER_PTR;
}
break;
case PCIT::OFFSET_IPTR_IPTR_IBIN32S_MBIN64S_MBIN64S:
{
DEF_ASSIGN(Int32, index, 2 * PCODEBINARIES_PER_PTR);
// Lookup the indexed row in the history buffer. Compute pointers
// to the attribute data, null indicator, and varchar indicator.
//
Int64 *srcData = NULL;
{
char *(*getRow)(void*,Int32,NABoolean,Lng32,Int32&) ;
Int32 rc;
getRow = (char *(*)(void*,Int32,NABoolean,Lng32,Int32&) )
GetPCodeBinaryAsPtr(pCode, 0);
char *row = (*(getRow))(
(void *) GetPCodeBinaryAsPtr(pCode, PCODEBINARIES_PER_PTR),
index, TRUE, 0, rc);
if(rc)
{
diagsArea = atp1->getDiagsArea();
ExRaiseSqlError(heap_, &diagsArea, EXE_HISTORY_BUFFER_TOO_SMALL);
if(diagsArea != atp1->getDiagsArea())
atp1->setDiagsArea(diagsArea);
return ex_expr::EXPR_ERROR;
}
if(row)
{
srcData = (Int64 *)(row + pCode[4 + 2 * PCODEBINARIES_PER_PTR]);
}
}
PTR_DEF_ASSIGN(Int64, dstData, 1 + 2 * PCODEBINARIES_PER_PTR);
*dstData = (srcData ? *srcData : 0);
pCode += 5 + 2 * PCODEBINARIES_PER_PTR;
}
break;
case PCIT::COMP_MBIN32S_MBIGS_MBIGS_IBIN32S_IBIN32S:
{
PTR_DEF_ASSIGN(Int32, result, 0 );
PTR_DEF_ASSIGN(UInt16, src1, 2 );
PTR_DEF_ASSIGN(UInt16, src2, 4 );
DEF_ASSIGN(Int32, len, 6 );
Int32 len16 = len >> 1;
// Pull out what type of comparison (e.g. ITM_EQUAL) to perform.
DEF_ASSIGN(Int32, op, 7 );
Int32 compCode = 1; // Assume comparison is EQ
// Extract signs.
char src1Sign = BIGN_GET_SIGN(src1, len);
char src2Sign = BIGN_GET_SIGN(src2, len);
// Clear sign bits
BIGN_CLR_SIGN(src1, len);
BIGN_CLR_SIGN(src2, len);
// If the signs aren't equal, then we only need to check that both src
// values are not 0 - otherwise we can clearly say what the result of
// the comparison should be
if (src1Sign != src2Sign) {
for (Int32 i=0; i < len16; i++) {
if ((src1[i] != 0) || (src2[i] != 0)) {
compCode = (src1Sign == 0) ? 2 : 0;
break;
}
}
}
else {
// Both signs are different, so find out where the difference is
for (Int32 i=len16-1; i >= 0; i--) {
if (src1[i] == src2[i])
continue;
// Here lies the difference. Return 0, 1, or 2 for compCode,
// depending on how src1[i] compares to src2[i]
compCode = (src1[i] > src2[i]) ? ((src1Sign) ? 0 : 2)
: ((src1Sign) ? 2 : 0);
break;
}
}
// Reset sign bits
if (src1Sign)
BIGN_SET_SIGN(src1, len);
if (src2Sign)
BIGN_SET_SIGN(src2, len);
// Assign result
*result = compTable[op - ITM_EQUAL][compCode];
pCode += 8;
break;
}
case PCIT::MOVE_MBIGS_MBIGS_IBIN32S_IBIN32S:
{
Int32 i;
DEF_ASSIGN(Int32, tgtLength, 4);
DEF_ASSIGN(Int32, srcLength, 5);
PTR_DEF_ASSIGN(char, tgt, 0 );
PTR_DEF_ASSIGN(char, src, 2 );
// Get length in terms of double-words
Int32 tgtLength16 = tgtLength >> 1;
Int32 srcLength16 = srcLength >> 1;
// Get source sign bit and then temporarily clear it
char srcSign = BIGN_GET_SIGN(src, srcLength);
BIGN_CLR_SIGN(src, srcLength);
// If src value is too big for tgt, report overflow
for (; srcLength16 > tgtLength16; srcLength16--) {
if (((Int16*)src)[srcLength16 - 1] != 0) {
// Reset source sign bit before reporting error
if (srcSign)
BIGN_SET_SIGN(src, srcLength);
goto Error1_;
}
}
// Only clear out tgt bits if move won't do it for you.
if (tgtLength > srcLength)
for (i=0; i < tgtLength16; i++)
((Int16*)tgt)[i] = 0;
// Copy over shorts from bignum src
for (i=0; i < srcLength16; i++)
((UInt16*)tgt)[i] = ((UInt16*)src)[i];
if (srcSign) {
BIGN_SET_SIGN(src, srcLength);
BIGN_SET_SIGN(tgt, tgtLength);
}
pCode += 6;
break;
}
case PCIT::MOVE_MBIGS_MBIN16S_IBIN32S:
case PCIT::MOVE_MBIGS_MBIN32S_IBIN32S:
case PCIT::MOVE_MBIGS_MBIN64S_IBIN32S:
{
Int32 i;
DEF_ASSIGN(Int32, tgtLength, 4 );
Int32 tgtLength16 = tgtLength >> 1;
PTR_DEF_ASSIGN(UInt16, tgt, 0 );
PTR_DEF_ASSIGN(Int64, src, 2 );
Int64* tgt64 = (Int64*)tgt;
Int64 srcVal;
if (pCodeOpc == PCIT::MOVE_MBIGS_MBIN64S_IBIN32S)
srcVal = *src;
else if (pCodeOpc == PCIT::MOVE_MBIGS_MBIN32S_IBIN32S)
srcVal = *((Int32*)(src));
else
srcVal = *((Int16*)(src));
NABoolean isNeg = FALSE;
for (i=0; i < tgtLength16; i++)
tgt[i] = 0;
if (srcVal < 0) {
srcVal = -srcVal;
isNeg = TRUE;
}
*tgt64 = srcVal;
#ifndef NA_LITTLE_ENDIAN
UInt16 temp1 = tgt[0];
UInt16 temp2 = tgt[1];
tgt[0] = tgt[3];
tgt[1] = tgt[2];
tgt[2] = temp2;
tgt[3] = temp1;
#endif
if (isNeg)
BIGN_SET_SIGN(tgt, tgtLength);
pCode += 5;
break;
}
case PCIT::MOVE_MBIN64S_MBIGS_IBIN32S:
{
Int32 i;
DEF_ASSIGN(Int32, srcLength, 4);
Int32 srcLength16 = srcLength >> 1;
PTR_DEF_ASSIGN(Int64, tgt, 0 );
PTR_DEF_ASSIGN(char, src, 2 );
// Get source sign bit and then temporarily clear it
char srcSign = BIGN_GET_SIGN(src, srcLength);
BIGN_CLR_SIGN(src, srcLength);
for (i=4; i < srcLength16; i++) {
if (((Int16*)src)[i] != 0) {
// Reset source sign bit before reporting error
if (srcSign)
BIGN_SET_SIGN(src, srcLength);
goto Error1_;
}
}
*tgt = *((Int64*)src);
#ifndef NA_LITTLE_ENDIAN
UInt16 temp1 = ((UInt16*)tgt)[0];
UInt16 temp2 = ((UInt16*)tgt)[1];
((UInt16*)tgt)[0] = ((UInt16*)tgt)[3];
((UInt16*)tgt)[1] = ((UInt16*)tgt)[2];
((UInt16*)tgt)[2] = temp2;
((UInt16*)tgt)[3] = temp1;
#endif
// Reset source sign bit
if (srcSign)
BIGN_SET_SIGN(src, srcLength);
// If bignum was positive but that resulted in the sign bit being set
// in the 64-bit target, then we overflowed.
if ((srcSign == 0) && (*tgt < 0))
goto Error1_;
else if ((srcSign) && (*tgt < 0) && (*tgt != LLONG_MIN))
goto Error1_;
if ((srcSign) && (*tgt != LLONG_MIN))
*tgt = -(*tgt);
pCode += 5;
break;
}
case PCIT::MUL_MBIGS_MBIGS_MBIGS_IBIN32S:
{
Int32 i, j, pos;
UInt16 carry;
PTR_DEF_ASSIGN(UInt16, tgt, 0 );
PTR_DEF_ASSIGN(UInt16, src1, 2 );
PTR_DEF_ASSIGN(UInt16, src2, 4 );
DEF_ASSIGN(Int32, tgtLength, 6 );
DEF_ASSIGN(Int32, leftLength, 7 );
DEF_ASSIGN(Int32, rightLength, 8 );
Int32 leftLength16 = leftLength >> 1;
Int32 rightLength16 = rightLength >> 1;
Int32 tgtLength16 = tgtLength >> 1;
// Get source sign bit and then temporarily clear it
char src1Sign = BIGN_GET_SIGN(src1, leftLength);
char src2Sign = BIGN_GET_SIGN(src2, rightLength);
BIGN_CLR_SIGN(src1, leftLength);
BIGN_CLR_SIGN(src2, rightLength);
for (i=0; i < tgtLength16; i++)
((Int16*)tgt)[i] = 0;
while ((leftLength16 > 0) && (src1[leftLength16 - 1] == 0))
leftLength16--;
while ((rightLength16 > 0) && (src2[rightLength16 - 1] == 0))
rightLength16--;
if ((leftLength16 != 0) && (rightLength16 != 0)) {
// Multiply shorts - this is because bignum stored this way.
for (j=0; j < rightLength16; j++) {
for (i=0, carry=0, pos=j; i < leftLength16; i++, pos++) {
UInt32 result = (((UInt32)src1[i]) * src2[j]) + tgt[pos] + carry;
tgt[pos] = (UInt16)(result & 0xffff);
carry = (UInt16)(result >> 16);
}
if (carry)
tgt[pos] = carry;
}
}
if (src1Sign)
BIGN_SET_SIGN(src1, leftLength);
if (src2Sign)
BIGN_SET_SIGN(src2, rightLength);
if (src1Sign != src2Sign)
BIGN_SET_SIGN(tgt, tgtLength);
pCode += 9;
break;
}
case PCIT::SUM_MATTR3_MATTR3_IBIN32S_MBIGS_MBIGS_IBIN32S:
case PCIT::ADD_MBIGS_MBIGS_MBIGS_IBIN32S:
case PCIT::SUB_MBIGS_MBIGS_MBIGS_IBIN32S:
{
UInt16 *tgt, *src1, *src2;
NABoolean performAdd = TRUE;
UInt16 carry = 0;
Int32 length;
Int32 i;
if (pCodeOpc == PCIT::SUM_MATTR3_MATTR3_IBIN32S_MBIGS_MBIGS_IBIN32S)
{
PTR_DEF_ASSIGN(UInt16, tgtPtr, 7 );
src1 = tgt = tgtPtr ;
PTR_DEF_ASSIGN(UInt16, src2Ptr, 9 );
src2 = src2Ptr;
DEF_ASSIGN(Int32,lenVal, 11);
length = lenVal;
DEF_ASSIGN(Int32, isNullable, 6 );
if ( isNullable )
{
NABoolean isNull;
PTR_DEF_ASSIGN(Int16, tgtNull, 0 );
PTR_DEF_ASSIGN(Int16, srcNull, 3 );
DEF_ASSIGN(Int16, indxTgt, 2 );
DEF_ASSIGN(Int16, indxSrc, 5 );
isNull = indxSrc == -1 ? *srcNull != 0 :
ExpAlignedFormat::isNullValue((char*)srcNull, indxSrc) ;
if (isNull) {
pCode += 12;
break;
}
isNull = indxTgt == -1 ? *tgtNull != 0 :
ExpAlignedFormat::isNullValue((char*)tgtNull, indxTgt );
if (isNull) {
if ( indxTgt == -1 )
*tgtNull = 0;
else
ExpAlignedFormat::clearNullBit((char*)tgtNull, indxTgt);
str_pad((char*)tgt, length, 0);
}
}
pCode += 5; // Re-position to align with ADD/SUB instruction.
}
else
{
PTR_DEF_ASSIGN(UInt16, tgtPtr, 0 );
PTR_DEF_ASSIGN(UInt16, src1Ptr, 2 );
PTR_DEF_ASSIGN(UInt16, src2Ptr, 4 );
tgt = tgtPtr; src1 = src1Ptr; src2 = src2Ptr;
DEF_ASSIGN(Int32,lenVal, 6);
length = lenVal;
}
Int32 length16 = length >> 1;
// Get source sign bits
char src1Sign = BIGN_GET_SIGN(src1, length);
char src2Sign = BIGN_GET_SIGN(src2, length);
char* origSrc1 = (char*)src1;
char* origSrc2 = (char*)src2;
char origSrc1Sign = src1Sign;
char origSrc2Sign = src2Sign;
// Temporarily clear sign bits
BIGN_CLR_SIGN(src1, length);
BIGN_CLR_SIGN(src2, length);
if (pCodeOpc == PCIT::SUB_MBIGS_MBIGS_MBIGS_IBIN32S) {
if (src1Sign == src2Sign) {
performAdd = FALSE;
// We want to distribute the SUB operation into the signs of the
// source operand so that everything is normalized as if we were
// just doing an ADD and the source operands carried the sign.
src2Sign = (src2Sign == 0) ? MSB_SET_MSK : 0;
}
}
else {
if (src1Sign != src2Sign)
performAdd = FALSE;
}
NABoolean notEqual = FALSE; // assuming src1 equals src2 for sub
if (performAdd)
{
// Add shorts - this is because bignum stored this way.
for (i=0; i < length16; i++) {
UInt32 result = (UInt32)src1[i] + src2[i] + carry;
tgt[i] = (UInt16)(result & 0xffff);
carry = (UInt16)(result >> 16);
}
}
else
{
// Determine which source is bigger
for (i = length16-1; i >= 0; i--) {
// Skip equality
if (src1[i] == src2[i])
continue;
notEqual = TRUE;
if (src1[i] < src2[i]) {
// swap src1 and src2 along with their signs so the result is
// positive and the src1Sign would be the result sign
UInt16* temp = src1; src1 = src2; src2 = temp;
char tempSign = src1Sign; src1Sign = src2Sign; src2Sign = tempSign;
}
break;
}
// Sub shorts - this is because bignum stored this way.
for (i=0; i < length16; i++) {
Int32 result = (Int32)src1[i] - src2[i] + (Int16)carry;
tgt[i] = (UInt16) (result + (Int32)0x10000) & 0xffff;
carry = (result < 0) ? -1 : 0;
}
}
if (origSrc1Sign)
BIGN_SET_SIGN(origSrc1, length);
if (origSrc2Sign)
BIGN_SET_SIGN(origSrc2, length);
// Set target sign - will always be src1Sign unless target is 0
if (src1Sign && (performAdd || notEqual)) {
BIGN_SET_SIGN(tgt, length);
} else {
BIGN_CLR_SIGN(tgt, length);
}
// Report overflow
if (carry != 0)
goto Error1_;
pCode += 7;
break;
}
case PCIT::SWITCH_MBIN32S_MBIN64S_MPTR32_IBIN32S_IBIN32S:
{
PTR_DEF_ASSIGN(UInt32, result, 0 );
PTR_DEF_ASSIGN(Int64, src, 2 );
DEF_ASSIGN(UInt32, flags, 7 );
NABoolean isInList = flags & 0x01;
DEF_ASSIGN(Int32, size, 6 );
Int32 i;
//
// Pointers to tables representing 64-bit values in IN-list and 32-bit
// pc-relative offsets for then clauses of case statement. Tables look
// as follows:
//
// In-list: val1, val2, ..., valN
// Case: val1, val2, ..., valN, pcOff1, pcOff2, ..., pcOffN, pcOffDflt
//
PTR_DEF_ASSIGN(Int64, vals, 4 );
Long* pcOffs = (Long*)(&vals[size]); // i.e. the jump table
// Assume no match
Int32 compCode = 0;
UInt32 hashVal = ExHDPHash::hash8((char*)src, ExHDPHash::NO_FLAGS);
UInt32 index = hashVal % size;
// Compare value at index, if element at index is valid.
for (i=0; (i < 4) && (vals[index] != PCodeCfg::INVALID_INT64); i++) {
// Compare values to ensure match, then return TRUE if match found.
if (vals[index] == *src) {
compCode = 1;
break;
}
// Assuming the next element is not at the end of the table, keep
// trying for at most 4 times in total.
if (++index >= (UInt32)size)
break;
}
// Get jump table location, using default case if item not found
if (!isInList)
compCode = ((compCode == 0) ? pcOffs[size] : pcOffs[index]);
*result = compCode;
pCode += 8;
break;
}
case PCIT::SWITCH_MBIN32S_MATTR5_MPTR32_IBIN32S_IBIN32S:
{
PTR_DEF_ASSIGN(UInt32, result, 0 );
DEF_ASSIGN(UInt32, flags, 10 );
NABoolean isInList = flags & 0x01;
NABoolean ignoreSpaces = flags & 0x02;
DEF_ASSIGN(Int32, size, 9 );
Int32 compCode = -1; // Assume no match
Int32 i;
//
// Pointer to table representing constant strings in IN-list and 32-bit
// pc-relative offsets for then clauses of case statement. Tables look
// as follows:
//
// In-list: [len1, off1], [len2, off2], ..., [lenN, offN]
// Case: [len1, off1], [len2, off2], ..., [lenN, offN],
// pcOff1, pcOff2, ..., pcOffDflt
//
PTR_DEF_ASSIGN(Int32, table, 7 );
Long *pcOffs = (isInList)? NULL: (Long*)&(table[size<<1]);
DEF_ASSIGN(Int32, offset, 3 );
DEF_ASSIGN(Int32, voaOffset, 4 );
DEF_ASSIGN(Int32, comboLen1, 6 );
char* comboPtr1 = (char*)&comboLen1;
Int16 srcNullIndLen = (Int16)comboPtr1[0];
Int16 srcVCIndLen = (Int16)comboPtr1[1];
DEF_ASSIGN(UInt32, len1, 5 );
BASE_PTR_DEF_ASSIGN(char, src1, 2 );
if (srcVCIndLen > 0) {
src1 += ExpTupleDesc::getVarOffset(src1,
offset,
voaOffset,
srcVCIndLen, // vcIndLen
srcNullIndLen // nullIndLen
);
len1 = ExpTupleDesc::getVarLength(src1, srcVCIndLen);
src1 += srcVCIndLen;
}
else {
src1 += offset;
}
// skip trailing blanks if asked to
if (!ignoreSpaces)
while ((len1 > 0) && (src1[len1-1] == ' '))
len1--;
UInt32 hashVal = ExHDPHash::hash(src1, ExHDPHash::NO_FLAGS, len1);
UInt32 index = (hashVal % size) << 1;
// Compare value at index, if element at index is valid.
for (i=0; (i < 4) && (table[index] != PCodeCfg::INVALID_INT32); i++) {
UInt32 len2 = table[index];
char* src2 = (char*)(stack[1] + table[index + 1]);
compCode = ((len1 != len2) || memcmp(src1, src2, len1));
// If match is false, try next entry in table (at most 4 checks).
if ((compCode == 0) || ((Int32)(index + 2) >= (size << 1)))
break;
index += 2;
}
if (compCode == 0) // match
*result = (isInList) ? 1 : pcOffs[(index >> 1)];
else // taking default
*result = (isInList) ? 0 : pcOffs[size];
pCode += 11;
break;
}
case PCIT::NULL_VIOLATION_MBIN16U_MBIN16U:
{
PTR_DEF_ASSIGN(Int16, tmp, 0 );
if ( *tmp != 0 )
{
// Raise an "assigning a null value to a NOT NULL".
diagsArea = atp1->getDiagsArea();
ExRaiseSqlError(getHeap(), &diagsArea,
EXE_ASSIGNING_NULL_TO_NOT_NULL);
if(diagsArea != atp1->getDiagsArea())
atp1->setDiagsArea(diagsArea);
return ex_expr::EXPR_ERROR;
}
pCode += 2;
// Do NOT break here...
// The first null has been processed above, so fall through to
// process the second null.
// These two cases belong together...
}
case PCIT::NULL_VIOLATION_MBIN16U:
{
PTR_DEF_ASSIGN(Int16, tmp, 0 );
if ( *tmp != 0 )
{
// Raise an "assigning a null value to a NOT NULL".
diagsArea = atp1->getDiagsArea();
ExRaiseSqlError(getHeap(), &diagsArea,
EXE_ASSIGNING_NULL_TO_NOT_NULL);
if(diagsArea != atp1->getDiagsArea())
atp1->setDiagsArea(diagsArea);
return ex_expr::EXPR_ERROR;
}
pCode += 2;
break;
}
case PCIT::NULL_TEST_MBIN32S_MATTR5_IBIN32S_IBIN32S:
{
// if the flag is set, operand is an indirect varchar and must
// use voaOffset to get to the nullIndicator.
// The flag will not be set for aligned format.
DEF_ASSIGN(Int16, idx, 6 );
DEF_ASSIGN(Int32, flag1, 7 );
DEF_ASSIGN(Int32, flag2, 8 );
DEF_ASSIGN(Int32, val, 3 );
PTR_DEF_ASSIGN(Int32, ptr, 0 );
UInt32 pCode3 = flag1 == 1 ? *((Int32*)(stack[pCode[2]] + pCode[4]))
: val;
NABoolean srcNull =
ExpTupleDesc::isNullValue((char*)(stack[pCode[2]]+pCode3), idx,
(ExpTupleDesc::TupleDataFormat)pCode[5]);
if ( srcNull && flag2 != 0 ) *ptr = 1;
else if ( !srcNull && flag2 == 0 ) *ptr = 1;
else *ptr = 0 ;
pCode += 9;
break;
}
case PCIT::END:
return retCode;
case PCIT::NOP:
break;
default:
assert(pCodeOpc == -1);
goto Error2_;
};
};
Error1_:
return reportOverflowError(atp1, pCodeOpcPtr, pCode, stack);
Error2_:
diagsArea = atp1->getDiagsArea();
ExRaiseSqlError(heap_, &diagsArea, EXE_INTERNAL_ERROR);
if(diagsArea != atp1->getDiagsArea())
atp1->setDiagsArea(diagsArea);
return ex_expr::EXPR_ERROR;
}
/**
*** This routine is only called when a divide by zero or overflow occurred
*** during expression evaluation in evalPCode(). Any time a new pCode
*** instruction is inserted which could result in such an exception, this
*** routine needs to be modified. The pCode pointer passed in is assumed to
*** be at the first operand position passed the opcode.
**/
ex_expr::exp_return_type ex_expr_base::reportOverflowError(
atp_struct *atp1,
PCodeBinary* pCodeOpcPtr,
PCodeBinary* pCode,
Long* stack)
{
ComDiagsArea *diagsArea = atp1->getDiagsArea();
char* op1;
char* op2;
ExeErrorCode ovfl;
Int32 instr;
// Retrieve the pCode opcode associated with this failure. Because certain
// instructions fall into others during expression evaluation, we need to be
// careful to assign instr as is expected when reporting the error.
if (*pCodeOpcPtr == PCIT::SUM_MATTR3_MATTR3_IBIN32S_MBIN64S_MBIN64S)
instr = PCIT::SUM_MBIN64S_MBIN64S;
else if (*pCodeOpcPtr == PCIT::SUM_MATTR3_MATTR3_IBIN32S_MFLT64_MFLT64)
instr = PCIT::SUM_MFLT64_MFLT64;
else if (*pCodeOpcPtr == PCIT::SUM_MATTR3_MATTR3_IBIN32S_MBIGS_MBIGS_IBIN32S)
instr = PCIT::ADD_MBIGS_MBIGS_MBIGS_IBIN32S;
else
instr = *(pCode-1);
switch (instr) {
case PCIT::ADD_MBIGS_MBIGS_MBIGS_IBIN32S:
case PCIT::SUB_MBIGS_MBIGS_MBIGS_IBIN32S:
case PCIT::ADD_MBIN64S_MBIN64S_MBIN64S:
case PCIT::ADD_MBIN64S_MBIN32S_MBIN64S:
case PCIT::SUB_MBIN64S_MBIN64S_MBIN64S:
case PCIT::MUL_MBIN64S_MBIN64S_MBIN64S:
case PCIT::ADD_MFLT64_MFLT64_MFLT64:
case PCIT::SUB_MFLT64_MFLT64_MFLT64:
case PCIT::MUL_MFLT64_MFLT64_MFLT64:
op1 = ((char*)(stack[pCode[2]] + pCode[3]));
op2 = ((char*)(stack[pCode[4]] + pCode[5]));
ovfl = EXE_NUMERIC_OVERFLOW;
break;
case PCIT::SUM_MBIN64S_MBIN64S:
case PCIT::SUM_MFLT64_MFLT64:
op1 = ((char*)(stack[pCode[0]] + pCode[1]));
op2 = ((char*)(stack[pCode[2]] + pCode[3]));
ovfl = EXE_NUMERIC_OVERFLOW;
break;
case PCIT::DIV_MBIN64S_MBIN64S_MBIN64S:
case PCIT::DIV_MBIN64S_MBIN64S_MBIN64S_ROUND:
op1 = ((char*)(stack[pCode[2]] + pCode[3]));
op2 = ((char*)(stack[pCode[4]] + pCode[5]));
if (*((Int64*)(stack[pCode[4]] + pCode[5])) == 0) {
ovfl = EXE_DIVISION_BY_ZERO;
}
else {
ovfl = EXE_NUMERIC_OVERFLOW;
}
break;
case PCIT::DIV_MFLT64_MFLT64_MFLT64:
op1 = ((char*)(stack[pCode[2]] + pCode[3]));
op2 = ((char*)(stack[pCode[4]] + pCode[5]));
if (*((double *)(stack[pCode[4]] + pCode[5])) == 0) {
ovfl = EXE_DIVISION_BY_ZERO;
}
else {
ovfl = EXE_NUMERIC_OVERFLOW;
}
break;
case PCIT::RANGE_MFLT64:
op1 = ((char*)(stack[pCode[0]] + pCode[1]));
op2 = NULL;
ovfl = EXE_NUMERIC_OVERFLOW;
break;
case PCIT::RANGE_LOW_S64S64:
op1 = ((char*)(stack[pCode[0]] + pCode[1]));
op2 = (char*)(&pCode[2]);
if (((*((Int64*)(stack[pCode[0]]+pCode[1]))) < 0) &&
((*(Int64*)&pCode[2]) >= 0))
{ // conversion of -ve num to unsigned field
ovfl = EXE_UNSIGNED_OVERFLOW;
}
else {
ovfl = EXE_NUMERIC_OVERFLOW;
}
break;
case PCIT::RANGE_LOW_S32S64:
op1 = ((char*)(stack[pCode[0]] + pCode[1]));
op2 = (char*)(&pCode[2]);
if (((*((Int32*)(stack[pCode[0]]+pCode[1]))) < 0) &&
((*(Int64*)&pCode[2]) >= 0))
{ // conversion of -ve num to unsigned field
ovfl = EXE_UNSIGNED_OVERFLOW;
}
else {
ovfl = EXE_NUMERIC_OVERFLOW;
}
break;
case PCIT::RANGE_LOW_S16S64:
op1 = ((char*)(stack[pCode[0]] + pCode[1]));
op2 = (char*)(&pCode[2]);
if (((*((short*)(stack[pCode[0]]+pCode[1]))) < 0) &&
((*(Int64*)&pCode[2]) >= 0))
{ // conversion of -ve num to unsigned field
ovfl = EXE_UNSIGNED_OVERFLOW;
}
else {
ovfl = EXE_NUMERIC_OVERFLOW;
}
break;
case PCIT::RANGE_LOW_S8S64:
op1 = ((char*)(stack[pCode[0]] + pCode[1]));
op2 = (char*)(&pCode[2]);
if (((*((Int8*)(stack[pCode[0]]+pCode[1]))) < 0) &&
((*(Int64*)&pCode[2]) >= 0))
{ // conversion of -ve num to unsigned field
ovfl = EXE_UNSIGNED_OVERFLOW;
}
else {
ovfl = EXE_NUMERIC_OVERFLOW;
}
break;
case PCIT::RANGE_LOW_U32S64:
case PCIT::RANGE_LOW_U16S64:
case PCIT::RANGE_LOW_U8S64:
case PCIT::RANGE_HIGH_S64S64:
case PCIT::RANGE_HIGH_S32S64:
case PCIT::RANGE_HIGH_U32S64:
case PCIT::RANGE_HIGH_S16S64:
case PCIT::RANGE_HIGH_U16S64:
case PCIT::RANGE_HIGH_S8S64:
case PCIT::RANGE_HIGH_U8S64:
op1 = ((char*)(stack[pCode[0]] + pCode[1]));
op2 = (char*)(&pCode[2]);
ovfl = EXE_NUMERIC_OVERFLOW;
break;
case PCIT::MOVE_MBIN64S_MBIGS_IBIN32S:
op2 = ((char*)(stack[pCode[2]] + pCode[3]));
ExRaiseDetailSqlError(getHeap(), &diagsArea, EXE_NUMERIC_OVERFLOW, op2,
pCode[4], REC_NUM_BIG_SIGNED, 0,
REC_BIN64_SIGNED, 0);
if(diagsArea != atp1->getDiagsArea())
atp1->setDiagsArea(diagsArea);
return ex_expr::EXPR_ERROR;
break;
case PCIT::MOVE_MBIGS_MBIGS_IBIN32S_IBIN32S:
op2 = ((char*)(stack[pCode[2]] + pCode[3]));
ExRaiseDetailSqlError(getHeap(), &diagsArea, EXE_NUMERIC_OVERFLOW, op2,
pCode[5], REC_NUM_BIG_SIGNED, 0,
REC_NUM_BIG_SIGNED,0);
if(diagsArea != atp1->getDiagsArea())
atp1->setDiagsArea(diagsArea);
return ex_expr::EXPR_ERROR;
break;
case PCIT::GENFUNC_MATTR5_MATTR5_MBIN32S_IBIN32S:
ExRaiseFunctionSqlError(getHeap(), &diagsArea, EXE_STRING_OVERFLOW,FALSE);
if(diagsArea != atp1->getDiagsArea())
atp1->setDiagsArea(diagsArea);
return ex_expr::EXPR_ERROR;
break;
case PCIT::CONCAT_MATTR5_MATTR5_MATTR5:
ExRaiseFunctionSqlError(getHeap(), &diagsArea, EXE_STRING_OVERFLOW,FALSE);
return ex_expr::EXPR_ERROR;
default:
ExRaiseSqlError(heap_,
&diagsArea,
EXE_INTERNAL_ERROR);
if(diagsArea != atp1->getDiagsArea())
atp1->setDiagsArea(diagsArea);
return ex_expr::EXPR_ERROR;
}
ExRaiseDetailSqlError(getHeap(),
&diagsArea,
ovfl,
(PCIT::Instruction)instr,
op1,
op2);
if(diagsArea != atp1->getDiagsArea())
atp1->setDiagsArea(diagsArea);
return ex_expr::EXPR_ERROR;
}
ex_expr::exp_return_type ex_clause::eval(char * /*op_data*/[],
CollHeap*,
ComDiagsArea**)
{
// default eval method does nothing and returns OK
return ex_expr::EXPR_OK;
};