| /********************************************************************** |
| // @@@ 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); |
| } |