blob: 2d07a84f81b72360bd69a9e331dee1a07b33263e [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: ExpPCodeClauseGen.cpp
* Description:
*
* Created: 8/25/97
* Language: C++
*
*
*
****************************************************************************
*/
// ExpPCodeClauseGen.cpp
//
// The files contains the implementations of the virtual function
// pCodeGenerate for the ex_clause and derived classes.
//
//
#include "Platform.h"
// Includes
//
#include "Platform.h"
#include "exp_stdh.h"
#include "str.h"
#include "exp_datetime.h"
#include "exp_expr.h"
#include "exp_function.h"
#include "exp_math_func.h"
#include "ExpPCode.h"
#include "ExpLOB.h"
// #include "DatetimeType.h"
// ex_clause::pCodeGenerate
//
// PCode generation for the default case (ie. no fundamental pcode
// instructions to do the operation) so the original clause->eval is
// executed via the PCode instruction CLAUSE_EVAL.
//
// IN : space - memory allocator
// OUT :
// RETURN : ex_expr::EXPR_OK is no errors
// EFFECTS: stores pointer to PCodeObject in clause
//
ex_expr::exp_return_type ex_clause::pCodeGenerate(Space *space, UInt32 f) {
PCIList code(space);
AttributesPtr *attrs = getOperand();
Int32 nNullableInputs = 0;
Int32 i = 0;
for(i=0; i<getNumOperands(); i++) {
if (! attrs[i])
continue;
if((i>0) && attrs[i]->getNullFlag())
nNullableInputs++;
}
// Generate necessary pre clause PCI's
//
PCode::preClausePCI(this, code);
// stackDepth is the total Depth of the stack (ie. the size of the
// op_data vector that is being created) for the eval call.
//
// stackPushesWaiting is the current number of stack pushes needed for
// the eval call. Pushes are not done immediately so that consective
// pushes can be coalesced.
//
//int stackDepth = 0;
//int stackPushesWaiting = 0;
Int32 useProcessNulls = 0;
// Branch target IDs
//
PCIID branchEndA = 0;
// Are any of the attributes varchar?
//
Int32 varchar = 0;
for(i=0; i<getNumOperands(); i++)
{
if (! attrs[i])
continue;
if(attrs[i]->getVCIndicatorLength() > 0)
varchar = 1;
}
//
// Set the first fixed field for the 2 disk formats.
if(getNumOperands() > 0)
code.append(PCode::storeVoa(attrs[0], space));
// If any of the operands are nullable, NULL is relevant for
// this clause, and any NULL input produces a NULL output, insert the
// appropriate PCODE sequence to compute the nullness of the result.
// (If branching is not desireable, then define the virtual methods
// below for that specific clause type.)
if(isAnyOperandNullable() && isNullRelevant() && isNullInNullOut()
&& (nNullableInputs < 3)) {
branchEndA = PCode::nullBranch(this, code, attrs);
}
// If any of the inputs are nullable, insert the appropriate PCODE
// sequence to load the null indicators onto the stack.
//
else if(isAnyOperandNullable())
{
// Load the address of the NULL indicator for the result into the
// OpData vector.
//
if(attrs[0]->getNullFlag())
{
if ( attrs[0]->isSQLMXAlignedFormat() )
code.append(PCode::loadOpDataNullBitmapAddress(attrs[0], 0, space));
else
code.append(PCode::loadOpDataNullAddress(attrs[0], 0, space));
}
// Load and test each nullable input for NULL, and leave the results
// on the stack for eval. If an operand is NULL leave a zero on the
// stack, otherwise a non-zero.
//
for(i=1; i<getNumOperands(); i++) {
if (! attrs[i])
continue;
if(attrs[i]->getNullFlag())
{
if ( attrs[i]->isSQLMXAlignedFormat() )
code.append(PCode::loadOpDataNullBitmap(attrs[i], i, space));
else
code.append(PCode::loadOpDataNull(attrs[i], i, space));
}
}
// If special NULL processing is needed, set flag so the process nulls
// flag in the CLAUSE_EVAL instruction will be set.
if(isNullRelevant())
useProcessNulls = 1;
}
// Setup the op_data vector for the call to eval. (The null indicator part
// of the vector has already been constructed if necessary).
//
// Compute pointers to the varchar indicators (if necessary) on the stack
//
if(varchar)
{
for(i=0; i<getNumOperands(); i++)
// For indirect varchars, this also loads the data address.
code.append(PCode::loadOpDataVCAddress(attrs[i], i, space));
}
// If there are no varchar, but there are NULL considerations, push empty
// space on the stack because eval may access the NULL information
//
else if(isAnyOperandNullable() && (1 || !isNullRelevant()))
{
;
}
// Load the data addresses.
//
for(i=0; i<getNumOperands(); i++)
{
// For indirect varchars, the data address is loaded at the same time
// as the VCLen Address.
if( attrs[i] && (! attrs[i]->isIndirectVC()))
code.append(PCode::loadOpDataDataAddress(attrs[i], i, space));
}
// Execute CLAUSE_EVAL which finishes pushing the stack, executes
// clause->eval(), and then pops the stack.
//
AML aml(PCIT::IPTR, PCIT::IBIN32S);
OL ol((Int64)this, useProcessNulls);
PCI pci(PCIT::Op_CLAUSE_EVAL, aml, ol);
setNoPCodeAvailable(TRUE);
code.append(pci);
// update the varOffset if this CLAUSE_EVAL writes to a varchar in aligned format.
// (unless this varchar is being treated as a fixed value in the aligned row).
// Note that the updateRowlen instruction also updates the varOffset cursor of evalPCode().
if ( getNumOperands() > 0 &&
attrs[0]->isSQLMXDiskFormat() &&
(attrs[0]->getVCIndicatorLength() > 0) &&
!attrs[0]->isForceFixed() )
{
code.append(PCode::updateRowLen(attrs[0], space, f));
}
// Branch targets
//
if(branchEndA)
{
AML aml1;
OL ol1((Int64)branchEndA);
PCI pci1(PCIT::Op_TARGET, aml1, ol1);
code.append(pci1);
}
// Handle clauses that branch. Insert a CLAUSE_BRANCH instruction into
// the code. A TARGET PCI instruction will be/has been added when PCI's are
// generated for the target clause. This no longer handles marking the
// target clauses because it is too late for backwards branching at this
// point. This is handled in ex_expr::pCodeGenerate().
//
if(isBranchingClause())
{
ex_branch_clause *branchClause = (ex_branch_clause*)this;
ex_clause *targetClause = branchClause->get_branch_clause();
AML aml(PCIT::IPTR, PCIT::IPTR);
OL ol((Int64)targetClause, (Int64)this);
PCI pci(PCIT::Op_CLAUSE_BRANCH, aml, ol);
code.append(pci);
}
// Generate the necessary post clause PCI's
//
PCode::postClausePCI(this, code);
setPCIList(code.getList());
return ex_expr::EXPR_OK;
}
// ex_inout_clause::pCodeGenerate
//
// For now simply calls the default ex_clause::pCodeGenerate
//
ex_expr::exp_return_type ex_inout_clause::pCodeGenerate(Space *space, UInt32 f) {
return ex_clause::pCodeGenerate(space, f);
}
// ex_aggr_min_max_clause::pCodeGenerate
//
ex_expr::exp_return_type ex_aggr_min_max_clause::pCodeGenerate(Space *space, UInt32 f) {
#ifdef _DEBUG
if (getenv("NO_PCODE_MIN_MAX"))
return ex_clause::pCodeGenerate(space, f);
#endif
if ((getOperand(1)->getNullFlag()) ||
(getOperand(0)->getVCIndicatorLength() > 0))
return ex_clause::pCodeGenerate(space, f);
// Get a handle on the operands
//
AttributesPtr *attrs = getOperand();
// Allocate the code list
//
PCIList code(space);
// Generate pre clause PCI's
//
PCode::preClausePCI(this, code);
// First operand is the memory location of the result (min/max)
// Second operand is the memory location of the 1st argument
// Third operand is the memory location of the result of comparison
// of new child value and current min/max.
// If third operand is 1(TRUE), then move the first operand to result.
// Fourth operand is the length of first operand. Data for this length
// will be moved to result as the nee min/max value.
AML aml(PCIT::MBIN8,PCIT::MBIN8,PCIT::MBIN32S,PCIT::IBIN32S);
OL ol(attrs[0]->getAtp(), attrs[0]->getAtpIndex(), attrs[0]->getOffset(),
attrs[1]->getAtp(), attrs[1]->getAtpIndex(), attrs[1]->getOffset(),
attrs[2]->getAtp(), attrs[2]->getAtpIndex(), attrs[2]->getOffset(),
attrs[1]->getLength());
PCI pci(PCIT::Op_MINMAX, aml, ol);
code.append(pci);
// Generate post clause PCI's
//
PCode::postClausePCI(this, code);
setPCIList(code.getList());
return ex_expr::EXPR_OK;
/* // if ((getOperand(0)->getNullFlag()) ||
if ((getOperand(1)->getNullFlag()) ||
(getOperand(0)->getVCIndicatorLength() > 0))
return ex_clause::pCodeGenerate(space, f);
// Get a handle on the operands
//
AttributesPtr *attrs = getOperand();
// Allocate the code list
//
PCIList code(space);
// Generate pre clause PCI's
//
PCode::preClausePCI(this, code);
// Load the second operand
//
code.append(PCode::loadValue(attrs[2], space));
// if second operand is 1(TRUE), then move the first operand to result.
// else branch out.
// The runtime BRANCH pcode instruction branches out if operand
// is TRUE. We want to branch out if operand is FALSE. So, complement
// the operand.
AML aml0(PCIT::IBIN32S, PCIT::IBIN32S);
PCI pci0(PCIT::Op_ZERO, aml0);
code.append(pci0);
// and branch out if it is true
AML aml(PCIT::IBIN32S);
OL ol(0);
PCI pci(PCIT::Op_BRANCH, aml, ol);
code.append(pci);
PCIID branchTgt = code.getTailId();
code.append(PCode::moveValue(attrs[0], attrs[1], space));
// End branch target.
//
AML aml6;
OL ol6((Int64)branchTgt);
PCI pci6(PCIType::Op_TARGET, aml6, ol6);
code.append(pci6);
// Generate post clause PCI's
//
PCode::postClausePCI(this, code);
setPCIList(code.getList());
return ex_expr::EXPR_OK; */
}
// ex_function_clause::pCodeGenerate
//
// For now simply calls the default ex_clause::pCodeGenerate
//
ex_expr::exp_return_type ex_function_clause::pCodeGenerate(Space *space, UInt32 f) {
return ex_clause::pCodeGenerate(space, f);
}
// ex_function_encode::pCodeGenerate
//
// For now PCode in only generated for very simple encodings. This is
// intended to improve scan/update node performance since the key encode
// expression is called frequently in these nodes.
//
// IN : space - memory allocator
// OUT :
// RETURN : ex_expr::EXPR_OK is no errors
// EFFECTS: stores pointer to PCodeObject in clause
//
ex_expr::exp_return_type ex_function_encode::pCodeGenerate(Space *space, UInt32 f) {
#ifdef _DEBUG
// For debugging...
if(getenv("PCODE_NO_ENCODE")) return ex_clause::pCodeGenerate(space, f);
#endif
// Generate the standard clause->eval PCode for cases that
// are not handled with more fundamental PCode operations
//
// For now, no nulls unless regularNullability has been explicitly asked.
//
if ((NOT regularNullability()) &&
(isAnyOperandNullable()))
return ex_clause::pCodeGenerate(space, f);
AttributesPtr *attrs = getOperand();
Attributes *src = attrs[1];
Lng32 fsDataType = src->getDatatype();
Lng32 length = src->getLength();
if (isDecode())
{
if (! getenv("PCODE_DECODE"))
return ex_clause::pCodeGenerate(space, f);
}
switch(fsDataType) {
case REC_BIN8_SIGNED:
case REC_BIN8_UNSIGNED:
break;
case REC_BIN16_SIGNED:
case REC_BIN16_UNSIGNED:
case REC_BIN32_SIGNED:
case REC_BIN32_UNSIGNED:
case REC_BIN64_SIGNED:
break;
case REC_DECIMAL_LSE:
case REC_DECIMAL_UNSIGNED:
{
// not enabled for NEO CA
return ex_clause::pCodeGenerate(space, f);
}
break;
case REC_BYTE_F_ASCII:
// case REC_NCHAR_F_UNICODE:
// for now, do non-pcode encoding for caseInsensitive datatypes.
// Later, add this to PCODE.
if (caseInsensitive())
return ex_clause::pCodeGenerate(space, f);
//no pcode for now for Czech collated encode
// this is for non nullable op(1)
if (CollationInfo::isSystemCollation(getCollation()))
{
return ex_clause::pCodeGenerate(space, f);
}
break;
case REC_DATETIME:
// Do not generate PCODE to encode the non-standard SQL/MP
// datetime types (for now).
// Do not generate PCODE on windows(Little Endian) platform.
// With little endian, we need to reversebytes the DATE and
// FRACTION part. Pcode cannot do that.
#ifdef NA_LITTLE_ENDIAN
return ex_clause::pCodeGenerate(space, f);
#else
if(src->getPrecision() > REC_DTCODE_TIMESTAMP)
return ex_clause::pCodeGenerate(space, f);
#endif
break;
default:
return ex_clause::pCodeGenerate(space, f);
}
// If we get to this point, we have decided to generate PCode for this
// particular encode operation.
//
PCIList code(space);
Attributes *tgt = attrs[0];
// Generate pre clause PCI's
//
PCode::preClausePCI(this, code);
// Add the null logic if necessary.
//
PCIID branchToEnd = PCode::nullBranch(this, code, attrs);
if ((fsDataType == REC_BYTE_F_ASCII) ||
(fsDataType == REC_DATETIME) ||
(fsDataType == REC_DECIMAL_LSE) ||
(fsDataType == REC_DECIMAL_UNSIGNED))
{
// The first operand is the memory location for the result.
// The second operand is the memory location for the source.
// The third operand is the length of data to encode.
// The fourth operand is a boolean for ascending/descending.
//
short attrs1Datatype = src->getDatatype();
if ((fsDataType == REC_DATETIME) ||
(fsDataType == REC_DECIMAL_UNSIGNED))
attrs1Datatype = REC_BYTE_F_ASCII;
AML aml(PCIT::getMemoryAddressingMode(tgt->getDatatype()),
PCIT::getMemoryAddressingMode(attrs1Datatype),
PCIT::IBIN32S,
PCIT::IBIN32S);
OL ol(tgt->getAtp(), tgt->getAtpIndex(),tgt->getOffset(),
src->getAtp(), src->getAtpIndex(),src->getOffset(),
tgt->getLength(),
(isDesc()));
// Add the encode instruction.
//
if (isDecode())
{
PCI pci(PCIT::Op_DECODE, aml, ol);
code.append(pci);
}
else
{
PCI pci(PCIT::Op_ENCODE, aml, ol);
code.append(pci);
}
}
else
{
// The first operand is the memory location for the result.
// The second operand is the memory location for the source.
// The third operand is a boolean for ascending/descending.
//
AML aml(PCIT::getMemoryAddressingMode(tgt->getDatatype()),
PCIT::getMemoryAddressingMode(src->getDatatype()),
PCIT::IBIN32S);
OL ol(tgt->getAtp(), tgt->getAtpIndex(),tgt->getOffset(),
src->getAtp(), src->getAtpIndex(),src->getOffset(),
(isDesc()));
// Add the encode instruction.
//
if (isDecode())
{
PCI pci(PCIT::Op_DECODE, aml, ol);
code.append(pci);
}
else
{
PCI pci(PCIT::Op_ENCODE, aml, ol);
code.append(pci);
}
}
// Add the branch target if necessary.
//
if(branchToEnd)
{
AML aml;
OL ol((Int64)branchToEnd);
PCI pci(PCIT::Op_TARGET, aml, ol);
code.append(pci);
}
// Generate post clause PCI's
//
PCode::postClausePCI(this, code);
setPCIList(code.getList());
return ex_expr::EXPR_OK;
}
// ex_aggregate_clause::pCodeGenerate
//
// For now simply calls the default ex_clause::pCodeGenerate
//
ex_expr::exp_return_type ex_aggregate_clause::pCodeGenerate(Space *space, UInt32 f) {
return ex_clause::pCodeGenerate(space, f);
};
// ex_aggr_one_row_clause::pCodeGenerate
//
// For now simply calls the default ex_clause::pCodeGenerate
//
ex_expr::exp_return_type ex_aggr_one_row_clause::pCodeGenerate(Space *space, UInt32 f) {
return ex_clause::pCodeGenerate(space, f);
};
// ex_aggr_any_true_max_clause::pCodeGenerate
//
// For now simply calls the default ex_clause::pCodeGenerate
//
ex_expr::exp_return_type ex_aggr_any_true_max_clause::pCodeGenerate(Space *space, UInt32 f) {
return ex_clause::pCodeGenerate(space, f);
};
// ex_bool_clause::pCodeGenerate
//
// Generates PCI's for ITM_AND and ITM_OR bool operations. The PCI's use
// tristate logic to compute either the logical AND or OR of the two
// input operands.
//
// IN : space - memory allocator
// OUT :
// RETURN : ex_expr::EXPR_OK is no errors
// EFFECTS: stores pointer to PCodeObject in clause
//
ex_expr::exp_return_type ex_bool_clause::pCodeGenerate(Space *space, UInt32 f) {
#ifdef _DEBUG
// For debugging...
if(getenv("PCODE_NO_BOOL")) return ex_clause::pCodeGenerate(space, f);
#endif
// Generate the standard clause->eval PCode for cases that
// are not handled with more fundamental PCode operations.
//
switch(getOperType()) {
case ITM_AND:
case ITM_OR:
break;
default:
return ex_clause::pCodeGenerate(space, f);
}
// If we get to this point, we have decided to generate PCI's for this
// particular bool operation. Get a handle on the attributes and allocate
// the code list.
//
AttributesPtr *attrs = getOperand();
PCIList code(space);
// Generate pre clause PCI's
//
PCode::preClausePCI(this, code);
// The first operand is the memory location of the boolean result.
// The second operand is the memory location of the 1st argument.
// The third operand is the memory location of the 2nd argument.
//
AML aml(PCIT::MBIN32S, PCIT::MBIN32S, PCIT::MBIN32S);
OL ol(attrs[0]->getAtp(), attrs[0]->getAtpIndex(), attrs[0]->getOffset(),
attrs[1]->getAtp(), attrs[1]->getAtpIndex(), attrs[1]->getOffset(),
attrs[2]->getAtp(), attrs[2]->getAtpIndex(), attrs[2]->getOffset());
// Generate the instruction
//
PCIT::Operation op = PCIT::Op_OPDATA; // prevent init warning
switch(getOperType()) {
case ITM_AND: op = PCIT::Op_AND; break;
case ITM_OR: op = PCIT::Op_OR; break;
};
PCI pci(op, aml, ol);
code.append(pci);
// Generate post clause PCI's
//
PCode::postClausePCI(this, code);
setPCIList(code.getList());
return ex_expr::EXPR_OK;
};
// ex_bool_result_clause::pCodeGenerate
//
// Generates PCI's for bool result operation. The PCI's should return
// ex_expr::EXPR_TRUE for the result of the expression if the 1st operand
// is TRUE, otherwise return ex_expr::EXPR_FALSE.
//
// IN : space - memory allocator
// OUT :
// RETURN : ex_expr::EXPR_OK is no errors
// EFFECTS: stores pointer to PCodeObject in clause
//
ex_expr::exp_return_type bool_result_clause::pCodeGenerate(Space *space, UInt32 f) {
#ifdef _DEBUG
// For debugging...
if(getenv("PCODE_NO_BOOL_RESULT")) return ex_clause::pCodeGenerate(space, f);
#endif
// Allocate the code list and get a handle on the operands
//
PCIList code(space);
AttributesPtr *attrs = getOperand();
// Generate pre clause PCI's
//
PCode::preClausePCI(this, code);
// The first operand is the memory location of the boolean return value.
//
AML aml(PCIT::MBIN32S);
OL ol(attrs[0]->getAtp(), attrs[0]->getAtpIndex(), attrs[0]->getOffset());
// Add the return instruction.
//
PCI pci(PCIT::Op_MOVE, aml, ol);
code.append(pci);
// Generate post clause PCI's
//
PCode::postClausePCI(this, code);
setPCIList(code.getList());
return ex_expr::EXPR_OK;
};
// ex_branch_clause::pCodeGenerate
//
// For now simply calls default ex_clause::pCodeGenerate(space, f)
//
// IN : space - memory allocator
// OUT :
// RETURN : ex_expr::EXPR_OK is no errors
// EFFECTS: stores pointer to PCodeObject in clause
//
ex_expr::exp_return_type ex_branch_clause::pCodeGenerate(Space *space, UInt32 f) {
if ((getOperType() != ITM_AND) &&
(getOperType() != ITM_OR))
return ex_clause::pCodeGenerate(space, f);
PCIList code(space);
AttributesPtr *attrs = getOperand();
// Generate pre clause PCI's
//
PCode::preClausePCI(this, code);
ex_clause *targetClause = get_branch_clause();
AML aml(PCIT::IPTR, PCIT::IPTR, PCIT::MBIN32S, PCIT::MBIN32S);
OL ol((Int64)targetClause, (Int64)0,
attrs[0]->getAtp(), attrs[0]->getAtpIndex(), (Int32)attrs[0]->getOffset(),
attrs[1]->getAtp(), attrs[1]->getAtpIndex(), (Int32)attrs[1]->getOffset());
// Generate the branch instruction
//
if (getOperType() == ITM_AND)
{
PCI pci(PCIT::Op_BRANCH_AND, aml, ol);
code.append(pci);
}
else
{
PCI pci(PCIT::Op_BRANCH_OR, aml, ol);
code.append(pci);
}
// Finish up and return
//
PCode::postClausePCI(this, code);
setPCIList(code.getList());
return ex_expr::EXPR_OK;
};
// ex_comp_clause::pCodeGenerate
//
// Generate PCI's for the comparison operation. The PCI's load the operands,
// do the comparison, and stores the tristate result.
//
// IN : space - memory allocator
// OUT :
// RETURN : ex_expr::EXPR_OK is no errors
// EFFECTS: stores pointer to PCodeObject in clause
//
ex_expr::exp_return_type ex_comp_clause::pCodeGenerate(Space *space, UInt32 f) {
#ifdef _DEBUG
// For debugging...
if(getenv("PCODE_NO_COMP")) return ex_clause::pCodeGenerate(space, f);
#endif
NABoolean flipOperands = FALSE;
AttributesPtr *attrs = getOperand();
Attributes *op1 = attrs[1];
Attributes *op2 = attrs[2];
// if this comp clause need to return the column num which caused the
// comparison to fail, then do not generate pcode. That functionality is
// not yet supported in pcode.
// This is used for rollup group computation which need to know the particular
// grouping column that caused the comparison to fail.
if (getRollupColumnNum() >= 0)
return ex_clause::pCodeGenerate(space, f);
// Generate the standard clause->eval PCode for cases that
// are not handled with more fundamental PCode operations.
//
switch(getInstruction()) {
case NE_ASCII_F_F:
case EQ_ASCII_F_F:
case LT_ASCII_F_F:
case LE_ASCII_F_F:
case GT_ASCII_F_F:
case GE_ASCII_F_F:
break;
case NE_UNICODE_F_F:
case EQ_UNICODE_F_F:
case LT_UNICODE_F_F:
case LE_UNICODE_F_F:
case GT_UNICODE_F_F:
case GE_UNICODE_F_F:
case UNICODE_COMP:
break ;
case COMP_COMPLEX:
if (attrs[1]->getClassID() != Attributes::BigNumID)
return ex_clause::pCodeGenerate(space, f);
break;
case ASCII_COMP:
// R2.4 has support for string compares of unequal lengths
if ((attrs[1]->getDatatype() != REC_BYTE_F_ASCII) ||
(attrs[2]->getDatatype() != REC_BYTE_F_ASCII))
return ex_clause::pCodeGenerate(space, f);
break;
case EQ_ASCII_COMP:
case NE_ASCII_COMP:
case LT_ASCII_COMP:
case LE_ASCII_COMP:
case GT_ASCII_COMP:
case GE_ASCII_COMP:
// PCIT::getMemoryAddressingMode(), used below, cannot currently handle these.
if ((attrs[1]->getDatatype() == REC_BYTE_V_ASCII_LONG ) ||
(attrs[2]->getDatatype() == REC_BYTE_V_ASCII_LONG ))
return ex_clause::pCodeGenerate(space, f);
break;
case EQ_BIN8S_BIN8S:
case EQ_BIN8U_BIN8U:
case EQ_BIN16S_BIN16S:
case EQ_BIN16S_BIN32S:
case EQ_BIN32S_BIN16S:
case EQ_BIN32S_BIN32S:
case EQ_BIN16U_BIN16U:
case EQ_BIN16U_BIN32U:
case EQ_BIN32U_BIN16U:
case EQ_BIN32U_BIN32U:
case EQ_BIN16S_BIN32U:
case EQ_BIN32U_BIN16S:
case LT_BIN8S_BIN8S:
case LT_BIN8U_BIN8U:
case LT_BIN16S_BIN16S:
case LT_BIN16S_BIN32S:
case LT_BIN32S_BIN16S:
case LT_BIN32S_BIN32S:
case LT_BIN16U_BIN16U:
case LT_BIN16U_BIN32U:
case LT_BIN32U_BIN16U:
case LT_BIN32U_BIN32U:
case LT_BIN16S_BIN32U:
case LT_BIN32U_BIN16S:
case GT_BIN8S_BIN8S:
case GT_BIN8U_BIN8U:
case GT_BIN16S_BIN16S:
case GT_BIN16S_BIN32S:
case GT_BIN32S_BIN16S:
case GT_BIN32S_BIN32S:
case GT_BIN16U_BIN16U:
case GT_BIN16U_BIN32U:
case GT_BIN32U_BIN16U:
case GT_BIN32U_BIN32U:
case GT_BIN16S_BIN32U:
case GT_BIN32U_BIN16S:
break;
case LE_BIN8S_BIN8S:
case LE_BIN8U_BIN8U:
case LE_BIN16S_BIN16S:
case LE_BIN16S_BIN32S:
case LE_BIN32S_BIN16S:
case LE_BIN32S_BIN32S:
case LE_BIN16U_BIN16U:
case LE_BIN16U_BIN32U:
case LE_BIN32U_BIN16U:
case LE_BIN32U_BIN32U:
case LE_BIN16S_BIN32U:
case LE_BIN32U_BIN16S:
case GE_BIN8S_BIN8S:
case GE_BIN8U_BIN8U:
case GE_BIN16S_BIN16S:
case GE_BIN16S_BIN32S:
case GE_BIN32S_BIN16S:
case GE_BIN32S_BIN32S:
case GE_BIN16U_BIN16U:
case GE_BIN16U_BIN32U:
case GE_BIN32U_BIN16U:
case GE_BIN32U_BIN32U:
case GE_BIN16S_BIN32U:
case GE_BIN32U_BIN16S:
break;
case EQ_BIN16U_BIN16S:
case LE_BIN16U_BIN16S:
case LT_BIN16U_BIN16S:
case GE_BIN16U_BIN16S:
case GT_BIN16U_BIN16S:
break;
case EQ_BIN64S_BIN64S:
case LE_BIN64S_BIN64S:
case LT_BIN64S_BIN64S:
case GE_BIN64S_BIN64S:
case GT_BIN64S_BIN64S:
case NE_BIN64S_BIN64S:
break;
case NE_BIN8S_BIN8S:
case NE_BIN8U_BIN8U:
case NE_BIN16S_BIN16S:
break;
case NE_FLOAT32_FLOAT32:
case EQ_FLOAT32_FLOAT32:
case LT_FLOAT32_FLOAT32:
case LE_FLOAT32_FLOAT32:
case GT_FLOAT32_FLOAT32:
case GE_FLOAT32_FLOAT32:
case NE_FLOAT64_FLOAT64:
case EQ_FLOAT64_FLOAT64:
case LT_FLOAT64_FLOAT64:
case LE_FLOAT64_FLOAT64:
case GT_FLOAT64_FLOAT64:
case GE_FLOAT64_FLOAT64:
break;
case EQ_DATETIME_DATETIME:
#ifndef NA_LITTLE_ENDIAN
case LT_DATETIME_DATETIME:
case GT_DATETIME_DATETIME:
case LE_DATETIME_DATETIME:
case GE_DATETIME_DATETIME:
#endif
// Do not generate PCODE to encode the non-standard SQL/MP
// datetime types (for now).
if ((attrs[1]->getPrecision() > REC_DTCODE_TIMESTAMP) ||
(attrs[1]->getPrecision() != attrs[2]->getPrecision()) ||
(attrs[1]->getLength() != attrs[2]->getLength()))
return ex_clause::pCodeGenerate(space, f);
break;
case EQ_BOOL_BOOL:
case NE_BOOL_BOOL:
break;
default:
return ex_clause::pCodeGenerate(space, f);
}
// Generate the comparison operator
//
PCIT::Operation op = PCIT::Op_OPDATA; // prevent init warning
switch(getInstruction()) {
case EQ_BIN32S_BIN16S:
case EQ_BIN32U_BIN16U:
case EQ_BIN32U_BIN16S:
// Normalize instructions so smaller operand comes first
flipOperands = TRUE;
op = PCIT::Op_EQ;
break;
case EQ_BIN8S_BIN8S:
case EQ_BIN8U_BIN8U:
case EQ_BIN16U_BIN16S:
case EQ_BIN16S_BIN16S:
case EQ_BIN16S_BIN32S:
case EQ_BIN32S_BIN32S:
case EQ_BIN16U_BIN16U:
case EQ_BIN16U_BIN32U:
case EQ_BIN32U_BIN32U:
case EQ_BIN16S_BIN32U:
case EQ_FLOAT32_FLOAT32:
case EQ_FLOAT64_FLOAT64:
case EQ_BIN64S_BIN64S:
case EQ_ASCII_F_F:
case EQ_ASCII_COMP:
case EQ_DATETIME_DATETIME:
op = PCIT::Op_EQ;
break;
case EQ_BOOL_BOOL:
op = PCIT::Op_EQ;
break;
case LT_BIN32S_BIN16S:
case LT_BIN32U_BIN16U:
case LT_BIN32U_BIN16S:
// Normalize instructions so smaller operand comes first
flipOperands = TRUE;
op = PCIT::Op_GT;
break;
case LT_BIN8S_BIN8S:
case LT_BIN8U_BIN8U:
case LT_BIN16U_BIN16S:
case LT_BIN16S_BIN16S:
case LT_BIN16S_BIN32S:
case LT_BIN32S_BIN32S:
case LT_BIN16U_BIN16U:
case LT_BIN16U_BIN32U:
case LT_BIN32U_BIN32U:
case LT_BIN16S_BIN32U:
case LT_BIN64S_BIN64S:
case LT_FLOAT32_FLOAT32:
case LT_FLOAT64_FLOAT64:
case LT_ASCII_F_F:
case LT_ASCII_COMP:
case LT_DATETIME_DATETIME:
op = PCIT::Op_LT;
break;
case GT_BIN32S_BIN16S:
case GT_BIN32U_BIN16U:
case GT_BIN32U_BIN16S:
// Normalize instructions so smaller operand comes first
flipOperands = TRUE;
op = PCIT::Op_LT;
break;
case GT_BIN8S_BIN8S:
case GT_BIN8U_BIN8U:
case GT_BIN16U_BIN16S:
case GT_BIN16S_BIN16S:
case GT_BIN16S_BIN32S:
case GT_BIN32S_BIN32S:
case GT_BIN16U_BIN16U:
case GT_BIN16U_BIN32U:
case GT_BIN32U_BIN32U:
case GT_BIN16S_BIN32U:
case GT_FLOAT32_FLOAT32:
case GT_FLOAT64_FLOAT64:
case GT_BIN64S_BIN64S:
case GT_ASCII_F_F:
case GT_ASCII_COMP:
case GT_DATETIME_DATETIME:
op = PCIT::Op_GT;
break;
case LE_BIN32S_BIN16S:
case LE_BIN32U_BIN16U:
case LE_BIN32U_BIN16S:
// Normalize instructions so smaller operand comes first
flipOperands = TRUE;
op = PCIT::Op_GE;
break;
case LE_BIN8S_BIN8S:
case LE_BIN8U_BIN8U:
case LE_BIN16U_BIN16S:
case LE_BIN16S_BIN16S:
case LE_BIN16S_BIN32S:
case LE_BIN32S_BIN32S:
case LE_BIN16U_BIN16U:
case LE_BIN16U_BIN32U:
case LE_BIN32U_BIN32U:
case LE_BIN16S_BIN32U:
case LE_FLOAT32_FLOAT32:
case LE_FLOAT64_FLOAT64:
case LE_BIN64S_BIN64S:
case LE_ASCII_F_F:
case LE_ASCII_COMP:
case LE_DATETIME_DATETIME:
op = PCIT::Op_LE;
break;
case GE_BIN32S_BIN16S:
case GE_BIN32U_BIN16U:
case GE_BIN32U_BIN16S:
// Normalize instructions so smaller operand comes first
flipOperands = TRUE;
op = PCIT::Op_LE;
break;
case GE_BIN8S_BIN8S:
case GE_BIN8U_BIN8U:
case GE_BIN16U_BIN16S:
case GE_BIN16S_BIN16S:
case GE_BIN16S_BIN32S:
case GE_BIN32S_BIN32S:
case GE_BIN16U_BIN16U:
case GE_BIN16U_BIN32U:
case GE_BIN32U_BIN32U:
case GE_BIN16S_BIN32U:
case GE_FLOAT32_FLOAT32:
case GE_FLOAT64_FLOAT64:
case GE_BIN64S_BIN64S:
case GE_ASCII_F_F:
case GE_ASCII_COMP:
#ifndef NA_LITTLE_ENDIAN
case GE_DATETIME_DATETIME:
#endif
op = PCIT::Op_GE;
break;
case NE_BIN8S_BIN8S:
case NE_BIN8U_BIN8U:
case NE_FLOAT32_FLOAT32:
case NE_FLOAT64_FLOAT64:
case NE_BIN64S_BIN64S:
case NE_BIN16S_BIN16S:
case NE_ASCII_COMP:
case NE_ASCII_F_F:
case NE_BOOL_BOOL:
op = PCIT::Op_NE;
break;
case ASCII_COMP:
case UNICODE_COMP:
case COMP_COMPLEX:
case EQ_UNICODE_F_F:
case LT_UNICODE_F_F:
case GT_UNICODE_F_F:
case LE_UNICODE_F_F:
case GE_UNICODE_F_F:
case NE_UNICODE_F_F:
op = PCIT::Op_COMP;
break;
}
// No NULLS for now
//
if (isAnyOperandNullable())
{
// if special nulls, only handle equality predicate.
if ( isSpecialNulls() && (getOperType() != ITM_EQUAL) )
return ex_clause::pCodeGenerate(space, f);
}
// Allocate the code list and get a handle on the attributes.
//
PCIList code(space);
// Don't get mixed up in interval conversions. The precision for
// interval conversions is not set up correctly.
//
Attributes *tgt = attrs[0];
if((op1->getDatatype() >= REC_MIN_INTERVAL) &&
(op1->getDatatype() <= REC_MAX_INTERVAL) &&
(op2->getDatatype() >= REC_MIN_INTERVAL) &&
(op2->getDatatype() <= REC_MAX_INTERVAL))
return ex_clause::pCodeGenerate(space, f);
// Generate pre clause PCI's
//
PCode::preClausePCI(this, code);
// Add the null logic if necessary.
//
PCIID branchToEnd = PCode::nullBranch(this, code, attrs);
if ((op1->getDatatype() == REC_NUM_BIG_SIGNED) ||
(op1->getDatatype() == REC_NUM_BIG_UNSIGNED))
{
// Operand 1: memory location of boolean result
// Operand 2: memory location of 1st argument
// Operand 3: memory location of 2nd argument
// Operand 4: length of data to compare
// Operand 5: comparison operand
AML aml(PCIT::getMemoryAddressingMode(attrs[0]->getDatatype()),
PCIT::MBIGS,
PCIT::MBIGS,
PCIT::IBIN32S,
PCIT::IBIN32S);
OL ol(attrs[0]->getAtp(), attrs[0]->getAtpIndex(), attrs[0]->getOffset(),
attrs[1]->getAtp(), attrs[1]->getAtpIndex(), attrs[1]->getOffset(),
attrs[2]->getAtp(), attrs[2]->getAtpIndex(), attrs[2]->getOffset(),
attrs[2]->getLength(), (Int32)getOperType());
// Add the comparison instruction.
//
PCI pci(op, aml, ol);
code.append(pci);
}
// both the operands are fixed chars/unicode or are of type DATETIME
// or of type boolean.
else if (((op1->getDatatype() == REC_BYTE_F_ASCII) &&
(op2->getDatatype() == REC_BYTE_F_ASCII)) ||
((op1->getDatatype() == REC_NCHAR_F_UNICODE) &&
(op2->getDatatype() == REC_NCHAR_F_UNICODE)) ||
(op1->getDatatype() == REC_DATETIME) ||
(op1->getDatatype() == REC_BOOLEAN))
{
// Operand 1: memory location of boolean result
// Operand 2: memory location of 1st argument
// Operand 3: memory location of 2nd argument
// Operand 4: length of data to compare
short attrs1Datatype = op1->getDatatype();
short attrs2Datatype = op2->getDatatype();
if (attrs1Datatype == REC_DATETIME)
{
attrs1Datatype = REC_BYTE_F_ASCII;
attrs2Datatype = REC_BYTE_F_ASCII;
}
// Set "s" for attribute number with smaller string.
Int32 s = (attrs[1]->getLength() > attrs[2]->getLength()) ? 2 : 1;
Int32 l = (s == 1) ? 2 : 1;
OperatorTypeEnum operType = getOperType();
// The operator must be "flipped" as well if the strings were flipped
if (s == 2) {
switch (operType) {
case ITM_LESS:
operType = ITM_GREATER;
break;
case ITM_GREATER:
operType = ITM_LESS;
break;
case ITM_GREATER_EQ:
operType = ITM_LESS_EQ;
break;
case ITM_LESS_EQ:
operType = ITM_GREATER_EQ;
break;
}
}
Int32 sLen = attrs[s]->getLength();
Int32 lLen = attrs[l]->getLength();
// Lens of unicode strings for this inst should be in num of double-bytes
if (attrs1Datatype == REC_NCHAR_F_UNICODE) {
sLen = sLen >> 1;
lLen = lLen >> 1;
}
if (op == PCIT::Op_COMP) {
// Only different lengths should use COMP pcode instruction. Regression
// seen otherwise if COMP instruction used for all cases - 3% in DWP.
AML aml(PCIT::getMemoryAddressingMode(attrs[0]->getDatatype()),
PCIT::getMemoryAddressingMode(attrs1Datatype),
PCIT::getMemoryAddressingMode(attrs2Datatype),
PCIT::IBIN32S, PCIT::IBIN32S, PCIT::IBIN32S);
// Smaller string is always the first operand
OL ol(attrs[0]->getAtp(), attrs[0]->getAtpIndex(), attrs[0]->getOffset(),
attrs[s]->getAtp(), attrs[s]->getAtpIndex(), attrs[s]->getOffset(),
attrs[l]->getAtp(), attrs[l]->getAtpIndex(), attrs[l]->getOffset(),
sLen, lLen, (Int32)operType);
// Add the comparison instruction.
//
PCI pci(PCIT::Op_COMP, aml, ol);
code.append(pci);
}
else
{
// Same length should use faster pcode
AML aml(PCIT::getMemoryAddressingMode(attrs[0]->getDatatype()),
PCIT::getMemoryAddressingMode(attrs1Datatype),
PCIT::getMemoryAddressingMode(attrs2Datatype),
PCIT::IBIN32S);
// Smaller string is always the first operand
OL ol(attrs[0]->getAtp(), attrs[0]->getAtpIndex(), attrs[0]->getOffset(),
attrs[s]->getAtp(), attrs[s]->getAtpIndex(), attrs[s]->getOffset(),
attrs[l]->getAtp(), attrs[l]->getAtpIndex(), attrs[l]->getOffset(),
sLen);
// Add the comparison instruction.
//
PCI pci(op, aml, ol);
code.append(pci);
}
}
// One of the operand is a varchar
else if (((op1->getDatatype() == REC_BYTE_V_ASCII) ||
(op2->getDatatype() == REC_BYTE_V_ASCII)) ||
((op1->getDatatype() == REC_NCHAR_V_UNICODE) ||
(op2->getDatatype() == REC_NCHAR_V_UNICODE)))
{
// get the actual length if operands are varchars.
UInt32 len1 = attrs[1]->getLength();
UInt32 len2 = attrs[2]->getLength();
UInt32 comboLen1 = 0, comboLen2 = 0;
char* comboPtr1 = (char*)&comboLen1;
char* comboPtr2 = (char*)&comboLen2;
PCIT::AddressingMode srcAm =
(((op1->getDatatype() == REC_BYTE_V_ASCII) ||
(op2->getDatatype() == REC_BYTE_V_ASCII))
? PCIT::MATTR5
: PCIT::MUNIV);
comboPtr1[0] = (char)attrs[1]->getNullIndicatorLength();
comboPtr1[1] = (char)attrs[1]->getVCIndicatorLength();
comboPtr2[0] = (char)attrs[2]->getNullIndicatorLength();
comboPtr2[1] = (char)attrs[2]->getVCIndicatorLength();
AML aml(PCIT::getMemoryAddressingMode(attrs[0]->getDatatype()), // target
srcAm, srcAm, PCIT::IBIN32S);
OL ol(attrs[0]->getAtp(), attrs[0]->getAtpIndex(), attrs[0]->getOffset(),
attrs[1]->getAtp(), attrs[1]->getAtpIndex(), attrs[1]->getOffset(),
attrs[1]->getVoaOffset(), len1, comboLen1,
attrs[2]->getAtp(), attrs[2]->getAtpIndex(), attrs[2]->getOffset(),
attrs[2]->getVoaOffset(), len2, comboLen2,
(Int32)getOperType());
// Add the comparison instruction.
//
PCI pci(PCIT::Op_COMP, aml, ol);
code.append(pci);
}
else
{
// Operand 1: memory location of boolean result
// Operand 2: memory location of 1st argument
// Operand 3: memory location of 2nd argument
//
if (flipOperands) {
Attributes* tempOp;
tempOp = op1;
op1 = op2;
op2 = tempOp;
}
AML aml(PCIT::getMemoryAddressingMode(attrs[0]->getDatatype()),
PCIT::getMemoryAddressingMode(op1->getDatatype()),
PCIT::getMemoryAddressingMode(op2->getDatatype()));
OL ol(attrs[0]->getAtp(), attrs[0]->getAtpIndex(), attrs[0]->getOffset(),
op1->getAtp(), op1->getAtpIndex(), op1->getOffset(),
op2->getAtp(), op2->getAtpIndex(), op2->getOffset());
// Add the comparison instruction.
//
PCI pci(op, aml, ol);
code.append(pci);
}
// Add the branch target if necessary.
//
if(branchToEnd)
{
AML aml;
OL ol((Int64)branchToEnd);
PCI pci(PCIT::Op_TARGET, aml, ol);
code.append(pci);
}
// Generate post clause PCI's
//
PCode::postClausePCI(this, code);
setPCIList(code.getList());
return ex_expr::EXPR_OK;
};
// ex_aggregate_clause::pCodeGenerate
//
// Does nothing.
//
ex_expr::exp_return_type ex_noop_clause::pCodeGenerate(Space *space, UInt32 f) {
//
PCIList code(space);
// Generate pre clause PCI's
//
PCode::preClausePCI(this, code);
// Generate post clause PCI's
//
PCode::postClausePCI(this, code);
setPCIList(code.getList());
return ex_expr::EXPR_OK;
};
// ex_unlogic_clause::pCodeGenerate
//
// Generate PCI's for the unilogic operations. The PCI's load the operand,
// perform the logical test, and store the tristate result.
//
// IN : space - memory allocator
// OUT :
// RETURN : ex_expr::EXPR_OK is no errors
// EFFECTS: stores pointer to PCodeObject in clause
//
ex_expr::exp_return_type ex_unlogic_clause::pCodeGenerate(Space *space, UInt32 f) {
#ifdef _DEBUG
// For debugging...
if(getenv("PCODE_NO_UNLOGIC")) return ex_clause::pCodeGenerate(space, f);
#endif
// Generate the standard clause->eval PCode for cases that
// are not handled with more fundamental PCode operations.
//
switch(getOperType()) {
case ITM_IS_NULL:
case ITM_IS_NOT_NULL:
break;
default:
return ex_clause::pCodeGenerate(space, f);
}
// Allocate the code list and get a handle on the attributes
//
PCIList code(space);
AttributesPtr *attrs = getOperand();
// Generate pre clause PCI's
//
PCode::preClausePCI(this, code);
// Do the test
//
switch(getOperType()) {
case ITM_IS_NULL:
// If the attribute is not nullable, then it is NOT NULL for sure
if(!attrs[1]->getNullFlag())
code.append(PCode::storeValue(0, attrs[0], space));
// Otherwise, actually test it
else
code.append(PCode::isNull(attrs[0], attrs[1], space));
break;
case ITM_IS_NOT_NULL:
// If the attribute is not nullable, then it is NOT NULL for sure
if(!attrs[1]->getNullFlag())
code.append(PCode::storeValue(1, attrs[0], space));
// Otherwise, actually test it
else
code.append(PCode::isNotNull(attrs[0], attrs[1], space));
break;
}
// Generate post clause PCI's
//
PCode::postClausePCI(this, code);
setPCIList(code.getList());
return ex_expr::EXPR_OK;
};
// ex_function_bool::pCodeGenerate
//
// Generate PCI's for the bool operation. The PCI's load the constant
// boolean value.
//
// IN : space - memory allocator
// OUT :
// RETURN : ex_expr::EXPR_OK is no errors
// EFFECTS: stores pointer to PCodeObject in clause
//
ex_expr::exp_return_type ex_function_bool::pCodeGenerate(Space *space, UInt32 f) {
#ifdef _DEBUG
// For debugging...
if(getenv("PCODE_NO_BOOL")) return ex_clause::pCodeGenerate(space, f);
#endif
// Get a handle on the operands
//
AttributesPtr *attrs = getOperand();
// Allocate the code list
//
PCIList code(space);
// Generate pre clause PCI's
//
PCode::preClausePCI(this, code);
Int32 returnValue;
switch(getOperType()) {
case ITM_RETURN_TRUE: returnValue = 1; break;
case ITM_RETURN_FALSE: returnValue = 0; break;
case ITM_RETURN_NULL: returnValue = -1; break;
default: return ex_clause::pCodeGenerate(space, f); break;
}
// First operand is the memory location of the result
// Second operand is the immediate value to store in the result
//
AML aml(PCIT::MBIN32S, PCIT::IBIN32S);
OL ol(attrs[0]->getAtp(), attrs[0]->getAtpIndex(), attrs[0]->getOffset(),
returnValue);
// Add the move instruction.
//
PCI pci(PCIT::Op_MOVE, aml, ol);
code.append(pci);
// Generate post clause PCI's
//
PCode::postClausePCI(this, code);
setPCIList(code.getList());
return ex_expr::EXPR_OK;
}
// ExHDPHash::pCodeGenerate
//
// Generate PCI's for the hash operation used by hash partitioning. The PCI's
// load the operands addresses and calls the hash function.
//
// IN : space - memory allocator
// OUT :
// RETURN : ex_expr::EXPR_OK is no errors
// EFFECTS: stores pointer to PCodeObject in clause
//
ex_expr::exp_return_type ExHDPHash::pCodeGenerate(Space *space, UInt32 f)
{
// NOTE - This code is identical to exp_function_hash::pCodeGenerate().
// Ideally we should be able to cast the this pointer to exp_function_hash
// and call its pCodeGenerate(), but it doesn't work that way - the vtbl
// entry isn't updated, and so we end up just calling this pCodeGenerate
// again, resulting in an infinite loop. So just duplicate the code below
// and keep it up-to-date.
#ifdef _DEBUG
// For debugging...
if(getenv("PCODE_NO_HASH")) return ex_clause::pCodeGenerate(space, f);
#endif
AttributesPtr *attrs = getOperand();
// Don't handle indirect varchars if CQD says so
if ( attrs[1]->isIndirectVC() && (NOT handleIndirectVC()) )
return ex_clause::pCodeGenerate(space, f);
// Allocate the code list and get a handle on the attributes
//
PCIList code(space);
// Generate pre clause PCI's
//
PCode::preClausePCI(this, code);
// Add the null logic if necessary.
//
PCIID branchToEnd = PCode::nullBranch(this, code, attrs);
// The first operand is the memory location of the result.
// The second operand is the memory location of the data.
// The third operand is the length of the data.
//
PCIType::AddressingMode oper;
if (attrs[1]->getLength() == 8)
oper = PCIT::MBIN64S;
else if (attrs[1]->getLength() == 4)
oper = PCIT::MBIN32S;
else if (attrs[1]->getLength() == 2)
oper = PCIT::MBIN16S;
else
oper = PCIT::MPTR32;
UInt32 flags = NO_FLAGS;
switch(attrs[1]->getDatatype()) {
case REC_NUM_BIG_UNSIGNED:
case REC_NUM_BIG_SIGNED:
case REC_BIN16_SIGNED:
case REC_BIN16_UNSIGNED:
case REC_NCHAR_F_UNICODE:
case REC_NCHAR_V_UNICODE:
case REC_NCHAR_V_ANSI_UNICODE:
flags = SWAP_TWO;
break;
case REC_BIN32_SIGNED:
case REC_BIN32_UNSIGNED:
case REC_IEEE_FLOAT32:
flags = SWAP_FOUR;
break;
case REC_BIN64_SIGNED:
case REC_IEEE_FLOAT64:
flags = SWAP_EIGHT;
break;
case REC_DATETIME:
{
oper = PCIT::MPTR32;
rec_datetime_field start;
rec_datetime_field end;
ExpDatetime *datetime = (ExpDatetime*) getOperand(1);
datetime->getDatetimeFields(attrs[1]->getPrecision(), start, end);
if(start == REC_DATE_YEAR) {
flags = SWAP_FIRSTTWO;
}
if(end == REC_DATE_SECOND && attrs[1]->getScale() > 0) {
flags |= SWAP_LASTFOUR;
}
}
break;
default:
if(attrs[1]->getDatatype() >= REC_MIN_INTERVAL &&
attrs[1]->getDatatype() <= REC_MAX_INTERVAL) {
if (attrs[1]->getLength() == 8)
flags = SWAP_EIGHT;
else if (attrs[1]->getLength() == 4)
flags = SWAP_FOUR;
else if (attrs[1]->getLength() == 2)
flags = SWAP_TWO;
else
assert(FALSE);
}
}
// handle varchar
if (attrs[1]->getVCIndicatorLength() > 0)
{
UInt32 comboLen = 0;
char* comboPtr = (char*)&comboLen;
// Use combo fields for specifying vc/null lengths of both operands
comboPtr[0] = (char)attrs[1]->getNullIndicatorLength(),
comboPtr[1] = (char)attrs[1]->getVCIndicatorLength();
AML aml(PCIT::MBIN32U,
PCIT::getMemoryAddressingMode(attrs[1]->getDatatype()));
OL ol(attrs[0]->getAtp(), attrs[0]->getAtpIndex(),attrs[0]->getOffset(),
attrs[1]->getAtp(), attrs[1]->getAtpIndex(),attrs[1]->getOffset(),
attrs[1]->getVoaOffset(), attrs[1]->getLength(), comboLen);
PCI pci(PCIT::Op_HASH, aml, ol);
code.append( pci);
}
else
{
AML aml(PCIT::MBIN32U, oper, PCIT::IBIN32S, PCIT::IBIN32S);
OL ol(attrs[0]->getAtp(), attrs[0]->getAtpIndex(), attrs[0]->getOffset(),
attrs[1]->getAtp(), attrs[1]->getAtpIndex(), attrs[1]->getOffset(),
flags, attrs[1]->getLength());
PCI pci(PCIT::Op_HASH, aml, ol);
code.append( pci);
}
// Add the branch target if necessary.
//
if(branchToEnd)
{
AML aml;
OL ol((Int64)branchToEnd);
PCI pci(PCIT::Op_TARGET, aml, ol);
code.append(pci);
}
// Generate post clause PCI's
//
PCode::postClausePCI(this, code);
setPCIList(code.getList());
return ex_expr::EXPR_OK;
}
// ex_function_hash::pCodeGenerate
//
// Generate PCI's for the hash operation. The PCI's load the operands
// addresses and calls the hash function.
//
// IN : space - memory allocator
// OUT :
// RETURN : ex_expr::EXPR_OK is no errors
// EFFECTS: stores pointer to PCodeObject in clause
//
ex_expr::exp_return_type ex_function_hash::pCodeGenerate(Space *space, UInt32 f)
{
#ifdef _DEBUG
// For debugging...
if(getenv("PCODE_NO_HASH")) return ex_clause::pCodeGenerate(space, f);
#endif
AttributesPtr *attrs = getOperand();
// Don't handle indirect varchars if CQD says so
if ( attrs[1]->isIndirectVC() && (NOT handleIndirectVC()) )
return ex_clause::pCodeGenerate(space, f);
// Allocate the code list and get a handle on the attributes
//
PCIList code(space);
// Generate pre clause PCI's
//
PCode::preClausePCI(this, code);
// Add the null logic if necessary.
//
PCIID branchToEnd = PCode::nullBranch(this, code, attrs);
// The first operand is the memory location of the result.
// The second operand is the memory location of the data.
// The third operand is the length of the data.
//
PCIType::AddressingMode oper;
if (attrs[1]->getLength() == 8)
oper = PCIT::MBIN64S;
else if (attrs[1]->getLength() == 4)
oper = PCIT::MBIN32S;
else if (attrs[1]->getLength() == 2)
oper = PCIT::MBIN16S;
else
oper = PCIT::MPTR32;
// handle varchar
if (attrs[1]->getVCIndicatorLength() > 0)
{
UInt32 comboLen = 0;
char* comboPtr = (char*)&comboLen;
// Use combo fields for specifying vc/null lengths of both operands
comboPtr[0] = (char)attrs[1]->getNullIndicatorLength(),
comboPtr[1] = (char)attrs[1]->getVCIndicatorLength();
AML aml(PCIT::MBIN32U,
PCIT::getMemoryAddressingMode(attrs[1]->getDatatype()));
OL ol(attrs[0]->getAtp(), attrs[0]->getAtpIndex(),attrs[0]->getOffset(),
attrs[1]->getAtp(), attrs[1]->getAtpIndex(),attrs[1]->getOffset(),
attrs[1]->getVoaOffset(), attrs[1]->getLength(), comboLen);
PCI pci(PCIT::Op_HASH, aml, ol);
code.append( pci);
}
else
{
UInt32 flags = ExHDPHash::NO_FLAGS;
AML aml(PCIT::MBIN32U, oper, PCIT::IBIN32S, PCIT::IBIN32S);
OL ol(attrs[0]->getAtp(), attrs[0]->getAtpIndex(), attrs[0]->getOffset(),
attrs[1]->getAtp(), attrs[1]->getAtpIndex(), attrs[1]->getOffset(),
flags, attrs[1]->getLength());
PCI pci(PCIT::Op_HASH, aml, ol);
code.append( pci);
}
// Add the branch target if necessary.
//
if(branchToEnd)
{
AML aml;
OL ol((Int64)branchToEnd);
PCI pci(PCIT::Op_TARGET, aml, ol);
code.append(pci);
}
// Generate post clause PCI's
//
PCode::postClausePCI(this, code);
setPCIList(code.getList());
return ex_expr::EXPR_OK;
}
// ExHDPHashComb::pCodeGenerate
//
// Generate PCI's for the hash value combination operation. The PCI's load
// the operands, perform the bit scrambling and bitwise xor operations,
// and store the result.
//
// IN : space - memory allocator
// OUT :
// RETURN : ex_expr::EXPR_OK is no errors
// EFFECTS: stores pointer to PCodeObject in clause
//
ex_expr::exp_return_type ExHDPHashComb::pCodeGenerate(Space *space, UInt32 f) {
#ifdef _DEBUG
// For debugging...
if(getenv("PCODE_NO_HASHCOMB")) return ex_clause::pCodeGenerate(space, f);
#endif
// Get a handle on the operands
//
AttributesPtr *attrs = getOperand();
// Use the default pCodeGenerate for cases not handles here
//
if((attrs[1]->getLength() != 4) || (attrs[2]->getLength() != 4))
return ex_clause::pCodeGenerate(space, f);
// Allocate the code list
//
PCIList code(space);
// Generate pre clause PCI's
//
PCode::preClausePCI(this, code);
// Operand 1: memory location of HASHCOMB result
// Operand 2: memory location of 1st argument
// Operand 3: memory location of 2nd argument
//
AML aml(PCIT::getMemoryAddressingMode(attrs[0]->getDatatype()),
PCIT::getMemoryAddressingMode(attrs[1]->getDatatype()),
PCIT::getMemoryAddressingMode(attrs[2]->getDatatype()));
OL ol(attrs[0]->getAtp(), attrs[0]->getAtpIndex(), attrs[0]->getOffset(),
attrs[1]->getAtp(), attrs[1]->getAtpIndex(), attrs[1]->getOffset(),
attrs[2]->getAtp(), attrs[2]->getAtpIndex(), attrs[2]->getOffset());
// Generate the operator
//
PCIT::Operation op = PCIT::Op_HASHCOMB;
// Add the comparison instruction.
//
PCI pci(op, aml, ol);
code.append(pci);
// Generate post clause PCI's
//
PCode::postClausePCI(this, code);
setPCIList(code.getList());
return ex_expr::EXPR_OK;
}
// ExHashComb::pCodeGenerate
//
// Generate PCI's for the hash value combination operation. The PCI's load
// the operands, perform the bit scrambling and bitwise xor operations,
// and store the result.
//
// IN : space - memory allocator
// OUT :
// RETURN : ex_expr::EXPR_OK is no errors
// EFFECTS: stores pointer to PCodeObject in clause
//
ex_expr::exp_return_type ExHashComb::pCodeGenerate(Space *space, UInt32 f) {
#ifdef _DEBUG
// For debugging...
if(getenv("PCODE_NO_HASHCOMB")) return ex_clause::pCodeGenerate(space, f);
#endif
// Get a handle on the operands
//
AttributesPtr *attrs = getOperand();
// Use the default pCodeGenerate for cases not handles here
//
if((attrs[1]->getLength() != 4) || (attrs[2]->getLength() != 4))
return ex_clause::pCodeGenerate(space, f);
// Allocate the code list
//
PCIList code(space);
// Generate pre clause PCI's
//
PCode::preClausePCI(this, code);
// Operand 1: memory location of HASHCOMB result
// Operand 2: memory location of 1st argument
// Operand 3: memory location of 2nd argument
//
AML aml(PCIT::getMemoryAddressingMode(attrs[0]->getDatatype()),
PCIT::getMemoryAddressingMode(attrs[1]->getDatatype()),
PCIT::getMemoryAddressingMode(attrs[2]->getDatatype()));
OL ol(attrs[0]->getAtp(), attrs[0]->getAtpIndex(), attrs[0]->getOffset(),
attrs[1]->getAtp(), attrs[1]->getAtpIndex(), attrs[1]->getOffset(),
attrs[2]->getAtp(), attrs[2]->getAtpIndex(), attrs[2]->getOffset());
// Generate the operator
//
PCIT::Operation op = PCIT::Op_HASHCOMB;
// Add the comparison instruction.
//
PCI pci(op, aml, ol);
code.append(pci);
// Generate post clause PCI's
//
PCode::postClausePCI(this, code);
setPCIList(code.getList());
return ex_expr::EXPR_OK;
}
// ex_replace_null_clause::pCodeGenerate
//
//
ex_expr::exp_return_type ex_function_replace_null::pCodeGenerate(Space *space, UInt32 f){
#ifdef _DEBUG
// For debugging...
if(getenv("PCODE_NO_REPLACE_NULL")) return ex_clause::pCodeGenerate(space, f);
#endif
// Get a handle on the attributes
//
AttributesPtr *attrs = getOperand();
switch(attrs[0]->getDatatype()) {
case REC_BIN32_SIGNED:
case REC_BIN32_UNSIGNED:
case REC_BIN16_SIGNED:
case REC_BIN16_UNSIGNED:
break;
default:
return ex_clause::pCodeGenerate(space, f);
}
// Allocate the code list and get a handle on the attributes
//
PCIList code(space);
// Generate pre clause PCI's
//
PCode::preClausePCI(this, code);
Attributes *tgt = attrs[0];
Attributes *op1 = attrs[1];
Attributes *op2 = attrs[2];
if (NOT op1->getNullFlag() ) // value is not nullable
{
AML aml(PCIT::MBIN8, PCIT::MBIN8, // these two types must be the same
PCIT::IBIN32S);
OL ol(tgt->getAtp(), tgt->getAtpIndex(), tgt->getOffset(), // result
op2->getAtp(), op2->getAtpIndex(), op2->getOffset(), // result to use for non-null
tgt->getLength());
PCI pci(PCIT::Op_MOVE, aml, ol);
code.append(pci);
}
else
{
Attributes *op3 = attrs[3];
// First operand is the result--either second or third operand is null.
// Second operand is the null indicator of the value to test for nullness
// Third operand is the immediate value to return if first value is not null
// Fourth operand is the immediate value to return if first value is null
// Fifth operand is the length of operands three and four.
AML aml(PCIT::getMemoryAddressingMode(op2->getDatatype()),
PCIT::MATTR3,PCIT::MBIN8,PCIT::MBIN8,PCIT::IBIN32S);
OL ol(tgt->getAtp(), tgt->getAtpIndex(), tgt->getOffset(), // result
op1->getAtp(), op1->getAtpIndex(),
op1->getNullIndOffset(), op1->getNullBitIndex(), // value to check
op2->getAtp(), op2->getAtpIndex(), op2->getOffset(), // result to use for non-null
op3->getAtp(), op3->getAtpIndex(), op3->getOffset(), // result to use for null
op2->getLength()); // length of replacement value
// Add the REPLACE NULL instruction.
//
PCI pci(PCIT::Op_REPLACE_NULL, aml, ol);
code.append(pci);
}
// Generate post clause PCI's
//
PCode::postClausePCI(this, code);
setPCIList(code.getList());
return ex_expr::EXPR_OK;
}
// Helpers for working with attributes
//
Int32 isSameAttribute(Attributes *attrA, Attributes *attrB) {
if(attrA->getAtpIndex() != attrB->getAtpIndex()) return 0;
if(attrA->getOffset() != attrB->getOffset()) return 0;
return 1;
};
Int32 isConstantAttribute(Attributes *attr) { return attr->getAtpIndex() == 0; };
Int32 isTemporaryAttribute(Attributes *attr) { return attr->getAtpIndex() == 1;};
Int32 isAtpAttribute(Attributes *attr) { return attr->getAtpIndex() > 1; };
ex_expr::exp_return_type ex_arith_clause::unaryArithPCodeGenerate
(Space *space, UInt32 f)
{
if (getNumOperands() != 2)
return ex_expr::EXPR_ERROR;
AttributesPtr *attrs = getOperand();
switch(getInstruction()) {
case NEGATE_BOOLEAN:
break;
default:
return ex_clause::pCodeGenerate(space, f);
}
// Allocate the code list and get a handle on the attributes
//
PCIList code(space);
// Don't get mixed up in interval conversions. The precision for
// interval conversions is not set up correctly.
//
Attributes *dst = attrs[0];
Attributes *op1 = attrs[1];
// Generate pre clause PCI's
//
PCode::preClausePCI(this, code);
// Construct the operands.
//
OL ol2(dst->getAtp(), dst->getAtpIndex(), dst->getOffset(),
op1->getAtp(), op1->getAtpIndex(), op1->getOffset());
AML aml2(PCIT::getMemoryAddressingMode(dst->getDatatype()),
PCIT::getMemoryAddressingMode(op1->getDatatype()));
// Construct the operation.
//
AML *aml = NULL;
OL *ol = NULL;
PCIT::Operation inst = PCIT::Op_OPDATA; // prevent uninitialized var warning
switch(getInstruction())
{
case NEGATE_BOOLEAN:
aml = &aml2;
ol = &ol2;
inst = PCIT::Op_NEG;
break;
}
// Add the null logic if necessary.
//
PCIID branchToEnd = PCode::nullBranch(this, code, attrs);
// Add the instruction.
//
PCI pci(inst, *aml, *ol);
code.append(pci);
// Add the branch target if necessary.
//
if(branchToEnd)
{
AML aml;
OL ol((Int64)branchToEnd);
PCI pci(PCIT::Op_TARGET, aml, ol);
code.append(pci);
}
// Generate post clause PCI's
//
PCode::postClausePCI(this, code);
setPCIList(code.getList());
return ex_expr::EXPR_OK;
}
// ex_arith_clause::pCodeGenerate
//
// Generate PCI's for the arithematic operations. The PCI's load the operands,
// do the arithematic, and then store the result.
//
// IN : space - memory allocator
// OUT :
// RETURN : ex_expr::EXPR_OK is no errors
// EFFECTS: stores pointer to PCodeObject in clause
//
ex_expr::exp_return_type ex_arith_clause::pCodeGenerate(Space *space, UInt32 f) {
#ifdef _DEBUG
// For debugging...
if(getenv("PCODE_NO_ARITH")) return ex_clause::pCodeGenerate(space, f);
#endif
// if unary arith operator, generator unary pcode.
if (getNumOperands() == 2) // 1 result and 1 operand
{
return unaryArithPCodeGenerate(space, f);
}
// Generate the standard clause->eval PCode for cases that
// are not handled with more fundamental PCode operations.
//
AttributesPtr *attrs = getOperand();
switch(getInstruction()) {
case ADD_BIN16S_BIN16S_BIN16S:
case ADD_BIN32S_BIN32S_BIN32S:
case ADD_BIN64S_BIN64S_BIN64S:
case SUB_BIN16S_BIN16S_BIN16S:
case SUB_BIN32S_BIN32S_BIN32S:
case SUB_BIN64S_BIN64S_BIN64S:
case MUL_BIN16S_BIN16S_BIN16S:
case MUL_BIN32S_BIN32S_BIN32S:
case MUL_BIN64S_BIN64S_BIN64S:
break;
case ADD_BIN16S_BIN16S_BIN32S:
case ADD_BIN16S_BIN32S_BIN32S:
case ADD_BIN32S_BIN16S_BIN32S:
case ADD_BIN32S_BIN64S_BIN64S:
case ADD_BIN64S_BIN32S_BIN64S:
case SUB_BIN16S_BIN16S_BIN32S:
case SUB_BIN16S_BIN32S_BIN32S:
case SUB_BIN32S_BIN16S_BIN32S:
case MUL_BIN16S_BIN16S_BIN32S:
case MUL_BIN16S_BIN32S_BIN32S:
case MUL_BIN32S_BIN16S_BIN32S:
break;
case MUL_BIN16S_BIN32S_BIN64S:
case MUL_BIN32S_BIN16S_BIN64S:
case MUL_BIN32S_BIN32S_BIN64S:
break;
case DIV_BIN64S_BIN64S_BIN64S:
break;
case DIV_BIN64S_BIN64S_BIN64S_ROUND:
break;
case ADD_FLOAT64_FLOAT64_FLOAT64:
case SUB_FLOAT64_FLOAT64_FLOAT64:
case MUL_FLOAT64_FLOAT64_FLOAT64:
case DIV_FLOAT64_FLOAT64_FLOAT64:
break;
case SUB_COMPLEX:
case ADD_COMPLEX:
case MUL_COMPLEX:
if (attrs[0]->getClassID() != Attributes::BigNumID)
return ex_clause::pCodeGenerate(space, f);
break;
default:
return ex_clause::pCodeGenerate(space, f);
}
// Allocate the code list and get a handle on the attributes
//
PCIList code(space);
// Don't get mixed up in interval conversions. The precision for
// interval conversions is not set up correctly.
//
Attributes *dst = attrs[0];
Attributes *op1 = attrs[1];
Attributes *op2 = attrs[2];
if((dst->getDatatype() < REC_MIN_NUMERIC) ||
(dst->getDatatype() > REC_MAX_NUMERIC) ||
(op1->getDatatype() < REC_MIN_NUMERIC) ||
(op1->getDatatype() > REC_MAX_NUMERIC))
return ex_clause::pCodeGenerate(space, f);
// Generate pre clause PCI's
//
PCode::preClausePCI(this, code);
// Construct the operands.
//
OL ols(dst->getAtp(), dst->getAtpIndex(), dst->getOffset(),
op1->getAtp(), op1->getAtpIndex(), op1->getOffset(),
op2->getAtp(), op2->getAtpIndex(), op2->getOffset());
OL olsFlipped(
dst->getAtp(), dst->getAtpIndex(), dst->getOffset(),
op2->getAtp(), op2->getAtpIndex(), op2->getOffset(),
op1->getAtp(), op1->getAtpIndex(), op1->getOffset());
OL olx(dst->getAtp(), dst->getAtpIndex(), dst->getOffset(),
dst->getPrecision(),
op1->getAtp(), op1->getAtpIndex(), op1->getOffset(),
op1->getPrecision(),
op2->getAtp(), op2->getAtpIndex(), op2->getOffset(),
op2->getPrecision());
OL olb(dst->getAtp(), dst->getAtpIndex(), dst->getOffset(),
op1->getAtp(), op1->getAtpIndex(), op1->getOffset(),
op2->getAtp(), op2->getAtpIndex(), op2->getOffset(),
dst->getLength());
OL olb2(dst->getAtp(), dst->getAtpIndex(), dst->getOffset(),
op1->getAtp(), op1->getAtpIndex(), op1->getOffset(),
op2->getAtp(), op2->getAtpIndex(), op2->getOffset(),
dst->getLength(), op1->getLength(), op2->getLength());
AML amlb(PCIT::MBIGS, PCIT::MBIGS, PCIT::MBIGS, PCIT::IBIN32S);
AML amlb2(PCIT::MBIGS, PCIT::MBIGS, PCIT::MBIGS,
PCIT::IBIN32S, PCIT::IBIN32S, PCIT::IBIN32S);
// OL for division using rounding. Need to pass in rounding mode and
// if this rounding division is being done to downscale.
// Lowest byte(byte 4) in roundingInfo is rounding mode.
// Rightmost bit in byte 3 is divToDownscale.
Lng32 roundingInfo;
roundingInfo = (Lng32)arithRoundingMode_;
if (getDivToDownscale())
roundingInfo |= 0x100;
OL ol_rd(dst->getAtp(), dst->getAtpIndex(), (Int32)dst->getOffset(),
op1->getAtp(), op1->getAtpIndex(), (Int32)op1->getOffset(),
op2->getAtp(), op2->getAtpIndex(), (Int32)op2->getOffset(),
roundingInfo);
// Construct the addressing modes.
//
// Construct the addressing modes.
//
AML amls(PCIT::getMemoryAddressingMode(dst->getDatatype()),
PCIT::getMemoryAddressingMode(op1->getDatatype()),
PCIT::getMemoryAddressingMode(op2->getDatatype()));
AML amlsFlipped(
PCIT::getMemoryAddressingMode(dst->getDatatype()),
PCIT::getMemoryAddressingMode(op2->getDatatype()),
PCIT::getMemoryAddressingMode(op1->getDatatype()));
AML amlx(PCIT::getMemoryAddressingMode(dst->getDatatype()),
PCIT::IBIN32S,
PCIT::getMemoryAddressingMode(op1->getDatatype()),
PCIT::IBIN32S,
PCIT::getMemoryAddressingMode(op2->getDatatype()),
PCIT::IBIN32S);
// AML for division using rounding. Need to pass in rounding mode.
AML aml_rd(PCIT::getMemoryAddressingMode(dst->getDatatype()),
PCIT::getMemoryAddressingMode(op1->getDatatype()),
PCIT::getMemoryAddressingMode(op2->getDatatype()),
PCIT::IBIN32S);
// Construct the operation.
//
AML *aml = NULL;
OL *ol = NULL;
PCIT::Operation inst = PCIT::Op_OPDATA; // prevent uninitialized var warning
switch(getInstruction())
{
case ADD_BIN32S_BIN16S_BIN32S:
case ADD_BIN64S_BIN32S_BIN64S:
// Normalize instructions so smaller operand comes first
aml = &amlsFlipped;
ol = &olsFlipped;
inst = PCIT::Op_ADD;
break;
case ADD_BIN16S_BIN16S_BIN16S:
case ADD_BIN32S_BIN32S_BIN32S:
case ADD_BIN64S_BIN64S_BIN64S:
case ADD_BIN16S_BIN16S_BIN32S:
case ADD_BIN16S_BIN32S_BIN32S:
case ADD_BIN32S_BIN64S_BIN64S:
case ADD_FLOAT64_FLOAT64_FLOAT64:
aml = &amls;
ol = &ols;
inst = PCIT::Op_ADD;
break;
case SUB_BIN16S_BIN16S_BIN16S:
case SUB_BIN32S_BIN32S_BIN32S:
case SUB_BIN64S_BIN64S_BIN64S:
case SUB_BIN16S_BIN16S_BIN32S:
case SUB_BIN16S_BIN32S_BIN32S:
case SUB_BIN32S_BIN16S_BIN32S:
case SUB_FLOAT64_FLOAT64_FLOAT64:
aml = &amls;
ol = &ols;
inst = PCIT::Op_SUB;
break;
case MUL_BIN32S_BIN16S_BIN32S:
case MUL_BIN32S_BIN16S_BIN64S:
// Normalize instructions so smaller operand comes first
aml = &amlsFlipped;
ol = &olsFlipped;
inst = PCIT::Op_MUL;
break;
case MUL_BIN16S_BIN16S_BIN16S:
case MUL_BIN32S_BIN32S_BIN32S:
case MUL_BIN64S_BIN64S_BIN64S:
case MUL_BIN16S_BIN16S_BIN32S:
case MUL_BIN16S_BIN32S_BIN32S:
case MUL_BIN16S_BIN32S_BIN64S:
case MUL_BIN32S_BIN32S_BIN64S:
case MUL_FLOAT64_FLOAT64_FLOAT64:
aml = &amls;
ol = &ols;
inst = PCIT::Op_MUL;
break;
case DIV_BIN64S_BIN64S_BIN64S:
case DIV_FLOAT64_FLOAT64_FLOAT64:
aml = &amls;
ol = &ols;
inst = PCIT::Op_DIV;
break;
case DIV_BIN64S_BIN64S_BIN64S_ROUND:
aml = &aml_rd;
ol = &ol_rd;
inst = PCIT::Op_DIV_ROUND;
break;
case SUB_COMPLEX:
aml = &amlb;
ol = &olb;
inst = PCIT::Op_SUB;
break;
case ADD_COMPLEX:
aml = &amlb;
ol = &olb;
inst = PCIT::Op_ADD;
break;
case MUL_COMPLEX:
aml = &amlb2;
ol = &olb2;
inst = PCIT::Op_MUL;
break;
#if 0
case MUL_COMPLEX:
aml = &amlx;
ol = &olx;
inst = PCIT::Op_MUL;
break;
#endif
case DIV_COMPLEX:
aml = &amlx;
ol = &olx;
inst = PCIT::Op_DIV;
break;
}
// Add the null logic if necessary.
//
PCIID branchToEnd = PCode::nullBranch(this, code, attrs);
// Add the instruction.
//
PCI pci(inst, *aml, *ol);
code.append(pci);
// Add the branch target if necessary.
//
if(branchToEnd)
{
AML aml;
OL ol((Int64)branchToEnd);
PCI pci(PCIT::Op_TARGET, aml, ol);
code.append(pci);
}
// Generate post clause PCI's
//
PCode::postClausePCI(this, code);
setPCIList(code.getList());
return ex_expr::EXPR_OK;
}
// ex_arith_sum_clause::pCodeGenerate
//
// Generate PCI's for the sum operation.
//
// IN : space - memory allocator
// OUT :
// RETURN : ex_expr::EXPR_OK is no errors
// EFFECTS: stores pointer to PCodeObject in clause
//
ex_expr::exp_return_type ex_arith_sum_clause::pCodeGenerate(Space *space, UInt32 f) {
#ifdef _DEBUG
// For debugging...
if(getenv("PCODE_NO_ARITH_SUM")) return ex_clause::pCodeGenerate(space, f);
#endif
// Allocate the code list and get a handle on the attributes
//
AttributesPtr *attrs = getOperand();
// Generate the standard clause->eval PCode for cases that
// are not handled with more fundamental PCode operations.
// Since this is arith_sum, only add operations should appear.
//
switch(getInstruction()) {
case ADD_BIN32S_BIN32S_BIN32S:
case ADD_BIN64S_BIN64S_BIN64S:
break;
case ADD_FLOAT64_FLOAT64_FLOAT64:
break;
case ADD_COMPLEX:
if (attrs[0]->getClassID() != Attributes::BigNumID)
return ex_clause::pCodeGenerate(space, f);
break;
default:
return ex_clause::pCodeGenerate(space, f);
}
// Don't get mixed up in interval conversions. The precision for
// interval conversions is not set up correctly.
//
Attributes *dst = attrs[0];
Attributes *op1 = attrs[1];
Attributes *op2 = attrs[2];
if((dst->getDatatype() < REC_MIN_NUMERIC) ||
(dst->getDatatype() > REC_MAX_NUMERIC) ||
(op1->getDatatype() < REC_MIN_NUMERIC) ||
(op1->getDatatype() > REC_MAX_NUMERIC))
return ex_clause::pCodeGenerate(space, f);
if (! isAugmentedAssignOperation())
return ex_clause::pCodeGenerate(space, f);
// The result should be the same as one of the operands.
//
Int32 firstOperand = isSameAttribute(dst, op1);
Int32 secondOperand = isSameAttribute(dst, op2);
if(!firstOperand && !secondOperand)
return ex_clause::pCodeGenerate(space, f);
// The offset must be positive for PCODE to work.
//
if(dst->getOffset() == ExpOffsetMax)
return ex_clause::pCodeGenerate(space, f);
// The sum's are implemented in PCODE by the increment operation.
// So, generate the appropriate increment operation.
//
Attributes *attrOp = (firstOperand ? op2 : op1);
// If the sum expression is nullable, then the sum must also be
// nullable for PCODE to work.
//
Int32 nullable = attrOp->getNullFlag();
if(nullable && !dst->getNullFlag())
return ex_clause::pCodeGenerate(space, f);
// Both operands must be the same type as well.
//
PCIT::AddressingMode amA
= PCIT::getMemoryAddressingMode(dst->getDatatype());
PCIT::AddressingMode amB
= PCIT::getMemoryAddressingMode(attrOp->getDatatype());
if(amA != amB)
return ex_clause::pCodeGenerate(space, f);
// Allocate the code list and get a handle on the attributes
//
PCIList code(space);
// Generate pre clause PCI's
//
PCode::preClausePCI(this, code);
// Based on the type of addition and whether the operand is nullable or
// not, choose the appropriate operand number and size for the
// increment operation.
//
if (getInstruction() == ADD_COMPLEX)
{
AML aml(PCIT::MATTR3, PCIT::MATTR3, PCIT::IBIN32S, PCIT::MBIGS,
PCIT::MBIGS, PCIT::IBIN32S);
OL ol(attrs[0]->getAtp(), attrs[0]->getAtpIndex(),
attrs[0]->getNullIndOffset(), attrs[0]->getNullBitIndex(),
attrOp->getAtp(), attrOp->getAtpIndex(),
attrOp->getNullIndOffset(), attrOp->getNullBitIndex(),
((nullable) ? 1 : 0),
attrs[0]->getAtp(), attrs[0]->getAtpIndex(), attrs[0]->getOffset(),
attrOp->getAtp(), attrOp->getAtpIndex(), attrOp->getOffset(),
attrs[0]->getLength());
PCI pci(PCIT::Op_SUM, aml, ol);
code.append(pci);
}
else if(!nullable)
{
AML aml(amA, amB);
OL ol(dst->getAtp(), dst->getAtpIndex(), (Int32)dst->getOffset(),
attrOp->getAtp(), attrOp->getAtpIndex(), (Int32)attrOp->getOffset());
PCI pci(PCIT::Op_SUM, aml, ol);
code.append(pci);
}
else
{
AML aml(PCIT::MATTR3, PCIT::MATTR3, PCIT::IBIN32S, amA, amB);
OL ol(dst->getAtp(), dst->getAtpIndex(), (Int32)dst->getNullIndOffset(),
(Int32)dst->getNullBitIndex(),
attrOp->getAtp(), attrOp->getAtpIndex(), attrOp->getNullIndOffset(),
(Int32)attrOp->getNullBitIndex(),
((nullable) ? 1 : 0),
dst->getAtp(), dst->getAtpIndex(), dst->getOffset(),
attrOp->getAtp(), attrOp->getAtpIndex(), attrOp->getOffset());
PCI pci(PCIT::Op_SUM, aml, ol);
code.append(pci);
}
// Generate post clause PCI's
//
PCode::postClausePCI(this, code);
setPCIList(code.getList());
return ex_expr::EXPR_OK;
}
// ex_arith_count_clause::pCodeGenerate
//
// Generate PCI's for the sum operation.
//
// IN : space - memory allocator
// OUT :
// RETURN : ex_expr::EXPR_OK is no errors
// EFFECTS: stores pointer to PCodeObject in clause
//
ex_expr::exp_return_type ex_arith_count_clause::pCodeGenerate(Space *space, UInt32 f) {
return ex_clause::pCodeGenerate(space, f);
};
static void computeBounds(Attributes *attr, Int64 &lowBounds,
UInt64 &highBounds, Int32 &bigBounds, Int32 &isSigned)
{
const UInt64 decimalPrecision[] = {
0,
9,
99,
999,
9999,
99999,
999999,
9999999,
99999999,
999999999,
9999999999LL,
99999999999LL,
999999999999LL,
9999999999999LL,
99999999999999LL,
999999999999999LL,
9999999999999999LL,
99999999999999999LL,
999999999999999999LL,
4999999999999999999LL,
9999999999999999999ULL
};
const Int32 bpPrecision[] = { 0, 1, 3, 7, 15, 31, 63, 127, 255, 511,
1023, 2047, 4095, 8191, 16483, 32767,
65535, 65535 };
// By default, unsigned ints.
//
isSigned = 0;
bigBounds = 0;
// Decimals have precision > 0 (Except for BPINTs).
//
if((attr->getPrecision() > 0) && (attr->getDatatype() != REC_BPINT_UNSIGNED))
{
isSigned = 1;
switch(attr->getDatatype())
{
case REC_BIN8_UNSIGNED:
isSigned = 0;
break;
case REC_BIN16_UNSIGNED:
isSigned = 0;
break;
case REC_BIN32_UNSIGNED:
isSigned = 0;
break;
case REC_BIN64_SIGNED:
bigBounds = 1;
break;
case REC_BIN64_UNSIGNED:
isSigned = 0;
bigBounds = 1;
break;
}
lowBounds = 0;
if (isSigned)
lowBounds = - decimalPrecision[attr->getPrecision()];
highBounds = decimalPrecision[attr->getPrecision()];
}
// Binarys have precision = 0
//
else
{
switch(attr->getDatatype())
{
case REC_BPINT_UNSIGNED:
lowBounds = 0;
highBounds = bpPrecision[attr->getPrecision()];
break;
case REC_BIN8_SIGNED:
lowBounds = CHAR_MIN;
highBounds = CHAR_MAX;
isSigned = 1;
break;
case REC_BIN8_UNSIGNED:
lowBounds = 0;
highBounds = UCHAR_MAX;
break;
case REC_BIN16_SIGNED:
lowBounds = SHRT_MIN;
highBounds = SHRT_MAX;
isSigned = 1;
break;
case REC_BIN16_UNSIGNED:
lowBounds = 0;
highBounds = USHRT_MAX;
break;
case REC_BIN32_SIGNED:
lowBounds = INT_MIN;
highBounds = INT_MAX;
isSigned = 1;
break;
case REC_BIN32_UNSIGNED:
lowBounds = 0;
highBounds = UINT_MAX;
break;
case REC_BIN64_SIGNED:
bigBounds = 1;
// lowBounds = -(Int64)9223372036854775808;
lowBounds = (Int64)LLONG_MIN;
// highBounds = (Int64)9223372036854775807;
highBounds = (Int64)LLONG_MAX;
isSigned = 1;
break;
case REC_BIN64_UNSIGNED:
bigBounds = 1;
lowBounds = 0;
highBounds = ULLONG_MAX;
break;
}
}
}
// ex_conv_clause::pCodeGenerate
//
// Generate PCI's for the conversion operations. The PCI's load the operand,
// do the conversion, and then store the result.
//
// IN : space - memory allocator
// OUT :
// RETURN : ex_expr::EXPR_OK is no errors
// EFFECTS: stores pointer to PCodeObject in clause
//
ex_expr::exp_return_type ex_conv_clause::pCodeGenerate(Space *space, UInt32 f) {
#ifdef _DEBUG
// For debugging...
if(getenv("PCODE_NO_CONV")) return ex_clause::pCodeGenerate(space, f);
#endif
if( ( flags_ & CONV_TO_NULL_WHEN_ERROR ) != 0 ) return ex_clause::pCodeGenerate(space, f);
// If there is a third argument to the convert, it indicates that
// a data conversion flag is present. This is used for converting keys
// where instead of an error, the expression needs to set the
// data conversion flag and the caller will insert either the
// min or max value instead of issuing an error. PCODE currently
// does not handle this case.
//
// Also, if there's a potential for a string truncation error,
// use the hybrid expression evaluator.
//
if ( (getNumOperands() > 2) || getCheckTruncationFlag() )
return ex_clause::pCodeGenerate(space, f);
// CIF bulk move -- no pcode yet --there will be later
if ( lastVOAoffset_>0)
{
if (getenv("NO_CIF_BULK_MOVE_PCODE"))
return ex_clause::pCodeGenerate(space, f);
}
// Get a handle on the operands.
//
AttributesPtr *attrs = getOperand();
Attributes *dst = attrs[0];
Attributes *src = attrs[1];
if (srcIsVarcharPtr())
{
if (NOT ((dst->getDatatype() == REC_BIN32_SIGNED) ||
(dst->getDatatype() == REC_BIN64_SIGNED) ||
(dst->getDatatype() == REC_FLOAT32) ||
(dst->getDatatype() == REC_BYTE_V_ASCII)))
return ex_clause::pCodeGenerate(space, f);
if (dst->getDatatype() == REC_BYTE_V_ASCII)
{
if(getenv("NO_PCODE_VC_PTR_CONV"))
return ex_clause::pCodeGenerate(space, f);
}
if (((dst->getDatatype() == REC_BIN32_SIGNED) ||
(dst->getDatatype() == REC_BIN64_SIGNED)) &&
(dst->getScale() > 0))
{
return ex_clause::pCodeGenerate(space, f);
}
}
else if ((dst->getDatatype() == REC_BOOLEAN) &&
(src->getDatatype() == REC_BOOLEAN))
{
// boolean conversions are pcode supported.
}
else if (((dst->getDatatype() < REC_MIN_NUMERIC) ||
(dst->getDatatype() > REC_MAX_NUMERIC) ||
(src->getDatatype() < REC_MIN_NUMERIC) ||
(src->getDatatype() > REC_MAX_NUMERIC)) &&
(((dst->getDatatype() != REC_BYTE_F_ASCII) ||
(src->getDatatype() != REC_BYTE_F_ASCII)) &&
((dst->getDatatype() != REC_BYTE_V_ASCII) ||
(src->getDatatype() != REC_BYTE_V_ASCII)) &&
((dst->getDatatype() != REC_BYTE_F_ASCII) ||
(src->getDatatype() != REC_BYTE_V_ASCII)) &&
((dst->getDatatype() != REC_BYTE_V_ASCII) ||
(src->getDatatype() != REC_BYTE_F_ASCII)) &&
((dst->getDatatype() != REC_NCHAR_V_UNICODE) ||
(src->getDatatype() != REC_NCHAR_V_UNICODE)) &&
((dst->getDatatype() != REC_NCHAR_F_UNICODE) ||
(src->getDatatype() != REC_NCHAR_F_UNICODE)) &&
((dst->getDatatype() != REC_DATETIME) ||
(src->getDatatype() != REC_DATETIME))))
return ex_clause::pCodeGenerate(space, f);
// Generate the standard clause->eval PCode for particular
// conversions that are not handled with more fundamental PCode
// operations.
//
switch(getInstruction()) {
case CONV_BPINTU_BPINTU:
case CONV_BIN16S_BIN16S: case CONV_BIN16S_BIN16U:
case CONV_BIN16S_BIN32S: case CONV_BIN16S_BIN32U:
case CONV_BIN16S_BIN64S:
/*case CONV_BIN16S_FLOAT32: case CONV_BIN16S_FLOAT64:*/
case CONV_BIN16U_BIN16S: case CONV_BIN16U_BIN16U:
case CONV_BIN16U_BIN32S: case CONV_BIN16U_BIN32U:
case CONV_BIN16U_BIN64S:
/*case CONV_BIN16U_FLOAT32: case CONV_BIN16U_FLOAT64:*/
case CONV_BIN32S_BIN16S: case CONV_BIN32S_BIN16U:
case CONV_BIN32S_BIN32S: case CONV_BIN32S_BIN32U:
case CONV_BIN32S_BIN64S:
/*case CONV_BIN32S_FLOAT32: case CONV_BIN32S_FLOAT64:*/
case CONV_BIN32U_BIN16S: case CONV_BIN32U_BIN16U:
case CONV_BIN32U_BIN32S: case CONV_BIN32U_BIN32U:
case CONV_BIN32U_BIN64S:
/*case CONV_BIN32U_FLOAT32: case CONV_BIN32U_FLOAT64:*/
case CONV_BIN64S_BIN16S: /*case CONV_BIN64S_BIN16U:*/
case CONV_BIN64S_BIN32S: case CONV_BIN64S_BIN32U:
case CONV_BIN64S_BIN64S:
case CONV_BIN64U_BIN64U:
case CONV_BIN64S_BIN64U:
// case CONV_BIN64U_BIN64S: // not yet supported
break;
/*case CONV_BIN64S_FLOAT32: case CONV_BIN64S_FLOAT64:*/
/*case CONV_FLOAT32_BIN16U: case CONV_FLOAT32_BIN16S:
case CONV_FLOAT32_BIN32U: case CONV_FLOAT32_BIN32S:*/
/*case CONV_FLOAT32_BIN64S:*/
/*case CONV_FLOAT64_BIN16U: case CONV_FLOAT64_BIN16S:
case CONV_FLOAT64_BIN32U: case CONV_FLOAT64_BIN32S:*/
/*case CONV_FLOAT64_BIN64S:*/
/*case CONV_FLOAT64_FLOAT32:*/
case CONV_DECS_BIN64S:
{
// not enabled for NEO CA
return ex_clause::pCodeGenerate(space, f);
if (attrs[0]->getScale() != attrs[1]->getScale())
return ex_clause::pCodeGenerate(space, f);
}
break;
case CONV_BIN16S_BIGNUM:
case CONV_BIN32S_BIGNUM:
case CONV_BIN64S_BIGNUM:
break;
case CONV_BIGNUM_BIN64S:
if ((src->getPrecision() > dst->getPrecision()) &&
(dst->getPrecision() > 0))
return ex_clause::pCodeGenerate(space, f);
break;
case CONV_BIGNUM_BIGNUM:
if (src->getPrecision() > dst->getPrecision())
return ex_clause::pCodeGenerate(space, f);
break;
case CONV_SIMPLE_TO_COMPLEX:
if ((dst->getDatatype() != REC_NUM_BIG_SIGNED) ||
(src->getDatatype() != REC_BIN64_SIGNED) ||
(src->getPrecision() > dst->getPrecision()))
return ex_clause::pCodeGenerate(space, f);
break;
case CONV_FLOAT32_FLOAT32:
case CONV_FLOAT64_FLOAT64:
break;
case CONV_BIN64S_FLOAT64:
case CONV_BIN32S_FLOAT64:
case CONV_BIN16S_FLOAT64:
case CONV_FLOAT32_FLOAT64:
break;
case CONV_ASCII_F_F:
case CONV_ASCII_V_V:
case CONV_ASCII_F_V:
case CONV_ASCII_V_F:
{
if (NOT srcIsVarcharPtr())
{
if (!requiresNoConvOrVal(src->getLength(),
src->getPrecision(),
src->getScale(),
dst->getLength(),
dst->getPrecision(),
dst->getScale(),
getInstruction()
))
return ex_clause::pCodeGenerate(space, f);
}
}
// fall through to next case
case CONV_UNICODE_F_F:
case CONV_UNICODE_V_V:
case CONV_DATETIME_DATETIME:
case CONV_DECS_DECS:
case CONV_ASCII_BIN32S:
case CONV_ASCII_BIN64S:
case CONV_ASCII_FLOAT32:
{
if (getInstruction() == CONV_DECS_DECS)
{
// not enabled for NEO CA
return ex_clause::pCodeGenerate(space, f);
}
// Only handle equal length strings.
//
if (NOT srcIsVarcharPtr())
{
if (dst->getLength() < src->getLength())
return ex_clause::pCodeGenerate(space, f);
}
if ((getInstruction() == CONV_ASCII_V_V) ||
(getInstruction() == CONV_DATETIME_DATETIME) ||
(getInstruction() == CONV_DECS_DECS))
{
if ((getInstruction() == CONV_DATETIME_DATETIME) ||
(getInstruction() == CONV_DECS_DECS))
{
if ((dst->getPrecision() != src->getPrecision()) ||
(dst->getScale() != src->getScale()))
return ex_clause::pCodeGenerate(space, f);
}
}
PCIList code(space);
// Generate pre clause PCI's
//
PCode::preClausePCI(this, code);
// handle NULLs (may jump)
PCIID nullJmp = PCode::nullBranch(this, code, attrs);
// copy the value
switch(getInstruction())
{
case CONV_ASCII_V_V:
case CONV_UNICODE_V_V:
{
if (NOT srcIsVarcharPtr())
{
code.append(PCode::moveVarcharValue(dst, src, space));
}
else
{
code.append(PCode::convertVarcharPtrToTarget(dst, src, space));
}
}
break;
case CONV_ASCII_F_V:
{
code.append(PCode::moveFixedVarcharValue(dst, src, space));
}
break;
case CONV_ASCII_V_F:
{
code.append(PCode::moveVarcharFixedValue(dst, src, space));
}
break;
case CONV_ASCII_BIN32S:
case CONV_ASCII_BIN64S:
case CONV_ASCII_FLOAT32:
{
code.append(PCode::convertVarcharPtrToTarget(dst, src, space));
}
break;
default:
{
if(lastVOAoffset_>0 )
{//cif bulk move
code.append(PCode::copyVarRow( dst,
src,
lastVOAoffset_,
lastVcIndicatorLength_,
lastNullIndicatorLength_,
alignment_,
space));
}
else
{
code.append(PCode::moveValue(dst, src, space));
}
}
}
// we'll jump here if the value is NULL
if (nullJmp)
{
AML aml;
OL ol((Int64) nullJmp);
PCI pci(PCIT::Op_TARGET, aml, ol);
code.append(pci);
}
// Update row length at the end of the loop. Move it to
// ex_expr::pCodeGenerate.
// if(getNumOperands() > 0)
// code.append(PCode::updateRowLen(attrs[0], space, f));
// Finish up and return
//
PCode::postClausePCI(this, code);
setPCIList(code.getList());
return ex_expr::EXPR_OK;
}
break;
case CONV_BIN8S_BIN8S:
case CONV_BIN8U_BIN8U:
case CONV_BIN8S_BIN16S:
case CONV_BIN8U_BIN16U:
case CONV_BIN8S_BIN32S:
case CONV_BIN8U_BIN32U:
case CONV_BIN8S_BIN64S:
case CONV_BIN8U_BIN64U:
case CONV_BIN16S_BIN8S:
case CONV_BIN16U_BIN8U:
case CONV_BIN16S_BIN8U:
case CONV_BIN16U_BIN8S:
break;
case CONV_BOOL_BOOL:
break;
default:
return ex_clause::pCodeGenerate(space, f);
}
#ifdef _DEBUG
// Allow 64 -> 64 with differing scale
//
if(getInstruction() == CONV_BIN64S_BIN64S)
{
if(getenv("PCODE_NO_INT64_SCALE_CONV"))
{
return ex_clause::pCodeGenerate(space, f);
}
}
#endif
// Generate the standard clause->eval PCODE if NULLS need to be handled
// specially and any of the inputs are nullable.
//
if(isAnyInputNullable() && isNullRelevant() && !isNullInNullOut())
return ex_clause::pCodeGenerate(space, f);
// If we get here, we have decided that we should generate PCI's to handle
// the particular conversion for this clause. Allocate the PCI list and
// get a handle on the operands for this clause.
//
PCIList code(space);
// Generate pre clause PCI's
//
PCode::preClausePCI(this, code);
// Handle the NULL processing
//
PCIID nullBranch = PCode::nullBranch(this, code, attrs);
if((getInstruction() != CONV_BIGNUM_BIN64S) &&
(getInstruction() != CONV_BIN64S_BIGNUM) &&
(getInstruction() != CONV_BIN32S_BIGNUM) &&
(getInstruction() != CONV_BIN16S_BIGNUM) &&
(getInstruction() != CONV_BIGNUM_BIGNUM) &&
(getInstruction() != CONV_SIMPLE_TO_COMPLEX) &&
(getInstruction() != CONV_FLOAT64_FLOAT64) &&
(getInstruction() != CONV_FLOAT32_FLOAT32) &&
(getInstruction() != CONV_FLOAT32_FLOAT64) &&
(getInstruction() != CONV_BIN16S_FLOAT64) &&
(getInstruction() != CONV_BIN32S_FLOAT64) &&
(getInstruction() != CONV_BIN64S_FLOAT64) &&
(getInstruction() != CONV_BOOL_BOOL)) {
// Compute the high and low bounds of the source and destination
// operands.
//
Int32 srcBig, dstBig, srcSigned, dstSigned;
UInt64 srcHighBounds = 0;
Int64 srcLowBounds = 0;
UInt64 dstHighBounds = 0;
Int64 dstLowBounds = 0;
computeBounds(src, srcLowBounds, srcHighBounds, srcBig, srcSigned);
computeBounds(dst, dstLowBounds, dstHighBounds, dstBig, dstSigned);
// Determine which bounds must be checked. If the source bound are
// tighter than the destination bound, then no check is necessary.
//
AML srcAml(PCIT::getMemoryAddressingMode(src->getDatatype()), PCIT::IBIN64S);
Int32 srcAtp = src->getAtp();
Int32 srcAtpIndex = src->getAtpIndex();
Int32 srcOffset = (Int32)src->getOffset();
if(srcLowBounds < dstLowBounds)
{
if (getInstruction() == CONV_DECS_BIN64S)
return ex_clause::pCodeGenerate(space, f);
OL ol(srcAtp, srcAtpIndex, srcOffset, (Int64)dstLowBounds);
PCI pci(PCIT::Op_RANGE_LOW, srcAml, ol); // RANGE_LOW_S32S64, RANGE_LOW_U32S64, RANGE_LOW_S64S64,
code.append(pci);
}
if(srcHighBounds > dstHighBounds)
{
if (getInstruction() == CONV_DECS_BIN64S)
return ex_clause::pCodeGenerate(space, f);
OL ol(srcAtp, srcAtpIndex, srcOffset, (Int64)dstHighBounds);
PCI pci(PCIT::Op_RANGE_HIGH, srcAml, ol); // RANGE_HIGH_S32S64, RANGE_HIGH_U32S64, RANGE_HIGH_S64S64,
code.append(pci);
}
}
#if (defined (_DEBUG) )
if(!getenv("NO_PCODE_FLOAT_RANGE"))
#endif
if( getInstruction() == CONV_FLOAT64_FLOAT64 &&
!ex_expr::notValidateFloat64(f)) {
AML aml(PCIT::MFLT64);
OL ol(src->getAtp(), src->getAtpIndex(), (Int32)src->getOffset());
PCI pci(PCIT::Op_RANGE_LOW, aml, ol); // RANGE_MFLT64
code.append(pci);
}
// Do the conversion
//
switch(getInstruction())
{
// For conversions that are simple moves, generate the byte move
// instruction. This includes unmatched signedness conversions such
// as BIN32U-->BIN32S since the bounds checking insures that
// copying the bytes will effect the correct conversion.
//
case CONV_BIN16U_BIN16U: case CONV_BIN16U_BIN16S:
case CONV_BIN16S_BIN16S: case CONV_BIN16S_BIN16U:
case CONV_BIN32U_BIN32U: case CONV_BIN32U_BIN32S:
case CONV_BIN32S_BIN32S: case CONV_BIN32S_BIN32U:
case CONV_BIN64S_BIN64S:
case CONV_BIN64U_BIN64U:
case CONV_BPINTU_BPINTU:
case CONV_FLOAT64_FLOAT64:
case CONV_FLOAT32_FLOAT32:
case CONV_BIN8S_BIN8S:
case CONV_BIN8U_BIN8U:
case CONV_BOOL_BOOL:
{
AML aml(PCIT::MBIN8, PCIT::MBIN8, PCIT::IBIN32S);
OL ol(dst->getAtp(), dst->getAtpIndex(), dst->getOffset(),
src->getAtp(), src->getAtpIndex(), src->getOffset(),
dst->getLength());
PCI pci(PCIT::Op_MOVE, aml, ol);
code.append(pci);
}
break;
// Conversions from bigger to smaller types can be accomplished by
// moving the right subset of bytes from the source to the destination.
//
case CONV_BIN32S_BIN16U: case CONV_BIN32S_BIN16S:
case CONV_BIN32U_BIN16U: case CONV_BIN32U_BIN16S:
case CONV_BIN64S_BIN16U: case CONV_BIN64S_BIN16S:
case CONV_BIN64S_BIN32U: case CONV_BIN64S_BIN32S:
case CONV_BIN16S_BIN8S: case CONV_BIN16U_BIN8U:
case CONV_BIN16S_BIN8U: case CONV_BIN16U_BIN8S:
{
AML aml(PCIT::MBIN8, PCIT::MBIN8, PCIT::IBIN32S);
#ifdef NA_LITTLE_ENDIAN
Int32 srcOffset = src->getOffset();
#else
Int32 srcOffset = src->getOffset() + src->getLength() - dst->getLength();
#endif
OL ol(dst->getAtp(), dst->getAtpIndex(), dst->getOffset(),
src->getAtp(), src->getAtpIndex(), srcOffset,
dst->getLength());
PCI pci(PCIT::Op_MOVE, aml, ol);
code.append(pci);
}
break;
// Other conversions require specific operations.
//
#if 0
case CONV_SIMPLE_TO_COMPLEX:
{
AML aml(PCIT::getMemoryAddressingMode(dst->getDatatype()),
PCIT::getMemoryAddressingMode(src->getDatatype()),
PCIT::IBIN32S);
OL ol(dst->getAtp(), dst->getAtpIndex(), dst->getOffset(),
src->getAtp(), src->getAtpIndex(), src->getOffset(),
dst->getPrecision());
PCI pci(PCIT::Op_MOVE, aml, ol);
code.append(pci);
}
break;
#endif
case CONV_COMPLEX_TO_COMPLEX:
{
if((dst->getPrecision() == src->getPrecision())
/*&& (dst->getScale() == src->getScale())*/)
{
AML aml(PCIT::getMemoryAddressingMode(dst->getDatatype()),
PCIT::getMemoryAddressingMode(src->getDatatype()),
PCIT::IBIN32S);
OL ol(dst->getAtp(), dst->getAtpIndex(), dst->getOffset(),
src->getAtp(), src->getAtpIndex(), src->getOffset(),
dst->getPrecision());
PCI pci(PCIT::Op_MOVE, aml, ol);
code.append(pci);
}
else
{
AML aml(PCIT::getMemoryAddressingMode(dst->getDatatype()),
PCIT::IBIN32S,
PCIT::getMemoryAddressingMode(src->getDatatype()),
PCIT::IBIN32S, PCIT::IBIN32S);
OL ol(dst->getAtp(), dst->getAtpIndex(), dst->getOffset(),
dst->getPrecision(),
src->getAtp(), src->getAtpIndex(), src->getOffset(),
src->getPrecision(), dst->getScale() - src->getScale());
PCI pci(PCIT::Op_MOVE, aml, ol);
code.append(pci);
}
}
break;
case CONV_DECS_BIN64S:
{
AML aml(PCIT::getMemoryAddressingMode(dst->getDatatype()),
PCIT::getMemoryAddressingMode(src->getDatatype()),
PCIT::IBIN32S);
OL ol(dst->getAtp(), dst->getAtpIndex(), dst->getOffset(),
src->getAtp(), src->getAtpIndex(), src->getOffset(),
src->getLength());
PCI pci(PCIT::Op_MOVE, aml, ol);
code.append(pci);
}
break;
case CONV_BIGNUM_BIGNUM:
{
AML aml(PCIT::MBIGS, PCIT::MBIGS, PCIT::IBIN32S, PCIT::IBIN32S);
OL ol(dst->getAtp(), dst->getAtpIndex(), dst->getOffset(),
src->getAtp(), src->getAtpIndex(), src->getOffset(),
dst->getLength(),
src->getLength());
PCI pci(PCIT::Op_MOVE, aml, ol);
code.append(pci);
break;
}
case CONV_BIGNUM_BIN64S:
{
AML aml(PCIT::MBIN64S, PCIT::MBIGS, PCIT::IBIN32S);
OL ol(dst->getAtp(), dst->getAtpIndex(), dst->getOffset(),
src->getAtp(), src->getAtpIndex(), src->getOffset(),
src->getLength());
PCI pci(PCIT::Op_MOVE, aml, ol);
code.append(pci);
break;
}
case CONV_SIMPLE_TO_COMPLEX:
case CONV_BIN64S_BIGNUM:
case CONV_BIN32S_BIGNUM:
case CONV_BIN16S_BIGNUM:
{
AML aml(PCIT::MBIGS,
PCIT::getMemoryAddressingMode(src->getDatatype()),
PCIT::IBIN32S);
OL ol(dst->getAtp(), dst->getAtpIndex(), dst->getOffset(),
src->getAtp(), src->getAtpIndex(), src->getOffset(),
dst->getLength());
PCI pci(PCIT::Op_MOVE, aml, ol);
code.append(pci);
break;
}
case CONV_BIN8S_BIN16S:
case CONV_BIN8U_BIN16U:
{
AML aml(PCIT::getMemoryAddressingMode(dst->getDatatype()),
PCIT::getMemoryAddressingMode(src->getDatatype()));
OL ol(dst->getAtp(), dst->getAtpIndex(), (Int32)dst->getOffset(),
src->getAtp(), src->getAtpIndex(), (Int32)src->getOffset());
PCI pci(PCIT::Op_MOVE, aml, ol);
code.append(pci);
}
break;
default:
{
AML aml(PCIT::getMemoryAddressingMode(dst->getDatatype()),
PCIT::getMemoryAddressingMode(src->getDatatype()));
OL ol(dst->getAtp(), dst->getAtpIndex(), (Int32)dst->getOffset(),
src->getAtp(), src->getAtpIndex(), (Int32)src->getOffset());
PCI pci(PCIT::Op_MOVE, aml, ol);
code.append(pci);
}
};
// Add the branch target if necessary.
//
if(nullBranch)
{
AML aml;
OL ol((Int64)nullBranch);
PCI pci(PCIT::Op_TARGET, aml, ol);
code.append(pci);
}
// Administration...
//
// store the first fixed field offset
code.append(PCode::storeVoa(attrs[0], space));
// if(getNumOperands() > 0)
// code.append(PCode::updateRowLen(attrs[0], space, f));
// Generate post clause PCI's
//
PCode::postClausePCI(this, code);
setPCIList(code.getList());
return ex_expr::EXPR_OK;
}
// ExUnPackCol::pCodeGenerate() ------------------------------------
// Generate PCode for the ExUnPackCol clause. The ExUnPackCol
// clause extracts a set of bits from a CHAR value. The set of
// bits to extract is described by a base offset, a width, and
// an index. The offset and width are known at compile time, but
// the index is a run time variable. ExUnPackCol clause also gets
// the null indicator of the result from a bitmap within the CHAR
// field. This clause is implemented using the following pCode instructions:
//
// 'loadValue' - to load the index value
// Op_MV_INDEX_ATP_NB - to move the NULL indicator
// Op_MV_INDEXED_ATP_BXX - to move the set of bits
// Op_POP - to remove the index from the stack
//
// where XX is one of {32,8,4,2,1} and indicates the width of the value
// in bits.
//
// A series of UnPackCol clauses will generate redundant loads and pops
// of the index value. These will be removed in a pass over the generated
// instructions.
//
// ExUnPackCol supports other bit widths, but no pCode will be generated
// for these.
//
ex_expr::exp_return_type ExUnPackCol::pCodeGenerate(Space *space, UInt32 f) {
return ex_clause::pCodeGenerate(space, f);
/*
#ifdef _DEBUG
// For debugging to disable the pCode generation
if(getenv("PCODE_NO_UNPACK"))
// Generate the default clause_eval instruction.
//
return ex_clause::pCodeGenerate(space, f);
#endif
// Get a handle on the operands
//
AttributesPtr *attrs = getOperand();
// Use the default pCodeGenerate for cases not handled here
//
if(((attrs[0]->getLength() == 4) && (width_ == 32)) ||
((attrs[0]->getLength() == 2) && (width_ == 8)) ||
((attrs[0]->getLength() == 2) && (width_ == 4)) ||
((attrs[0]->getLength() == 2) && (width_ == 2)) ||
((attrs[0]->getLength() == 2) && (width_ == 1))) {
// Determine the instruction to use to extract (UnPack) the bits.
//
PCIType::Operation oper;
switch(width_) {
case 32:
oper = PCIT::Op_MV_INDEXED_ATP_B32;
break;
case 8:
oper = PCIT::Op_MV_INDEXED_ATP_B8;
break;
case 4:
oper = PCIT::Op_MV_INDEXED_ATP_B4;
break;
case 2:
oper = PCIT::Op_MV_INDEXED_ATP_B2;
break;
case 1:
oper = PCIT::Op_MV_INDEXED_ATP_B1;
break;
}
// Allocate the code list
//
PCIList code(space);
// Generate pre clause PCI's
//
PCode::preClausePCI(this, code);
// Load the index value.
//
code.append(PCode::loadValue(attrs[2], space));
// Null Processing...
// If packed value has a null bitmap, extract the bit into
// the NULL indicator of the result.
//
if(nullsPresent_) {
AML aml(PCIT::IBIN32S, PCIT::IBIN32S);
OL ol(attrs[0]->getAtp(),
attrs[0]->getAtpIndex(),
attrs[0]->getNullIndOffset(),
attrs[1]->getAtp(),
attrs[1]->getAtpIndex(),
attrs[1]->getOffset() + sizeof(int));
PCI pci(PCIT::Op_MV_INDEXED_ATP_NB, aml, ol);
code.append(pci);
}
// UnPack the value at the specified index.
//
AML aml(PCIT::IBIN32S, PCIT::IBIN32S);
OL ol(attrs[0]->getAtp(),
attrs[0]->getAtpIndex(),
attrs[0]->getOffset(),
attrs[1]->getAtp(),
attrs[1]->getAtpIndex(),
attrs[1]->getOffset() + base_);
PCI pci(oper, aml, ol);
code.append(pci);
// Consume the index...
//
AML aml1;
OL ol1(1);
PCI pci1(PCIT::Op_POP, aml1, ol1);
code.append(pci1);
// Generate post clause PCI's
//
PCode::postClausePCI(this, code);
setPCIList(code.getList());
return ex_expr::EXPR_OK;
} else if ((attrs[0]->getLength() * 8) == width_) {
// Allocate the code list
//
PCIList code(space);
// Generate pre clause PCI's
//
PCode::preClausePCI(this, code);
// Load the index value.
//
code.append(PCode::loadValue(attrs[2], space));
// Null Processing...
// If packed value has a null bitmap, extract the bit into
// the NULL indicator of the result.
//
if(nullsPresent_) {
AML aml(PCIT::I32, PCIT::I32);
OL ol(attrs[0]->getAtp(),
attrs[0]->getAtpIndex(),
attrs[0]->getNullIndOffset(),
attrs[1]->getAtp(),
attrs[1]->getAtpIndex(),
attrs[1]->getOffset() + sizeof(int));
PCI pci(PCIT::Op_MV_INDEXED_ATP_NB, aml, ol);
code.append(pci);
}
// UnPack the value at the specified index.
//
AML aml(PCIT::I32, PCIT::I32);
OL ol(attrs[0]->getAtp(),
attrs[0]->getAtpIndex(),
attrs[0]->getOffset(),
attrs[1]->getAtp(),
attrs[1]->getAtpIndex(),
attrs[1]->getOffset() + base_,
attrs[0]->getLength());
PCI pci(PCIT::Op_MV_INDEXED_ATP_N, aml, ol);
code.append(pci);
// Consume the index...
//
AML aml1;
OL ol1(1);
PCI pci1(PCIT::Op_POP, aml1, ol1);
code.append(pci1);
// Generate post clause PCI's
//
PCode::postClausePCI(this, code);
setPCIList(code.getList());
return ex_expr::EXPR_OK;
} else {
return ex_clause::pCodeGenerate(space, f);
} */
}
ex_expr::exp_return_type ex_function_mod::pCodeGenerate(Space *space, UInt32 f)
{
PCIID branchEnd = 0;
// Get a handle on the operands
//
AttributesPtr *attrs = getOperand();
// Use the default pCodeGenerate for cases not handled here
//
if (NOT (((attrs[0]->getDatatype() == REC_BIN32_SIGNED) &&
(attrs[1]->getDatatype() == REC_BIN32_SIGNED) &&
(attrs[2]->getDatatype() == REC_BIN32_SIGNED)) ||
((attrs[0]->getDatatype() == REC_BIN32_UNSIGNED) &&
(attrs[1]->getDatatype() == REC_BIN32_UNSIGNED) &&
(attrs[2]->getDatatype() == REC_BIN32_SIGNED)))) {
return ex_clause::pCodeGenerate(space, f);
}
// If any of the inputs are nullable, and we need to
// call processNulls, use clauseEval.
//
if(isAnyOperandNullable() && (!isNullRelevant() || !isNullInNullOut())) {
return ex_clause::pCodeGenerate(space, f);
}
// Allocate the code list
//
PCIList code(space);
// Generate pre clause PCI's
//
PCode::preClausePCI(this, code);
// If any of the operands are nullable, NULL is relevant for this clause,
// and any NULL input produces a NULL output, insert the appropriate
// PCODE sequence to compute the nullness of the result.
//
if(isAnyOperandNullable() && isNullRelevant() && isNullInNullOut()) {
branchEnd = PCode::nullBranch(this, code, attrs);
}
// First operand is the memory location of the result of the modulo
// Second operand is the memory location of the 1st argument to modulo
// Third operand is the memory location of the 2nd argument to modulo
//
AML aml(PCIT::getMemoryAddressingMode(attrs[0]->getDatatype()),
PCIT::getMemoryAddressingMode(attrs[1]->getDatatype()),
PCIT::getMemoryAddressingMode(attrs[2]->getDatatype()));
OL ol(attrs[0]->getAtp(), attrs[0]->getAtpIndex(), attrs[0]->getOffset(),
attrs[1]->getAtp(), attrs[1]->getAtpIndex(), attrs[1]->getOffset(),
attrs[2]->getAtp(), attrs[2]->getAtpIndex(), attrs[2]->getOffset());
PCI pci(PCIT::Op_MOD, aml, ol);
code.append(pci);
// Generate post clause PCI's
//
PCode::postClausePCI(this, code);
if(branchEnd)
{
AML aml1;
OL ol1((Int64)branchEnd);
PCI pci1(PCIT::Op_TARGET, aml1, ol1);
code.append(pci1);
}
setPCIList(code.getList());
return ex_expr::EXPR_OK;
}
ex_expr::exp_return_type
ex_function_nullifzero::pCodeGenerate(Space *space, UInt32 f)
{
// Get a handle on the operands
//
AttributesPtr *attrs = getOperand();
Attributes *dst = attrs[0];
Attributes *src = attrs[1];
//
PCIList code(space);
// Generate pre clause PCI's
//
PCode::preClausePCI(this, code);
// handle NULLs (may jump)
PCIID nullBranch = PCode::nullBranch(this, code, attrs);
AML aml(PCIT::MPTR32, // target ptr
PCIT::MATTR3, // source null ptr
PCIT::MPTR32, // source ptr
PCIT::IBIN32S); // source/target length
OL ol(dst->getAtp(), dst->getAtpIndex(), (Int32)dst->getOffset(),
dst->getAtp(), dst->getAtpIndex(), dst->getNullIndOffset(),
dst->getNullBitIndex(),
src->getAtp(), src->getAtpIndex(), (Int32)src->getOffset(),
src->getLength());
PCI pci(PCIT::Op_NULLIFZERO, aml, ol);
code.append(pci);
// Add the branch target if necessary.
//
if (nullBranch)
{
AML aml;
OL ol((Int64)nullBranch);
PCI pci(PCIT::Op_TARGET, aml, ol);
code.append(pci);
}
// Generate post clause PCI's
//
PCode::postClausePCI(this, code);
setPCIList(code.getList());
return ex_expr::EXPR_OK;
}
//
// NVL(e1, e2) returns e2 if e1 is NULL otherwise e1. NVL(e1, e2) is
// equivalent to ANSI/ISO
// COALESCE(e1, e2)
// or,
// CASE WHEN e1 IS NULL THEN e2 ELSE e1 END
// Both arguments can be nullable and actually null; they both can
// be constants as well.
// NVL() on CHAR type expressions is mapped to CASE. ISNULL(e1, e2) is
// mapped into NVL(e1, e2)
// Datatypes of e1 and e2 must be comparable/compatible.
//
ex_expr::exp_return_type ex_function_nvl::pCodeGenerate(Space *space, UInt32 f)
{
// Get a handle on the operands
//
AttributesPtr *attrs = getOperand();
Attributes *res = attrs[0];
Attributes *arg1 = attrs[1];
Attributes *arg2 = attrs[2];
Int16 resAtp = res->getAtp();
Int16 resAtpIdx = res->getAtpIndex();
UInt32 resOffs = res->getOffset();
Int32 resNullOffs = res->getNullIndOffset();
// As of today, NVL() on CHAR types becomes CASE. So make sure we are
// not dealing with any CHAR types
assert(!DFS2REC::isAnyCharacter(arg1->getDatatype()) &&
!DFS2REC::isAnyCharacter(arg2->getDatatype()));
PCIList code(space);
// Generate pre clause PCI's
//
PCode::preClausePCI(this, code);
PCIID nullBranch = 0;
// If the argument is nullable, then proceed to perform a null test first.
// Otherwise we skip the test and just copy the column to the result.
if (arg1->getNullFlag()) {
// handle NULLs (may jump)
// PCIID nullBranch = PCode::nullBranch(this, code, attrs);
PCIID notNullBranch = 0;
if (arg1->isSQLMXAlignedFormat())
{
PCodeTupleFormats tpf(res->getTupleFormat(),
arg1->getTupleFormat());
AML aml(PCIT::MBIN32S,PCIT::MBIN32S,PCIT::IATTR3,PCIT::IBIN32S);
OL ol(resAtp, resAtpIdx, resNullOffs,
arg1->getAtp(), arg1->getAtpIndex(), arg1->getNullIndOffset(),
EXPAND_PCODEATTRNULL2(*(UInt32 *)&tpf, res, arg1),
0);
PCI pci(PCIT::Op_NOT_NULL_BRANCH, aml, ol);
code.append(pci);
notNullBranch = code.getTailId();
}
else
{
AML aml(PCIT::MBIN16S, PCIT::IBIN32S);
OL ol(arg1->getAtp(), arg1->getAtpIndex(), arg1->getNullIndOffset(), 0);
PCI pci(PCIT::Op_NOT_NULL_BRANCH, aml, ol);
code.append(pci);
notNullBranch = code.getTailId();
}
// it will come here if arg1 is a NULL value.
// Move arg2 to dst. arg2 and dst have the same data attrs.
{
assert((UInt32)(res->getLength()) >= (UInt32)(arg2->getLength()));
AML aml(PCIT::MBIN8,PCIT::MBIN8,PCIT::IBIN32S);
OL ol(resAtp, resAtpIdx, (Int32)resOffs,
arg2->getAtp(), arg2->getAtpIndex(), (Int32)arg2->getOffset(),
(Int32)arg2->getLength());
PCI pci(PCIT::Op_MOVE, aml, ol);
code.append(pci);
// Set or Clear NULL flag.
// if the second operand is not nullable then just clear the null
// indicator in the result
if (!arg2->getNullFlag() && res->getNullFlag())
{
AML amlNotNull(PCIT::MBIN16U,PCIT::IBIN16U);
OL olNotNull(resAtp, resAtpIdx, resNullOffs, 0);
PCI pciNotNull(PCIT::Op_MOVE, amlNotNull, olNotNull);
code.append(pciNotNull);
}
else
{
// second argument is NULLABLE, so copy the null status from the
// second argument into the null status of the result using one
// of the two possible formats
code.append(PCode::isNull(res, arg2, space));
}
}
nullBranch = PCode::generateJumpAndBranch(res, code, notNullBranch);
}
// it will come here if arg1 is not a NULL value.
// Move arg1 to dst. arg1 and dst have the same data attrs.
{
assert((UInt32)(res->getLength()) >= (UInt32)(arg1->getLength()));
AML aml(PCIT::MBIN8,PCIT::MBIN8,PCIT::IBIN32S);
OL ol(resAtp, resAtpIdx, (Int32)resOffs,
arg1->getAtp(), arg1->getAtpIndex(), (Int32)arg1->getOffset(),
(Int32)arg1->getLength());
PCI pci(PCIT::Op_MOVE, aml, ol);
code.append(pci);
// first operand is NOT NULL, simply clear the status in result
if (res->getNullFlag())
{
AML amlNotNull(PCIT::MBIN16U,PCIT::IBIN16U);
OL olNotNull(resAtp, resAtpIdx, resNullOffs, (Int16)0);
PCI pciNotNull(PCIT::Op_MOVE, amlNotNull, olNotNull);
code.append(pciNotNull);
}
}
// Add the branch target if necessary.
//
if (nullBranch)
{
AML aml;
OL ol((Int64)nullBranch);
PCI pci(PCIT::Op_TARGET, aml, ol);
code.append(pci);
}
// Generate post clause PCI's
//
PCode::postClausePCI(this, code);
setPCIList(code.getList());
return ex_expr::EXPR_OK;
}
ex_expr::exp_return_type ExFunctionRandomNum::pCodeGenerate(Space *space, UInt32 f)
{
if (NOT simpleRandom())
return ex_clause::pCodeGenerate(space, f);
// Get a handle on the operands
//
AttributesPtr *attrs = getOperand();
Attributes *dst = attrs[0];
Attributes *src = attrs[1];
if (getNumOperands() > 1)
return ex_clause::pCodeGenerate(space, f);
//
PCIList code(space);
// Generate pre clause PCI's
//
PCode::preClausePCI(this, code);
AML aml(PCIT::IBIN32S, // OperTypeEnum
PCIT::MBIN8, // target ptr
PCIT::MBIN8, // not needed
PCIT::IBIN32S, // not needed
PCIT::MBIN8, // not needed
PCIT::IBIN32S); // seed
OL ol(getOperType(),
dst->getAtp(), dst->getAtpIndex(), (Lng32)dst->getOffset(),
-1, -1, -1,
-1,
-1, -1, -1,
0); // init seed to zero
PCI pci(PCIT::Op_GENFUNC, aml, ol);
code.append(pci);
// Generate post clause PCI's
//
PCode::postClausePCI(this, code);
setPCIList(code.getList());
return ex_expr::EXPR_OK;
}
ex_expr::exp_return_type ExHash2Distrib::pCodeGenerate(Space *space, UInt32 f)
{
// Get a handle on the operands
//
AttributesPtr *attrs = getOperand();
PCIList code(space);
PCode::preClausePCI(this, code);
AML aml(PCIT::MBIN32U, // Target (the partition number)
PCIT::MBIN32U, // The hash value
PCIT::MBIN32U); // Number of partitions
// attr[0] = result
// attr[1] = keyValue
// attr[2] = numParts
OL ols(attrs[0]->getAtp(),attrs[0]->getAtpIndex(),(Int32)attrs[0]->getOffset(),
attrs[1]->getAtp(),attrs[1]->getAtpIndex(),(Int32)attrs[1]->getOffset(),
attrs[2]->getAtp(),attrs[2]->getAtpIndex(),(Int32)attrs[2]->getOffset());
PCI pci(PCIT::Op_HASH2_DISTRIB, aml, ols);
code.append(pci);
// Generate post clause PCI's
//
PCode::postClausePCI(this, code);
setPCIList(code.getList());
return ex_expr::EXPR_OK;
}
ex_expr::exp_return_type
ex_function_concat::pCodeGenerate(Space *space, UInt32 f)
{
AttributesPtr *attrs = getOperand();
Int32 len0 = attrs[0]->getLength(); // Length of output string space
Int32 len1 = attrs[1]->getLength(); // Length of input string 1
Int32 len2 = attrs[2]->getLength(); // Length of input string 2
if ( len0 < (len1 + len2) ) // If output space is too small
return ex_clause::pCodeGenerate(space, f);
CharInfo::CharSet cs1 = ((SimpleType *)getOperand(1))->getCharSet();
CharInfo::CharSet cs2 = ((SimpleType *)getOperand(2))->getCharSet();
// If a character set is SJIS or Unicode
if( (cs1 == CharInfo::UTF8) /* || (cs2 == CharInfo::SJIS) */ )
{
Int32 prec1 = ((SimpleType *)getOperand(1))->getPrecision();
Int32 prec2 = ((SimpleType *)getOperand(2))->getPrecision();
if ( ( prec1 && (prec1 != len1) )
|| ( prec2 && (prec2 != len2) )
)
// Strings may have filler spaces at the end which pcode concat function
// cannot handle, so call ex_clause version instead.
return ex_clause::pCodeGenerate(space, f);
}
//
PCIList code(space);
// Generate pre clause PCI's
//
PCode::preClausePCI(this, code);
// Add the null logic if necessary.
//
PCIID branchToEnd = PCode::nullBranch(this, code, attrs);
AML aml(PCIT::MATTR5, // target ptr
PCIT::MATTR5, // src1 ptr
PCIT::MATTR5); // src2 ptr
UInt32 comboLen1=0;
UInt32 comboLen2=0;
UInt32 comboLen3=0;
char* comboPtr1 = (char*)&comboLen1;
char* comboPtr2 = (char*)&comboLen2;
char* comboPtr3 = (char*)&comboLen3;
// Use combo fields for specifying null/vc lengths of both operands
comboPtr1[0] = (char)attrs[0]->getNullIndicatorLength(),
comboPtr1[1] = (char)attrs[0]->getVCIndicatorLength();
comboPtr2[0] = (char)attrs[1]->getNullIndicatorLength(),
comboPtr2[1] = (char)attrs[1]->getVCIndicatorLength();
comboPtr3[0] = (char)attrs[2]->getNullIndicatorLength(),
comboPtr3[1] = (char)attrs[2]->getVCIndicatorLength();
OL ol(attrs[0]->getAtp(), attrs[0]->getAtpIndex(), attrs[0]->getOffset(),
attrs[0]->getVoaOffset(), len0, comboLen1,
attrs[1]->getAtp(), attrs[1]->getAtpIndex(), attrs[1]->getOffset(),
attrs[1]->getVoaOffset(), len1, comboLen2,
attrs[2]->getAtp(), attrs[2]->getAtpIndex(), attrs[2]->getOffset(),
attrs[2]->getVoaOffset(), len2, comboLen3);
PCI pci(PCIT::Op_GENFUNC, aml, ol);
code.append(pci);
// Add the branch target if necessary.
//
if(branchToEnd)
{
AML aml;
OL ol((Int64)branchToEnd);
PCI pci(PCIT::Op_TARGET, aml, ol);
code.append(pci);
}
// Generate post clause PCI's
//
PCode::postClausePCI(this, code);
setPCIList(code.getList());
return ex_expr::EXPR_OK;
}
ex_expr::exp_return_type ex_function_substring::pCodeGenerate(Space *space,
UInt32 f)
{
// How many nullable attrs are there?
//
AttributesPtr *attrs = getOperand();
Int32 numOfNullableFields = 0;
for(Int32 i=0; i<getNumOperands(); i++) {
// Count nullable attributes (but not output)
if (attrs[i]->getNullFlag() && (i != 0))
numOfNullableFields++;
}
// Temporary fix for substring function. Since pcode substring function
// cannot handle SJIS and UTF-8 characters, call ex_clause version of
// substring. The following 5 lines of code can be removed after pcode
// substring function can handle SJIS and UTF-8 characters on SJIS or
// Unicode configuration.
CharInfo::CharSet cs = ((SimpleType *)getOperand(0))->getCharSet();
if(cs != CharInfo::ISO88591)
return ex_clause::pCodeGenerate(space, f);
// If there are too many nullable fields
if (numOfNullableFields > 2)
return ex_clause::pCodeGenerate(space, f);
//
PCIList code(space);
// Generate pre clause PCI's
//
PCode::preClausePCI(this, code);
// Get a handle on the operands
//
Attributes *dst = attrs[0];
Attributes *src = attrs[1];
// Add the null logic if necessary.
//
PCIID nullBranch = PCode::nullBranch(this, code, attrs);
AML aml(PCIT::MATTR5, // target ptr
PCIT::MATTR5, // operand1 (string)
PCIT::MBIN32S, // operand2 (start position)
PCIT::MBIN32S); // operand3 (length)
UInt32 comboLen1 = 0;
UInt32 comboLen2 = 0;
char* comboPtr1 = (char*)&comboLen1;
char* comboPtr2 = (char*)&comboLen2;
// Use combo fields for specifying vc/null lengths of both operands
comboPtr1[0] = (char)dst->getNullIndicatorLength(),
comboPtr1[1] = (char)dst->getVCIndicatorLength();
comboPtr2[0] = (char)src->getNullIndicatorLength(),
comboPtr2[1] = (char)src->getVCIndicatorLength();
// Use part of combo field to specify additional info
comboPtr2[2] = (getNumOperands() == 4); // Was length passed in?
comboPtr2[3] = getOperType(); // What is the operation type?
// If no length field exists, just copy over "start" (attribute 2) instead
Int32 a3 = 3;
if (comboPtr2[2] == 0)
a3 = 2;
OL ol(dst->getAtp(), dst->getAtpIndex(), dst->getOffset(),
dst->getVoaOffset(), dst->getLength(), comboLen1,
src->getAtp(), src->getAtpIndex(), src->getOffset(),
src->getVoaOffset(), src->getLength(), comboLen2,
attrs[2]->getAtp(), attrs[2]->getAtpIndex(), attrs[2]->getOffset(),
attrs[a3]->getAtp(), attrs[a3]->getAtpIndex(), attrs[a3]->getOffset());
PCI pci(PCIT::Op_GENFUNC, aml, ol);
code.append(pci);
// Add the branch target if necessary.
//
if (nullBranch)
{
AML aml;
OL ol((Int64)nullBranch);
PCI pci(PCIT::Op_TARGET, aml, ol);
code.append(pci);
}
// Generate post clause PCI's
//
PCode::postClausePCI(this, code);
setPCIList(code.getList());
return ex_expr::EXPR_OK;
}
ex_expr::exp_return_type ExFunctionBitOper::pCodeGenerate(Space *space, UInt32 f)
{
if ((getOperType() == ITM_CONVERTTOBITS) ||
(getOperType() == ITM_BITEXTRACT))
return ex_clause::pCodeGenerate(space, f);
AttributesPtr *attrs = getOperand();
//
PCIList code(space);
// Generate pre clause PCI's
//
PCode::preClausePCI(this, code);
// Add the null logic if necessary.
//
PCIID branchToEnd = PCode::nullBranch(this, code, attrs);
AML aml(PCIT::IBIN32S, // OperTypeEnum
PCIT::MBIN8, // target ptr
PCIT::MBIN8, // operand1
PCIT::MBIN8, // operand2
PCIT::IBIN32S, // datatype operand0
PCIT::IBIN32S); // length operand0
OL ol(getOperType(),
attrs[0]->getAtp(), attrs[0]->getAtpIndex(), (Lng32)attrs[0]->getOffset(),
attrs[1]->getAtp(), attrs[1]->getAtpIndex(), (Lng32)attrs[1]->getOffset(),
((getOperType() == ITM_BITNOT) ? attrs[1]->getAtp() : attrs[2]->getAtp()),
((getOperType() == ITM_BITNOT) ? attrs[1]->getAtpIndex() : attrs[2]->getAtpIndex()),
((getOperType() == ITM_BITNOT) ? (Lng32)attrs[1]->getOffset() : (Lng32)attrs[2]->getOffset()),
attrs[0]->getDatatype(), attrs[0]->getLength());
PCI pci(PCIT::Op_GENFUNC, aml, ol);
code.append(pci);
// Add the branch target if necessary.
//
if(branchToEnd)
{
AML aml;
OL ol((Int64)branchToEnd);
PCI pci(PCIT::Op_TARGET, aml, ol);
code.append(pci);
}
// Generate post clause PCI's
//
PCode::postClausePCI(this, code);
setPCIList(code.getList());
return ex_expr::EXPR_OK;
}
ex_expr::exp_return_type ExHeaderClause::pCodeGenerate( Space *space,
UInt32 flags )
{
Attributes *tgt = getOperand(0);
// Initialize the pCode
PCIList code(space);
// Generate pre clause PCI's
PCode::preClausePCI(this, code);
AML aml(PCIT::MPTR32,
PCIT::IBIN32S,PCIT::IBIN32S,PCIT::IBIN32S,PCIT::IBIN32S,PCIT::IBIN32S);
OL ol(tgt->getAtp(), tgt->getAtpIndex(), (Int32)tgt->getOffset(),
(Int32)adminSz_, // bytes to clear
(Int32)firstFixedOffset_,
(Int32)( isSQLMXAlignedFormat()
? ExpAlignedFormat::OFFSET_SIZE : ExpVoaSize),
(Int32)bitmapOffset_,
(Int32)entryOffset_
);
PCI pci(PCIT::Op_HDR, aml, ol);
code.append(pci);
// Generate post clause PCI's
PCode::postClausePCI(this, code);
setPCIList(code.getList());
return ex_expr::EXPR_OK;
}
ex_expr::exp_return_type
ex_function_upper::pCodeGenerate(Space *space, UInt32 f)
{
// Get a handle on the operands
//
AttributesPtr *attrs = getOperand();
Attributes *dst = attrs[0];
Attributes *src = attrs[1];
// Temporary fix for upper function. Since pcode substring function
// cannot handle SJIS and UTF-8 characters, call ex_clause version of
// upper. The following 5 lines of code can be removed after pcode
// upper function can handle SJIS and UTF-8 characters on SJIS or
// Unicode configuration.
CharInfo::CharSet cs = ((SimpleType *)getOperand(0))->getCharSet();
if(cs != CharInfo::ISO88591)
return ex_clause::pCodeGenerate(space, f);
if (src->widechar())
return ex_clause::pCodeGenerate(space, f);
//
PCIList code(space);
// Generate pre clause PCI's
//
PCode::preClausePCI(this, code);
// handle NULLs (may jump)
PCIID nullBranch = PCode::nullBranch(this, code, attrs);
UInt32 comboLen1=0;
UInt32 comboLen2=0;
char* comboPtr1 = (char*)&comboLen1;
char* comboPtr2 = (char*)&comboLen2;
// Use combo fields for specifying null/vc lengths of both operands
comboPtr1[0] = (char)dst->getNullIndicatorLength(),
comboPtr1[1] = (char)dst->getVCIndicatorLength();
comboPtr2[0] = (char)src->getNullIndicatorLength(),
comboPtr2[1] = (char)src->getVCIndicatorLength();
AML aml(PCIT::MATTR5, // target ptr
PCIT::MATTR5, // source ptr
PCIT::IBIN32S); // OperTypeEnum
OL ol(dst->getAtp(), dst->getAtpIndex(), dst->getOffset(),
dst->getVoaOffset(), dst->getLength(), comboLen1,
src->getAtp(), src->getAtpIndex(), src->getOffset(),
src->getVoaOffset(), src->getLength(), comboLen2,
getOperType());
PCI pci(PCIT::Op_GENFUNC, aml, ol);
code.append(pci);
// Add the branch target if necessary.
//
if (nullBranch)
{
AML aml;
OL ol((Int64)nullBranch);
PCI pci(PCIT::Op_TARGET, aml, ol);
code.append(pci);
}
// Generate post clause PCI's
//
PCode::postClausePCI(this, code);
setPCIList(code.getList());
return ex_expr::EXPR_OK;
}
ex_expr::exp_return_type
ex_function_lower::pCodeGenerate(Space *space, UInt32 f)
{
// Get a handle on the operands
//
AttributesPtr *attrs = getOperand();
Attributes *dst = attrs[0];
Attributes *src = attrs[1];
// Temporary fix for upper function. Since pcode substring function
// cannot handle SJIS and UTF-8 characters, call ex_clause version of
// upper. The following 5 lines of code can be removed after pcode
// upper function can handle SJIS and UTF-8 characters on SJIS or
// Unicode configuration.
CharInfo::CharSet cs = ((SimpleType *)getOperand(0))->getCharSet();
if(cs != CharInfo::ISO88591)
return ex_clause::pCodeGenerate(space, f);
if (src->widechar())
return ex_clause::pCodeGenerate(space, f);
//
PCIList code(space);
// Generate pre clause PCI's
//
PCode::preClausePCI(this, code);
// handle NULLs (may jump)
PCIID nullBranch = PCode::nullBranch(this, code, attrs);
UInt32 comboLen1=0;
UInt32 comboLen2=0;
char* comboPtr1 = (char*)&comboLen1;
char* comboPtr2 = (char*)&comboLen2;
// Use combo fields for specifying null/vc lengths of both operands
comboPtr1[0] = (char)dst->getNullIndicatorLength(),
comboPtr1[1] = (char)dst->getVCIndicatorLength();
comboPtr2[0] = (char)src->getNullIndicatorLength(),
comboPtr2[1] = (char)src->getVCIndicatorLength();
AML aml(PCIT::MATTR5, // target ptr
PCIT::MATTR5, // source ptr
PCIT::IBIN32S); // OperTypeEnum
OL ol(dst->getAtp(), dst->getAtpIndex(), dst->getOffset(),
dst->getVoaOffset(), dst->getLength(), comboLen1,
src->getAtp(), src->getAtpIndex(), src->getOffset(),
src->getVoaOffset(), src->getLength(), comboLen2,
getOperType());
PCI pci(PCIT::Op_GENFUNC, aml, ol);
code.append(pci);
// Add the branch target if necessary.
//
if (nullBranch)
{
AML aml;
OL ol((Int64)nullBranch);
PCI pci(PCIT::Op_TARGET, aml, ol);
code.append(pci);
}
// Generate post clause PCI's
//
PCode::postClausePCI(this, code);
setPCIList(code.getList());
return ex_expr::EXPR_OK;
}
ex_expr::exp_return_type
ex_function_trim_char::pCodeGenerate(Space *space, UInt32 f)
{
// Only trim where the trim character is a single space literal
// is supported. The flag noPCodeAvailable is set by the caller if
// the trim char is something other than a single space literal.
if (noPCodeAvailable())
return ex_clause::pCodeGenerate(space, f);
// Get a handle on the operands
//
AttributesPtr *attrs = getOperand();
Attributes *dst = attrs[0];
Attributes *src = attrs[2];
// Temporary fix for trim function. Since pcode trim function
// cannot handle SJIS and UTF-8 characters, call ex_clause version of
// trim. The following 5 lines of code can be removed after pcode
// trim function can handle SJIS and UTF-8 characters on SJIS or
// Unicode configuration.
CharInfo::CharSet cs = ((SimpleType *)getOperand(0))->getCharSet();
if(cs != CharInfo::ISO88591)
return ex_clause::pCodeGenerate(space, f);
if (src->widechar())
return ex_clause::pCodeGenerate(space, f);
//
PCIList code(space);
// Generate pre clause PCI's
//
PCode::preClausePCI(this, code);
// handle NULLs (may jump)
PCIID nullBranch = PCode::nullBranch(this, code, attrs);
UInt32 comboLen1=0;
UInt32 comboLen2=0;
char* comboPtr1 = (char*)&comboLen1;
char* comboPtr2 = (char*)&comboLen2;
// Use combo fields for specifying null/vc lengths of both operands
comboPtr1[0] = (char)dst->getNullIndicatorLength(),
comboPtr1[1] = (char)dst->getVCIndicatorLength();
comboPtr2[0] = (char)src->getNullIndicatorLength(),
comboPtr2[1] = (char)src->getVCIndicatorLength();
AML aml(PCIT::MATTR5, // target ptr
PCIT::MATTR5, // source ptr
PCIT::IBIN32S); // OperTypeEnum
OL ol(dst->getAtp(), dst->getAtpIndex(), dst->getOffset(),
dst->getVoaOffset(), dst->getLength(), comboLen1,
src->getAtp(), src->getAtpIndex(), src->getOffset(),
src->getVoaOffset(), src->getLength(), comboLen2,
(getTrimMode() == 0 ? ITM_RTRIM :
(getTrimMode() == 1 ? ITM_LTRIM : ITM_TRIM)));
PCI pci(PCIT::Op_GENFUNC, aml, ol);
code.append(pci);
// Add the branch target if necessary.
//
if (nullBranch)
{
AML aml;
OL ol((Int64)nullBranch);
PCI pci(PCIT::Op_TARGET, aml, ol);
code.append(pci);
}
// Generate post clause PCI's
//
PCode::postClausePCI(this, code);
setPCIList(code.getList());
return ex_expr::EXPR_OK;
}
ex_expr::exp_return_type
ex_function_char_length_doublebyte::pCodeGenerate(Space *space, UInt32 f)
{
// Get a handle on the operands
//
AttributesPtr *attrs = getOperand();
// Only proceed (for now) with unicode strings. Other charsets, like Kanji,
// have 2 bytes for chars, but let's not deal with that now.
if ((attrs[1]->getDatatype() != REC_NCHAR_F_UNICODE) &&
(attrs[1]->getDatatype() != REC_NCHAR_V_UNICODE))
return ex_clause::pCodeGenerate(space, f);
// Allocate the code list
//
PCIList code(space);
// Generate pre clause PCI's
PCode::preClausePCI(this, code);
// Add the null logic if necessary.
PCIID branchToEnd = PCode::nullBranch(this, code, attrs);
// Just return length/2 if the string is fixed
if (attrs[1]->getDatatype() == REC_NCHAR_F_UNICODE) {
AML aml(PCIT::MBIN32S, PCIT::IBIN32S);
OL ol(attrs[0]->getAtp(), attrs[0]->getAtpIndex(), attrs[0]->getOffset(),
(Int32)(attrs[1]->getLength() / 2));
PCI pci(PCIT::Op_MOVE, aml, ol);
code.append(pci);
}
else
{
UInt32 comboLen1=0;
char* comboPtr1 = (char*)&comboLen1;
// Use combo fields for specifying null/vc lengths of both operands
comboPtr1[0] = (char)attrs[1]->getNullIndicatorLength(),
comboPtr1[1] = (char)attrs[1]->getVCIndicatorLength();
AML aml(PCIT::MBIN32U, PCIT::MUNIV);
OL ol(attrs[0]->getAtp(), attrs[0]->getAtpIndex(), attrs[0]->getOffset(),
attrs[1]->getAtp(), attrs[1]->getAtpIndex(), attrs[1]->getOffset(),
attrs[1]->getVoaOffset(), attrs[1]->getLength(), comboLen1);
PCI pci(PCIT::Op_GENFUNC, aml, ol);
code.append(pci);
}
// Add the branch target if necessary.
//
if(branchToEnd)
{
AML aml;
OL ol((Int64)branchToEnd);
PCI pci(PCIT::Op_TARGET, aml, ol);
code.append(pci);
}
// Generate post clause PCI's
//
PCode::postClausePCI(this, code);
setPCIList(code.getList());
return ex_expr::EXPR_OK;
}
ex_expr::exp_return_type
ex_function_char_length::pCodeGenerate(Space *space, UInt32 f)
{
// Get a handle on the operands
//
AttributesPtr *attrs = getOperand();
// Only support ascii strings for now
CharInfo::CharSet cs = ((SimpleType *)getOperand(1))->getCharSet();
if(cs != CharInfo::ISO88591)
return ex_clause::pCodeGenerate(space, f);
// Allocate the code list
//
PCIList code(space);
// Generate pre clause PCI's
PCode::preClausePCI(this, code);
// Add the null logic if necessary.
PCIID branchToEnd = PCode::nullBranch(this, code, attrs);
// Just return length if the string is fixed
if (attrs[1]->getDatatype() == REC_BYTE_F_ASCII) {
AML aml(PCIT::MBIN32S, PCIT::IBIN32S);
OL ol(attrs[0]->getAtp(), attrs[0]->getAtpIndex(), attrs[0]->getOffset(),
(Int32)attrs[1]->getLength());
PCI pci(PCIT::Op_MOVE, aml, ol);
code.append(pci);
}
else
{
UInt32 comboLen1=0;
char* comboPtr1 = (char*)&comboLen1;
// Use combo fields for specifying null/vc lengths of both operands
comboPtr1[0] = (char)attrs[1]->getNullIndicatorLength(),
comboPtr1[1] = (char)attrs[1]->getVCIndicatorLength();
AML aml(PCIT::MBIN32U, PCIT::MATTR5);
OL ol(attrs[0]->getAtp(), attrs[0]->getAtpIndex(), attrs[0]->getOffset(),
attrs[1]->getAtp(), attrs[1]->getAtpIndex(), attrs[1]->getOffset(),
attrs[1]->getVoaOffset(), attrs[1]->getLength(), comboLen1);
PCI pci(PCIT::Op_GENFUNC, aml, ol);
code.append(pci);
}
// Add the branch target if necessary.
//
if(branchToEnd)
{
AML aml;
OL ol((Int64)branchToEnd);
PCI pci(PCIT::Op_TARGET, aml, ol);
code.append(pci);
}
// Generate post clause PCI's
//
PCode::postClausePCI(this, code);
setPCIList(code.getList());
return ex_expr::EXPR_OK;
}
ex_expr::exp_return_type
ExFunctionRepeat::pCodeGenerate(Space *space, UInt32 f)
{
// Get a handle on the operands
//
AttributesPtr *attrs = getOperand();
Attributes *dst = attrs[0];
Attributes *src = attrs[1];
if ( ( src->getScale() == SQLCHARSETCODE_UTF8 ) &&
( src->getPrecision() > 0 ) &&
( src->getPrecision() < src->getLength() ) )
return( ex_expr::EXPR_NULL ); //pCode cannot handle this case
//
PCIList code(space);
// Generate pre clause PCI's
//
PCode::preClausePCI(this, code);
// handle NULLs (may jump)
PCIID nullBranch = PCode::nullBranch(this, code, attrs);
AML aml(PCIT::MATTR5, // target ptr
PCIT::MATTR5, // source ptr
PCIT::MBIN32S, // len
PCIT::IBIN32S); // OperTypeEnum
UInt32 comboLen1=0;
UInt32 comboLen2=0;
char* comboPtr1 = (char*)&comboLen1;
char* comboPtr2 = (char*)&comboLen2;
// Use combo fields for specifying null/vc lengths of both operands
comboPtr1[0] = (char)dst->getNullIndicatorLength(),
comboPtr1[1] = (char)dst->getVCIndicatorLength();
comboPtr2[0] = (char)src->getNullIndicatorLength(),
comboPtr2[1] = (char)src->getVCIndicatorLength();
OL ol(dst->getAtp(), dst->getAtpIndex(), dst->getOffset(),
dst->getVoaOffset(), dst->getLength(), comboLen1,
src->getAtp(), src->getAtpIndex(), src->getOffset(),
src->getVoaOffset(), src->getLength(), comboLen2,
attrs[2]->getAtp(), attrs[2]->getAtpIndex(), attrs[2]->getOffset(),
ITM_REPEAT);
PCI pci(PCIT::Op_GENFUNC, aml, ol);
code.append(pci);
// Add the branch target if necessary.
//
if (nullBranch)
{
AML aml;
OL ol((Int64)nullBranch);
PCI pci(PCIT::Op_TARGET, aml, ol);
code.append(pci);
}
// Generate post clause PCI's
//
PCode::postClausePCI(this, code);
setPCIList(code.getList());
return ex_expr::EXPR_OK;
}
ex_expr::exp_return_type
ex_function_position::pCodeGenerate(Space *space, UInt32 f)
{
// Get a handle on the operands
//
AttributesPtr *attrs = getOperand();
// Only support ascii strings for now
CharInfo::CharSet cs = ((SimpleType *)getOperand(1))->getCharSet();
if(cs != CharInfo::ISO88591)
return ex_clause::pCodeGenerate(space, f);
// pcode currently doesn't handle non-default start position or n'th occurrence
if (getNumOperands() > 3)
return ex_clause::pCodeGenerate(space, f);
// We don't support system collations (e.g. czech). Note, some clauses have
// the collation defined in the clause. Others don't - in which case the
// info needs to be derived from the operand.
CharInfo::Collation co = getCollation();
if (CollationInfo::isSystemCollation(co))
return ex_clause::pCodeGenerate(space, f);
// Allocate the code list
//
PCIList code(space);
// Generate pre clause PCI's
PCode::preClausePCI(this, code);
// Add the null logic if necessary.
PCIID branchToEnd = PCode::nullBranch(this, code, attrs);
UInt32 comboLen1=0;
UInt32 comboLen2=0;
char* comboPtr1 = (char*)&comboLen1;
char* comboPtr2 = (char*)&comboLen2;
// Use combo fields for specifying null/vc lengths of both operands
comboPtr1[0] = (char)attrs[1]->getNullIndicatorLength(),
comboPtr1[1] = (char)attrs[1]->getVCIndicatorLength();
comboPtr2[0] = (char)attrs[2]->getNullIndicatorLength(),
comboPtr2[1] = (char)attrs[2]->getVCIndicatorLength();
AML aml(PCIT::MBIN32S, PCIT::MATTR5, PCIT::MATTR5);
OL ol(attrs[0]->getAtp(), attrs[0]->getAtpIndex(), attrs[0]->getOffset(),
attrs[1]->getAtp(), attrs[1]->getAtpIndex(), attrs[1]->getOffset(),
attrs[1]->getVoaOffset(), attrs[1]->getLength(), comboLen1,
attrs[2]->getAtp(), attrs[2]->getAtpIndex(), attrs[2]->getOffset(),
attrs[2]->getVoaOffset(), attrs[2]->getLength(), comboLen2);
PCI pci(PCIT::Op_GENFUNC, aml, ol);
code.append(pci);
// Add the branch target if necessary.
//
if(branchToEnd)
{
AML aml;
OL ol((Int64)branchToEnd);
PCI pci(PCIT::Op_TARGET, aml, ol);
code.append(pci);
}
// Generate post clause PCI's
//
PCode::postClausePCI(this, code);
setPCIList(code.getList());
return ex_expr::EXPR_OK;
}
ex_expr::exp_return_type
ex_like_clause_base::pCodeGenerate(Space *space, UInt32 f)
{
// Get a handle on the operands
//
AttributesPtr *attrs = getOperand();
// Only support ascii strings for now
CharInfo::CharSet cs = ((SimpleType *)getOperand(1))->getCharSet();
//
// The following criteria must be met for PCode to be generated for LIKE
//
// 1. Pattern string must be a constant
// 2. Pattern can't contain any ESCAPE characters
// 3. We can't use a collation for the comparison.
// 4. Pattern can't contain any '_' characters
// 5. Character set can't have a possibility of matching partial characters
// in a % wildcard (issue with SJIS, not an issue with UTF-8, due to the
// way UTF-8 is encoded where the first byte indicates the length and
// continuation bytes can never match the first byte of a UTF-8 character).
// 6. Pattern string and UTF-8 char limits can't exceed 255 bytes in length.
// This is because both relative offsets and lengths of patterns are
// stored in 32-bit containers divided into 4 unsigned chars.
// 7. Pattern string must contain 1-4 non-zero-length sub-patterns which
// are separated by '%', with at least one '%'. For example:
//
// a) '%pat1%pat2%pat3'
// b) 'pat1%'
// c) 'pat1%pat2%%%pat3%'
//
// Here are some examples of pattern strings that aren't supported:
//
// a) 'sank'
// b) 'pat1%pat2%pat3%pat4%pat5%'
// c) '%'
//
// Criteria (1) and (2) were checked in the generator. The rest must be done
// here. The member variable "pattern_" is used to retrieve the pattern char
// string - this is registered, again, by the generator.
//
// (3) We don't support system collations (e.g. czech). Note, some clauses have
// the collation defined in the clause. Others don't - in which case the
// info needs to be derived from the operand.
CharInfo::Collation co = ((SimpleType *)getOperand(1))->getCollation();
if (CollationInfo::isSystemCollation(co))
return ex_clause::pCodeGenerate(space, f);
// (5) Allow only ISO and UTF8 charsets
if(cs != CharInfo::ISO88591 && cs != CharInfo::UTF8)
return ex_clause::pCodeGenerate(space, f);
Int32 precision = 0;
if (cs == CharInfo::UTF8)
{
precision = attrs[1]->getPrecision();
}
// Get pattern string and length
char* pat = getPatternStr();
Int32 patLen = attrs[2]->getLength();
// (6) Generator restrictions met, as well as pattern length restriction
if (noPCodeAvailable() || (patLen > UCHAR_MAX) || (precision > UCHAR_MAX))
return ex_clause::pCodeGenerate(space, f);
char numOfPatterns = 0;
Int32 patternOffsets = -1;
Int32 patternLengths = -1;
UInt8* pOffPtr = (UInt8*)&patternOffsets;
UInt8* pLenPtr = (UInt8*)&patternLengths;
Int32 i;
NABoolean open = FALSE, percentFound = FALSE;
for (i=0; i < patLen; i++)
{
// (4) No underscore allowed (i.e. no "any" character)
if (pat[i] == '_')
return ex_clause::pCodeGenerate(space, f);
if (pat[i] == '%') {
percentFound = TRUE;
// If open pattern found, close it off by setting the pattern length
if (open) {
pLenPtr[numOfPatterns-1] = (UInt8)(i - pOffPtr[numOfPatterns-1]);
open = FALSE; // Indicate end of pattern
}
}
else if (!open) {
// (7a) Can only support 4 patterns - bail out otherwise
if (numOfPatterns >= 4)
return ex_clause::pCodeGenerate(space, f);
// Otherwise start new pattern. Assume max length of pattern
pOffPtr[numOfPatterns] = (UInt8)i;
pLenPtr[numOfPatterns] = (UInt8)(patLen - i);
numOfPatterns++; // Increase num of patterns
open = TRUE; // Indicate start of new pattern
}
}
// (7b) Return if no pattern strings or no wildcard found
if ((numOfPatterns == 0) || (percentFound == FALSE))
return ex_clause::pCodeGenerate(space, f);
// Allocate the code list
//
PCIList code(space);
// Generate pre clause PCI's
PCode::preClausePCI(this, code);
// Add the null logic if necessary.
PCIID branchToEnd = PCode::nullBranch(this, code, attrs);
UInt32 comboLen1=0;
UInt32 comboLen2=0;
char* comboPtr1 = (char*)&comboLen1;
char* comboPtr2 = (char*)&comboLen2;
// Use combo fields for specifying null/vc lengths of both operands
comboPtr1[0] = (char)attrs[1]->getNullIndicatorLength(),
comboPtr1[1] = (char)attrs[1]->getVCIndicatorLength();
comboPtr2[0] = (char)attrs[2]->getNullIndicatorLength(),
comboPtr2[1] = (char)attrs[2]->getVCIndicatorLength();
// Indicate if boundary checks are needed, and set other flags
comboPtr1[2] |= (pat[0] != '%') ? ex_like_clause_base::LIKE_HEAD : 0;
comboPtr1[2] |= (pat[patLen-1] != '%') ? ex_like_clause_base::LIKE_TAIL : 0;
comboPtr1[3] = numOfPatterns;
comboPtr2[2] = (UInt8) precision;
AML aml(PCIT::MBIN32S, PCIT::MATTR5, PCIT::MATTR5,
PCIT::IBIN32S, PCIT::IBIN32S);
OL ol(attrs[0]->getAtp(), attrs[0]->getAtpIndex(), attrs[0]->getOffset(),
attrs[1]->getAtp(), attrs[1]->getAtpIndex(), attrs[1]->getOffset(),
attrs[1]->getVoaOffset(), attrs[1]->getLength(), comboLen1,
attrs[2]->getAtp(), attrs[2]->getAtpIndex(), attrs[2]->getOffset(),
attrs[2]->getVoaOffset(), attrs[2]->getLength(), comboLen2,
patternOffsets, patternLengths);
PCI pci(PCIT::Op_GENFUNC, aml, ol);
code.append(pci);
// Add the branch target if necessary.
//
if(branchToEnd)
{
AML aml;
OL ol((Int64)branchToEnd);
PCI pci(PCIT::Op_TARGET, aml, ol);
code.append(pci);
}
// Generate post clause PCI's
//
PCode::postClausePCI(this, code);
setPCIList(code.getList());
return ex_expr::EXPR_OK;
}
ex_expr::exp_return_type
ex_function_extract::pCodeGenerate(Space *space, UInt32 f)
{
// Get a handle on the operands
//
AttributesPtr *attrs = getOperand();
// Only deal with datetime types, for now. Also, no extracting seconds with
// fractional precision - this requires slightly more work.
if ((attrs[1]->getDatatype() != REC_DATETIME) ||
(getExtractField() > REC_DATE_MAX_SINGLE_FIELD) ||
(getExtractField()>=REC_DATE_CENTURY && getExtractField()<=REC_DATE_WOM) ||
((getExtractField() == REC_DATE_SECOND) && (attrs[1]->getScale() > 0)))
return ex_clause::pCodeGenerate(space, f);
// Determine what the offset is of the field to be extracted
rec_datetime_field start;
rec_datetime_field end;
ExpDatetime *datetime = (ExpDatetime*) getOperand(1);
if (datetime->getDatetimeFields(attrs[1]->getPrecision(), start, end) != 0)
assert(FALSE);
Int32 offset = 0, lastFieldSize = 0;
for (Int32 field = start; field <= getExtractField(); field++) {
offset += lastFieldSize;
switch (field) {
case REC_DATE_YEAR:
lastFieldSize = 2;
break;
case REC_DATE_MONTH:
case REC_DATE_DAY:
case REC_DATE_HOUR:
case REC_DATE_MINUTE:
case REC_DATE_SECOND:
lastFieldSize = 1;
break;
default:
assert(FALSE);
}
}
// Allocate the code list
//
PCIList code(space);
// Generate pre clause PCI's
PCode::preClausePCI(this, code);
// Add the null logic if necessary.
PCIID branchToEnd = PCode::nullBranch(this, code, attrs);
PCIT::AddressingMode type = (getExtractField() == REC_DATE_YEAR)
? PCIT::MBIN16U : PCIT::MBIN8;
AML aml(PCIT::MBIN16U, type);
OL ol(attrs[0]->getAtp(), attrs[0]->getAtpIndex(), attrs[0]->getOffset(),
attrs[1]->getAtp(), attrs[1]->getAtpIndex(),
attrs[1]->getOffset() + offset);
PCI pci(PCIT::Op_MOVE, aml, ol);
code.append(pci);
// Add the branch target if necessary.
//
if(branchToEnd)
{
AML aml;
OL ol((Int64)branchToEnd);
PCI pci(PCIT::Op_TARGET, aml, ol);
code.append(pci);
}
// Generate post clause PCI's
//
PCode::postClausePCI(this, code);
setPCIList(code.getList());
return ex_expr::EXPR_OK;
}
// ExpLOBoper::pCodeGenerate
//
// For now simply calls the default ex_clause::pCodeGenerate
//
ex_expr::exp_return_type ExpLOBoper::pCodeGenerate(Space *space, UInt32 f)
{
return ex_clause::pCodeGenerate(space, f);
}