blob: 13f87da58d9e65205dbe2c334150e5774db825d6 [file] [log] [blame]
/**********************************************************************
// @@@ START COPYRIGHT @@@
//
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
//
// @@@ END COPYRIGHT @@@
**********************************************************************/
/* -*-C++-*-
******************************************************************************
*
* File: SynthType.C
* Description: Methods for synthesizing a type
* Created: 3/15/95
* Language: C++
*
*
*
*
******************************************************************************
*/
#define SQLPARSERGLOBALS_NADEFAULTS
#include "Sqlcomp.h"
#include "AllItemExpr.h"
#include "BindWA.h"
#include "CmpStatement.h"
#include "CmpErrors.h"
#include "ComSqlId.h"
#include "OptimizerSimulator.h"
#include "exp_datetime.h"
#include "ComSSL.h"
// For TRIGGERS_STATUS_VECTOR_SIZE and SIZEOF_UNIQUE_EXECUTE_ID
#include "Triggers.h"
#include "TriggerEnable.h"
#ifndef NDEBUG
static Int32 NCHAR_DEBUG = -1; // note that, for perf, we call getenv only once
#endif
#include "SqlParserGlobalsCmn.h"
//#define getDefaultCharSet CharInfo::getCharSetEnum(ActiveSchemaDB()->getDefaults().getValue(DEFAULT_CHARSET))
#define getDefaultCharSet SqlParser_DEFAULT_CHARSET
// -----------------------------------------------------------------------
// utility functions -- cosmetics of error message arguments
// -----------------------------------------------------------------------
// These just shorten error messages by removing irrelevant junk
static void shortenTypeSQLname(NAString &typStr)
{
size_t i = typStr.index('(');
if (i && i != NA_NPOS)
typStr.remove(i); // remove from lparen onward
i = typStr.index(' ');
if (i && i != NA_NPOS)
typStr.remove(i); // remove from space onward
}
static void shortenTypeSQLname(const NAType &op,
NABuiltInTypeEnum typEnum,
NAString &typStr)
{
if (op.getTypeQualifier() == typEnum) {
size_t i = typStr.index(')');
if (i != NA_NPOS)
i = typStr.index(" ", i); // find space AFTER the parens
else
i = typStr.index(' '); // find first space (no parens)
if (i && i != NA_NPOS)
typStr.remove(i); // remove from space onward
}
}
void emitDyadicTypeSQLnameMsg(Lng32 sqlCode,
const NAType &op1,
const NAType &op2,
const char *str1 = NULL,
const char *str2 = NULL,
ComDiagsArea * diagsArea = NULL,
const Lng32 int1 = -999999)
{
NAString tsn1(op1.closestEquivalentExternalType( HEAP )->getTypeSQLname(TRUE /*terse*/));
NAString tsn2(op2.closestEquivalentExternalType( HEAP )->getTypeSQLname(TRUE /*terse*/));
NABoolean charShorten = TRUE, numShorten = TRUE;
if (op1.getTypeQualifier() == NA_CHARACTER_TYPE &&
op2.getTypeQualifier() == NA_CHARACTER_TYPE) {
const CharType &ct1 = (CharType&)op1;
const CharType &ct2 = (CharType&)op2;
NABoolean csDiff = (ct1.getCharSet() != ct2.getCharSet() ||
ct1.getCharSet() == CharInfo::UnknownCharSet);
NABoolean coDiff = (ct1.getCollation() != ct2.getCollation() ||
ct1.getCollation() == CharInfo::UNKNOWN_COLLATION);
if (csDiff)
charShorten = FALSE; // leave the CHARACTER SET info as is in tsnX
else if (coDiff) { // add COLLATE info to the type-texts
tsn1 += NAString(" ") + ct1.getCollateClause(ct1.getCollation());
tsn2 += NAString(" ") + ct2.getCollateClause(ct2.getCollation());
charShorten = FALSE;
}
// else, do do the charShorten thing
numShorten = FALSE; // both args are character: shorten is a no-op
}
else if (op1.getTypeQualifier() == NA_NUMERIC_TYPE &&
op2.getTypeQualifier() == NA_NUMERIC_TYPE) {
if (!str1 || strcmp(str1, "||")) // If a CONCAT, we do shorten; else:
numShorten = FALSE; // do not shorten, we need distinguishing info
charShorten = FALSE; // both args are numeric: shorten is a no-op
}
if (charShorten) { // "CHAR(8) CHARACTER SET UNICODE" => "CHAR(8)"
shortenTypeSQLname(op1, NA_CHARACTER_TYPE, tsn1);
shortenTypeSQLname(op2, NA_CHARACTER_TYPE, tsn2);
}
if (numShorten) { // "NUMERIC(8, 2) SIGNED" => "NUMERIC(8, 2)"
shortenTypeSQLname(op1, NA_NUMERIC_TYPE, tsn1);
shortenTypeSQLname(op2, NA_NUMERIC_TYPE, tsn2);
}
ComDiagsArea * da = (diagsArea ? diagsArea : CmpCommon::diags());
*da << DgSqlCode(sqlCode);
switch (sqlCode) {
case -4034:
CMPASSERT(str1);
*da
<< DgString0(tsn1)
<< DgString1(str1)
<< DgString2(tsn2)
<< DgString3(str2 ? str2 : "");
break;
case -4039:
CMPASSERT(str1);
*da
<< DgColumnName(str1)
<< DgString0(tsn1)
<< DgString1(tsn2);
break;
case arkcmpErrorISPWrongDataType: // -19016
CMPASSERT(str1);
CMPASSERT(int1 != -999999);
*da
<< DgString0(str1)
<< DgString1(tsn1)
<< DgInt0(int1)
<< DgString2(tsn2);
break;
default:
*da
<< DgString0(tsn1)
<< DgString1(tsn2);
}
} // emitDyadicTypeSQLnameMsg
// -----------------------------------------------------------------------
// helper functions for *Type::isComparable() methods
// -----------------------------------------------------------------------
static inline NABoolean involvesEQorNE(const OperatorType &opType)
{
return opType.match(ITM_WILDCARD_EQ_NE) ||
OperatorTypeEnum(opType) == ITM_LIKE ||
OperatorTypeEnum(opType) == ITM_LIKE_DOUBLEBYTE ||
OperatorTypeEnum(opType) == ITM_POSITION ||
OperatorTypeEnum(opType) == ITM_REPLACE ||
OperatorTypeEnum(opType) == ITM_REPLACE_UNICODE ||
OperatorTypeEnum(opType) == ITM_TRIM || // == ' ' (space char)
OperatorTypeEnum(opType) == ITM_VALUEIDUNION; // when DISTINCT flag
}
static ItemExpr * propagateCoAndCoToItem(ItemExpr *ie,
CharInfo::Collation co,
CharInfo::Coercibility ce)
{
// The special check is here for isAUserSuppliedInput()
// because we cannot directly mutate the type of a
// ConstValue, HostVar, DynamicParam, or AnsiUSERFunction
// because their bindNode's call ItemExpr::bindUserInput()
// which makes multiple refs to an input all map to
// (all share) the SAME valueId.
//
// Here we only want to mutate THIS ref's type,
// or, equivalently, CAST a leaf type to the new type --
// where leaves are basic items the Binder does lookup on --
// ColRefs (Base/IndexColumns), ConstValues, HostVars, DynamicParams.
// In these lookups we do NOT want to change the leaf's original ValueId
// NOR its original type -- hence, we CAST.
// It is safe not to do an additional bindNode (we have no bindWA anyway!)
// because we KNOW the new type is okay!
CharType *ct = (CharType *)&ie->getValueId().getType();
CMPASSERT(ct->getTypeQualifier() == NA_CHARACTER_TYPE);
if (ct->getCollation() != co) {
#ifndef NDEBUG
if (NCHAR_DEBUG > 0)
cerr << "CMP--:\t"
<< ct->getCollation() << ',' << ct->getCoercibility() << ' '
<< co << ',' << ce
<< '\t' << ie->getText()
<< '\t' << ie->getValueId();
CMPASSERT(co != CharInfo::UNKNOWN_COLLATION); // sanity check
CMPASSERT(ce != CharInfo::NO_COLLATING_SEQUENCE); // sanity check
#endif
ct = (CharType *)ct->newCopy(HEAP);
ct->setCoAndCo(co, ce);
// add a cast to the right type
// (since the child may be shared by other ItemExprs we can't
// simply change it, but we might someday be able to do an
// optimization similar to what ICAT does)
ie = new HEAP Cast(ie, ct);
ie->synthTypeAndValueId();
#ifndef NDEBUG
if (NCHAR_DEBUG > 0)
cerr << '\t' << ie->getValueId()
<< endl;
#endif
} // collation of operand overridden
return ie;
}
static void propagateCoAndCoToChildren(ItemExpr *parentOp,
CharInfo::Collation co,
CharInfo::Coercibility ce)
{
// Propagate the new co & ce to the immediate operands --
// yes, a shallow propagation is what we want.
#ifndef NDEBUG
// Just double-check that Cast::synthType() is NOT calling here...
// If it did, we would rewrite its child and the Cast would get optimized
// away as a no-op.
CMPASSERT(!parentOp->getOperator().match(ITM_ANY_CAST));
#endif
for (Int32 i = 0; i < parentOp->getArity(); i++) {
ItemExpr *ie = parentOp->child(i);
if (ie &&
ie->getValueId().getType().getTypeQualifier() == NA_CHARACTER_TYPE)
parentOp->child(i) = propagateCoAndCoToItem(ie, co, ce);
}
}
static Int32 getNumCHARACTERArgs(ItemExpr *parentOp)
{
Int32 n = 0;
for (Int32 i = 0; i < parentOp->getArity(); i++) {
ItemExpr *ie = parentOp->child(i);
if (ie &&
ie->getValueId().getType().getTypeQualifier() == NA_CHARACTER_TYPE)
n++;
}
return n;
}
// -----------------------------------------------------------------------
// The virtual NAType::isComparable() methods -- implemented here rather than
// ../common/*Type.cpp because they're called only from here, and here
// we've embedded stuff like ../optimizer/ItemExpr methods and
// the ../arkcmp/CmpCommon global-diags-area.
// -----------------------------------------------------------------------
NABoolean NAType::isComparable(const NAType &other,
ItemExpr *parentOp,
Int32 emitErr,
UInt32 * flags) const
{
#ifndef NDEBUG
CMPASSERT(parentOp); //## reserved for future errmsg 4034 w/ unparse,
#endif // for CoAndCo propagation and for errmsgs!
if (isCompatible(other, flags))
return TRUE;
NAString defVal;
NABoolean charsetInference =
(CmpCommon::getDefault(INFER_CHARSET, defVal) == DF_ON);
if(charsetInference &&
getTypeQualifier() == NA_CHARACTER_TYPE &&
other.getTypeQualifier() == NA_CHARACTER_TYPE){ // do not reject matches of UNKNOWN_CHARSET with UNKNOWN_CHARSET
CharType *ct = (CharType *)this;
if (ct->isCompatibleAllowUnknownCharset(other))
return TRUE;
}
if (emitErr == EmitErrIfAnyChar)
if (getTypeQualifier() != NA_CHARACTER_TYPE &&
other.getTypeQualifier() != NA_CHARACTER_TYPE)
emitErr = FALSE;
if (emitErr) {
// 4041 Type $1 cannot be compared with type $2.
//10-070228-2913 -Begin
//When MODE_SPECIAL_1 'ON', UNICODE CHARSET, and UPPER
//function is involved data type is converted to VARCHAR(dataStorageSize).
//dataSotragesize = getMaxCharLen() * bytesPerChar.
//see in Upper::synthesizeType() method.
//When generating error condition we convert it back to original size.
if ( getTypeQualifier() == NA_CHARACTER_TYPE)
{
CharType &ct1 = (CharType&)*this;
if((ct1.isCaseinsensitive()) &&
(ct1.getCharSet() == CharInfo::UNICODE) &&
(parentOp->child(0)->castToItemExpr()->getOperatorType() == ITM_UPPER))
{
ct1.setDataStorageSize(ct1.getDataStorageSize()/3);
}
//10-070228-2913 -End
}
emitDyadicTypeSQLnameMsg(-4041, *this, other);
}
return FALSE;
}
NABoolean CharType::isComparable(const NAType &otherNA,
ItemExpr *parentOp,
Int32 emitErr,
UInt32 * flags) const
{
if (NOT NAType::isComparable(otherNA, parentOp, emitErr, flags))
return FALSE;
const CharType &other = (const CharType &)otherNA;
CharInfo::Collation co;
CharInfo::Coercibility ce;
computeCoAndCo(other, co, ce);
NABoolean cmpOK = (co != CharInfo::UNKNOWN_COLLATION);
if (emitErr) emitErr = +1; // for fall-thru msg suppression
if (cmpOK) {
// a "mini-cache" to avoid proc call, for perf
static THREAD_P CharInfo::Collation cachedCO = CharInfo::UNKNOWN_COLLATION;
static THREAD_P Int32 cachedFlags = CollationInfo::ALL_NEGATIVE_SYNTAX_FLAGS;
if (cachedCO != co) { // use the mini-cache
cachedCO = co;
cachedFlags = CharInfo::getCollationFlags(co);
}
if (involvesEQorNE(parentOp->getOperator())) {
if (cachedFlags & CollationInfo::EQ_NE_CMP_ILLEGAL)
cmpOK = FALSE;
}
else if (cachedFlags & CollationInfo::ORDERED_CMP_ILLEGAL)
cmpOK = FALSE;
if (!cmpOK && emitErr > 0) {
// 4044 Collation $0~String0 does not support the $1~String1 operator.
*CmpCommon::diags() << DgSqlCode(-4044)
<< DgString0(CharInfo::getCollationName(co))
<< DgString1(parentOp->getTextUpper());
emitErr = -1; // We fall thru but do not also emit error 4041.
}
} // additional collation flag checks
if (cmpOK)
propagateCoAndCoToChildren(parentOp, co, ce); // type-synth/propagate!
else {
if (emitErr > 0)
// 4041 Type $1 cannot be compared with type $2.
emitDyadicTypeSQLnameMsg(-4041, *this, other);
// if (emitErr) // +1 OR -1
// //## also emit errmsg 4034 w/ unparse?
}
#ifndef NDEBUG
if (NCHAR_DEBUG < 0) NCHAR_DEBUG = getenv("NCHAR_DEBUG") ? +1 : 0;
if (NCHAR_DEBUG > 0) {
NAString p(CmpCommon::statementHeap());
parentOp->unparse(p);
NAString s(getTypeSQLname(TRUE /*terse*/));
s += NAString(" ") + getCollateClause(getCollation());
cerr << "CMP" << (cmpOK ? "==" : "<>") << ":\t"
<< (Int32)parentOp->getOperatorType() << '\t'
<< p << endl
<< s << '\t' << getCoercibilityText(getCoercibility())
<< endl;
s = other.getTypeSQLname(TRUE /*terse*/);
s += NAString(" ") + other.getCollateClause(other.getCollation());
cerr << s << '\t' << other.getCoercibilityText(other.getCoercibility())
<< endl;
cerr << CharInfo::getCollationName(co) << '\t'
<< CharType::getCoercibilityText(ce)
<< endl;
if (!cmpOK)
cerr << endl;
}
#endif
return cmpOK;
}
// -----------------------------------------------------------------------
// additional, miscellaneous helper functions
// -----------------------------------------------------------------------
// Called by BiRelat and QuantifiedComp comparison predicates.
static NABoolean synthItemExprLists(ItemExprList &exprList1,
ItemExprList &exprList2,
NABoolean allowIncompatibleComparison,
NABoolean &allowsUnknown,
ItemExpr *parentOp)
{
if (exprList1.entries() != exprList2.entries()) {
// 4042 The operands of a comparison predicate must be of equal degree.
*CmpCommon::diags() << DgSqlCode(-4042);
return FALSE;
}
NABoolean ODBC = (CmpCommon::getDefault(ODBC_PROCESS) == DF_ON);
NABoolean JDBC = (CmpCommon::getDefault(JDBC_PROCESS) == DF_ON);
allowsUnknown = FALSE;
for (CollIndex i = 0; i < exprList1.entries(); i++) {
//
// Type cast any params.
//
ValueId vid1 = exprList1[i]->getValueId();
ValueId vid2 = exprList2[i]->getValueId();
NABoolean dummy;
if (vid1.getType().getTypeQualifier() != NA_UNKNOWN_TYPE &&
vid2.getType().getTypeQualifier() == NA_UNKNOWN_TYPE &&
vid2.getItemExpr()->getOperatorType() == ITM_CONSTANT &&
(vid2.getItemExpr()->castToConstValue(dummy))->isNull())
{
vid2.coerceType(vid1.getType());
}
else
if (vid2.getType().getTypeQualifier() != NA_UNKNOWN_TYPE &&
vid1.getType().getTypeQualifier() == NA_UNKNOWN_TYPE &&
vid1.getItemExpr()->getOperatorType() == ITM_CONSTANT &&
(vid1.getItemExpr()->castToConstValue(dummy))->isNull())
{
vid1.coerceType(vid2.getType());
}
// if this query is being processed for ODBC, then type cast param
// to have the same type as the other side of birelat op. Otherwise,
// give param the default type if the other side is an exact numeric.
if ((NOT ODBC) && (NOT JDBC)) {
// give param the default type if the other side is an exact numeric.
if (vid1.getType().getTypeQualifier() == NA_UNKNOWN_TYPE &&
vid2.getType().getTypeQualifier() == NA_NUMERIC_TYPE) {
// if op1 is a param with unknown type and
// op2 is an exact numeric, type cast op1 to the default numeric type
const NumericType& op2 = (NumericType&)vid2.getType();
if (op2.isExact())
vid1.coerceType(NA_NUMERIC_TYPE);
}
else if (vid2.getType().getTypeQualifier() == NA_UNKNOWN_TYPE &&
vid1.getType().getTypeQualifier() == NA_NUMERIC_TYPE) {
const NumericType& op1 = (NumericType&)vid1.getType();
if (op1.isExact())
vid2.coerceType(NA_NUMERIC_TYPE);
};
vid1.coerceType(vid2.getType(), NA_NUMERIC_TYPE);
}
else {
// coerce to default character type(VARCHAR(32)) for ODBC.
vid1.coerceType(vid2.getType(), NA_CHARACTER_TYPE);
}
vid2.coerceType(vid1.getType());
//
// Check that the operands are comparable.
//
const NAType *operand1 = &vid1.getType();
const NAType *operand2 = &vid2.getType();
NABoolean DoCompatibilityTest = TRUE;
NAString defVal;
if ( operand1->getTypeQualifier() == NA_CHARACTER_TYPE &&
operand2->getTypeQualifier() == NA_CHARACTER_TYPE
)
{
if ( CmpCommon::getDefault(ALLOW_IMPLICIT_CHAR_CASTING) == DF_ON )
{
DoCompatibilityTest = FALSE;
//
// NOTE: The Generator has code to throw in a Translate node if an
// incompatible character set comparison is attempted.
//
}
const CharType *charOp1 = (CharType*)&(vid1.getType());
const CharType *charOp2 = (CharType*)&(vid2.getType());
NABoolean charsetInference =
(CmpCommon::getDefault(INFER_CHARSET, defVal) == DF_ON);
if ( charsetInference ) {
const CharType* desiredType =
CharType::findPushDownCharType(getDefaultCharSet,
charOp1, charOp2, 0);
if ( desiredType )
{
// just push down the charset field. All other fields are
// meaningless.
vid1.coerceType((NAType&)*desiredType, NA_CHARACTER_TYPE);
vid2.coerceType((NAType&)*desiredType, NA_CHARACTER_TYPE);
}
}
// get the newly pushed-down/relaxed types
operand1 = &vid1.getType();
operand2 = &vid2.getType();
if ( DoCompatibilityTest && NOT operand1->isCompatible(*operand2) ) {
// 4041 comparison between these two types is not allowed
emitDyadicTypeSQLnameMsg(-4041, *operand1, *operand2);
return FALSE;
}
}
allowsUnknown = allowsUnknown OR
operand1->supportsSQLnullLogical() OR
operand2->supportsSQLnullLogical();
if (allowIncompatibleComparison)
{
// incompatible conversion is only allowed between:
// 1. char and numeric types.
// 2. char literal and date types
// Or for special_1 mode:
// 3. DATE and numeric. Date is an interval from year 1900.
// 4. interval and numeric.
// Check if this is char and numeric comparison
if (((operand1->getTypeQualifier() == NA_CHARACTER_TYPE) &&
(operand2->getTypeQualifier() == NA_NUMERIC_TYPE) &&
((((CharType*)operand1)->getCharSet() == CharInfo::ISO88591) ||
(((CharType*)operand1)->getCharSet() == CharInfo::UTF8))) ||
((operand1->getTypeQualifier() == NA_NUMERIC_TYPE) &&
(operand2->getTypeQualifier() == NA_CHARACTER_TYPE) &&
((((CharType*)operand2)->getCharSet() == CharInfo::ISO88591) ||
(((CharType*)operand2)->getCharSet() == CharInfo::UTF8))))
{
return TRUE;
}
// Check if this is char and date comparison
if (((operand1->getTypeQualifier() == NA_CHARACTER_TYPE) &&
(operand2->getTypeQualifier() == NA_DATETIME_TYPE) &&
((((CharType*)operand1)->getCharSet() == CharInfo::ISO88591) ||
(((CharType*)operand1)->getCharSet() == CharInfo::UTF8))) ||
((operand1->getTypeQualifier() == NA_DATETIME_TYPE) &&
(operand2->getTypeQualifier() == NA_CHARACTER_TYPE) &&
((((CharType*)operand2)->getCharSet() == CharInfo::ISO88591) ||
(((CharType*)operand2)->getCharSet() == CharInfo::UTF8))))
{
return TRUE;
}
if (CmpCommon::getDefault(MODE_SPECIAL_1) == DF_ON)
{
// Check if this is numeric literal and date comparison
if (((operand1->getTypeQualifier() == NA_NUMERIC_TYPE) &&
(operand2->getTypeQualifier() == NA_DATETIME_TYPE)) ||
((operand1->getTypeQualifier() == NA_DATETIME_TYPE) &&
(operand2->getTypeQualifier() == NA_NUMERIC_TYPE)))
{
NumericType *numOper;
DatetimeType *dtOper;
if (operand1->getTypeQualifier() == NA_NUMERIC_TYPE)
{
numOper = &(NumericType&)vid1.getType();
dtOper = &(DatetimeType&)vid2.getType();
}
else
{
numOper = &(NumericType&)vid2.getType();
dtOper = &(DatetimeType&)vid1.getType();
}
// make sure it is DATE to exact NUMERIC with scale
// of 0 comparison.
if ((numOper->isExact()) &&
(numOper->getScale() == 0) &&
(dtOper->getPrecision() == SQLDTCODE_DATE))
return TRUE;
}
// Check if this is numeric literal and interval comparison
if (((operand1->getTypeQualifier() == NA_NUMERIC_TYPE) &&
(operand2->getTypeQualifier() == NA_INTERVAL_TYPE) &&
(vid1.getItemExpr()->getOperatorType() == ITM_CONSTANT)) ||
((operand1->getTypeQualifier() == NA_INTERVAL_TYPE) &&
(operand2->getTypeQualifier() == NA_NUMERIC_TYPE) &&
(vid2.getItemExpr()->getOperatorType() == ITM_CONSTANT)))
{
IntervalType* interval;
const NumericType* numeric;
if (operand1->getTypeQualifier() == NA_NUMERIC_TYPE)
{
numeric = &(NumericType&)vid1.getType();
interval = &(IntervalType&)vid2.getType();
}
else
{
numeric = &(NumericType&)vid2.getType();
interval = &(IntervalType&)vid1.getType();
}
// make sure it is exact NUMERIC with scale
// of 0 comparison.
if ((numeric->isExact()) &&
(numeric->getScale() == 0) &&
(interval->getFractionPrecision() == 0))
return TRUE;
}
}
}
UInt32 flags = 0;
if (CmpCommon::getDefault(ALLOW_INCOMPATIBLE_OPERATIONS) == DF_ON)
{
flags |= NAType::ALLOW_INCOMP_OPER;
}
//## errmsg 4034 w/ unparse?
if ( DoCompatibilityTest &&
NOT operand1->isComparable(*operand2, parentOp,
NAType::EmitErrAlways, &flags) )
return FALSE;
}
return TRUE; // success
} // synthItemExprLists
static const NAType *synthAvgSum(const NAType& operand,
NABoolean inScalarGroup)
{
NABoolean aggNeedsToBeNullable;
aggNeedsToBeNullable = operand.supportsSQLnullPhysical() || inScalarGroup;
switch (operand.getTypeQualifier()) {
case NA_NUMERIC_TYPE:
{
NumericType * const type = (NumericType * const ) &operand;
if(type->isExact())
{
/////////////////////////////////////////////////////////////////////
// Rules to compute datatype, precision and scale of SUM/AVG for
// EXACT numerics.
//
// Precision and Datatype computation:
//
// If precision is less than 19, make it LargeInt (Int64).
//
// If precision is > 19, make result precision = operand precision
// + 10 and result to be BigNum datatype.
//
// Scale computation:
// Result scale is always equal to operand's scale.
//
// Result is also signed if operand is signed.
//
/////////////////////////////////////////////////////////////////////
Lng32 precision = (type->getMagnitude() + 9) / 10 + type->getScale();
Lng32 scale = type->getScale();
NABoolean isARealBigNum = FALSE;
if (type->isBigNum())
{
// make the max precision to be the precision of operand + 10.
// Just a nice, round number.
//
// It could also be always made to
// be MAX_NUMERIC_PRECISION_ALLOWED. But that would mean that
// the result is always NUMERIC(128) which may be too much
// for all aggregates. We can think about it.
precision = MINOF(precision + 10,
(Lng32)CmpCommon::getDefaultNumeric(MAX_NUMERIC_PRECISION_ALLOWED));
isARealBigNum = ((SQLBigNum*)type)->isARealBigNum();
}
else
{
NABoolean limitPrecision =
(CmpCommon::getDefault(LIMIT_MAX_NUMERIC_PRECISION) == DF_ON);
if (precision <= MAX_NUMERIC_PRECISION)
precision = MAX_NUMERIC_PRECISION;
if (limitPrecision)
{
if (precision > MAX_NUMERIC_PRECISION)
{
precision = MAX_NUMERIC_PRECISION;
}
} else {
if ( precision >= MAX_NUMERIC_PRECISION + 1 )
precision = MINOF(precision + 10,
(Lng32)CmpCommon::getDefaultNumeric(MAX_NUMERIC_PRECISION_ALLOWED));
}
}
if ((NOT type->isBigNum()) &&
(precision <= MAX_NUMERIC_PRECISION))
{
if (scale > 0)
return new HEAP
SQLNumeric(HEAP, 8, // length = 8 bytes
precision,
scale,
(precision > 9 ? TRUE : type->isSigned()),
aggNeedsToBeNullable);
else
return new HEAP SQLLargeInt(HEAP, TRUE, aggNeedsToBeNullable);
}
else
{
return new HEAP
SQLBigNum(HEAP, precision,
scale,
isARealBigNum,
type->isSigned(),
aggNeedsToBeNullable);
}
}
else
{
return new HEAP SQLDoublePrecision(HEAP, aggNeedsToBeNullable);
}
}
break;
case NA_INTERVAL_TYPE:
{
IntervalType * const type = (IntervalType * const ) &operand;
if (type->isSupportedType())
{
return new HEAP
SQLInterval(HEAP, aggNeedsToBeNullable,
type->getStartField(),
type->computeLeadingPrecision(type->getStartField(),
MAX_NUMERIC_PRECISION,
type->getEndField(),
type->getFractionPrecision()),
type->getEndField(),
type->getFractionPrecision());
}
// else fall through to error
}
break;
}
// 4038 The operand of an AVG or SUM function must be numeric or interval.
*CmpCommon::diags() << DgSqlCode(-4038);
return NULL;
}
//
// getFirstKnownCharSet() - get CharSet of first vid that has one.
//
CharInfo::CharSet getFirstKnownCharSet( ValueId vid1, ValueId vid2, ValueId vid3)
{
CharInfo::CharSet first_cs = CharInfo::ISO88591; // Default to ISO88591
if ( CmpCommon::getDefault(ALLOW_IMPLICIT_CHAR_CASTING) == DF_ON )
{
const NAType *otyp1 = &(vid1.getType());
const NAType *otyp2 = &(vid2.getType());
const NAType *otyp3 = &(vid3.getType());
if (otyp1->getTypeQualifier() == NA_CHARACTER_TYPE)
first_cs = ((CharType *)otyp1)->getCharSet();
else if (otyp2->getTypeQualifier() == NA_CHARACTER_TYPE)
first_cs = ((CharType *)otyp2)->getCharSet();
else if (otyp3->getTypeQualifier() == NA_CHARACTER_TYPE)
first_cs = ((CharType *)otyp3)->getCharSet();
}
return first_cs;
}
// -----------------------------------------------------------------------
// member functions for class ItemExpr
// -----------------------------------------------------------------------
const NAType *ItemExpr::synthTypeWithCollateClause(BindWA *bindWA,
const NAType *type)
{
// First, call the VIRTUAL method, if we were not passed a type to use
if (!type) // e.g. ColReference::bindNode passes a type
type = synthesizeType();
if (type && collateClause()) {
CharInfo::Collation co = collateClause()->collation_;
CharInfo::Coercibility ce = collateClause()->coercibility_;
collateClause() = NULL;
CMPASSERT(ce == CharInfo::EXPLICIT); // else, Parser screwed up?
const ColumnDescList *cols = NULL;
if (isASubquery())
cols = ((Subquery *)this)->getRETDesc()->getColumnList();
if (type->getTypeQualifier() != NA_CHARACTER_TYPE) {
// 4034 The operation (operand COLLATE coll-name) is not allowed.
NAString optext(CmpCommon::statementHeap());
unparse(optext, DEFAULT_PHASE, USER_FORMAT_DELUXE);
if (isASubquery()) {
// Cosmetics: convert 'SCAN C.S.T' to '(SELECT a,b FROM C.S.T)'
NAString x(optext, CmpCommon::statementHeap());
x.remove(5); //offset of "SCAN "
x.toUpper();
if (x == "SCAN " || x == "SCAN(") {
x = NAString("(SELECT ") + cols->getColumnDescListAsString() +
" FROM ";
optext.remove(0,5);
optext.prepend(x);
optext += ")";
}
}
*CmpCommon::diags() << DgSqlCode(-4034)
<< DgString0(optext)
<< DgString1("COLLATE")
<< DgString2(CharInfo::getCollationName(co));
// 4073 COLLATE may not appear after a $string0 type expression.
NAString typnam(type->getTypeSQLname(TRUE/*terse*/));
shortenTypeSQLname(typnam);
if (typnam.length() == 9) { //len("SQLRecord")
// Cosmetics: convert 'SQLRecord' to 'NON-SCALAR'
NAString x(typnam, CmpCommon::statementHeap());
x.toUpper();
if (x == "SQLRECORD") typnam="NON-SCALAR";
}
*CmpCommon::diags() << DgSqlCode(-4073)
<< DgString0(typnam);
type = NULL;
}
else if (co == CharInfo::UNKNOWN_COLLATION &&
bindWA->getCurrentScope()->context()->inOrderBy()) {
// 3169 $0~string0 is not a known collation.
*CmpCommon::diags() << DgSqlCode(-3169)
<< DgString0(CharInfo::getCollationName(co));
type = NULL;
}
else {
// Consider
// ('a' COLLATE AAA || 'b') COLLATE BBB
// 'a' is AAA/EXPLICIT, so the concat within the parens is too --
// but ANSI 6.13 SR 4(a)(i) says that outside the parens we override
// the inner EXPLICIT, so the expression outside the parens
// is BBB/EXPLICIT. No computeCoAndCo() needed, simply setCoAndCo().
//
type = type->newCopy(HEAP);
CharType *ct = (CharType *)type;
ct->setCoAndCo(co, ce);
if (!ct->isCharSetAndCollationComboOK()) {
// 3179 Collation $0 is not defined on character set $1.
*CmpCommon::diags() << DgSqlCode(-3179)
<< DgString0(CharInfo::getCollationName(ct->getCollation()))
<< DgString1(CharInfo::getCharSetName(ct->getCharSet()));
type = NULL;
}
if (isASubquery()) {
CMPASSERT(cols->entries() == 1);
ColumnDesc *col = cols->at(0);
ItemExpr *ie = propagateCoAndCoToItem(
col->getValueId().getItemExpr(), co, ce);
col->setValueId(ie->getValueId());
}
}
}
if (!type) bindWA->setErrStatus();
return type;
}
// This is the virtual method for ItemExpr's that do not define their own
const NAType *ItemExpr::synthesizeType()
{
if (getArity() > 0)
return &child(0)->castToItemExpr()->getValueId().getType();
return new HEAP SQLUnknown(HEAP);
}
// Propagate type information down the ItemExpr tree.
// Called by coerceType(). The default implementation
// does nothing. Currently is only redefined by ValueIdUnion
// to propagate the desired type to the sources of the ValueIdUnion.
//
const NAType *
ItemExpr::pushDownType(NAType& desiredType,
enum NABuiltInTypeEnum defaultQualifier)
{
for(CollIndex i = 0; i < getArity(); i++) {
child(i) -> getValueId().coerceType(desiredType, defaultQualifier);
}
return (NAType *)synthesizeType();
//return &desiredType;
}
const NAType *
Cast::pushDownType(NAType& desiredType,
enum NABuiltInTypeEnum defaultQualifier)
{
for(CollIndex i = 0; i < getArity(); i++) {
child(i) -> getValueId().coerceType(desiredType, defaultQualifier);
}
if (getType()->getTypeQualifier() == NA_UNKNOWN_TYPE &&
desiredType.getTypeQualifier() != NA_UNKNOWN_TYPE)
{
type_ = desiredType.newCopy(HEAP);
}
return (NAType *)synthesizeType();
}
void ItemExpr::coerceChildType(NAType& desiredType,
enum NABuiltInTypeEnum defaultQualifier)
{
for(CollIndex i = 0; i < getArity(); i++) {
child(i) -> getValueId().coerceType(desiredType, defaultQualifier);
}
}
// -----------------------------------------------------------------------
// member functions for class BuiltinFunction.
// This methods is for those functions which are not defined as a
// derived class or do not have a derived synthesizeType method.
// This method should not be called from any derived class's
// synthesizeType method.
// -----------------------------------------------------------------------
const NAType *BuiltinFunction::synthesizeType()
{
NAType * retType = NULL;
switch (getOperatorType())
{
case ITM_CONVERTTOBITS:
{
ValueId vid1 = child(0)->getValueId();
// untyped param operands are typed as Int32 Unsigned.
SQLInt si(NULL, FALSE);
vid1.coerceType(si, NA_NUMERIC_TYPE);
const NAType &typ1 = vid1.getType();
// one byte of display size for each bit.
// 8 bits per byte.
Int32 maxLength = typ1.getNominalSize() * 8;
if ( typ1.getTypeQualifier() == NA_CHARACTER_TYPE &&
typ1.isVaryingLen() == TRUE )
retType = new HEAP
SQLVarChar(HEAP, maxLength, typ1.supportsSQLnull());
else
retType = new HEAP
SQLChar(HEAP, maxLength, typ1.supportsSQLnull());
}
break;
case ITM_SHA1:
{
// type cast any params
ValueId vid1 = child(0)->getValueId();
SQLChar c1(NULL, ComSqlId::MAX_QUERY_ID_LEN);
vid1.coerceType(c1, NA_CHARACTER_TYPE);
//input type must be string
const NAType &typ1 = child(0)->getValueId().getType();
if (typ1.getTypeQualifier() != NA_CHARACTER_TYPE)
{
*CmpCommon::diags() << DgSqlCode(-4067) << DgString0("SHA");
return NULL;
}
retType = new HEAP
SQLChar(HEAP, 128, FALSE);
if (typ1.supportsSQLnull())
{
retType->setNullable(TRUE);
}
}
break;
case ITM_SHA2_256:
case ITM_SHA2_224:
case ITM_SHA2_384:
case ITM_SHA2_512:
{
ValueId vid1 = child(0)->getValueId();
SQLChar c1(NULL, ComSqlId::MAX_QUERY_ID_LEN);
vid1.coerceType(c1, NA_CHARACTER_TYPE);
const NAType &typ1 = child(0)->getValueId().getType();
if (typ1.getTypeQualifier() != NA_CHARACTER_TYPE)
{
*CmpCommon::diags() << DgSqlCode(-4067) << DgString0("SHA2");
return NULL;
}
Lng32 resultLen = 0;
switch (getOperatorType()) {
case ITM_SHA2_224:
resultLen = (224 * 2) / 8;
break;
case ITM_SHA2_256:
resultLen = (256 * 2) / 8;
break;
case ITM_SHA2_384:
resultLen = (384 * 2) / 8;
break;
case ITM_SHA2_512:
resultLen = (512 * 2) / 8;
break;
default:
break;
}
retType = new HEAP
SQLChar(HEAP, resultLen, typ1.supportsSQLnull());
}
break;
case ITM_MD5:
{
// type cast any params
ValueId vid1 = child(0)->getValueId();
SQLChar c1(NULL, ComSqlId::MAX_QUERY_ID_LEN);
vid1.coerceType(c1, NA_CHARACTER_TYPE);
//input type must be string
const NAType &typ1 = child(0)->getValueId().getType();
if (typ1.getTypeQualifier() != NA_CHARACTER_TYPE)
{
*CmpCommon::diags() << DgSqlCode(-4067) << DgString0("MD5");
return NULL;
}
retType = new HEAP
SQLChar(HEAP, 32, FALSE);
if (typ1.supportsSQLnull())
{
retType->setNullable(TRUE);
}
}
break;
case ITM_CRC32:
{
const NAType &typ1 = child(0)->getValueId().getType();
retType = new HEAP
SQLInt(HEAP, FALSE, FALSE); //unsigned int
if (typ1.supportsSQLnull())
{
retType->setNullable(TRUE);
}
}
break;
case ITM_ISIPV4:
case ITM_ISIPV6:
{
// type cast any params
ValueId vid1 = child(0)->getValueId();
SQLChar c1(NULL, ComSqlId::MAX_QUERY_ID_LEN);
vid1.coerceType(c1, NA_CHARACTER_TYPE);
//input type must be string
const NAType &typ1 = child(0)->getValueId().getType();
if (typ1.getTypeQualifier() != NA_CHARACTER_TYPE)
{
*CmpCommon::diags() << DgSqlCode(-4067) << DgString0("IS_IP");
return NULL;
}
retType = new HEAP
SQLSmall(HEAP, TRUE, FALSE);
if (typ1.supportsSQLnull())
{
retType->setNullable(TRUE);
}
}
break;
case ITM_INET_ATON:
{
// type cast any params
ValueId vid1 = child(0)->getValueId();
SQLChar c1(NULL, ComSqlId::MAX_QUERY_ID_LEN);
vid1.coerceType(c1, NA_CHARACTER_TYPE);
//input type must be string
const NAType &typ1 = child(0)->getValueId().getType();
if (typ1.getTypeQualifier() != NA_CHARACTER_TYPE)
{
*CmpCommon::diags() << DgSqlCode(-4067) << DgString0("INET_ATON");
return NULL;
}
retType = new HEAP
SQLInt(HEAP, FALSE, FALSE);
if (typ1.supportsSQLnull())
{
retType->setNullable(TRUE);
}
}
break;
case ITM_INET_NTOA:
{
// type cast any params
ValueId vid = child(0)->getValueId();
vid.coerceType(NA_NUMERIC_TYPE);
const NAType &typ1 = child(0)->getValueId().getType();
if (typ1.getTypeQualifier() != NA_NUMERIC_TYPE)
{
*CmpCommon::diags() << DgSqlCode(-4045) << DgString0("INET_NTOA");
return NULL;
}
const NumericType &ntyp1 = (NumericType &) typ1;
if (NOT ntyp1.isExact() || ntyp1.getScale() != 0)
{
*CmpCommon::diags() << DgSqlCode(-4046) << DgString0("INET_NTOA");
return NULL;
}
retType = new HEAP
SQLVarChar(HEAP, 15, FALSE);
if (typ1.supportsSQLnull())
{
retType->setNullable(TRUE);
}
}
break;
case ITM_NULLIFZERO:
{
// type cast any params
ValueId vid = child(0)->getValueId();
vid.coerceType(NA_NUMERIC_TYPE);
const NAType &typ1 = child(0)->getValueId().getType();
if (typ1.getTypeQualifier() != NA_NUMERIC_TYPE)
{
// 4045 nullifzero function is only defined for numeric types.
*CmpCommon::diags() << DgSqlCode(-4045) << DgString0(getTextUpper());
return NULL;
}
// returned type is the same as child's type but always nullable.
retType = typ1.newCopy(HEAP);
if (NOT typ1.supportsSQLnull())
{
retType->setNullable(TRUE);
}
}
break;
case ITM_NVL:
{
// type cast any params
ValueId vid1 = child(0)->getValueId();
vid1.coerceType(NA_NUMERIC_TYPE);
const NAType &typ1 = vid1.getType();
ValueId vid2 = child(1)->getValueId();
vid2.coerceType(typ1);
const NAType &typ2 = vid2.getType();
//
// Synthesize the result.
//
UInt32 flags =
((CmpCommon::getDefault(LIMIT_MAX_NUMERIC_PRECISION) == DF_ON)
? NAType::LIMIT_MAX_NUMERIC_PRECISION : 0);
retType = (NAType*)typ1.synthesizeType(SYNTH_RULE_UNION,
typ1,
typ2,
HEAP,
&flags);
if (retType == NULL)
{
// 4049 CASE can't have result types that are mixed
emitDyadicTypeSQLnameMsg(-4049, typ1, typ2);
return NULL;
}
if (NOT typ1.supportsSQLnull())
{
retType = typ1.newCopy(HEAP);
}
}
break;
case ITM_JSONOBJECTFIELDTEXT:
{
ValueId vid1 = child(0)->getValueId();
ValueId vid2 = child(1)->getValueId();
// untyped param operands are typed as CHAR
vid2.coerceType(NA_CHARACTER_TYPE);
const NAType &typ1 = vid1.getType();
const NAType &typ2 = vid2.getType();
if ((typ1.getTypeQualifier() != NA_CHARACTER_TYPE) ||
(typ2.getTypeQualifier() != NA_CHARACTER_TYPE))
{
// 4043 The operand of a $0~String0 function must be character.
*CmpCommon::diags() << DgSqlCode(-4043) << DgString0(getTextUpper());
return NULL;
}
retType = new HEAP
SQLVarChar(HEAP, typ1.getNominalSize(), typ1.supportsSQLnull());
}
break;
case ITM_QUERYID_EXTRACT:
{
// type cast any params
ValueId vid1 = child(0)->getValueId();
SQLChar c1(NULL, ComSqlId::MAX_QUERY_ID_LEN);
vid1.coerceType(c1, NA_CHARACTER_TYPE);
ValueId vid2 = child(1)->getValueId();
SQLChar c2(NULL, 40, FALSE);
vid2.coerceType(c2, NA_CHARACTER_TYPE);
const CharType &typ1 = (CharType&)child(0)->getValueId().getType();
if (typ1.getTypeQualifier() != NA_CHARACTER_TYPE)
{
// 4043 The operand of a $0~String0 function must be character.
*CmpCommon::diags() << DgSqlCode(-4043) << DgString0(getTextUpper());
return NULL;
}
const CharType &typ2 = (CharType&)child(1)->getValueId().getType();
if (typ2.getTypeQualifier() != NA_CHARACTER_TYPE)
{
// 4043 The operand of a $0~String0 function must be character.
*CmpCommon::diags() << DgSqlCode(-4043) << DgString0(getTextUpper());
return NULL;
}
retType = new HEAP
SQLVarChar(HEAP, ComSqlId::MAX_QUERY_ID_LEN,
(typ1.supportsSQLnull() || typ2.supportsSQLnull()),
FALSE, // not upshifted
FALSE, // not case-insensitive
CharInfo::ISO88591);
}
break;
case ITM_TOKENSTR:
{
// tokenstr('token', 'string');
// First param is a quoted_string and is typed as char during
// parsing phase.
ValueId vid1 = child(0)->getValueId();
ValueId vid2 = child(1)->getValueId();
// untyped param operands are typed as CHAR
vid2.coerceType(NA_CHARACTER_TYPE);
const NAType &typ1 = vid1.getType();
const NAType &typ2 = vid2.getType();
if ((typ1.getTypeQualifier() != NA_CHARACTER_TYPE) ||
(typ2.getTypeQualifier() != NA_CHARACTER_TYPE))
{
// 4043 The operand of a $0~String0 function must be character.
*CmpCommon::diags() << DgSqlCode(-4043) << DgString0(getTextUpper());
return NULL;
}
retType = new HEAP
SQLVarChar(HEAP, typ2.getNominalSize(), typ2.supportsSQLnull());
}
break;
case ITM_REVERSE:
{
// reserve(<value>);
ValueId vid1 = child(0)->getValueId();
// untyped param operands are typed as CHAR
vid1.coerceType(NA_CHARACTER_TYPE);
const NAType &typ1 = vid1.getType();
if (typ1.getTypeQualifier() != NA_CHARACTER_TYPE)
{
// 4043 The operand of a $0~String0 function must be character.
*CmpCommon::diags() << DgSqlCode(-4043) << DgString0(getTextUpper());
return NULL;
}
// return type same as child type
retType = typ1.newCopy(HEAP);
}
break;
case ITM_UNIQUE_ID:
{
//please check the ExFunctionUniqueId::eval if the size is changed
retType = new HEAP SQLChar(HEAP, 36, FALSE);
}
case ITM_UNIQUE_ID_SYS_GUID:
{
//please check the ExFunctionUniqueId::eval if the size is changed
retType = new HEAP SQLChar(HEAP, 16, FALSE);
}
break;
case ITM_UNIQUE_SHORT_ID:
{
//please check the ExFunctionUniqueId::eval if the size is changed
retType = new HEAP SQLChar(HEAP, 21, FALSE);
}
break;
case ITM_SOUNDEX:
{
// type cast any params
ValueId vid1 = child(0)->getValueId();
SQLChar c1(NULL, ComSqlId::MAX_QUERY_ID_LEN);
vid1.coerceType(c1, NA_CHARACTER_TYPE);
//input type must be string
const NAType &typ1 = vid1.getType();
if (typ1.getTypeQualifier() != NA_CHARACTER_TYPE)
{
*CmpCommon::diags() << DgSqlCode(-4067) << DgString0("SOUNDEX");
return NULL;
}
retType = new HEAP SQLChar(HEAP, 4, FALSE);
if (typ1.supportsSQLnull())
{
retType->setNullable(TRUE);
}
}
break;
case ITM_AES_ENCRYPT:
case ITM_AES_DECRYPT:
{
const NAType &typ1 = child(0)->getValueId().getType();
const NAType &typ2 = child(1)->getValueId().getType();
if (typ1.getTypeQualifier() != NA_CHARACTER_TYPE ||
typ2.getTypeQualifier() != NA_CHARACTER_TYPE)
{
*CmpCommon::diags() << DgSqlCode(-4043) << DgString0(getTextUpper());
return NULL;
}
if (getArity() == 3)
{
// check the optional init_vector argument
const NAType &typ3 = child(0)->getValueId().getType();
if (typ3.getTypeQualifier() != NA_CHARACTER_TYPE)
{
*CmpCommon::diags() << DgSqlCode(-4043) << DgString0(getTextUpper());
}
}
Int32 source_len = typ1.getNominalSize();
Int32 maxLength = source_len;
// the origin string is short than encrypted string, so for descrypt process,
// the length of source string is enough.
// When encrypting a string, we need a formula to calculate the length
if (getOperatorType() == ITM_AES_ENCRYPT)
{
// the length of crypt_str can be calculated by
// block_size * (trunc(string_length / block_size) + 1)
//
// the block_size should be get using EVP_CIPHER_block_size(), but in some Algorithm
// type, it return 1 in OpenSSL 1.0.1e . So using EVP_MAX_BLOCK_LENGTH instead of it,
// which can make sure longer then block size.
//Int32 aes_mode = CmpCommon::getDefaultNumeric(BLOCK_ENCRYPTION_MODE);
//size_t block_size = EVP_CIPHER_block_size(aes_algorithm_type[aes_mode]);
Int32 block_size = EVP_MAX_IV_LENGTH;
if (block_size > 1) {
maxLength = block_size * (source_len / block_size) + block_size;
}
}
retType = new HEAP
SQLVarChar(HEAP, maxLength, TRUE);
}
break;
default:
{
retType = (NAType *)ItemExpr::synthesizeType();
}
} // switch
return retType;
}
// -----------------------------------------------------------------------
// member functions for class UDFunction.
// -----------------------------------------------------------------------
const NAType *UDFunction::synthesizeType()
{
const NAType * retType = NULL;
ValueId outVarId;
// We assosiate the type of the UDFunction ItemExpr to that of the
// first output of the Function. If the function has more than one output
// that gets hadled when we flatten the MVF out and use the ValueIdProxies
// to represent those outputs. See bindRowValues().
if (udfDesc_ != NULL)
{
outVarId = udfDesc_->getOutputColumnList()[0];
const NAType &funcType = outVarId.getType();
retType = &funcType;
}
return retType;
}
// -----------------------------------------------------------------------
// member functions for class Abs
// -----------------------------------------------------------------------
const NAType *Abs::synthesizeType()
{
// The expression is ABS(<value>)
// The result is the absolute value of the operand.
// type cast any params
ValueId vid = child(0)->getValueId();
SQLDoublePrecision dp(NULL, TRUE);
vid.coerceType(dp, NA_NUMERIC_TYPE);
const NAType &typ1 = child(0)->getValueId().getType();
if (typ1.getTypeQualifier() != NA_NUMERIC_TYPE)
{
// 4045 Absolute function is only defined for numeric types.
*CmpCommon::diags() << DgSqlCode(-4045) << DgString0(getTextUpper());
return NULL;
}
// now it's safe to cast the types to numeric type
const NumericType &ntyp1 = (NumericType &) typ1;
NAType *result = NULL;
if (ntyp1.isExact())
{
Lng32 precision = (ntyp1.getMagnitude() + 9) / 10 + ntyp1.getScale();
if (precision <= MAX_NUMERIC_PRECISION)
{
Int32 length;
if (precision < 5)
length = 2;
else if (precision < 10)
length = 4;
else
length = 8;
result = new HEAP SQLNumeric(HEAP, length,
precision,
ntyp1.getScale(),
ntyp1.isSigned());
}
else if (NOT ntyp1.isBigNum() && (ntyp1.getScale()==0) ) // this must be LargeInt
result = new HEAP SQLLargeInt(HEAP, ntyp1.isSigned());
else
result = new HEAP SQLDoublePrecision(HEAP);
}
else
{
result = new HEAP SQLDoublePrecision(HEAP);
}
if (ntyp1.supportsSQLnullLogical()) result->setNullable(TRUE);
return result;
}
// -----------------------------------------------------------------------
// member functions for class CodeVal
// -----------------------------------------------------------------------
const NAType *CodeVal::synthesizeType()
{
// The expression is ASCII(<value>)/CODE_VALUE(<value>)
// The result is the ASCII or UNICODE value of the first character in <value>.
//
// Type cast any params.
//
ValueId vid1 = child(0)->getValueId();
vid1.coerceType(NA_CHARACTER_TYPE);
const CharType &typ1 = (CharType&)child(0)->getValueId().getType();
if (typ1.getTypeQualifier() != NA_CHARACTER_TYPE)
{
// 4043 The operand of a $0~String0 function must be character.
*CmpCommon::diags() << DgSqlCode(-4043) << DgString0(getTextUpper());
return NULL;
}
switch (getOperatorType())
{
case ITM_NCHAR_MP_CODE_VALUE:
if ( CharInfo::is_NCHAR_MP(typ1.getCharSet()) != TRUE )
{
// 4000: internal binder error. This should not happen because we set the
// operator type according to the charset of the operand in NO_OPERATOR_TYPE
// case first. If we get to here, then type code/operand has been changed
// such that they do no match.
*CmpCommon::diags() << DgSqlCode(-4000);
return NULL;
}
break;
case ITM_UNICODE_CODE_VALUE:
if ( typ1.getCharSet() != CharInfo::UNICODE ) {
// 4000: internal binder error. This should not happen because we set the
// operator type according to the charset of the operand in NO_OPERATOR_TYPE
// case first. If we get to here, then type code/operand has been changed
// such that they do no match.
*CmpCommon::diags() << DgSqlCode(-4000);
return NULL;
}
break;
case ITM_ASCII:
{
CharInfo::CharSet cs = typ1.getCharSet();
if ( CharInfo::maxBytesPerChar( cs ) != 1 ) {
if ( cs == CharInfo::UNICODE ) {
// 4106 The character set for the operand of string function
// ascii/code_value must be $1~String1.
*CmpCommon::diags() << DgSqlCode(-4106) <<
DgString0(getTextUpper()) <<
DgString1(SQLCHARSETSTRING_ISO88591);
return NULL;
}
}
}
break;
case ITM_CODE_VALUE:
// Before R2.4, code_value and ASCII functions returned the same result.
// In R2.4, code_value will return the code value of the first
// character. ASCII will return an error if the first character in the
// buffer is not an ASCII character, for example, SJIS or UTF8
// character. Add one case for code_value.
break;
case NO_OPERATOR_TYPE:
{
switch ( typ1.getCharSet() )
{
case CharInfo::KANJI_MP:
case CharInfo::KSC5601_MP:
setOperatorType(ITM_NCHAR_MP_CODE_VALUE);
break;
case CharInfo::UNICODE:
setOperatorType(ITM_UNICODE_CODE_VALUE);
break;
case CharInfo::ISO88591:
default:
setOperatorType(ITM_CODE_VALUE);
break;
}
break;
// fall through
}
default:
// Character set $0~string0 is not supported for function $1~string1
*CmpCommon::diags() << DgSqlCode(-3403) <<
DgString0(getTextUpper()) <<
DgString1(CharInfo::getCharSetName(typ1.getCharSet()));
return NULL;
}
NAType *result = new (HEAP) SQLInt(HEAP, FALSE, typ1.supportsSQLnullLogical());
return result;
}
// -----------------------------------------------------------------------
// member functions for class Aggregate
// -----------------------------------------------------------------------
const NAType *Aggregate::synthesizeType()
{
const NAType *result;
switch (getEffectiveOperatorType()) {
case ITM_COUNT:
case ITM_COUNT_NONULL:
result = new HEAP
SQLLargeInt(HEAP, TRUE /* 'long long' on NSK can't be unsigned */,
FALSE /*not null*/);
break;
case ITM_AVG:
case ITM_SUM: {
ValueId vid = child(0)->getValueId();
vid.coerceType(NA_NUMERIC_TYPE);
const NAType& operand = child(0)->castToItemExpr()->getValueId().getType();
// If Top of a split aggregate, use the data type of the child
// aggregate.
if(topPartOfAggr()) {
// If this is in a scalar groupby, it can potentially return NULL.
// Make sure that the type is nullable.
if (inScalarGroupBy())
result = operand.synthesizeNullableType(HEAP);
else
result = operand.newCopy(HEAP);
} else {
result = synthAvgSum(operand, inScalarGroupBy());
}
break;
}
case ITM_MAX:
case ITM_MIN: {
ValueId vid = child(0)->getValueId();
vid.coerceType(NA_CHARACTER_TYPE);
const NAType& operand = child(0)->castToItemExpr()->getValueId().getType();
if ( operand.getTypeQualifier() == NA_CHARACTER_TYPE ) {
if (CmpCommon::wantCharSetInference()) {
const CharType *charOp = (CharType*)&(vid.getType());
const CharType* desiredType =
CharType::findPushDownCharType(getDefaultCharSet, charOp, 0);
if ( desiredType ) {
// just push down the charset field. All other fields are
// meaningless.
vid.coerceType((NAType&)*desiredType, NA_CHARACTER_TYPE);
}
}
}
if (!operand.isSupportedType())
{
emitDyadicTypeSQLnameMsg(-4041, operand, operand);
return NULL;
}
if (inScalarGroupBy())
result = operand.synthesizeNullableType(HEAP);
else
result = operand.newCopy(HEAP);
break;
}
case ITM_GROUPING:
{
// grouping result is an unsigned int (32 bit)
result = new HEAP
SQLInt(HEAP, FALSE /*unsigned*/,
FALSE /*not null*/);
}
break;
case ITM_ONE_ROW:
case ITM_ONEROW:
{
const NAType& operand = child(0)->castToItemExpr()->getValueId().getType();
result = operand.synthesizeNullableType(HEAP);
break;
}
case ITM_ONE_TRUE:
case ITM_ANY_TRUE_MAX:
case ITM_ANY_TRUE:
{
const SQLBooleanRelat& operand = (const SQLBooleanRelat &)
child(0)->castToItemExpr()->getValueId().getType();
// The argument of a ONE/ANY TRUE must be of type SQLBoolean
CMPASSERT(operand.getTypeQualifier() == NA_BOOLEAN_TYPE);
result = new HEAP SQLBooleanRelat(HEAP, operand.canBeSQLUnknown());
break;
}
default:
result = ItemExpr::synthesizeType();
break;
}
return result;
}
// -----------------------------------------------------------------------
// member functions for class AggMinMax
// -----------------------------------------------------------------------
const NAType *AggrMinMax::synthesizeType()
{
const NAType *result;
const NAType& operand = child(0)->castToItemExpr()->getValueId().getType();
result = operand.newCopy(HEAP);
return result;
}
// -----------------------------------------------------------------------
// member functions for class AggGrouping
// -----------------------------------------------------------------------
const NAType *AggrGrouping::synthesizeType()
{
// result unsigned 32 bit integer
const NAType *result = new HEAP SQLInt(HEAP, FALSE, FALSE);
return result;
}
// -----------------------------------------------------------------------
// member functions for class PivotGroup
// -----------------------------------------------------------------------
const NAType *PivotGroup::synthesizeType()
{
//for Character type, need to consider the charset
//the output charset should be same as input child 0
const NAType &operand = child(0)->getValueId().getType();
if(operand.getTypeQualifier() == NA_CHARACTER_TYPE)
{
CharType & origType = (CharType &) operand;
return new HEAP SQLVarChar(HEAP, maxLen_, TRUE, origType.isUpshifted(), FALSE, operand.getCharSet());
}
else
return new HEAP SQLVarChar(HEAP, maxLen_, TRUE);
}
// -----------------------------------------------------------------------
// member functions for class AnsiUSERFunction
// -----------------------------------------------------------------------
static const Lng32 MAX_NT_DOMAIN_NAME_LEN = 30;
static const Lng32 MAX_NT_USERNAME_LEN = 20;
//the ldap username needs to fit into this field, so make them equal
static const Lng32 OPT_MAX_USERNAME_LEN = ComSqlId::MAX_LDAP_USER_NAME_LEN+1;
const NAType *AnsiUSERFunction::synthesizeType()
{
return new HEAP SQLVarChar(HEAP, OPT_MAX_USERNAME_LEN, FALSE);
}
const NAType *MonadicUSERFunction::synthesizeType()
{
//
// Type cast any params.
//
ValueId vid = child(0)->getValueId();
SQLInt si(NULL, TRUE);
vid.coerceType(si, NA_NUMERIC_TYPE);
//
// Check that the operands are compatible.
//
const NAType& typ1 = vid.getType();
if (typ1.getTypeQualifier() != NA_NUMERIC_TYPE) {
// 4043 The operand of a USER function must be character.
*CmpCommon::diags() << DgSqlCode(-4045) << DgString0(getTextUpper());
return NULL;
}
// now it's safe to cast the types to numeric type
const NumericType &ntyp1 = (NumericType &) typ1;
if (NOT ntyp1.isExact())
{
// 4046 USER function is only defined for exact numeric types.
*CmpCommon::diags() << DgSqlCode(-4046) << DgString0(getTextUpper());
return NULL;
}
if (ntyp1.getScale() != 0)
{
// 4047 Arguments of USER function must have a scale of 0.
*CmpCommon::diags() << DgSqlCode(-4047) << DgString0(getTextUpper());
return NULL;
}
//
// Return the result.
//
return new HEAP SQLVarChar(HEAP, OPT_MAX_USERNAME_LEN, typ1.supportsSQLnullLogical());
}
const NAType *MonadicUSERIDFunction::synthesizeType()
{
//
// Type cast any params.
//
ValueId vid = child(0)->getValueId();
vid.coerceType(NA_CHARACTER_TYPE);
//
// Check that the operands are compatible.
//
const NAType& operand = vid.getType();
if (operand.getTypeQualifier() != NA_CHARACTER_TYPE) {
// 4043 The operand of a USERID function must be character.
*CmpCommon::diags() << DgSqlCode(-4043) << DgString0(getTextUpper());
return NULL;
}
//
// Return the result.
//
return new HEAP SQLVarChar(HEAP, OPT_MAX_USERNAME_LEN, operand.supportsSQLnullLogical());
}
// -----------------------------------------------------------------------
// member functions for class Assign
// -----------------------------------------------------------------------
const NAType *Assign::doSynthesizeType(ValueId & targetId, ValueId & sourceId)
{
NABoolean ODBC = (CmpCommon::getDefault(ODBC_PROCESS) == DF_ON);
NABoolean JDBC = (CmpCommon::getDefault(JDBC_PROCESS) == DF_ON);
NABoolean isSourceNullConst = FALSE;
NABoolean forceSourceParamToBeNullable =
(CmpCommon::getDefault(COMP_BOOL_173) == DF_ON);
//
// Type cast any params.
//
targetId = child(0)->castToItemExpr()->getValueId();
sourceId = child(1)->castToItemExpr()->getValueId();
const NAType& targetType = targetId.getType();
NABoolean sourceIsUntypedParam =
(sourceId.getType().getTypeQualifier() == NA_UNKNOWN_TYPE);
// Charset inference.
const NAType& sourceType = sourceId.getType();
targetId.coerceType(sourceType);
sourceId.coerceType(targetType);
// if this param is the source of an insert/update stmt coming in
// from odbc/jdbc interface and is not nullable, then make it nullable
// if the user has asked for it.
if ((NOT sourceId.getType().supportsSQLnull()) &&
(ODBC || JDBC) && (forceSourceParamToBeNullable) &&
(sourceIsUntypedParam))
{
NAType &sourceType = (NAType&)(sourceId.getType());
sourceType.setNullable(TRUE);
// Propagate (pushDowntype()) this type to the children of this valueid
// in case one of the children could not be typed.
//
const NAType* synthesizedNewType =
sourceId.getItemExpr()->pushDownType(sourceType);
sourceId.changeType(synthesizedNewType);
}
//
// Check that the operands are compatible.
//
if (NOT targetId.getType().isCompatible(sourceId.getType())) {
if ((CmpCommon::getDefault(ALLOW_INCOMPATIBLE_OPERATIONS) == DF_ON) &&
(sourceId.getType().getTypeQualifier() != NA_RECORD_TYPE ) &&
((child(1)->getOperatorType() != ITM_CONSTANT) ||
(NOT ((ConstValue *) child(1).getPtr() )->isNull())))
{
// target type is not the same as source type.
// Assignment allowed in special_1 mode.
// bindNode will add an explicit CAST node.
// All supported incompatible conversions will be handled by CAST.
return &targetType;
}
return NULL;
}
//
// Return the result.
//
return &targetType;
}
const NAType *Assign::synthesizeType(const char * str1, const Lng32 int1)
{
ValueId targetId, sourceId;
const NAType * result = doSynthesizeType(targetId, sourceId);
if (result == NULL)
{
emitDyadicTypeSQLnameMsg(arkcmpErrorISPWrongDataType,
targetId.getType(),
sourceId.getType(),
str1,
NULL, // No str2 value
NULL, // Default diags area
int1);
return NULL;
}
//
// Return the result.
//
return result;
}
const NAType *Assign::synthesizeType()
{
ValueId targetId, sourceId;
const NAType * result = doSynthesizeType(targetId, sourceId);
if (result == NULL)
{
emitDyadicTypeSQLnameMsg(-4039,
targetId.getType(),
sourceId.getType(),
ToAnsiIdentifier(targetId.getNAColumn()->getColName()));
return NULL;
}
//
// Return the result.
//
return result;
}
// -----------------------------------------------------------------------
// member functions for class BaseColumn
// -----------------------------------------------------------------------
const NAType *BaseColumn::synthesizeType()
{
return &getType();
}
// -----------------------------------------------------------------------
// member functions for class IndexColumn
// -----------------------------------------------------------------------
const NAType * IndexColumn::synthesizeType()
{
return &indexColDefinition_.getType();
}
// -----------------------------------------------------------------------
// member functions for class Between
// -----------------------------------------------------------------------
const NAType *Between::synthesizeType()
{
ItemExprList exprList1(child(0).getPtr(), HEAP);
ItemExprList exprList2(child(1).getPtr(), HEAP);
ItemExprList exprList3(child(2).getPtr(), HEAP);
if (exprList1.entries() != exprList2.entries() OR
exprList1.entries() != exprList3.entries()) {
// 4040 The operands of a between predicate must be of equal degree.
*CmpCommon::diags() << DgSqlCode(-4040);
return NULL;
}
NABoolean allowsUnknown = FALSE;
NABoolean allowIncompatibleComparison =
((CmpCommon::getDefault(ALLOW_INCOMPATIBLE_OPERATIONS) == DF_ON) &&
(child(0)->castToItemExpr()->getOperatorType() != ITM_ONE_ROW) &&
(child(1)->castToItemExpr()->getOperatorType() != ITM_ONE_ROW) &&
(child(2)->castToItemExpr()->getOperatorType() != ITM_ONE_ROW) &&
(child(0)->castToItemExpr()->getOperatorType() != ITM_ONEROW) &&
(child(1)->castToItemExpr()->getOperatorType() != ITM_ONEROW) &&
(child(2)->castToItemExpr()->getOperatorType() != ITM_ONEROW));
for (CollIndex i = 0; i < exprList1.entries(); i++) {
//
// Type cast any params.
//
ValueId vid1 = exprList1[i]->getValueId();
ValueId vid2 = exprList2[i]->getValueId();
ValueId vid3 = exprList3[i]->getValueId();
vid1.coerceType(vid2.getType());
vid1.coerceType(vid3.getType(), NA_NUMERIC_TYPE);
vid2.coerceType(vid1.getType());
vid3.coerceType(vid1.getType());
//
// Check that the operands are comparable.
//
const NAType& op1 = vid1.getType();
const NAType& op2 = vid2.getType();
const NAType& op3 = vid3.getType();
NABoolean compareOp2 = TRUE;
NABoolean compareOp3 = TRUE;
if (allowIncompatibleComparison)
{
if(((op1.getTypeQualifier() == NA_DATETIME_TYPE) &&
(op2.getTypeQualifier() == NA_CHARACTER_TYPE) &&
(vid2.getItemExpr()->getOperatorType() == ITM_CONSTANT)) ||
((op2.getTypeQualifier() == NA_DATETIME_TYPE) &&
(op1.getTypeQualifier() == NA_CHARACTER_TYPE) &&
(vid1.getItemExpr()->getOperatorType() == ITM_CONSTANT)))
compareOp2 = FALSE;
if(((op1.getTypeQualifier() == NA_DATETIME_TYPE) &&
(op3.getTypeQualifier() == NA_CHARACTER_TYPE) &&
(vid3.getItemExpr()->getOperatorType() == ITM_CONSTANT)) ||
((op3.getTypeQualifier() == NA_DATETIME_TYPE) &&
(op1.getTypeQualifier() == NA_CHARACTER_TYPE) &&
(vid1.getItemExpr()->getOperatorType() == ITM_CONSTANT)))
compareOp3 = FALSE;
}
if (op1.getTypeQualifier() == NA_CHARACTER_TYPE &&
op2.getTypeQualifier() == NA_CHARACTER_TYPE &&
op3.getTypeQualifier() == NA_CHARACTER_TYPE)
{
if ( CmpCommon::getDefault(ALLOW_IMPLICIT_CHAR_CASTING) == DF_ON )
{
compareOp2 = FALSE;
compareOp3 = FALSE;
}
}
if ((compareOp2) && (NOT op1.isComparable(op2, this))) //## errmsg 4034 w/ unparse?
return FALSE;
if ((compareOp3) && (NOT op1.isComparable(op3, this))) //## errmsg 4034 w/ unparse?
return FALSE;
// If any of the operands is nullable the result could be unknown
allowsUnknown = allowsUnknown OR
op1.supportsSQLnullLogical() OR
op2.supportsSQLnullLogical() OR
op3.supportsSQLnullLogical();
}
//
// Return the result.
//
return new HEAP SQLBooleanRelat(HEAP, allowsUnknown);
}
// -----------------------------------------------------------------------
// member functions for class BiArith
// -----------------------------------------------------------------------
const NAType *BiArith::synthesizeType()
{
//
// Type cast any params.
//
ValueId vid1 = child(0)->getValueId();
ValueId vid2 = child(1)->getValueId();
if (vid1.getType().getTypeQualifier() == NA_UNKNOWN_TYPE &&
vid2.getType().getTypeQualifier() == NA_NUMERIC_TYPE) {
// if op1 is a param with unknown type and op2
// is an exact numeric, type cast op1 to the default
// numeric type
const NumericType& op2 = (NumericType&)vid2.getType();
if (op2.isExact())
vid1.coerceType(NA_NUMERIC_TYPE);
}
else if (vid2.getType().getTypeQualifier() == NA_UNKNOWN_TYPE &&
vid1.getType().getTypeQualifier() == NA_NUMERIC_TYPE) {
// if op2 is a param with unknown type and op1
// is an exact numeric, type cast op2 to the default
// numeric type
const NumericType& op1 = (NumericType&)vid1.getType();
if (op1.isExact())
vid2.coerceType(NA_NUMERIC_TYPE);
};
vid1.coerceType(vid2.getType(), NA_NUMERIC_TYPE);
vid2.coerceType(vid1.getType());
UInt32 flags =
((CmpCommon::getDefault(LIMIT_MAX_NUMERIC_PRECISION) == DF_ON)
? NAType::LIMIT_MAX_NUMERIC_PRECISION : 0);
if (CmpCommon::getDefault(MODE_SPECIAL_1) == DF_ON)
{
flags |= NAType::MODE_SPECIAL_1;
}
if (CmpCommon::getDefault(MODE_SPECIAL_4) == DF_ON)
{
flags |= NAType::MODE_SPECIAL_4;
}
NABoolean limitPrecision =
((flags & NAType::LIMIT_MAX_NUMERIC_PRECISION) != 0);
//
// Synthesize the result.
//
const NAType& operand1 = vid1.getType();
const NAType& operand2 = vid2.getType();
const NAType *result;
switch (getOperatorType()) {
case ITM_PLUS:
result = operand1.synthesizeType(SYNTH_RULE_ADD, operand1, operand2, HEAP,
&flags);
break;
case ITM_MINUS:
result = (getIntervalQualifier() == NULL)
? operand1.synthesizeType(SYNTH_RULE_SUB, operand1, operand2, HEAP,
&flags)
: operand1.synthesizeTernary(SYNTH_RULE_SUB,
operand1,
operand2,
*getIntervalQualifier(),
HEAP);
break;
case ITM_TIMES:
result = operand1.synthesizeType(SYNTH_RULE_MUL, operand1, operand2, HEAP,
&flags);
break;
case ITM_DIVIDE:
{
// if roundingMode is already set in this node, use it.
// ignoreSpecialRounding() == TRUE indicates rounding disabled, in
// which case follow default roundingMode = 0.
short roundingMode = getRoundingMode();
if (roundingMode == 0 && ! ignoreSpecialRounding() )
roundingMode = (short)CmpCommon::getDefaultLong(ROUNDING_MODE);
if (roundingMode != 0)
{
flags |= NAType::ROUND_RESULT;
// also limit precision, if rounding is to be done.
// Rounding is only supported using division rounding mechanism
// for exact and simple (no BigNums) numerics.
flags |= NAType::LIMIT_MAX_NUMERIC_PRECISION;
}
result =
operand1.synthesizeType(SYNTH_RULE_DIV, operand1, operand2, HEAP,
&flags);
if ((roundingMode != 0) && (result) &&
((flags & NAType::RESULT_ROUNDED) != 0))
{
// if rounding was requested and done, set that info in
// the BiArith node.
setRoundingMode(roundingMode);
}
else
{
setRoundingMode(0);
}
}
break;
case ITM_EXPONENT:
result = operand1.synthesizeType(SYNTH_RULE_EXP, operand1, operand2, HEAP,
&flags);
break;
default:
result = ItemExpr::synthesizeType();
break;
}
if (!result) {
if (operand1.getTypeQualifier() == NA_RECORD_TYPE ||
operand2.getTypeQualifier() == NA_RECORD_TYPE) {
// 4020 arith operation not allowed on row-value-constructor.
*CmpCommon::diags() << DgSqlCode(-4020);
}
else {
const char *intervalQ;
if (getIntervalQualifier())
intervalQ = getIntervalQualifier()->getTypeSQLname(TRUE /*terse*/);
else
intervalQ = "";
// 4034 The operation (~op1 ~operator ~op2) ~iq is not allowed.
emitDyadicTypeSQLnameMsg(-4034, operand1, operand2,
getTextUpper(), intervalQ);
}
}
return result;
}
// -----------------------------------------------------------------------
// member functions for class UnArith
// -----------------------------------------------------------------------
const NAType *UnArith::synthesizeType()
{
//
// Type cast any params.
//
ValueId vid1 = child(0)->getValueId();
if (vid1.getType().getTypeQualifier() == NA_UNKNOWN_TYPE)
{
vid1.coerceType(NA_BOOLEAN_TYPE);
}
const NAType& operand1 = vid1.getType();
if (operand1.getFSDatatype() != REC_BOOLEAN)
{
*CmpCommon::diags() << DgSqlCode(-4034)
<< DgString0("!")
<< DgString1(child(0)->getText())
<< DgString2("");
return NULL;
}
NAType * retType = new HEAP SQLBooleanNative(HEAP, operand1.supportsSQLnull());
return retType;
}
// -----------------------------------------------------------------------
// member functions for class BiLogic
// -----------------------------------------------------------------------
const NAType *BiLogic::synthesizeType()
{
const SQLBooleanRelat& operand0 = (SQLBooleanRelat&) child(0).getValueId().getType();
const SQLBooleanRelat& operand1 = (SQLBooleanRelat&) child(1).getValueId().getType();
NABoolean allowsUnknown = operand0.canBeSQLUnknown() OR
operand1.canBeSQLUnknown();
return new HEAP SQLBooleanRelat(HEAP, allowsUnknown);
}
// -----------------------------------------------------------------------
// member functions for class BiRelat
// -----------------------------------------------------------------------
const NAType *BiRelat::synthesizeType()
{
ItemExpr *ie1 = child(0);
ItemExpr *ie2 = child(1);
if (ie1->getOperatorType() == ITM_ONE_ROW) ie1 = ie1->child(0);
if (ie2->getOperatorType() == ITM_ONE_ROW) ie2 = ie2->child(0);
ItemExprList exprList1(ie1, HEAP);
ItemExprList exprList2(ie2, HEAP);
// in some cases, we allow comparisons between 'incompatible' datatypes.
// This is allowed if CQD is set, and it is a single valued scaler
// predicate (a <op> b), and the comparison is done between a char/varhar
// and numeric type.
// In these conditions, the char type is converted to numeric by putting
// a CAST node on top of it.
// This incompatible comparison is not allowed if the statement is a DDL
NABoolean allowIncompatibleComparison = FALSE;
if ((CmpCommon::getDefault(ALLOW_INCOMPATIBLE_OPERATIONS) == DF_ON) &&
(child(0)->castToItemExpr()->getOperatorType() != ITM_ONE_ROW) &&
(child(1)->castToItemExpr()->getOperatorType() != ITM_ONE_ROW) &&
(exprList1.entries() == 1) &&
(exprList2.entries() == 1))
allowIncompatibleComparison = TRUE;
NABoolean allowsUnknown;
if (!synthItemExprLists(exprList1, exprList2, allowIncompatibleComparison,
allowsUnknown, this))
return NULL;
return new HEAP SQLBooleanRelat(HEAP, allowsUnknown);
}
// -----------------------------------------------------------------------
// member functions for class BoolResult
// -----------------------------------------------------------------------
const NAType *BoolResult::synthesizeType()
{
return new HEAP SQLBooleanRelat(HEAP, getOperatorType() == ITM_RETURN_NULL);
}
// -----------------------------------------------------------------------
// member functions for class BoolVal
// -----------------------------------------------------------------------
const NAType *BoolVal::synthesizeType()
{
return new HEAP SQLBooleanRelat(HEAP, getOperatorType() == ITM_RETURN_NULL);
}
//------------------------------------------------------------------
// member functions for class RaiseError
//------------------------------------------------------------------
const NAType *RaiseError::synthesizeType()
{
// -- Triggers
if (getArity() == 1)
{ // Verify the string expression is of character type.
if (child(0)->getValueId().getType().getTypeQualifier() != NA_CHARACTER_TYPE)
{
// parameter 3 must be of type string.
*CmpCommon::diags() << DgSqlCode(-3185);
return NULL;
}
}
return new HEAP SQLBooleanRelat(FALSE); // can be overridden in IfThenElse
}
// -----------------------------------------------------------------------
// member functions for class IfThenElse
// -----------------------------------------------------------------------
const NAType *IfThenElse::synthesizeType()
{
//
// The ELSE clause may be a NULL pointer if this is part of a CASE statement
// created by the generator.
//
ValueId thenId = child(1)->getValueId();
if (child(2).getPtr() == NULL)
return &thenId.getType();
ValueId elseId = child(2)->getValueId();
//
// Type cast any params.
//
thenId.coerceType(elseId.getType(), NA_NUMERIC_TYPE);
elseId.coerceType(thenId.getType());
// infer the charset if unknown.
if ( thenId.getType().getTypeQualifier() == NA_CHARACTER_TYPE &&
elseId.getType().getTypeQualifier() == NA_CHARACTER_TYPE
)
{
const CharType *thenCharType = (CharType*)&thenId.getType();
const CharType *elseCharType = (CharType*)&elseId.getType();
if (CmpCommon::wantCharSetInference()) {
const CharType* desiredType =
CharType::findPushDownCharType(getDefaultCharSet,
thenCharType, elseCharType, 0);
if ( desiredType ) {
// just push down the charset field. All other fields are
// meaningless.
thenId.coerceType((NAType&)*desiredType, NA_CHARACTER_TYPE);
elseId.coerceType((NAType&)*desiredType, NA_CHARACTER_TYPE);
}
}
}
//
// Synthesize the result.
//
UInt32 flags =
((CmpCommon::getDefault(LIMIT_MAX_NUMERIC_PRECISION) == DF_ON)
? NAType::LIMIT_MAX_NUMERIC_PRECISION : 0);
if (CmpCommon::getDefault(MODE_SPECIAL_1) == DF_ON)
{
flags |= NAType::MODE_SPECIAL_1;
}
if (CmpCommon::getDefault(TYPE_UNIONED_CHAR_AS_VARCHAR) == DF_ON)
{
flags |= NAType::MAKE_RESULT_VARCHAR;
}
const NAType& thenType = thenId.getType();
const NAType& elseType = elseId.getType();
const NAType *result = thenType.synthesizeType(SYNTH_RULE_UNION,
thenType,
elseType,
HEAP,
&flags);
if (result == NULL) {
// Ignore the RaiseError's type and pass thru the other operand's type
if (thenId.getItemExpr()->getOperatorType() == ITM_RAISE_ERROR)
return &elseType;
if (elseId.getItemExpr()->getOperatorType() == ITM_RAISE_ERROR)
return &thenType;
// 4049 CASE can't have result types that are mixed
emitDyadicTypeSQLnameMsg(-4049, thenType, elseType);
}
return result;
}
// -----------------------------------------------------------------------
// member functions for class Cast
// -----------------------------------------------------------------------
// Exact numeric can be cast to a single-field interval, and vice versa.
// In special_1 mode, numerics can be cast to multi-field intervals.
static NABoolean numericCastIsCompatible(const NAType &src, const NAType &tgt)
{
if (src.getTypeQualifier() == NA_NUMERIC_TYPE &&
tgt.getTypeQualifier() == NA_INTERVAL_TYPE &&
tgt.isSupportedType())
{
if (CmpCommon::getDefault(ALLOW_INCOMPATIBLE_OPERATIONS) == DF_ON)
return TRUE;
NumericType& numeric = (NumericType&)src;
IntervalType& interval = (IntervalType&)tgt;
if (numeric.isExact())
{
if (CmpCommon::getDefault(MODE_SPECIAL_1) == DF_ON)
return TRUE;
else if (interval.getStartField() == interval.getEndField())
return TRUE;
}
}
//check for numeric to date conversion
else if ((CmpCommon::getDefault(MODE_SPECIAL_1) == DF_ON) &&
(tgt.getTypeQualifier() == NA_DATETIME_TYPE) &&
(src.getTypeQualifier() == NA_NUMERIC_TYPE))
{
DatetimeType &dtType = (DatetimeType&)tgt;
NumericType &numeric = (NumericType&)src;
if ((dtType.getPrecision() == SQLDTCODE_DATE) &&
(numeric.isExact()) &&
(NOT numeric.isBigNum()) &&
(numeric.getScale() == 0))
{
return TRUE;
}
}
return FALSE;
}
// Begin_Fix 10-040114-2431
// 02/18/2004
// Added as part of above mentioned fix
// synthesizeType for Narrow ensures that
// if we match the nullability of the child
// if that is required. This is done by setting
// Cast::matchChildType_ flag, if it is not already
// set. If Cast::matchChildType_ is not set, we set
// it and then unset it after Cast::synthesizeType().
// Setting Cast::matchChildType_ does more than just
// matching my child's nullability (please see class
// Cast in ItemFunc.h), therefore if it is not set
// initially we just unset it after calling
// Cast::synthesizeType().
const NAType *Narrow::synthesizeType()
{
//check if we Cast::matchChildType_ is set
NABoolean matchChildType = Cast::matchChildType();
//if Cast::matchChildType_ is not set and we
//want to force our nullability to be the same
//as the child's nullability, set Cast::matchChildType_
if ((!matchChildType) && (matchChildNullability_))
{
//setting this flag will force our nullability
//to be the same as the child's nullability
Cast::setMatchChildType(TRUE);
}
//call Cast::synthesizeType() to do the real type synthesis
const NAType * result = Cast::synthesizeType();
//if Cast::matchChildType_ was not initially set
//then just unset it again.
if ((!matchChildType) && (matchChildNullability_))
{
Cast::setMatchChildType(FALSE);
}
return result;
}
// End_Fix 10-040114-2431
const NAType *Cast::synthesizeType()
{
//
// Type cast any params.
// Assert that we are bound, or created by Generator, so we have type info.
//
ValueId vid = child(0)->getValueId();
CMPASSERT(vid != NULL_VALUE_ID);
NABoolean untypedParam =
((child(0)->getOperatorType() == ITM_DYN_PARAM) &&
(vid.getType().getTypeQualifier() == NA_UNKNOWN_TYPE));
NAType * result = NULL;
NABoolean typeChanged = FALSE;
NABoolean sensitiveChanged = FALSE;
NABoolean charsetChanged = FALSE;
vid.coerceType(*getType());
if (untypedParam)
{
// an untyped param is being typed using CAST.
if (vid.getType().supportsSQLnull() != getType()->supportsSQLnull())
{
// Set the null attribute to be the same as that of the cast node.
NAType * newType = vid.getType().newCopy(HEAP);
newType->setNullable(getType()->supportsSQLnull());
vid.changeType(newType);
}
// mark this cast node so code for it is not generated at code
// generation time.
setMatchChildType(TRUE);
}
// Fix for CR 10-010426-2464: If its child supports NULL but itself
// does not AND the node's nullability is changable (i.e. not specified
// explicitly in the application), set it same as its child.
// NOTE: the new copy is necessary only because that the type_ is a const
// member. If the const is ever removed, setNullable can be called
// directly
else if (vid.getType().supportsSQLnull() != getType()->supportsSQLnull())
{
if (matchChildType())
// NOT NULL phrase not specified
{
result = getType()->newCopy(HEAP);
result->setNullable(vid.getType());
typeChanged = TRUE;
}
}
const NAType &src = vid.getType();
const NAType &tgt = (typeChanged)? *result: *getType();
NABuiltInTypeEnum srcQual = src.getTypeQualifier();
NABuiltInTypeEnum tgtQual = tgt.getTypeQualifier();
if ((src.getTypeQualifier() == NA_CHARACTER_TYPE) &&
(tgt.getTypeQualifier() == NA_CHARACTER_TYPE))
{
const CharType &cSrc = (CharType&)src;
CharType &cTgt = (CharType&)tgt;
if (cSrc.isCaseinsensitive() && (NOT cTgt.isCaseinsensitive()))
sensitiveChanged = TRUE;
if ( cSrc.getCharSet() != CharInfo::UnknownCharSet &&
cTgt.getCharSet() == CharInfo::UnknownCharSet)
charsetChanged = TRUE;
if (sensitiveChanged || charsetChanged)
{
result = tgt.newCopy(HEAP);
typeChanged = TRUE;
if (sensitiveChanged)
((CharType*)result)->setCaseinsensitive(TRUE);
if (charsetChanged)
((CharType*)result)->setCharSet(cSrc.getCharSet());
}
}
const NAType &res = (typeChanged)? *result: *getType();
//
// The NULL constant can be cast to any type.
//
if (getExpr()->getOperatorType() == ITM_CONSTANT)
if (((ConstValue*)getExpr())->isNull())
return (typeChanged)? result: getType();
//
// See the chart in ANSI 6.10, a rather symmetrical piece of work.
// Currently the "M" (Maybe) general subrules are being interpreted
// as "Y" (Yes, legally castable).
// Also, the Bitstring datatypes are not currently supported.
// Internally, we use SQLBooleans for some predicate results (=ANY, e.g.).
//
// The diagonal of compatible types is fine.
// Character types can be cast from or to with impunity.
// Numeric can be cast to our internal SQLBoolean.
// Exact numeric can be cast to a single-field interval, and vice versa.
// Timestamp can be cast to time or date; date or time can cast to timestamp.
//
NABoolean legal = FALSE;
// If both operands are char, they must be compatible (i.e., same charset);
// they do NOT have to be comparable (i.e., collation/coercibility ok)!
//
// The result type takes the charset from the target, and:
// - if target is a standard Ansi data type -- i.e., no COLLATE-clause --
// then DEFAULT collation and COERCIBLE coercibility are used,
// per Ansi 6.10 SR 8;
// - if target is a Tandem-extension data type declaration --
// i.e., with an explicit COLLATE-clause, such as
// CAST(a AS CHAR(n) COLLATE SJIS) --
// then the specified collation and coercibility (EXPLICIT) are used.
//
// Note that both of these come "for free":
// - if no COLLATE-clause was specified,
// SqlParser.y and the CharType-ctor-defaults will give
// DEFAULT/COERCIBLE to the unadorned data type;
// - if a COLLATE-clause was specified by user
// or if we are doing internal-expr casts --
// e.g., if our caller is
// propagateCoAndCoToXXX(), or CodeGen, or ColReference::bindNode --
// we simply use that collate/coerc.
//
// In fact, if these DIDN'T come for free, we would break INTERNAL casts:
// if (srcQual == NA_CHARACTER_TYPE && tgtQ == NA_CHARACTER_TYPE)[
// if (((const CharType&)src).getCharSet() == tgt.getCharSet())[
// CharType* newType = (CharType*)(tgtCT.newCopy(HEAP));
// newType->setCoAndCo(CharInfo::DefaultCollation, COERCIBLE);
// return newType;
//
// But if in future we support Ansi "domains",
// then need to revisit this, per Ansi 6.10 SR 1a + 8.
//
// In other words, a) use isCompatible(), not isComparable(),
// and b) just pass the tgt's collation/coercibility along!
//
if ((srcQual == NA_LOB_TYPE) && (tgtQual != NA_LOB_TYPE))
legal = FALSE;
else if (charsetChanged && src.isCompatible(res))
legal = TRUE;
else if (src.isCompatible(tgt))
legal = TRUE;
else if (srcQual == NA_CHARACTER_TYPE || tgtQual == NA_CHARACTER_TYPE)
{
legal = (srcQual != tgtQual); // if BOTH are CHAR: isCompatible() failed
// disable casting KANJI/KSC5601 from/to any other data types. Same behavior as MP.
if ( (srcQual == NA_CHARACTER_TYPE && CharInfo::is_NCHAR_MP(((const CharType&)src).getCharSet())) ||
(tgtQual == NA_CHARACTER_TYPE && CharInfo::is_NCHAR_MP(((const CharType&)tgt).getCharSet()))
)
legal = FALSE;
// if BOTH are CHAR: make legal if both unknown charset
if ( (srcQual == NA_CHARACTER_TYPE && (((const CharType&)src).getCharSet())==CharInfo::UnknownCharSet) &&
(tgtQual == NA_CHARACTER_TYPE && (((const CharType&)tgt).getCharSet())==CharInfo::UnknownCharSet)
)
legal = TRUE;
if ( srcQual == tgtQual ) // if BOTH are CHAR
{
if ( CmpCommon::getDefault(ALLOW_IMPLICIT_CHAR_CASTING) == DF_ON )
{
legal = TRUE;
//
// NOTE: The Generator has code to throw in a Translate node if an
// incompatible character set comparison is attempted.
//
}
}
}
else if (srcQual == NA_NUMERIC_TYPE)
legal = numericCastIsCompatible(src, tgt);
else if (srcQual == NA_INTERVAL_TYPE)
legal = numericCastIsCompatible(tgt, src);
else if (srcQual == NA_DATETIME_TYPE && tgtQual == NA_NUMERIC_TYPE)
{
legal =
(((DatetimeType&)src).getSubtype() == DatetimeType::SUBTYPE_SQLDate);
}
else if (srcQual == NA_DATETIME_TYPE && tgtQual == NA_DATETIME_TYPE) {
legal =
((DatetimeType&)src).getSubtype() == DatetimeType::SUBTYPE_SQLTimestamp
||
((DatetimeType&)tgt).getSubtype() == DatetimeType::SUBTYPE_SQLTimestamp
||
((DatetimeType&)tgt).fieldsOverlap((DatetimeType &)src);
}
if (!src.isSupportedType() || !tgt.isSupportedType())
{
if (src == tgt)
{
legal = TRUE;
}
else
{
legal = FALSE;
}
}
if (legal)
return (typeChanged)? result: getType();
// 4035 can't cast type from src to tgt
emitDyadicTypeSQLnameMsg(-4035, src, tgt);
return NULL;
}
const NAType *CastConvert::synthesizeType()
{
const NAType * type = Cast::synthesizeType();
if (type == NULL)
return NULL;
NABuiltInTypeEnum qual = type->getTypeQualifier();
if (qual != NA_CHARACTER_TYPE)
return type;
// return a char type that is large enough to hold the ascii
// representation of the operand.
const NAType &childType =
child(0)->castToItemExpr()->getValueId().getType();
Lng32 maxLength = childType.getDisplayLength(childType.getFSDatatype(),
childType.getNominalSize(),
childType.getPrecision(),
childType.getScale(),
0);
CharType * origType = (CharType *)getType();
if (DFS2REC::isAnyVarChar(origType->getFSDatatype()) == FALSE)
type = new HEAP
SQLChar(HEAP, maxLength, childType.supportsSQLnull(),
origType->isUpshifted());
else
type = new HEAP
SQLVarChar(HEAP, maxLength, childType.supportsSQLnull(),
origType->isUpshifted());
return type;
}
const NAType *CastType::synthesizeType()
{
if (getType())
return getType();
ValueId childVid = child(0)->getValueId();
NAType *newType = childVid.getType().newCopy(HEAP);
if (makeNullable_ && (NOT newType->supportsSQLnull()))
{
newType->setNullable(TRUE);
}
changeType(newType);
return getType();
}
// -----------------------------------------------------------------------
// member functions for class CharFunc
// -----------------------------------------------------------------------
const NAType *CharFunc::synthesizeType()
{
// The expression is CHAR(<num>) or UNICODE_CHAR(<num>) or NCHAR(<num>)
// The result is the character that has the
// ASCII or UNICODE or <NATIONAL_CHARSET> code of <num>.
//
// Type cast any params.
//
SQLInt nType(NULL, FALSE);
ValueId vid1 = child(0)->getValueId();
vid1.coerceType(nType, NA_NUMERIC_TYPE);
const NAType &typ1 = child(0)->getValueId().getType();
if (typ1.getTypeQualifier() != NA_NUMERIC_TYPE)
{
// 4045 Operand must be numeric.
*CmpCommon::diags() << DgSqlCode(-4045) << DgString0(getTextUpper());
return NULL;
}
// now it's safe to cast the type to numeric type
const NumericType &ntyp1 = (NumericType &) typ1;
if (! ntyp1.isExact())
{
// 4046 Operand must be exact.
*CmpCommon::diags() << DgSqlCode(-4046) << DgString0(getTextUpper());
return NULL;
}
if (typ1.getScale() != 0)
{
// 4047 Operand must be not have scale.
*CmpCommon::diags() << DgSqlCode(-4047) << DgString0(getTextUpper());
return NULL;
}
CharInfo::CharSet cs_to_use = charSet_ ;
CharType *result;
if(charSet_ == CharInfo::UCS2 || charSet_ < 0) // UCS2, kanji and KSC5601_MP
result = new (HEAP) SQLChar ( HEAP, 1,
typ1.supportsSQLnullLogical(),
FALSE/*not upshift*/,
FALSE/*case sensitive*/,
FALSE/*not varchar*/,
charSet_);
else
result = new (HEAP) SQLVarChar(HEAP, CharInfo::maxBytesPerChar( cs_to_use )
, typ1.supportsSQLnullLogical()
, FALSE /*not upshift*/
, FALSE /*case sensitive*/
, cs_to_use
, CharInfo::DefaultCollation
, CharInfo::COERCIBLE
);
return result;
}
// -----------------------------------------------------------------------
// member functions for class ConvertHex
// -----------------------------------------------------------------------
const NAType *ConvertHex::synthesizeType()
{
//
// Type cast any params.
//
ValueId vid = child(0)->getValueId();
vid.coerceType(NA_CHARACTER_TYPE);
//
// Check that the operands are compatible.
//
const NAType* operand = &vid.getType();
if (getOperatorType() == ITM_CONVERTFROMHEX)
{
if (operand->getTypeQualifier() != NA_CHARACTER_TYPE) {
// 4043 The operand of an ConvertHex function must be character.
*CmpCommon::diags() << DgSqlCode(-4043) << DgString0(getTextUpper());
return NULL;
}
const CharType* charType = (CharType*)operand;
if ( charType->getCharSet() == CharInfo::UnknownCharSet ) {
const CharType* desiredType =
CharType::desiredCharType(CharInfo::ISO88591);
vid.coerceType(*desiredType, NA_CHARACTER_TYPE);
operand = &vid.getType();
}
// operand's size must be an even number since two hex characters make
// up one result byte.
const CharType* chartype1 = (CharType*)operand;
if (NOT chartype1->sizeIsEven()) {
*CmpCommon::diags() << DgSqlCode(-4068) << DgString0(getTextUpper());
return NULL;
}
}
Int32 maxLength;
if (getOperatorType() == ITM_CONVERTTOHEX)
maxLength = operand->getNominalSize() * 2;
else
maxLength = operand->getNominalSize() / 2;
NAType * type;
if ( operand -> getTypeQualifier() == NA_CHARACTER_TYPE &&
( (operand -> isVaryingLen() == TRUE) ||
( (const CharType*)operand)->getCharSet()==CharInfo::UTF8 )
)
type = new HEAP
SQLVarChar(HEAP, maxLength, operand->supportsSQLnull());
else
type = new HEAP
SQLChar(HEAP, maxLength, operand->supportsSQLnull());
//
// Return the result.
//
return type;
}
// -----------------------------------------------------------------------
// member functions for class CharLength
// -----------------------------------------------------------------------
const NAType *CharLength::synthesizeType()
{
//
// Type cast any params.
//
ValueId vid = child(0)->getValueId();
vid.coerceType(NA_CHARACTER_TYPE);
//
// Check that the operands are compatible.
//
const NAType& operand = vid.getType();
if (operand.getTypeQualifier() != NA_CHARACTER_TYPE) {
// 4043 The operand of a CHAR_LENGTH function must be character.
*CmpCommon::diags() << DgSqlCode(-4043) << DgString0(getTextForError());
return NULL;
}
const CharType* charOperand = (CharType*)&(vid.getType());
NAString defVal;
NABoolean charsetInference =
(CmpCommon::getDefault(INFER_CHARSET, defVal) == DF_ON);
if(charsetInference)
{
const CharType* desiredType =
CharType::findPushDownCharType(getDefaultCharSet, charOperand, 0);
if ( desiredType )
{
// just push down the charset field. All other fields are
// ignored.
//coerceChildType((NAType&)*desiredType, NA_CHARACTER_TYPE);
vid.coerceType(*desiredType, NA_CHARACTER_TYPE);
// get the newly pushed-down types
charOperand = (CharType*)&(vid.getType());
}
}
if ( charOperand -> getCharSet() == CharInfo::UnknownCharSet ) {
*CmpCommon::diags() << DgSqlCode(-4127);
return NULL;
}
//
// Return the result.
//
return new HEAP
SQLInt(HEAP, FALSE // unsigned
,operand.supportsSQLnullLogical()
);
}
// -----------------------------------------------------------------------
// member functions for class Concat
// -----------------------------------------------------------------------
const NAType *Concat::synthesizeType()
{
//
// Type cast any params.
//
ValueId vid1 = child(0)->getValueId();
ValueId vid2 = child(1)->getValueId();
// these first two extra calls handle any parameters
// operands must be gotten twice because they could change types.
CharInfo::CharSet new_cs = getFirstKnownCharSet(vid1, vid2, vid2);
// If vid not aleady of NA_CHARACTER_TYPE, make varchar(255) of character set = new_cs
vid1.coerceType(NA_CHARACTER_TYPE, new_cs);
vid2.coerceType(NA_CHARACTER_TYPE, new_cs);
vid1.coerceType(vid2.getType(), NA_CHARACTER_TYPE);
vid2.coerceType(vid1.getType());
//
// Synthesize the result.
//
const NAType* operand1 = &vid1.getType();
const NAType* operand2 = &vid2.getType();
NABoolean isCaseInsensitive = FALSE;
if ( operand1 -> getTypeQualifier() == NA_CHARACTER_TYPE &&
operand2 -> getTypeQualifier() == NA_CHARACTER_TYPE
)
{
const CharType *op1 = (CharType *)operand1;
const CharType *op2 = (CharType *)operand2;
if (CmpCommon::wantCharSetInference()) {
const CharType* desiredType =
CharType::findPushDownCharType(getDefaultCharSet, op1, op2, 0);
if ( desiredType )
{
// just push down the charset field. All other fields are
// meaningless.
vid1.coerceType((NAType&)*desiredType, NA_CHARACTER_TYPE);
vid2.coerceType((NAType&)*desiredType, NA_CHARACTER_TYPE);
}
}
if (op1->isCaseinsensitive() || op2->isCaseinsensitive())
{
isCaseInsensitive = TRUE;
}
}
const NAType *result = operand1->synthesizeType(SYNTH_RULE_CONCAT,
*operand1,
*operand2,
HEAP);
if (result == NULL)
{
// 4034 The operation (~op1 ~operator ~op2) is not allowed.
emitDyadicTypeSQLnameMsg(-4034, *operand1, *operand2, getTextUpper());
return result;
}
if ((result->getTypeQualifier() == NA_CHARACTER_TYPE) &&
(isCaseInsensitive))
{
CharType *ct = (CharType *)result;
ct->setCaseinsensitive(TRUE);
}
return result;
}
// -----------------------------------------------------------------------
// member functions for class ConstValue
// -----------------------------------------------------------------------
const NAType * ConstValue::synthesizeType()
{
return getType();
}
// -----------------------------------------------------------------------
// member functions for class ConvertTimestamp
// -----------------------------------------------------------------------
const NAType *ConvertTimestamp::synthesizeType()
{
//
// Type cast any params.
//
ValueId vid = child(0)->getValueId();
SQLLargeInt largeintType(NULL);
vid.coerceType(largeintType);
//
// Check that the operands are compatible.
//
const NAType& operand = vid.getType();
if (operand.getTypeQualifier() != NA_NUMERIC_TYPE OR
NOT ((NumericType&) operand).isExact()) {
// 4070 The operand of a CONVERTTIMESTAMP function must be exact numeric.
*CmpCommon::diags() << DgSqlCode(-4070) << DgString0(getTextUpper());
return NULL;
}
//
// Return the result.
//
return new HEAP SQLTimestamp (HEAP, operand.supportsSQLnullLogical(),
SQLTimestamp::DEFAULT_FRACTION_PRECISION);
}
// -----------------------------------------------------------------------
// member functions for class SleepFunction
// -----------------------------------------------------------------------
const NAType *SleepFunction::synthesizeType()
{
return new HEAP SQLInt(HEAP, TRUE, TRUE);
}
// -----------------------------------------------------------------------
// member functions for class UnixTimestamp
// -----------------------------------------------------------------------
const NAType *UnixTimestamp::synthesizeType()
{
return new HEAP SQLLargeInt(HEAP, FALSE,FALSE);
}
// -----------------------------------------------------------------------
// member functions for class CurrentTimestamp
// -----------------------------------------------------------------------
const NAType *CurrentTimestamp::synthesizeType()
{
return new HEAP SQLTimestamp (HEAP, FALSE,
SQLTimestamp::DEFAULT_FRACTION_PRECISION);
}
// -----------------------------------------------------------------------
// member functions for class InternalTimestamp
// -----------------------------------------------------------------------
const NAType *InternalTimestamp::synthesizeType()
{
return new HEAP SQLTimestamp(HEAP, FALSE);
}
// -----------------------------------------------------------------------
// member functions for class CurrentTimestampRunning
// -----------------------------------------------------------------------
const NAType *CurrentTimestampRunning::synthesizeType()
{
return new HEAP SQLTimestamp(HEAP, FALSE);
}
// -----------------------------------------------------------------------
// member functions for class DateFormat
// -----------------------------------------------------------------------
const NAType *DateFormat::synthesizeType()
{
//
// Type cast any params.
//
ValueId vid = child(0)->getValueId();
SQLTimestamp timestampType(NULL);
vid.coerceType(timestampType);
//
// Check that the operands are compatible.
//
if (!vid.getType().isSupportedType()) {
// 4071 The operand of a DATEFORMAT function must be a datetime.
*CmpCommon::diags() << DgSqlCode(-4071) << DgString0(getTextUpper());
return NULL;
}
if ((getDateFormat() == TIME_FORMAT_STR) &&
((vid.getType().getTypeQualifier() != NA_NUMERIC_TYPE) &&
(vid.getType().getTypeQualifier() != NA_CHARACTER_TYPE) &&
(vid.getType().getTypeQualifier() != NA_DATETIME_TYPE))) {
// 4071 The operand of a DATEFORMAT function must be a datetime.
*CmpCommon::diags() << DgSqlCode(-4071) << DgString0(getTextUpper());
return NULL;
}
Lng32 length = 0;
NABoolean formatAsDate = FALSE;
NABoolean formatAsTimestamp = FALSE;
NABoolean formatAsTime = FALSE;
if (vid.getType().getTypeQualifier() == NA_DATETIME_TYPE)
{
const DatetimeType& operand = (DatetimeType &)vid.getType();
Lng32 frmt = ExpDatetime::getDatetimeFormat(formatStr_.data());
if (wasDateformat_)
{
length = operand.getDisplayLength();
if(operand.containsField(REC_DATE_HOUR) &&
((frmt == ExpDatetime::DATETIME_FORMAT_USA) ||
(frmt == ExpDatetime::DATETIME_FORMAT_TS7)))
length += 3; // add 3 for a blank and "am" or "pm"
}
else
{
length = ExpDatetime::getDatetimeFormatMaxLen(frmt);
}
}
else if (vid.getType().getTypeQualifier() == NA_CHARACTER_TYPE)
{
length = formatStr_.length();
if (getDateFormat() == DATE_FORMAT_STR)
{
formatAsDate = TRUE;
}
else if (getDateFormat() == TIMESTAMP_FORMAT_STR)
{
formatAsTimestamp = TRUE;
}
else if (getDateFormat() == TIME_FORMAT_STR)
{
formatAsTime = TRUE;
}
}
else if (vid.getType().getTypeQualifier() == NA_NUMERIC_TYPE)
{
length = formatStr_.length();
}
if (formatAsDate)
return new HEAP SQLDate(HEAP, vid.getType().supportsSQLnullLogical());
else if (formatAsTimestamp)
return new HEAP SQLTimestamp(HEAP, vid.getType().supportsSQLnullLogical());
else if (formatAsTime)
return new HEAP SQLTime(HEAP, vid.getType().supportsSQLnullLogical());
else
return new HEAP SQLChar(HEAP, length, vid.getType().supportsSQLnullLogical());
}
// -----------------------------------------------------------------------
// member functions for class DayOfWeek
// -----------------------------------------------------------------------
const NAType *DayOfWeek::synthesizeType()
{
//
// Type cast any params.
//
ValueId vid = child(0)->getValueId();
SQLTimestamp timestampType(NULL);
vid.coerceType(timestampType);
//
// Check that the operand contains a DAY field
//
const NAType& operand = vid.getType();
if ((operand.getTypeQualifier() != NA_DATETIME_TYPE) ||
(!((DatetimeType&) operand).containsField (REC_DATE_YEAR)) ||
(!((DatetimeType&) operand).containsField (REC_DATE_MONTH)) ||
(!((DatetimeType&) operand).containsField (REC_DATE_DAY))) {
// Need to reword:
// 4072 The operand of function DAYOFWEEK must be a Datetime containing a DAY field.
*CmpCommon::diags() << DgSqlCode(-4072) << DgString0(getTextUpper()) << DgString1("YEAR, MONTH and DAY");
return NULL;
}
//
// Return the result.
//
const Int16 DisAmbiguate = 0; // added for 64bit project
return new HEAP SQLNumeric(HEAP, FALSE, 1, 0, DisAmbiguate,
operand.supportsSQLnullLogical());
}
// -----------------------------------------------------------------------
// member functions for class DynamicParam
// -----------------------------------------------------------------------
const NAType *DynamicParam::synthesizeType()
{
// dynamic params are always nullable.
return new HEAP SQLUnknown(HEAP, TRUE);
}
const NAType *ExplodeVarchar::synthesizeType()
{
return getType();
}
const NAType *Format::synthesizeType()
{
NAType * retType = NULL;
retType = (NAType *)ItemExpr::synthesizeType();
return retType;
}
// -----------------------------------------------------------------------
// member functions for class RoutineParam
// -----------------------------------------------------------------------
const NAType *RoutineParam::synthesizeType()
{
return getType();
}
// -----------------------------------------------------------------------
// member functions for class Function -- a catchall for those funx which
// don't have their own virtual synthType()
// -----------------------------------------------------------------------
const NAType *Function::synthesizeType()
{
// Function derives directly from ItemExpr, so safe to do this
const NAType *result = ItemExpr::synthesizeType();
if (0)
{
if (result->getTypeQualifier() == NA_CHARACTER_TYPE) {
Int32 n = getNumCHARACTERArgs(this);
if (n > 1) {
#ifndef NDEBUG
// if (NCHAR_DEBUG > 0)
{
NAString unparsed(CmpCommon::statementHeap());
unparse(unparsed, DEFAULT_PHASE, USER_FORMAT_DELUXE);
cerr << "## FUNCTION " << (Int32)getOperatorType()
<< " (" << n << " char-type args)\t"
<< unparsed
<< "\t *might* not be computing its result collation/coercibility properly and/or pushing co/co back down to its children..." << endl;
// Also emit a warning so you can catch this in regression results
unparsed.prepend("## FUNCTION, co/co issue: ");
*CmpCommon::diags() << DgSqlCode(+1110) << DgString0(unparsed);
}
#endif
}
// WE DO *NOT* SYNTHESIZE A RESULT CoAndCo here
// nor push it back down to children via propagateCoAndCoToChildren,
// because that might not be the right thing.
// If the above CERR msg appears and you see a problem,
// you should add a synthesizeType method for that particular
// Function-derived class.
// CharType *ct = (CharType *)result;
// propagateCoAndCoToChildren(this,
// ct->getCollation(), ct->getCoercibility());
}
}
return result;
}
// -----------------------------------------------------------------------
// member functions for class Hash
// -----------------------------------------------------------------------
const NAType *Hash::synthesizeType()
{
// result of hash function is always a non-nullable, unsigned 32 bit integer
return new HEAP SQLInt(HEAP, FALSE, FALSE);
}
// -----------------------------------------------------------------------
// member functions for class HashComb
// -----------------------------------------------------------------------
NABoolean HashCommon::areChildrenExactNumeric(Lng32 left, Lng32 right)
{
const NAType &typ1 = child(left)->getValueId().getType();
const NAType &typ2 = child(right)->getValueId().getType();
if (typ1.getTypeQualifier() != NA_NUMERIC_TYPE ||
typ2.getTypeQualifier() != NA_NUMERIC_TYPE)
return FALSE;
// now it's safe to cast the types to numeric type
const NumericType &ntyp1 = (NumericType &) typ1;
const NumericType &ntyp2 = (NumericType &) typ2;
return (ntyp1.isExact() AND ntyp2.isExact() AND
ntyp1.binaryPrecision() AND ntyp2.binaryPrecision() AND
ntyp1.getPrecision() == ntyp2.getPrecision() AND
ntyp1.isUnsigned() AND ntyp2.isUnsigned());
}
const NAType *HashComb::synthesizeType()
{
// Both dividend and divisor must be exact numeric with scale 0.
// The result has values from 0 to <divisor> - 1 and therefore
// can always fit into the data type of the divisor.
// HashComb is an internal operator and errors are fatal
CMPASSERT(areChildrenExactNumeric(0, 1));
// result of hashcomb function is always a non-nullable,
// unsigned 32 bit integer
return new HEAP SQLInt(HEAP, FALSE, FALSE);
}
const NAType *HiveHashComb::synthesizeType()
{
// Both dividend and divisor must be exact numeric with scale 0.
// The result has values from 0 to <divisor> - 1 and therefore
// can always fit into the data type of the divisor.
// HashComb is an internal operator and errors are fatal
CMPASSERT(areChildrenExactNumeric(0, 1));
// result of hashcomb function is always a non-nullable,
// unsigned 32 bit integer
return new HEAP SQLInt(HEAP, FALSE, FALSE);
}
// -----------------------------------------------------------------------
// member functions for class HashDistHash
// Hash Function used by Hash Partitioning. This function cannot change
// once Hash Partitioning is released! Defined for all data types,
// returns a 32 bit non-nullable hash value for the data item.
// -----------------------------------------------------------------------
const NAType *HashDistPartHash::synthesizeType()
{
// result of hash function is always a non-nullable, unsigned 32 bit integer
return new HEAP SQLInt(HEAP, FALSE, FALSE);
}
// -----------------------------------------------------------------------
// member functions for class HiveHash
// -----------------------------------------------------------------------
const NAType *HiveHash::synthesizeType()
{
// result of hivehash function is always a non-nullable, unsigned 32 bit integer
return new HEAP SQLInt(HEAP, FALSE, FALSE);
}
// -----------------------------------------------------------------------
// member functions for class HashDistHashComb
// This function is used to combine two hash values to produce a new
// hash value. Used by Hash Partitioning. This function cannot change
// once Hash Partitioning is released! Defined for all data types,
// returns a 32 bit non-nullable hash value for the data item.
// -----------------------------------------------------------------------
const NAType *HashDistPartHashComb::synthesizeType()
{
// Both dividend and divisor must be exact numeric with scale 0.
// The result has values from 0 to <divisor> - 1 and therefore
// can always fit into the data type of the divisor.
const NAType &typ1 = child(0)->getValueId().getType();
const NAType &typ2 = child(1)->getValueId().getType();
// HashDistHashComb is an internal operator and errors are fatal
CMPASSERT(typ1.getTypeQualifier() == NA_NUMERIC_TYPE AND
typ2.getTypeQualifier() == NA_NUMERIC_TYPE);
// now it's safe to cast the types to numeric type
const NumericType &ntyp1 = (NumericType &) typ1;
const NumericType &ntyp2 = (NumericType &) typ2;
// Make sure both operands are SQLInt.
//
CMPASSERT(ntyp1.getFSDatatype() == REC_BIN32_UNSIGNED AND
ntyp2.getFSDatatype() == REC_BIN32_UNSIGNED AND
ntyp1.isAnyUnsignedInt() AND
ntyp2.isAnyUnsignedInt() AND
ntyp1.getPrecision() == SQL_UINT_PRECISION AND
ntyp2.getPrecision() == SQL_UINT_PRECISION);
// result of hashcomb function is always a non-nullable,
// unsigned 32 bit integer
return new HEAP SQLInt(HEAP, FALSE, FALSE);
}
// -----------------------------------------------------------------------
// member functions for class ReplaceNull
// -----------------------------------------------------------------------
const NAType *ReplaceNull::synthesizeType()
{
// result of ReplaceNull is always the same as the second argument
// except it is non nullable.
ValueId childId = child(1)->getValueId();
NAType *newType = childId.getType().newCopy(HEAP);
//newType->setNullable(FALSE);
return newType;
}
// -----------------------------------------------------------------------
// member functions for class JulianTimestamp
// -----------------------------------------------------------------------
const NAType *JulianTimestamp::synthesizeType()
{
//
// Type cast any params.
//
ValueId vid = child(0)->getValueId();
SQLTimestamp timestampType(NULL);
vid.coerceType(timestampType);
//
// Check that the operands are compatible.
//
const NAType& operand = vid.getType();
if (operand.getTypeQualifier() != NA_DATETIME_TYPE) {
// 4071 The operand of a JULIANTIMESTAMP function must be a datetime.
*CmpCommon::diags() << DgSqlCode(-4071) << DgString0(getTextUpper());
return NULL;
}
//
// Return the result.
//
return new HEAP SQLLargeInt(HEAP, TRUE, operand.supportsSQLnullLogical());
}
// -----------------------------------------------------------------------
// member functions for class StatementExecutionCount
// -----------------------------------------------------------------------
const NAType * StatementExecutionCount::synthesizeType()
{
return new HEAP SQLLargeInt(HEAP, TRUE,FALSE);
}
// -----------------------------------------------------------------------
// member functions for class CurrentTransId
// -----------------------------------------------------------------------
const NAType * CurrentTransId::synthesizeType()
{
return new HEAP SQLLargeInt(HEAP, TRUE,FALSE);
}
// -----------------------------------------------------------------------
// member functions for class BitOperFunc
// -----------------------------------------------------------------------
const NAType *BitOperFunc::synthesizeType()
{
NABoolean nullable = FALSE;
for (Int32 i = 0; i < getArity(); i++)
{
// type cast any params
ValueId vid = child(i)->getValueId();
// untyped param operands are typed as Int32 Unsigned.
SQLInt dp(NULL, FALSE);
vid.coerceType(dp, NA_NUMERIC_TYPE);
const NAType &typ = vid.getType();
if (typ.getTypeQualifier() != NA_NUMERIC_TYPE)
{
// 4045 operand must be numeric.
// 4052 2nd operand must be numeric.
// 4059 1st operand must be numeric.
if (getArity() == 1)
*CmpCommon::diags()
<< DgSqlCode(-4045) << DgString0(getTextUpper());
else
{
if (i == 0)
*CmpCommon::diags()
<< DgSqlCode(-4059) << DgString0(getTextUpper());
else if (i == 1)
*CmpCommon::diags()
<< DgSqlCode(-4052) << DgString0(getTextUpper());
else
*CmpCommon::diags()
<< DgSqlCode(-4053) << DgString0(getTextUpper());
}
return NULL;
}
if (typ.supportsSQLnullLogical())
nullable = TRUE;
}
const NAType *result = NULL;
switch (getOperatorType())
{
case ITM_BITAND:
case ITM_BITOR:
case ITM_BITXOR:
{
CMPASSERT(getArity() == 2);
// now it's safe to cast the types to numeric type
const NumericType &ntyp1 = (NumericType &) child(0)->getValueId().getType();
const NumericType &ntyp2 = (NumericType &) child(1)->getValueId().getType();
if (NOT ntyp1.isExact() OR NOT ntyp2.isExact() OR
ntyp1.isBigNum() OR ntyp2.isBigNum())
{
// 4046 BIT operation is only defined for exact numeric types.
*CmpCommon::diags() << DgSqlCode(-4046) << DgString0(getTextUpper());
return NULL;
}
if (ntyp1.getScale() != 0 OR
ntyp2.getScale() != 0)
{
// 4047 Arguments of BIT operation must both have a scale of 0.
*CmpCommon::diags() << DgSqlCode(-4047) << DgString0(getTextUpper());
return NULL;
}
UInt32 flags = NAType::MAKE_UNION_RESULT_BINARY;
result = ntyp1.synthesizeType(
SYNTH_RULE_UNION,
ntyp1,
ntyp2,
HEAP,
&flags);
}
break;
case ITM_BITNOT:
{
CMPASSERT(getArity() == 1);
// now it's safe to cast the types to numeric type
const NumericType &ntyp1 = (NumericType &) child(0)->getValueId().getType();
if (NOT ntyp1.isExact() OR ntyp1.isBigNum())
{
// 4046 BIT operation is only defined for exact numeric types.
*CmpCommon::diags() << DgSqlCode(-4046) << DgString0(getTextUpper());
return NULL;
}
if (ntyp1.getScale() != 0)
{
// 4047 Arguments of BIT operation must both have a scale of 0.
*CmpCommon::diags() << DgSqlCode(-4047) << DgString0(getTextUpper());
return NULL;
}
// result of BITNOT is the same type as the operand, if the
// operand is binary.
// If operand is decimal, then convert it to equivalent binary.
NAType * result1 = NULL;
if (ntyp1.binaryPrecision())
result1 = (NumericType*)ntyp1.newCopy(HEAP);
else
{
const Int16 DisAmbiguate = 0;
result1 = new HEAP SQLNumeric(HEAP, NOT ntyp1.isUnsigned(),
ntyp1.getPrecision(),
ntyp1.getScale(),
DisAmbiguate); // added for 64bit proj.
}
result1->setNullable(nullable);
result = result1;
}
break;
case ITM_BITEXTRACT:
{
CMPASSERT(getArity() == 3);
// now it's safe to cast the types to numeric type
const NumericType &ntyp1 = (NumericType &) child(0)->getValueId().getType();
const NumericType &ntyp2 = (NumericType &) child(1)->getValueId().getType();
const NumericType &ntyp3 = (NumericType &) child(2)->getValueId().getType();
if (ntyp1.isBigNum() ||
ntyp1.isDecimal())
{
// 4046 BIT operation is only defined for exact numeric types.
*CmpCommon::diags() << DgSqlCode(-4046) << DgString0(getTextUpper());
return NULL;
}
if ((NOT ntyp2.isExact()) ||
(NOT ntyp3.isExact()))
{
// 4046 BIT operation is only defined for exact numeric types.
*CmpCommon::diags() << DgSqlCode(-4046) << DgString0(getTextUpper());
return NULL;
}
if ((ntyp2.getScale() != 0) ||
(ntyp3.getScale() != 0))
{
// 4047 Arguments of BIT operation must both have a scale of 0.
*CmpCommon::diags() << DgSqlCode(-4047) << DgString0(getTextUpper());
return NULL;
}
// result can contain as many bits as the length of the operand.
// Make the result an Int32 or Int64.
NAType * result1 = NULL;
if (ntyp1.getNominalSize() <= 9)
result = new HEAP SQLInt(HEAP, TRUE, nullable);
else
result = new HEAP SQLLargeInt(HEAP, TRUE, nullable);
}
break;
default:
{
// 4000 Internal Error. This function not supported.
*CmpCommon::diags() << DgSqlCode(-4000);
result = NULL;
}
break;
}
return result;
}
// -----------------------------------------------------------------------
// member functions for class MathFunc
// -----------------------------------------------------------------------
NAType* MathFunc::findReturnTypeForFloorCeil(NABoolean nullable)
{
assert (getArity() == 1);
for (Int32 i = 0; i < getArity(); i++) {
ValueId vid = child(i)->getValueId();
const NAType &typ = vid.getType();
if (typ.getTypeQualifier() != NA_NUMERIC_TYPE)
break;
const NumericType& nuTyp = (NumericType&)(typ);
// If the child is a SQL integer, just return the same type
// for the function.
if ( nuTyp.isInteger() )
return nuTyp.newCopy(HEAP);
// Here we only return a modified data type for SQLDecimal
// or SQLNumeric. For all others, we return SQLDoublePrecision.
if ( !nuTyp.decimalPrecision() )
break;
switch ( nuTyp.getFSDatatype() ) {
// for SQLDecimal
case REC_DECIMAL_UNSIGNED:
case REC_DECIMAL_LSE:
return new HEAP SQLDecimal(HEAP, nuTyp.getNominalSize()
,0
,!nuTyp.isUnsigned()
,nuTyp.supportsSQLnull()
);
break;
// for SQLNumeric
case REC_BIN8_UNSIGNED:
case REC_BIN16_UNSIGNED:
case REC_BIN32_UNSIGNED:
case REC_BIN64_UNSIGNED:
case REC_BIN8_SIGNED:
case REC_BIN16_SIGNED:
case REC_BIN32_SIGNED:
case REC_BIN64_SIGNED:
return new HEAP SQLNumeric(HEAP, nuTyp.getNominalSize()
,nuTyp.getPrecision()
,0
,!nuTyp.isUnsigned()
,nuTyp.supportsSQLnull()
);
default:
break;
}
}
return new HEAP SQLDoublePrecision(HEAP, nullable);
}
const NAType *MathFunc::synthesizeType()
{
CMPASSERT(getArity() <= 2);
NABoolean nullable = FALSE;
for (Int32 i = 0; i < getArity(); i++)
{
// type cast any params
ValueId vid = child(i)->getValueId();
SQLDoublePrecision dp(NULL, TRUE);
vid.coerceType(dp, NA_NUMERIC_TYPE);
const NAType &typ = vid.getType();
if (typ.getTypeQualifier() != NA_NUMERIC_TYPE)
{
// 4045 operand must be numeric.
// 4052 2nd operand must be numeric.
// 4059 1st operand must be numeric.
if (getArity() == 1)
*CmpCommon::diags()
<< DgSqlCode(-4045) << DgString0(getTextUpper());
else
*CmpCommon::diags()
<< DgSqlCode(i ? -4052 : -4059) << DgString0(getTextUpper());
return NULL;
}
if (typ.supportsSQLnullLogical())
nullable = TRUE;
}
const NAType *result = NULL;
switch (getOperatorType())
{
case ITM_ABS:
case ITM_ACOS:
case ITM_ASIN:
case ITM_ATAN:
case ITM_ATAN2:
case ITM_COS:
case ITM_COSH:
case ITM_DEGREES:
case ITM_EXP:
case ITM_EXPONENT:
case ITM_LOG:
case ITM_LOG10:
case ITM_LOG2:
case ITM_PI:
case ITM_POWER:
case ITM_RADIANS:
case ITM_ROUND:
case ITM_SCALE_TRUNC:
case ITM_SIN:
case ITM_SINH:
case ITM_SQRT:
case ITM_TAN:
case ITM_TANH:
{
result = new HEAP SQLDoublePrecision(HEAP, nullable);
}
break;
case ITM_FLOOR:
case ITM_CEIL:
{
result = findReturnTypeForFloorCeil(nullable);
}
break;
default:
{
// 4000 Internal Error. This function not supported.
*CmpCommon::diags() << DgSqlCode(-4000);
result = NULL;
}
break;
}
return result;
}
// -----------------------------------------------------------------------
// member functions for class Modulus
// -----------------------------------------------------------------------
const NAType *Modulus::synthesizeType()
{
// The expression is <dividend> mod <divisor>.
// Both dividend and divisor must be exact numeric with scale 0.
// The result has values from 0 to <divisor> - 1 and therefore
// can always fit into the data type of the divisor.
//
// Type cast any params.
//
ValueId vid1 = child(0)->getValueId();
ValueId vid2 = child(1)->getValueId();
SQLInt si(NULL, TRUE);
vid1.coerceType(si, NA_NUMERIC_TYPE);
vid2.coerceType(si, NA_NUMERIC_TYPE);
const NAType &typ1 = child(0)->getValueId().getType();
const NAType &typ2 = child(1)->getValueId().getType();
if (typ1.getTypeQualifier() != NA_NUMERIC_TYPE OR
typ2.getTypeQualifier() != NA_NUMERIC_TYPE)
{
// 4046 Modulus function is only defined for exact numeric types.
*CmpCommon::diags() << DgSqlCode(-4046) << DgString0(getTextUpper());
return NULL;
}
// now it's safe to cast the types to numeric type
const NumericType &ntyp1 = (NumericType &) typ1;
const NumericType &ntyp2 = (NumericType &) typ2;
if (NOT ntyp1.isExact() OR NOT ntyp2.isExact())
{
// 4046 Modulus function is only defined for exact numeric types.
*CmpCommon::diags() << DgSqlCode(-4046) << DgString0(getTextUpper());
return NULL;
}
if (ntyp1.getScale() != 0 OR
ntyp2.getScale() != 0)
{
// 4047 Arguments of modulus function must both have a scale of 0.
*CmpCommon::diags() << DgSqlCode(-4047) << DgString0(getTextUpper());
return NULL;
}
if (ntyp1.decimalPrecision() && ntyp1.getPrecision() > MAX_NUMERIC_PRECISION)
{
// 3037: precision of dividend cannot exceed 18.
*CmpCommon::diags() << DgSqlCode(-3037) << DgString0(child(0)->getTextUpper());
return NULL;
}
if (ntyp2.decimalPrecision() && ntyp2.getPrecision() > MAX_NUMERIC_PRECISION)
{
// 3037: precision of divisor cannot exceed 18.
*CmpCommon::diags() << DgSqlCode(-3037) << DgString0(child(1)->getTextUpper());
return NULL;
}
NumericType * result = (NumericType*)ntyp2.newCopy(HEAP);
result->setNullable(typ1.supportsSQLnullLogical() ||
typ2.supportsSQLnullLogical());
if (ntyp1.isUnsigned())
result->makeUnsigned();
else
result->makeSigned();
return result;
}
// -----------------------------------------------------------------------
// member functions for class Repeat
// -----------------------------------------------------------------------
const NAType *Repeat::synthesizeType()
{
// The expression is REPEAT(<value1>, <value2>)
// The result is string <value1> repeated <value2> times.
//
// Type cast any params.
//
ValueId vid1 = child(0)->getValueId();
ValueId vid2 = child(1)->getValueId();
vid1.coerceType(NA_CHARACTER_TYPE);
const SQLInt t(FALSE);
vid2.coerceType(t, NA_NUMERIC_TYPE);
const NAType &typ1 = child(0)->getValueId().getType();
if (typ1.getTypeQualifier() != NA_CHARACTER_TYPE)
{
// 4051 Operand 1 must be character.
*CmpCommon::diags() << DgSqlCode(-4051) << DgString0(getTextUpper());
return NULL;
}
const NAType &typ2 = child(1)->getValueId().getType();
if (typ2.getTypeQualifier() != NA_NUMERIC_TYPE)
{
// 4052 Operand 2 must be numeric.
*CmpCommon::diags() << DgSqlCode(-4052) << DgString0(getTextUpper());
return NULL;
}
const CharType &ctyp1 = (CharType &) typ1;
// now it's safe to cast the type to numeric type
const NumericType &ntyp2 = (NumericType &) typ2;
if (ntyp2.getScale() != 0)
{
// 4047 Operand must be not have scale.
*CmpCommon::diags() << DgSqlCode(-4047) << DgString0(getTextUpper());
return NULL;
}
if (! ntyp2.isExact())
{
// 4046 Operand 2 must be exact.
*CmpCommon::diags() << DgSqlCode(-4046) << DgString0(getTextUpper());
return NULL;
}
Int64 size_in_bytes;
Int64 size_in_chars;
Int32 maxCharColLen = CmpCommon::getDefaultNumeric(TRAF_MAX_CHARACTER_COL_LENGTH);
// figure out the max length of result.
NABoolean negate;
if (maxLengthWasExplicitlySet_)
{
// cap max len at traf_max_character_col_length
size_in_bytes =
MINOF(maxCharColLen, getMaxLength());
size_in_chars =
size_in_bytes / CharInfo::minBytesPerChar(ctyp1.getCharSet());
}
else if ((child(1)->getOperatorType() == ITM_CONSTANT) &&
(child(1)->castToConstValue(negate)))
{
ConstValue * cv = child(1)->castToConstValue(negate);
Int64 repeatCount;
if (! cv->isNull())
{
if (cv->canGetExactNumericValue()) {
repeatCount = cv->getExactNumericValue();
if (repeatCount <= 0)
repeatCount = 1;
} else {
// 4116 The 2nd operand of REPEAT(o1, o2) is invalid
*CmpCommon::diags() << DgSqlCode(-4116) << DgString0(getTextUpper());
return NULL;
}
}
else
{
repeatCount = 1;
}
size_in_bytes = typ1.getNominalSize() * repeatCount;
size_in_chars = ctyp1.getStrCharLimit() * repeatCount;
// check size limit only for fixed character type
if ( ! typ1.isVaryingLen() ) {
if ( size_in_bytes > maxCharColLen ) {
*CmpCommon::diags() << DgSqlCode(-4129)
<< DgString0(getTextUpper());
return NULL;
}
} else // varchar. The nominal size of the result is
// the min of (size, maxCharColLen).
{
size_in_bytes = MINOF(maxCharColLen, size_in_bytes);
size_in_chars = size_in_bytes / CharInfo::minBytesPerChar(ctyp1.getCharSet());
}
}
else if (getMaxLength() > -1)
{
size_in_bytes = MINOF(maxCharColLen,
getMaxLength() * typ1.getNominalSize());
size_in_chars = size_in_bytes / CharInfo::minBytesPerChar(ctyp1.getCharSet());
}
else
{
// Assign some arbitrary max result size since we can't
// figure out the actual max size.
size_in_bytes = maxCharColLen;
size_in_chars = size_in_bytes / CharInfo::minBytesPerChar(ctyp1.getCharSet());
}
NAType *result =
new (HEAP) SQLVarChar(HEAP, CharLenInfo((Lng32)size_in_chars, (Lng32)size_in_bytes),
(typ1.supportsSQLnullLogical() ||
typ2.supportsSQLnullLogical()),
ctyp1.isUpshifted(),
ctyp1.isCaseinsensitive(),
ctyp1.getCharSet(),
ctyp1.getCollation(),
ctyp1.getCoercibility());
return result;
}
// -----------------------------------------------------------------------
// member functions for class Replace
// -----------------------------------------------------------------------
const NAType *Replace::synthesizeType()
{
//
// Type cast any params.
//
ValueId vid1 = child(0)->getValueId();
ValueId vid2 = child(1)->getValueId();
ValueId vid3 = child(2)->getValueId();
CharInfo::CharSet new_cs = getFirstKnownCharSet(vid1, vid2, vid3);
vid1.coerceType(NA_CHARACTER_TYPE, new_cs);
vid2.coerceType(NA_CHARACTER_TYPE, new_cs);
vid3.coerceType(NA_CHARACTER_TYPE, new_cs);
const NAType *typ1 = &(child(0)->getValueId().getType());
const NAType *typ2 = &(child(1)->getValueId().getType());
const NAType *typ3 = &(child(2)->getValueId().getType());
/* Soln-10-050426-7137 begin */
NAString defVal;
NABoolean charsetInference =
(CmpCommon::getDefault(INFER_CHARSET, defVal) == DF_ON);
if(charsetInference)
{
const CharType *replaceSource = (CharType *)typ1;
const CharType *replaceChar= (CharType *)typ2;
const CharType *replacingChar = (CharType *)typ3;
const CharType* desiredType =
CharType::findPushDownCharType(getDefaultCharSet,
replaceSource, replaceChar, replacingChar, 0);
if ( desiredType )
{
// push down charset and re-synthesize
vid1.coerceType((NAType&)*desiredType, NA_CHARACTER_TYPE);
vid2.coerceType((NAType&)*desiredType, NA_CHARACTER_TYPE);
vid3.coerceType((NAType&)*desiredType, NA_CHARACTER_TYPE);
// get the newly pushed-down types
typ1 = (CharType*)&vid1.getType();
typ2 = (CharType*)&vid2.getType();
typ3 = (CharType*)&vid3.getType();
}
}
/* Soln-10-050426-7137 end */
// typ3 does not need to be comparable, only compatible!
//
if (typ1->getTypeQualifier() != NA_CHARACTER_TYPE OR
NOT typ1->isCompatible(*typ3)) {
// 4064 The operands of a $0 function must be compatible character types.
// ##Should say "The FIRST and THIRD operands must be compatible..."
*CmpCommon::diags() << DgSqlCode(-4064) << DgString0(getTextForError());;
return NULL;
}
if (NOT typ1->isComparable(*typ2, this)) {
// 4063 The operands of a $0 function must be comparable character types.
// ##Should say "The FIRST and SECOND operands must be comparable..."
*CmpCommon::diags() << DgSqlCode(-4063) << DgString0(getTextForError());
return NULL;
}
const CharType *ctyp1 = (CharType *)typ1;
Lng32 minLength_in_bytes = ctyp1->getDataStorageSize();
Lng32 minLength_in_chars = ctyp1->getStrCharLimit();
Lng32 ctype2Length_in_bytes = ((CharType *)typ2)->getDataStorageSize();
Lng32 ctype3Length_in_bytes = ((CharType *)typ3)->getDataStorageSize();
Lng32 ctype2Length_in_chars = ((CharType *)typ2)->getStrCharLimit();
Lng32 ctype3Length_in_chars = ((CharType *)typ3)->getStrCharLimit();
if ( ctype2Length_in_bytes == 0 ) {
*CmpCommon::diags() << DgSqlCode(-8428) << DgString0(getTextForError());
return NULL;
}
// Fix for CR 10-000724-1369
// figure out result size.
Lng32 size_in_bytes = minLength_in_bytes;;
Lng32 size_in_chars = minLength_in_chars;
// NOTE: We are trying to find the MAX result size!
if ( ((CharType *)typ2)->isVaryingLen() )
{
ctype2Length_in_chars = 1; // Use *minimum* possible length
ctype2Length_in_bytes = 1; // Use *minimum* possible length
}
if ( ctyp1->getCharSet() == CharInfo::UNICODE )
{
if (ctype2Length_in_chars < ctype3Length_in_chars)
{
Int32 maxOccurrences = size_in_chars / ctype2Length_in_chars;
Int32 remainder = size_in_chars - (maxOccurrences * ctype2Length_in_chars);
size_in_chars = maxOccurrences * ctype3Length_in_chars + remainder;
size_in_bytes = size_in_chars * ctyp1->getBytesPerChar();
}
}
else
{
if (ctype2Length_in_chars < ctype3Length_in_chars)
{
Int32 maxOccurrences = size_in_chars / ctype2Length_in_chars;
Int32 remainder = size_in_chars - (maxOccurrences * ctype2Length_in_chars);
size_in_chars = maxOccurrences * ctype3Length_in_chars + remainder;
}
if (ctype2Length_in_bytes < ctype3Length_in_bytes)
{
Int32 maxOccurrences = size_in_bytes / ctype2Length_in_bytes;
Int32 remainder = size_in_bytes - (maxOccurrences * ctype2Length_in_bytes);
size_in_bytes = maxOccurrences * ctype3Length_in_bytes + remainder;
}
}
Int32 maxLenInBytes = CmpCommon::getDefaultNumeric(TRAF_MAX_CHARACTER_COL_LENGTH);
if (size_in_bytes > maxLenInBytes)
{
size_in_bytes = maxLenInBytes;
size_in_chars = size_in_bytes / CharInfo::minBytesPerChar(ctyp1->getCharSet());
}
CharLenInfo CLInfo( size_in_chars, size_in_bytes );
NAType *result =
new (HEAP) SQLVarChar(HEAP, CLInfo,
(typ1->supportsSQLnullLogical() ||
typ2->supportsSQLnullLogical() ||
typ3->supportsSQLnullLogical()),
ctyp1->isUpshifted(),
ctyp1->isCaseinsensitive(),
ctyp1->getCharSet(),
ctyp1->getCollation(),
ctyp1->getCoercibility());
return result;
}
// -----------------------------------------------------------------------
// member functions for class HashDistrib
// -----------------------------------------------------------------------
const NAType *HashDistrib::synthesizeType()
{
// Both operands (hash of the partitioning keys and number of partitions)
// must be exact numeric with scale 0. The result has values from 0 to
// <number of partitions> - 1 and therefore can always fit into the data
// type of the number of partitions.
const NAType &typ1 = child(0)->getValueId().getType();
const NAType &typ2 = child(1)->getValueId().getType();
if (typ1.getTypeQualifier() != NA_NUMERIC_TYPE OR
typ2.getTypeQualifier() != NA_NUMERIC_TYPE)
{
// 4045 Progressive Distribution function is only defined
// for numeric types.
*CmpCommon::diags() << DgSqlCode(-4045);
return NULL;
}
// now it's safe to cast the types to numeric type
const NumericType &ntyp1 = (NumericType &) typ1;
const NumericType &ntyp2 = (NumericType &) typ2;
if (NOT ntyp1.isExact() OR NOT ntyp2.isExact())
{
// 4046 Progessive Distribution function is only defined for
// exact numeric types.
*CmpCommon::diags() << DgSqlCode(-4046);
return NULL;
}
if (ntyp1.getScale() != 0 OR
ntyp2.getScale() != 0)
{
// 4047 Arguments of Progessive Distribution function must both
// have a scale of 0.
*CmpCommon::diags() << DgSqlCode(-4047);
return NULL;
}
NAType *result = typ2.newCopy(HEAP);
// the only thing the LHS contributes is that the result may become nullable
if (typ1.supportsSQLnullLogical()) result->setNullable(TRUE);
return result;
}
const NAType *ProgDistribKey::synthesizeType()
{
// return: Large Int.
return new HEAP SQLLargeInt(HEAP, TRUE, FALSE);
}
// -----------------------------------------------------------------------
// member functions for class PAGroup
// -----------------------------------------------------------------------
const NAType *PAGroup::synthesizeType()
{
// Both operands (pre-grouped number of partitions and number of groups)
// must be exact numeric with scale 0. The result has values from 0 to
// <number of groups> - 1 and therefore can always fit into the data
// type of the number of groups.
const NAType &typ1 = child(0)->getValueId().getType();
const NAType &typ2 = child(1)->getValueId().getType();
const NAType &typ3 = child(2)->getValueId().getType();
if (typ1.getTypeQualifier() != NA_NUMERIC_TYPE OR
typ2.getTypeQualifier() != NA_NUMERIC_TYPE OR
typ3.getTypeQualifier() != NA_NUMERIC_TYPE)
{
// 4045 PA Group function is only defined
// for numeric types.
*CmpCommon::diags() << DgSqlCode(-4045);
return NULL;
}
// now it's safe to cast the types to numeric type
const NumericType &ntyp1 = (NumericType &) typ1;
const NumericType &ntyp2 = (NumericType &) typ2;
const NumericType &ntyp3 = (NumericType &) typ3;
if (NOT ntyp1.isExact() OR NOT ntyp2.isExact() OR NOT ntyp3.isExact())
{
// 4046 PA Group function is only defined for
// exact numeric types.
*CmpCommon::diags() << DgSqlCode(-4046);
return NULL;
}
if (ntyp1.getScale() != 0 OR ntyp2.getScale() != 0 OR ntyp3.getScale() != 0)
{
// 4047 Arguments of the PA Group function must both
// have a scale of 0.
*CmpCommon::diags() << DgSqlCode(-4047);
return NULL;
}
NAType *result = typ1.newCopy(HEAP);
return result;
}
// -----------------------------------------------------------------------
// member functions for class Encode
// -----------------------------------------------------------------------
const NAType *CompEncode::synthesizeType()
{
ValueId vid = child(0)->getValueId();
const NAType &src = vid.getType();
// result of encode function is a non-nullable fixed char.
// Result is not nullable
// because null values are encoded too.
// Length of encode function is equal to length_ field, if it
// is set to a positive number. Otherwise, it is equal to the
// total size of operand.
Lng32 keyLength = 0;
NABoolean supportsSQLnull = FALSE;
if (regularNullability_)
{
// should not be common for CompEncode, preserve nullability of child
keyLength = src.getNominalSize();
supportsSQLnull = src.supportsSQLnull();
}
else
{
if (length_ < 0)
// common case for encode, include prefix fields but leave
// out the var len header (if any), which is not order-preserving
keyLength = src.getTotalSize() - src.getVarLenHdrSize();
else
keyLength = length_;
}
if (src.getTypeQualifier() != NA_CHARACTER_TYPE)
{
return new HEAP SQLChar(HEAP, keyLength, supportsSQLnull);
}
else
{
const CharType &cSrc = (CharType&)src;
CharInfo::Collation collation = cSrc.getCollation();
// set casesensitivity of encoding based on child's type.
// This may get overwritten by the caller (for example, to
// build a key for a predicate of the form: where keycol = 'val',
// both sides of the predicate must be caseinsensitive.
if (cSrc.isCaseinsensitive())
{
setCaseinsensitiveEncode(TRUE);
}
setEncodedCollation(cSrc.getCollation());
if (CollationInfo::isSystemCollation(collation))
{
keyLength =
CompEncode::getEncodedLength( collation,
collationType_,
child(0)->getValueId().getType().getNominalSize(),
cSrc.supportsSQLnull());
switch (collationType_)
{
case CollationInfo::Sort:
{
// in this case the encode is non nullable if not regularNullability
return new HEAP SQLChar(HEAP, keyLength,
supportsSQLnull);
}
case CollationInfo::Compare:
{
return new HEAP SQLChar(HEAP, keyLength,
cSrc.supportsSQLnull());
}
case CollationInfo::Search:
{
return new HEAP SQLVarChar(HEAP, keyLength,
cSrc.supportsSQLnull());
}
default:
{
CMPASSERT(0);
return NULL;
}
}
}
else
{
return new HEAP SQLChar(HEAP, keyLength, supportsSQLnull);
}
}
}
const NAType *CompDecode::synthesizeType()
{
if (unencodedType_)
return unencodedType_;
else
return CompEncode::synthesizeType();
}
// -----------------------------------------------------------------------
// member functions for class Extract
// -----------------------------------------------------------------------
const NAType *Extract::synthesizeType()
{
// Assert that we are bound, or created by Generator, so we have type info.
ValueId vid = child(0)->getValueId();
CMPASSERT(vid != NULL_VALUE_ID);
const DatetimeIntervalCommonType &dti =
(DatetimeIntervalCommonType &)vid.getType();
NABuiltInTypeEnum type = dti.getTypeQualifier();
if (type != NA_DATETIME_TYPE && type != NA_INTERVAL_TYPE) {
// 4036 The source field must be of DateTime or Interval type.
*CmpCommon::diags() << DgSqlCode(-4036);
if (getFieldFunction())
{
// 4062 The preceding error actually occurred in function $0~String0.
*CmpCommon::diags() << DgSqlCode(-4062) << DgString0(dti.getFieldName(getExtractField()));
}
return NULL;
}
if ( type != NA_DATETIME_TYPE )
{
enum rec_datetime_field eField = getExtractField();
NAString sErr;
if ( REC_DATE_WEEK == eField
|| REC_DATE_DOW == eField
|| REC_DATE_DOY == eField
|| REC_DATE_WOM == eField
|| REC_DATE_CENTURY == eField)
sErr = dti.getFieldName(eField);
if (sErr.length() > 0)
{
*CmpCommon::diags() << DgSqlCode(-4496) << DgString0(sErr);
return NULL;
}
}
// ANSI 6.6 SR 3a.
enum rec_datetime_field extractStartField = getExtractField();
enum rec_datetime_field extractEndField = extractStartField;
if (extractStartField > REC_DATE_MAX_SINGLE_FIELD)
{
// YEARQUARTER, YEARMONTH, or YEARWEEK
extractStartField = REC_DATE_YEAR;
if (extractEndField > REC_DATE_YEARMONTH_EXTRACT)
extractEndField = REC_DATE_DAY; // extracting week requires the day
else
extractEndField = REC_DATE_MONTH; // months/quarters need only the month
if (type == NA_INTERVAL_TYPE) // YEARQUARTER etc. are not supported on intervals
{
*CmpCommon::diags() << DgSqlCode(-4037)
<< DgString0(dti.getFieldName(getExtractField()))
<< DgString1(dti.getTypeSQLname(TRUE /*terse*/));
return NULL;
}
}
if ( !(extractStartField >=REC_DATE_CENTURY && extractStartField<=REC_DATE_WOM) )
{
if (dti.getStartField() > extractStartField ||
dti.getEndField() < extractEndField ||
!dti.isSupportedType()) {
// 4037 cannot extract field from type
*CmpCommon::diags() << DgSqlCode(-4037)
<< DgString0(dti.getFieldName(getExtractField()))
<< DgString1(dti.getTypeSQLname(TRUE /*terse*/));
return NULL;
}
}
// ANSI 6.6 SR 4. Precision is implementation-defined:
// EXTRACT(YEAR from datetime): result precision is 4 + scale
// EXTRACT(other from datetime): result precision is 2 + scale
// EXTRACT(startfield from interval): result precision is leading prec + scal
// EXTRACT(other from interval): result precision is 2 + scale
// where scale is 0 if extract field is not SECOND, else at least fract prec.
//
Lng32 prec, scale = 0;
if (type == NA_INTERVAL_TYPE && getExtractField() == dti.getStartField())
prec = dti.getLeadingPrecision();
else if (getExtractField() == REC_DATE_YEAR)
prec = 4; // YEAR field can be 9999 max
else if (getExtractField() == REC_DATE_YEARQUARTER_EXTRACT ||
getExtractField() == REC_DATE_YEARQUARTER_D_EXTRACT)
prec = 5; // YEARQUARTER is yyyyq
else if (getExtractField() == REC_DATE_YEARMONTH_EXTRACT ||
getExtractField() == REC_DATE_YEARMONTH_D_EXTRACT)
prec = 6; // YEARMONTH is yyyymm
else if (getExtractField() == REC_DATE_YEARWEEK_EXTRACT ||
getExtractField() == REC_DATE_YEARWEEK_D_EXTRACT)
prec = 6; // YEARMWEEK is yyyyww
else if (getExtractField() == REC_DATE_DECADE ||
getExtractField() == REC_DATE_DOY)
prec = 3;
else if (getExtractField() == REC_DATE_QUARTER ||
getExtractField() == REC_DATE_DOW)
prec = 1;
else if (getExtractField() == REC_DATE_EPOCH)
prec = 10;
else
prec = 2; // else max of 12, 31, 24, 59
if (getExtractField() == REC_DATE_SECOND) {
prec += dti.getFractionPrecision();
scale += dti.getFractionPrecision();
}
if (getExtractField() == REC_DATE_EPOCH)
{
prec += dti.getFractionPrecision();
scale += dti.getFractionPrecision();
}
NABoolean bNegValue = FALSE;
if (getExtractField() == REC_DATE_DECADE
|| getExtractField() == REC_DATE_QUARTER
|| getExtractField() == REC_DATE_EPOCH )
bNegValue = TRUE;
const Int16 disAmbiguate = 0; // added for 64bit project
return new HEAP
SQLNumeric(HEAP, (type == NA_INTERVAL_TYPE) || bNegValue, /*allowNegValues*/
prec,
scale,
disAmbiguate,
dti.supportsSQLnull());
}
// -----------------------------------------------------------------------
// member functions for class Increment
// -----------------------------------------------------------------------
const NAType *Increment::synthesizeType()
{
// It should get the type of its child
return &child(0)->getValueId().getType();
}
// -----------------------------------------------------------------------
// member functions for class Decrement
// -----------------------------------------------------------------------
const NAType *Decrement::synthesizeType()
{
return &child(0)->getValueId().getType();
}
// -----------------------------------------------------------------------
// member functions for class TriRelational
// -----------------------------------------------------------------------
const NAType *TriRelational::synthesizeType()
{
ItemExprList exprList1(child(0).getPtr(), HEAP);
ItemExprList exprList2(child(1).getPtr(), HEAP);
if (exprList1.entries() != exprList2.entries()) {
// 4042 The operands of a comparison predicate must be of equal degree.
*CmpCommon::diags() << DgSqlCode(-4042);
return NULL;
}
NABoolean allowsUnknown = FALSE;
for (CollIndex i = 0; i < exprList1.entries(); i++) {
//
// Type cast any params.
//
ValueId vid1 = exprList1[i]->getValueId();
ValueId vid2 = exprList2[i]->getValueId();
vid1.coerceType(vid2.getType(), NA_NUMERIC_TYPE);
vid2.coerceType(vid1.getType());
//
// Check that the operands are compatible.
//
const NAType& operand1 = vid1.getType();
const NAType& operand2 = vid2.getType();
if (NOT operand1.isCompatible(operand2)) {
// 4041 comparison between these two types is not allowed
emitDyadicTypeSQLnameMsg(-4041, operand1, operand2);
return NULL;
}
allowsUnknown = allowsUnknown OR
operand1.supportsSQLnullLogical() OR
operand2.supportsSQLnullLogical();
}
//
// is the third operand a boolean?
//
if (child(2)->getValueId().getType().getTypeQualifier() != NA_BOOLEAN_TYPE) {
// 4048 third arg of ternary comparison must be boolean
*CmpCommon::diags() << DgSqlCode(-4048) <<
DgString0(child(2)->getValueId().getType().getTypeSQLname(TRUE /*terse*/));
return NULL;
}
//
// Return the result.
//
return new HEAP SQLBooleanRelat(HEAP, allowsUnknown);
}
// -----------------------------------------------------------------------
// member functions for class RangeLookup
// -----------------------------------------------------------------------
const NAType *RangeLookup::synthesizeType()
{
// the result is a signed 32 bit number
return new HEAP SQLInt(HEAP, TRUE,FALSE);
}
// -----------------------------------------------------------------------
// member functions for class HostVar
// -----------------------------------------------------------------------
const NAType *HostVar::synthesizeType()
{
return getType();
}
// -----------------------------------------------------------------------
// member functions for class InverseOrder
// -----------------------------------------------------------------------
const NAType *InverseOrder::synthesizeType()
{
return &child(0)->getValueId().getType();
}
// member functions for class Like
// -----------------------------------------------------------------------
const NAType *PatternMatchingFunction::synthesizeType()
{
//
// Type cast any params.
//
ValueId vid1 = child(0)->getValueId();
ValueId vid2 = child(1)->getValueId();
ValueId vid3;
CharType * cType1 = 0;
CharType * cType2 = 0;
// if either side of LIKE was an untyped param, then assign it
// the same casesensitive attr, collation, and character set as the other side.
if ( vid1.getType().getTypeQualifier() != NA_UNKNOWN_TYPE &&
vid2.getType().getTypeQualifier() == NA_UNKNOWN_TYPE)
{
vid1.coerceType(NA_CHARACTER_TYPE);
cType1 = (CharType*)&vid1.getType();
vid2.coerceType(NA_CHARACTER_TYPE, cType1->getCharSet());
cType2 = (CharType*)&vid2.getType();
cType2->setCollation(cType1->getCollation());
cType2->setCaseinsensitive(cType1->isCaseinsensitive());
}
else if ( vid2.getType().getTypeQualifier() != NA_UNKNOWN_TYPE &&
vid1.getType().getTypeQualifier() == NA_UNKNOWN_TYPE)
{
vid2.coerceType(NA_CHARACTER_TYPE);
cType2 = (CharType*)&vid2.getType();
vid1.coerceType(NA_CHARACTER_TYPE, cType2->getCharSet());
cType1 = (CharType*)&vid1.getType();
cType1->setCollation(cType2->getCollation());
cType1->setCaseinsensitive(cType2->isCaseinsensitive());
}
else
{
vid1.coerceType(NA_CHARACTER_TYPE);
vid2.coerceType(NA_CHARACTER_TYPE);
}
const NAType *typ1 = &vid1.getType();
const NAType *typ2 = &vid2.getType();
const NAType *typ3 = NULL;
if (getArity() > 2) { // Escape clause was specified
vid3 = child(2)->getValueId();
const SQLChar charType(NULL, 1);
vid3.coerceType(charType);
typ3 = &vid3.getType();
}
// 2/13/98: make sure like pattern and source types are comparable.
const NAType& operand1 = vid1.getType();
const NAType& operand2 = vid2.getType();
const CharType *likeSource = (CharType*)&operand1;
const CharType *likePat = (CharType*)&operand2;
const CharType *escapeChar = ( getArity() > 2 ) ?
(CharType*)&(vid3.getType()) : 0;
NAString defVal;
NABoolean charsetInference =
(CmpCommon::getDefault(INFER_CHARSET, defVal) == DF_ON);
if(charsetInference)
{
const CharType* desiredType =
CharType::findPushDownCharType(getDefaultCharSet,
likeSource, likePat, escapeChar, 0);
if ( desiredType )
{
// push down charset and re-synthesize
vid1.coerceType((NAType&)*desiredType, NA_CHARACTER_TYPE);
vid2.coerceType((NAType&)*desiredType, NA_CHARACTER_TYPE);
if ( getArity() > 2 )
vid3.coerceType((NAType&)*desiredType, NA_CHARACTER_TYPE);
// get the newly pushed-down types
typ1 = &vid1.getType();
typ2 = &vid2.getType();
typ3 = ( getArity() > 2 ) ? &vid3.getType() : 0;
}
}
// Check that the operands are comparable.
//
if (NOT typ1->isComparable(*typ2, this, NAType::EmitErrIfAnyChar) OR
(typ3 AND
NOT typ1->isComparable(*typ3, this, NAType::EmitErrIfAnyChar)) OR
typ1->getTypeQualifier() != NA_CHARACTER_TYPE) {
// 4050 The operands of a LIKE predicate must be comparable character types.
*CmpCommon::diags() << DgSqlCode(-4050) << DgString0("LIKE");
return NULL;
}
// If any of the arguments can be nullable then LIKE can evaluate to Unknown
NABoolean allowsUnknown = typ1->supportsSQLnull() OR
typ2->supportsSQLnull() OR
(typ3 AND
typ3->supportsSQLnull());
return new HEAP SQLBooleanRelat(HEAP, allowsUnknown);
}
// -----------------------------------------------------------------------
// member functions for classes Lower and Upper`
// -----------------------------------------------------------------------
const NAType *Lower::synthesizeType()
{
//
// Type cast any params.
//
ValueId vid = child(0)->getValueId();
vid.coerceType(NA_CHARACTER_TYPE);
//
// Check that the operands are compatible.
//
const NAType& operand = vid.getType();
if (operand.getTypeQualifier() != NA_CHARACTER_TYPE) {
// 4043 The operand of a LOWER function must be character.
*CmpCommon::diags() << DgSqlCode(-4043) << DgString0(getTextForError());
return NULL;
}
CharType *ct = (CharType *)&operand;
if ( CharInfo::is_NCHAR_MP(ct->getCharSet()) ) {
// 3217: Character set KANJI/KSC5601 is not allowed in the LOWER function.
*CmpCommon::diags() << DgSqlCode(-3217)
<< DgString0(CharInfo::getCharSetName(ct->getCharSet()))
<< DgString1("LOWER");
}
if ((ct->isUpshifted()) ||
(ct->isCaseinsensitive())) {
ct = (CharType *)ct->newCopy(HEAP);
if (ct->isUpshifted())
ct->setUpshifted(FALSE);
if (ct->isCaseinsensitive())
ct->setCaseinsensitive(TRUE);
}
//
// For UTF8 strings, we must make the TYPE be a VARCHAR because there are certain
// UCS2 characters (e.g. 0x0130) where the value of LOWER is actually fewer bytes in
// length than the original character!
//
if (ct->getCharSet() == CharInfo::UTF8) {
// NOTE: See comment near end of Upper::synthesizeType() for reason we don't multiply by 3 here.
ct = new (HEAP) SQLVarChar(HEAP, CharLenInfo(ct->getStrCharLimit(), (ct->getDataStorageSize()))
,ct->supportsSQLnull()
,ct->isUpshifted()
,ct->isCaseinsensitive()
,ct->getCharSet()
,ct->getCollation()
,ct->getCoercibility()
);
}
return ct;
}
const NAType *Upper::synthesizeType()
{
//
// Type cast any params.
//
ValueId vid = child(0)->getValueId();
vid.coerceType(NA_CHARACTER_TYPE);
//
// Check that the operands are compatible.
//
const NAType& operand = vid.getType();
if (operand.getTypeQualifier() != NA_CHARACTER_TYPE) {
// 4043 The operand of an UPPER function must be character.
*CmpCommon::diags() << DgSqlCode(-4043) << DgString0(getTextForError());
return NULL;
}
CharType *ct = (CharType *)&operand;
if ( CharInfo::is_NCHAR_MP(ct->getCharSet()) ) {
*CmpCommon::diags() << DgSqlCode(-3217)
<< DgString0(CharInfo::getCharSetName(ct->getCharSet()))
<< DgString1("UPPER");
}
if (NOT ct->isUpshifted()) {
ct = (CharType *)ct->newCopy(HEAP);
ct->setUpshifted(TRUE);
}
if (ct->getCharSet() == CharInfo::UNICODE) {
ct = new (HEAP) SQLVarChar(HEAP, 3*(ct->getStrCharLimit())
,ct->supportsSQLnull()
,ct->isUpshifted()
,ct->isCaseinsensitive()
,ct->getCharSet()
,ct->getCollation()
,ct->getCoercibility()
);
}
if (ct->getCharSet() == CharInfo::UTF8) {
//
// NOTE: For some UCS2 characters, the UPPER function can produce *three* UCS2 characters
// and for that reason, the UPPER function provides for 3 times as much output as the
// input string is long. HOWEVER, such is never the case for the LOWER function.
//
ct = new (HEAP) SQLVarChar(HEAP, CharLenInfo(3*ct->getStrCharLimit(), 3*(ct->getDataStorageSize()))
,ct->supportsSQLnull()
,ct->isUpshifted()
,ct->isCaseinsensitive()
,ct->getCharSet()
,ct->getCollation()
,ct->getCoercibility()
);
}
return ct;
}
// -----------------------------------------------------------------------
// member functions for class NATypeToItem
// -----------------------------------------------------------------------
const NAType * NATypeToItem::synthesizeType()
{
return natype_pointer;
};
const NAType*
NATypeToItem::pushDownType(NAType& newType,
enum NABuiltInTypeEnum defaultQualifier)
{
return &newType;
}
// -----------------------------------------------------------------------
// member functions for class OctetLength
// -----------------------------------------------------------------------
const NAType *OctetLength::synthesizeType()
{
//
// Type cast any params.
//
ValueId vid = child(0)->getValueId();
vid.coerceType(NA_CHARACTER_TYPE);
//
// Check that the operands are compatible.
//
const NAType& operand = vid.getType();
if (operand.getTypeQualifier() != NA_CHARACTER_TYPE) {
// 4043 The operand of an OCTET_LENGTH function must be character.
*CmpCommon::diags() << DgSqlCode(-4043) << DgString0(getTextUpper());
return NULL;
}
const CharType* charOperand = (CharType*)&(vid.getType());
NAString defVal;
NABoolean charsetInference =
(CmpCommon::getDefault(INFER_CHARSET, defVal) == DF_ON);
if(charsetInference)
{
const CharType* desiredType =
CharType::findPushDownCharType(getDefaultCharSet, charOperand, 0);
if ( desiredType )
{
// push down charset and re-synthesize
vid.coerceType((NAType&)*desiredType, NA_CHARACTER_TYPE);
// get the newly pushed-down types
charOperand = (CharType*)&(vid.getType());
}
}
if ( charOperand -> getCharSet() == CharInfo::UnknownCharSet ) {
*CmpCommon::diags() << DgSqlCode(-4127);
return NULL;
}
//
// Return the result.
//
return new HEAP SQLInt(HEAP, FALSE // unsigned
,operand.supportsSQLnullLogical()
);
}
// -----------------------------------------------------------------------
// member functions for class PositionFunc
// -----------------------------------------------------------------------
const NAType *PositionFunc::synthesizeType()
{
//
// Type cast any params.
//
ValueId vid1 = child(0)->getValueId();
ValueId vid2 = child(1)->getValueId();
CharInfo::CharSet new_cs = getFirstKnownCharSet(vid1, vid2, vid2);
vid1.coerceType(NA_CHARACTER_TYPE, new_cs);
vid2.coerceType(NA_CHARACTER_TYPE, new_cs);
const NAType *operand1 = &vid1.getType();
const NAType *operand2 = &vid2.getType();
const NAType *operand3 = NULL;
const NAType *operand4 = NULL;
//
// Check that the operands are comparable.
// ##Hmm, Ansi 6.6 does NOT say they need to be comparable,
// ##just compatible (same char repertoire, i.e. same charset),
// ##but that must be a mistake (we need string =ity testing
// ##to do POSITION, so the collations will need to be the same)...
//
/*
if (NOT operand1.isComparable(operand2, this, NAType::EmitErrIfAnyChar) ||
operand1.getTypeQualifier() != NA_CHARACTER_TYPE ||
operand2.getTypeQualifier() != NA_CHARACTER_TYPE) {
// 4063 The operands of a $0 function must be comparable character types.
*CmpCommon::diags() << DgSqlCode(-4063) << DgString0(getTextForError());
return NULL;
}
*/
if (operand1->getTypeQualifier() != NA_CHARACTER_TYPE OR
operand2->getTypeQualifier() != NA_CHARACTER_TYPE) {
// 4063 The operands of a POSITION function must be character.
*CmpCommon::diags() << DgSqlCode(-4063) << DgString0(getTextForError());
return NULL;
}
// 1/5/98: make sure position pattern and source types are comparable.
const CharType *posPat = (CharType*)operand1;
const CharType *posSource = (CharType*)operand2;
NAString defVal;
NABoolean charsetInference =
(CmpCommon::getDefault(INFER_CHARSET, defVal) == DF_ON);
if(charsetInference)
{
// 9/24/98: charset inference
const CharType* desiredType =
CharType::findPushDownCharType(getDefaultCharSet,
posPat, posSource, 0);
if ( desiredType )
{
// push down charset and re-synthesize
vid1.coerceType((NAType&)*desiredType, NA_CHARACTER_TYPE);
vid2.coerceType((NAType&)*desiredType, NA_CHARACTER_TYPE);
// get the newly pushed-down types
/*
posPat = (CharType*)&(vid1.getType());
posSource = (CharType*)&(vid2.getType());
*/
operand1 = &vid1.getType();
operand2 = &vid2.getType();
}
}
/*
if ( ! (posPat->isComparable(*posSource, TRUE)) ) { // }
*/
if ( ! (operand1->isComparable(*operand2, this, NAType::EmitErrIfAnyChar)) ) {
// 4063 The operands of a POSITION function must be character.
*CmpCommon::diags() << DgSqlCode(-4063) << DgString0(getTextForError());
return NULL;
}
//
// Return the result.
//
return new HEAP
SQLInt(HEAP, FALSE, // unsigned
operand1->supportsSQLnullLogical() ||
operand2->supportsSQLnullLogical()
);
}
// -----------------------------------------------------------------------
// member functions for class Substring
// -----------------------------------------------------------------------
const NAType *Substring::synthesizeType()
{
//
// Type cast any params.
//
ValueId vid1 = child(0)->getValueId();
ValueId vid2 = child(1)->getValueId();
vid1.coerceType(NA_CHARACTER_TYPE);
SQLInt si(NULL);
vid2.coerceType(si, NA_NUMERIC_TYPE);
if (getArity() == 3)
{
ValueId vid3 = child(2)->getValueId();
vid3.coerceType(si, NA_NUMERIC_TYPE);
}
const NAType *operand1 = &child(0)->getValueId().getType();
const NAType *operand2 = &child(1)->getValueId().getType();
const NAType *operand3 = NULL;
if (getArity() == 3)
{
operand3 = &child(2)->getValueId().getType();
}
if ((operand1->getTypeQualifier() != NA_CHARACTER_TYPE) &&
(operand1->getFSDatatype() != REC_CLOB)) {
// 4051 The first operand of a SUBSTRING function must be character.
*CmpCommon::diags() << DgSqlCode(-4051) << DgString0(getTextUpper());
return NULL;
}
if (operand2->getTypeQualifier() != NA_NUMERIC_TYPE) {
// 4052 The second operand of a SUBSTRING function must be numeric.
*CmpCommon::diags() << DgSqlCode(-4052) << DgString0(getTextUpper());
return NULL;
}
if (((NumericType*)operand2)->getScale() != 0) {
// 4047 The second operand of a SUBSTRING function must have a scale of 0.
*CmpCommon::diags() << DgSqlCode(-4047) << DgString0(getTextUpper());
return NULL;
}
if (operand3) {
if (operand3->getTypeQualifier() != NA_NUMERIC_TYPE) {
// 4053 The third operand of a SUBSTRING function must be numeric.
*CmpCommon::diags() << DgSqlCode(-4053) << DgString0(getTextUpper());
return NULL;
}
if (((NumericType*)operand3)->getScale() != 0) {
// 4047 The third operand of a SUBSTR function must have a scale of 0.
*CmpCommon::diags() << DgSqlCode(-4047) << DgString0(getTextUpper());
return NULL;
}
}
CharInfo::CharSet op1_cs = operand1->getCharSet();
/*
((operand1->getFSDatatype() == REC_CLOB) ?
((SQLClob*)operand1)->getCharSet() :
((CharType *)operand1)->getCharSet());
*/
const CharType *charOperand = (CharType *) operand1;
Lng32 maxLength_bytes = charOperand->getDataStorageSize();
Lng32 maxLength_chars = charOperand->getPrecisionOrMaxNumChars();
if ( maxLength_chars <= 0 ) // If unlimited
maxLength_chars = maxLength_bytes / CharInfo::minBytesPerChar(op1_cs);
NABoolean negate;
Lng32 pos = 0;
{
// The position arg is allowed to be negative (see Ansi 6.7 GR 1).
ConstValue *cv = child(1)->castToConstValue(negate);
// adjust the max length for the result only if it is a positive start position.
// solu 10-030603-6815.
if (cv && negate == FALSE) {
if (cv->canGetExactNumericValue()) {
Int64 pos64 = cv->getExactNumericValue();
if (pos64 <= MINOF(maxLength_chars,INT_MAX)) {
pos = int64ToInt32(pos64);
if ((pos-1) > 0) {
maxLength_chars -= (pos-1); // shorten max
maxLength_bytes -= (pos-1) * CharInfo::minBytesPerChar(op1_cs);
if ( maxLength_bytes > charOperand->getDataStorageSize() )
maxLength_bytes = charOperand->getDataStorageSize() ;
}
} // value is in bounds
} // can get exact numeric
} // constant pos op
} // position operand
NABoolean resultIsFixedChar = FALSE;
Lng32 length = 0;
Int64 length64 = 0;
if (operand3) {
ConstValue *cv = child(2)->castToConstValue(negate);
if (cv) {
if (negate) {
// 8403 The length arg of a SUBSTRING function cannot be less than zero.
*CmpCommon::diags() << DgSqlCode(-8403);
return NULL;
}
if (cv->canGetExactNumericValue()) {
length64 = cv->getExactNumericValue();
if (length64 <= INT_MAX) {
length = int64ToInt32(length64);
if (maxLength_chars > length) {
maxLength_chars = length;
maxLength_bytes = MINOF(maxLength_bytes, length * CharInfo::maxBytesPerChar(op1_cs));
}
} // value is in bounds
} // can get exact numeric
} // constant length op
} // length operand specified
/*
length64 = length;
if ((NOT DFS2REC::isAnyVarChar(operand1->getFSDatatype())) &&
(pos > 0) &&
(length64 > 0) &&
((pos + length64 - 1) <= maxLength))
resultIsFixedChar = TRUE;
*/
// 12/22/97: the substring inherits the charset, collation and
// coercibility from the source string.
/* if (resultIsFixedChar)
return new HEAP
SQLChar(maxLength,
operand1->supportsSQLnull() OR
operand2->supportsSQLnull() OR
((operand3 != NULL) AND operand3->supportsSQLnull())
,charOperand->isUpshifted()
,charOperand->isCaseinsensitive()
,FALSE
,charOperand->getCharSet()
,charOperand->getCollation()
,charOperand->getCoercibility()
);
else
*/
if (operand1->getFSDatatype() == REC_CLOB)
{
return new HEAP
SQLClob(HEAP, maxLength_bytes, Lob_Invalid_Storage,
operand1->supportsSQLnull() OR
operand2->supportsSQLnull() OR
((operand3 != NULL) AND operand3->supportsSQLnull()));
}
else
{
return new HEAP
SQLVarChar(HEAP, CharLenInfo(maxLength_chars, maxLength_bytes), // OLD: maxLength
operand1->supportsSQLnull() OR
operand2->supportsSQLnull() OR
((operand3 != NULL) AND operand3->supportsSQLnull())
,charOperand->isUpshifted()
,charOperand->isCaseinsensitive()
,operand1->getCharSet()
,charOperand->getCollation()
,charOperand->getCoercibility()
);
}
}
// -----------------------------------------------------------------------
// member functions for class Trim
// -----------------------------------------------------------------------
const NAType *Trim::synthesizeType()
{
//
// Type cast any params.
//
ValueId vid1 = child(0)->getValueId();
ValueId vid2 = child(1)->getValueId();
CharInfo::CharSet new_cs = getFirstKnownCharSet(vid1, vid2, vid2);
vid1.coerceType(NA_CHARACTER_TYPE, new_cs);
vid2.coerceType(NA_CHARACTER_TYPE, new_cs);
if (vid1.getType().getTypeQualifier() != NA_CHARACTER_TYPE ||
vid2.getType().getTypeQualifier() != NA_CHARACTER_TYPE)
{
//4133: Both trim character and source have to be CHARACTER typed.
*CmpCommon::diags() << DgSqlCode(-4133);
return NULL;
}
//
// Check that the operands are compatible.
//
const CharType *trimChar = (const CharType *)&vid1.getType();
const CharType *trimSource = (const CharType *)&vid2.getType();
// charset inference
if ( trimChar->getCharSet() == CharInfo::UnknownCharSet &&
trimSource->getCharSet() != CharInfo::UnknownCharSet
)
{
// Special case for MP NCHAR when the default trim character is
// a single single-byte character like ' '. Here we prepend a space
// character to the local string copy (locale_string) inside
// the constant value holding the sinlge byte trim character. During
// invocation of vid1.coerceType(), the newly fabricated double-byte
// trim character will be instantiated in the constant value object.
if (CharInfo::is_NCHAR_MP(trimSource->getCharSet()) &&
vid1.getItemExpr()-> getOperator() == ITM_CONSTANT)
{
ConstValue* trimCharValue = (ConstValue*)vid1.getItemExpr();
if ( trimCharValue -> getStorageSize() == 1) {
trimCharValue->getLocaleString()->prepend(' ');
}
}
vid1.coerceType(*trimSource, NA_CHARACTER_TYPE);
trimChar = (CharType*)&vid1.getType();
} else
if ( trimChar->getCharSet() != CharInfo::UnknownCharSet &&
trimSource->getCharSet() == CharInfo::UnknownCharSet
)
{
vid2.coerceType(*trimChar, NA_CHARACTER_TYPE);
trimSource = (CharType*)&vid2.getType();
} else
if ( trimChar->getCharSet() == CharInfo::UnknownCharSet &&
trimSource->getCharSet() == CharInfo::UnknownCharSet
)
{
const CharType* desiredType =
CharType::findPushDownCharType(getDefaultCharSet, 0);
vid1.coerceType(*desiredType, NA_CHARACTER_TYPE);
trimChar = (CharType*)&vid1.getType();
vid2.coerceType(*trimChar, NA_CHARACTER_TYPE);
trimSource = (CharType*)&vid2.getType();
}
if (NOT trimChar->isComparable(*trimSource, this, NAType::EmitErrIfAnyChar)) {
// Per Ansi 6.7 SR 6(f), trim source and trim char must be comparable.
//
// 4063 The operands of a $0 function must be comparable character types.
*CmpCommon::diags() << DgSqlCode(-4063) << DgString0(getTextForError());
return NULL;
}
// Per Ansi 6.7 SR 6(g,h), the result
// takes the collation and coercibility of the trim source.
//
Int32 size = trimSource->getDataStorageSize();
return new HEAP
SQLVarChar(HEAP, CharLenInfo(trimSource->getStrCharLimit(), size )
,trimChar->supportsSQLnull() OR trimSource->supportsSQLnull()
,trimSource->isUpshifted()
,trimSource->isCaseinsensitive()
,trimSource->getCharSet()
,trimSource->getCollation()
,trimSource->getCoercibility()
);
}
// -----------------------------------------------------------------------
// member functions for class UnLogic
// -----------------------------------------------------------------------
const NAType *UnLogic::synthesizeType()
{
NABoolean allowsUnknown = FALSE;
// All Unary Ops evaluate to TRUE/FALSE except NOT which can also
// evaluate to UNKNOWN
switch(getOperatorType())
{
case ITM_NOT:
{
CMPASSERT(child(0).getValueId().getType().getTypeQualifier() == NA_BOOLEAN_TYPE);
const SQLBooleanRelat& operand0 = (SQLBooleanRelat &) child(0).getValueId().getType();
allowsUnknown = operand0.canBeSQLUnknown();
break;
}
case ITM_IS_UNKNOWN:
case ITM_IS_NOT_UNKNOWN:
case ITM_IS_FALSE:
case ITM_IS_TRUE:
CMPASSERT(child(0).getValueId().getType().getTypeQualifier() == NA_BOOLEAN_TYPE);
// Falling throuuuuuuuuuu
case ITM_IS_NULL:
case ITM_IS_NOT_NULL:
allowsUnknown = FALSE;
break;
default:
CMPASSERT(0); // Case not handled
break;
}
return new HEAP SQLBooleanRelat(HEAP, allowsUnknown);
}
// -----------------------------------------------------------------------
// member functions for class Translate
// -----------------------------------------------------------------------
const NAType *Translate::synthesizeType()
{
//
// Type cast any params.
//
ValueId vid = child(0)->getValueId();
vid.coerceType(NA_CHARACTER_TYPE);
//
// Check that the operands are compatible.
//
const NAType& operand = vid.getType();
if (operand.getTypeQualifier() != NA_CHARACTER_TYPE) {
// 4043 The operand of an UPPER function must be character.
*CmpCommon::diags() << DgSqlCode(-4043) << DgString0(getTextUpper());
return NULL;
}
const CharType *translateSource = (CharType*)&operand;
// pushdown ISO88591 if the charset is unknown at this time.
switch ( getTranslateMapTableId() ) {
case ISO88591_TO_UNICODE:
case SJIS_TO_UCS2:
case UTF8_TO_UCS2: case UTF8_TO_ISO88591: case UTF8_TO_SJIS:
case SJIS_TO_UNICODE:
case ISO88591_TO_UTF8:
case SJIS_TO_UTF8:
if ( translateSource->getCharSet() == CharInfo::UnknownCharSet)
{
CharInfo::CharSet assumedSrcCS = CharInfo::ISO88591;
switch (getTranslateMapTableId())
{
case SJIS_TO_UCS2: case SJIS_TO_UNICODE: case SJIS_TO_UTF8:
assumedSrcCS = CharInfo::SJIS; break;
case UTF8_TO_UCS2: case UTF8_TO_ISO88591: case UTF8_TO_SJIS:
assumedSrcCS = CharInfo::UTF8; break;
default:
break;
}
vid.coerceType(*CharType::desiredCharType(assumedSrcCS),
NA_CHARACTER_TYPE
);
translateSource = (CharType*)&vid.getType();
}
break;
case UCS2_TO_SJIS:
case UCS2_TO_UTF8:
case UNICODE_TO_SJIS:
case UNICODE_TO_ISO88591:
case KANJI_MP_TO_ISO88591:
case KSC5601_MP_TO_ISO88591:
if ( translateSource->getCharSet() == CharInfo::UnknownCharSet )
{
vid.coerceType(*CharType::desiredCharType(CharInfo::UNICODE),
NA_CHARACTER_TYPE
);
translateSource = (CharType*)&vid.getType();
}
break;
}
CharInfo::CharSet charsetTarget = CharInfo::UnknownCharSet;
NAString err4106arg(CmpCommon::statementHeap());
switch (getTranslateMapTableId()) {
case ISO88591_TO_UNICODE:
case SJIS_TO_UCS2:
case UTF8_TO_UCS2:
case SJIS_TO_UNICODE:
if (translateSource->getCharSet() == CharInfo::ISO88591
|| translateSource->getCharSet() == CharInfo::UTF8
|| translateSource->getCharSet() == CharInfo::SJIS
)
{
charsetTarget = CharInfo::UNICODE;
}
else
switch (getTranslateMapTableId()) {
case UTF8_TO_UCS2:
err4106arg = SQLCHARSETSTRING_UTF8; break;
case SJIS_TO_UCS2:
case SJIS_TO_UNICODE:
err4106arg = SQLCHARSETSTRING_SJIS; break;
case ISO88591_TO_UNICODE:
default:
err4106arg = SQLCHARSETSTRING_ISO88591; break;
}
break;
case UNICODE_TO_SJIS:
if (translateSource->getCharSet() == CharInfo::UNICODE)
charsetTarget = CharInfo::SJIS;
else
err4106arg = SQLCHARSETSTRING_UNICODE;
break;
case UNICODE_TO_ISO88591:
if (translateSource->getCharSet() == CharInfo::UNICODE)
charsetTarget = CharInfo::ISO88591;
else
err4106arg = SQLCHARSETSTRING_UNICODE;
break;
case UCS2_TO_SJIS:
if (translateSource->getCharSet() == CharInfo::UNICODE)
charsetTarget = CharInfo::SJIS;
else
err4106arg = SQLCHARSETSTRING_UNICODE;
break;
case UCS2_TO_UTF8:
if (translateSource->getCharSet() == CharInfo::UNICODE)
charsetTarget = CharInfo::UTF8;
else
err4106arg = SQLCHARSETSTRING_UNICODE;
break;
case KANJI_MP_TO_ISO88591:
if (translateSource->getCharSet() == CharInfo::KANJI_MP)
charsetTarget = CharInfo::ISO88591;
else
err4106arg = SQLCHARSETSTRING_KANJI;
break;
case KSC5601_MP_TO_ISO88591:
if (translateSource->getCharSet() == CharInfo::KSC5601_MP)
charsetTarget = CharInfo::ISO88591;
else
err4106arg = SQLCHARSETSTRING_KSC5601;
break;
case UTF8_TO_SJIS:
if ( (translateSource->getCharSet() == CharInfo::UTF8) ||
(translateSource->getCharSet() == CharInfo::ISO88591) )
charsetTarget = CharInfo::SJIS;
else
err4106arg = SQLCHARSETSTRING_UTF8;
break;
case GBK_TO_UTF8:
if (translateSource->getCharSet() == CharInfo::GBK )
charsetTarget = CharInfo::UTF8;
else
err4106arg = SQLCHARSETSTRING_GBK;
break;
case ISO88591_TO_UTF8:
if (translateSource->getCharSet() == CharInfo::ISO88591)
{
charsetTarget = CharInfo::UTF8;
}
else
err4106arg = SQLCHARSETSTRING_ISO88591;
break;
case UTF8_TO_ISO88591:
if ( (translateSource->getCharSet() == CharInfo::UTF8) ||
(translateSource->getCharSet() == CharInfo::ISO88591) )
charsetTarget = CharInfo::ISO88591;
else
err4106arg = SQLCHARSETSTRING_UTF8;
break;
default:
// 4105 Unknown translation
*CmpCommon::diags() << DgSqlCode(-4105);
return NULL;
}
if (charsetTarget != CharInfo::UnknownCharSet)
{
Lng32 resultLen =
CharInfo::getMaxConvertedLenInBytes(translateSource->getCharSet(),
translateSource->getNominalSize(),
charsetTarget);
return new HEAP SQLVarChar(HEAP, CharLenInfo(translateSource->getStrCharLimit(), resultLen),
TRUE, FALSE,
translateSource->isCaseinsensitive(),
charsetTarget,
CharInfo::DefaultCollation,
CharInfo::IMPLICIT); // ANSI 6.7 SR 5b
}
*CmpCommon::diags() << DgSqlCode(-4106)
<< DgString0(getTextUpper()) << DgString1(err4106arg);
return NULL;
}
// -----------------------------------------------------------------------
// member functions for class ValueIdUnion
// -----------------------------------------------------------------------
const NAType *ValueIdUnion::synthesizeType()
{
const NAType *result = NULL;
CollIndex i = 0;
// if this is the case of insert values list tuples, then
// isTrueUnion() will not be set and isCastTo() will be set.
// Last entry of sources_ valueidlist will be set to target valueId,
// it is set in method TupleList::bindNode.
// Validate that each source entry is compatible with target type.
if ((NOT isTrueUnion()) &&
(isCastTo()))
{
result = &getSource(entries()-1).getType();
const NAType& opR = *result;
for (i = 0; i < entries()-1; i++)
{
getSource(i).coerceType(*result);
ValueId vidI = getSource(i);
const NAType& opI = vidI.getType();
if ((NOT opR.isCompatible(opI)) &&
(CmpCommon::getDefault(ALLOW_INCOMPATIBLE_OPERATIONS) == DF_OFF))
{
// 4055 The select lists or tuples must have compatible data types.
emitDyadicTypeSQLnameMsg(-4055, opR, opI);
return NULL;
}
} // for
return result;
}
for (i = 0; i < entries(); i++) {
result = &getSource(i).getType();
if (result->getTypeQualifier() != NA_UNKNOWN_TYPE)
break;
}
CMPASSERT(result);
if (result->getTypeQualifier() == NA_UNKNOWN_TYPE)
return result->newCopy(HEAP);
CollIndex r = i; // the r'th source was the first non-unknown
for (i = 0; i < entries(); i++) {
if (i != r) { // r'th source started it all, we did it already
getSource(i).coerceType(*result);
ValueId vidi = getSource(i);
const NAType& opR = *result; // save operand BEFORE synth
const NAType& opI = vidi.getType();
UInt32 flags =
((CmpCommon::getDefault(LIMIT_MAX_NUMERIC_PRECISION) == DF_ON)
? NAType::LIMIT_MAX_NUMERIC_PRECISION : 0);
if (CmpCommon::getDefault(TYPE_UNIONED_CHAR_AS_VARCHAR) == DF_ON)
flags |= NAType::MAKE_RESULT_VARCHAR;
if (CmpCommon::getDefault(MODE_SPECIAL_4) == DF_ON)
{
flags |= NAType::MODE_SPECIAL_4;
}
result = result->synthesizeType(SYNTH_RULE_UNION, opR, opI, HEAP, &flags);
if (!result) {
// 4055 The select lists or tuples must have compatible data types.
emitDyadicTypeSQLnameMsg(-4055, opR, opI);
//## Here, also emit errmsg 4034 w/ unparse?
return NULL;
}
else if (getUnionFlags() == Union::UNION_DISTINCT) {
if (NOT opR.isComparable(opI, this)) {
// 4134 The operation (x UNION y) is not allowed. Try UNION ALL.
*CmpCommon::diags() << DgSqlCode(-4134)
<< DgString0(getText(USER_FORMAT_DELUXE));
return NULL;
}
}
}
}
return result;
}
// ValueIdUnion::pushDownType() -----------------------------------
// Propagate type information down the ItemExpr tree. This method
// is called by coerceType(). It will attempt to coerce (a recursive call)
// the type of each member of the ValueIdUnion to the desired type.
// This only has an effect when none of the members of the ValueIdUnion
// could be typed bottom up. An example query that illustrates this
// is:
// Select NULL from t1
// Union all
// Select NULL from t2
// Union all
// Select c from t3;
//
// This results in a tree of ValueIdUnion nodes:
// ValueIdUnion(c (ValueIdUnion(Null, Null)));
//
// The inner ValueIdUnion node can not be typed bottom up, but
// the outer ValueIdUnion node will attempt to coerce the type of
// the inner node. This will in turn (through pushDownType) coerce
// the types of the members (NULLs) of the inner ValueIdUnion node
// and re-synthesize the Type of the inner ValueIdUnion node.
//
//
const NAType *
ValueIdUnion::pushDownType(NAType& desiredType,
enum NABuiltInTypeEnum defaultQualifier)
{
for(CollIndex i = 0; i < entries(); i++) {
getSource(i).coerceType(desiredType, defaultQualifier);
}
return (NAType *)synthesizeType();
}
const NAType *
RowsetArrayScan::pushDownType(NAType& desiredType,
enum NABuiltInTypeEnum defaultQualifier)
{
elemType_ = &desiredType;
const NAType *newType = child(0)->pushDownType(desiredType, desiredType.getTypeQualifier());
child(0)->getValueId().changeType(newType);
//BEGIN 10-050523-8022
//When datatype has constraint NOT_NULL_DROPPABLE , getting the
//null indicator from
//supportsSQLnullogical was leading to truncation of host data in
//ExRowsetArrayScan::eval function of file exp_function.cpp.
elemNullInd_ = desiredType.supportsSQLnull();
//End 10-050523-8022
return &desiredType;
}
const NAType *
HostVar::pushDownType(NAType& desiredType,
enum NABuiltInTypeEnum defaultQualifier)
{
// If this is a rowset host var, we need to propagate the desired type into it
if (varType_->getTypeQualifier() == NA_ROWSET_TYPE) {
SQLRowset *rw1 = (SQLRowset *) varType_;
SQLRowset *rw2 = new HEAP SQLRowset(HEAP, &desiredType, rw1->getMaxNumElements(),
rw1->getNumElements());
NAType *tempType = &desiredType;
rw2->setNullable(*tempType);
varType_ = rw2;
return rw2;
}
return &desiredType;
}
// -----------------------------------------------------------------------
// member functions for class ValueIdProxy
// -----------------------------------------------------------------------
const NAType *ValueIdProxy::synthesizeType()
{
const NAType *proxyType = &getOutputId().getType();
return proxyType->newCopy(HEAP);
}
// Propagate type information down the node we are Proxy for.
// Called by coerceType().
//
const NAType *
ValueIdProxy::pushDownType(NAType& desiredType,
enum NABuiltInTypeEnum defaultQualifier)
{
outputValueId_.coerceType(desiredType, defaultQualifier);
return (NAType *)synthesizeType();
}
// -----------------------------------------------------------------------
// member functions for class VEGPredicate
// -----------------------------------------------------------------------
const NAType *VEGPredicate::synthesizeType()
{
return new HEAP SQLBooleanRelat(HEAP);
}
// -----------------------------------------------------------------------
// member functions for class VEGReference
// $$$ WORK REMAINING TO BE DONE:
// $$$ compute the intersection of the datatypes
// $$$ of the members of the VEG and assign it as the type
// $$$ for the VEGReference.
// -----------------------------------------------------------------------
const NAType *VEGReference::synthesizeType()
{
if (getVEG()->seenBefore())
return NULL;
getVEG()->markAsSeenBefore();
NAType *type = NULL;
if (NOT getVEG()->getAllValues().isEmpty())
{
// return the type of any one expression from the VEG.
ValueId exprId;
const ValueIdSet & vegValues = getVEG()->getAllValues();
for (exprId = vegValues.init();
vegValues.next(exprId);
vegValues.advance(exprId))
{
if (exprId.getItemExpr()->getOperatorType() == ITM_VEG_REFERENCE)
{
// Saw a VEGReference inside the VEG which is not type synthesized
// yet. Drive its synthesis if it's not a VEGReference to a VEG
// which we are in the process of type synthesizing. In that case,
// we could ignore the VEGRef, since (1) we want to avoid infinite
// recursion; (2) it will get its type after the completion of an
// earlier call to synthesizeType().
//
if (exprId.getValueDesc()->getDomainDesc() == NULL)
{
VEGReference *vegref = (VEGReference *)(exprId.getItemExpr());
if (NOT vegref->getVEG()->seenBefore())
{
vegref->synthTypeAndValueId(FALSE);
// Remember the first non-null type seen.
if (type == NULL) type = (NAType *) &(exprId.getType());
}
}
else
{
// Remember the first non-null type seen.
if (type == NULL) type = (NAType *) &(exprId.getType());
}
}
else
{
// Remember the first non-null type seen.
if (type == NULL) type = (NAType *) &(exprId.getType());
}
}
}
else
{
type = new HEAP SQLUnknown(HEAP);
}
getVEG()->markAsNotSeenBefore();
CMPASSERT(type);
return type;
}
const NAType *ScalarVariance::synthesizeType()
{
return new HEAP SQLDoublePrecision(HEAP, TRUE); // Variance is always Nullable
}
// UnPackCol::synthesizeType() --------------------------------
// The type of the UnPackCol is the type of the original unpacked
// column. This type is store within the UnPackCol node.
//
const NAType *UnPackCol::synthesizeType()
{
// The type of the original unpacked column.
//
return getType();
}
// RowsetArrayScan::synthesizeType() --------------------------------
// The type of the RowsetArrayScan is the type of the original unpacked
// element. This type is store within the RowsetArrayScan node.
//
const NAType *RowsetArrayScan::synthesizeType()
{
// The element type
return getType();
}
const NAType *RowsetArrayInto::synthesizeType()
{
// The element type
return getType();
}
const NAType *RandomNum::synthesizeType()
{
NAType *result = NULL;
if (getArity() == 1)
{
//
// Type cast any params.
//
SQLInt nType(NULL, FALSE);
ValueId vid = child(0)->getValueId();
vid.coerceType(nType, NA_NUMERIC_TYPE);
const NAType& operand = vid.getType();
if (operand.getTypeQualifier() != NA_NUMERIC_TYPE) {
// 4045 The operand of a Random function must be numeric.
*CmpCommon::diags() << DgSqlCode(-4045) << DgString0(getTextUpper());
return NULL;
}
// now it's safe to cast the types to numeric type
const NumericType &ntyp1 = (NumericType &) operand;
if (NOT ntyp1.isExact())
{
// 4070 Random function is only defined for exact numeric types.
*CmpCommon::diags() << DgSqlCode(-4070) << DgString0(getTextUpper());
return NULL;
}
if (ntyp1.getScale() != 0)
{
// 4047 Arguments of random function must have a scale of 0.
*CmpCommon::diags() << DgSqlCode(-4047) << DgString0(getTextUpper());
return NULL;
}
// return: int unsigned
result = (NAType *) new HEAP SQLInt(HEAP, FALSE, ntyp1.supportsSQLnullLogical());
}
else
{
// return: int unsigned not null
result = (NAType *) new HEAP SQLInt(HEAP, FALSE,FALSE);
}
return result;
}
const NAType *Mask::synthesizeType()
{
// The expression is <op1> Mask <op2>.
// Both operands must be exact numeric with scale 0.
// The result can always fit into the data type of the first child.
const NAType &typ1 = child(0)->getValueId().getType();
const NAType &typ2 = child(1)->getValueId().getType();
// Mask is an internal operator and errors are fatal
CMPASSERT(typ1.getTypeQualifier() == NA_NUMERIC_TYPE AND
typ2.getTypeQualifier() == NA_NUMERIC_TYPE);
// now it's safe to cast the types to numeric type
const NumericType &ntyp1 = (NumericType &) typ1;
const NumericType &ntyp2 = (NumericType &) typ2;
// for now make sure both operands basically have the same binary
// type, but this may be changed in the future
CMPASSERT(ntyp1.isExact() AND ntyp2.isExact() AND
ntyp1.getScale() == 0 AND ntyp2.getScale() == 0 AND
ntyp1.getPrecision() == ntyp2.getPrecision() AND
ntyp1.binaryPrecision() AND
ntyp2.binaryPrecision());
const NAType *result = typ1.newCopy(HEAP);
return result;
}
const NAType *Shift::synthesizeType()
{
// The expression is <op1> Shift <op2>.
// Both operands must be exact numeric with scale 0.
// The result can always fit into the data type of the first child.
const NAType &typ1 = child(0)->getValueId().getType();
const NAType &typ2 = child(1)->getValueId().getType();
// Mask is an internal operator and errors are fatal
CMPASSERT(typ1.getTypeQualifier() == NA_NUMERIC_TYPE AND
typ2.getTypeQualifier() == NA_NUMERIC_TYPE);
// now it's safe to cast the types to numeric type
const NumericType &ntyp1 = (NumericType &) typ1;
const NumericType &ntyp2 = (NumericType &) typ2;
// for now make sure both operands basically have the same binary
// type, but this may be changed in the future
CMPASSERT(ntyp1.isExact() AND ntyp2.isExact() AND
ntyp1.getScale() == 0 AND ntyp2.getScale() == 0 AND
ntyp1.binaryPrecision() AND
ntyp2.binaryPrecision());
const NAType *result = typ1.newCopy(HEAP);
return result;
}
// -----------------------------------------------------------------------
// member functions for class PackFunc
// -----------------------------------------------------------------------
const NAType* PackFunc::synthesizeType()
{
// ---------------------------------------------------------------------
// If format information is valid, type is already available. Otherwise,
// compute type information for the result of the PackFunc from the type
// information of its operand.
// ---------------------------------------------------------------------
if(NOT isFormatInfoValid_)
{
// Type of column to be packed.
const NAType* columnType = &child(0)->getValueId().getType();
deriveFormatInfoFromUnpackType(columnType);
}
return type_;
}
const NAType * ZZZBinderFunction::synthesizeType()
{
// the synthesizeType method is needed only when we process an item
// expression at DDL time. For DML the function gets transformed into
// another function in the binder before we reach type synthesis
switch (getOperatorType())
{
case ITM_DATEDIFF_YEAR:
case ITM_DATEDIFF_MONTH:
case ITM_DATEDIFF_QUARTER:
case ITM_DATEDIFF_WEEK:
return new HEAP SQLInt(HEAP, TRUE,
child(0)->getValueId().getType().supportsSQLnull() ||
child(1)->getValueId().getType().supportsSQLnull());
case ITM_LEFT:
{
// make a temporary transformation for synthesizing the right type
Substring *temp = new HEAP Substring(child(0).getPtr(),
new HEAP ConstValue((Lng32) 1, (NAMemory *) HEAP),
child(1));
temp->synthTypeAndValueId();
return temp->getValueId().getType().newCopy(HEAP);
}
case ITM_YEARWEEK:
case ITM_YEARWEEKD:
return new HEAP SQLNumeric(HEAP, 4,
6,
0,
TRUE,
child(0)->getValueId().getType().supportsSQLnull());
default:
// use the parent class implementation by default
return BuiltinFunction::synthesizeType();
}
}
const NAType *Subquery::synthesizeType()
{
return new HEAP SQLBooleanRelat(HEAP);
}
const NAType *RowSubquery::synthesizeType()
{
const NAType *rowType = &getSubquery()->selectList()->getValueId().getType();
return rowType->newCopy(HEAP);
}
// Propagate type information down the compExpr of the RowSubquery
// Called by coerceType(). We only change type if the selectList of
// the RowSubquery is of degree 1 and the returned value in the select
// list is of unknown or character type.
//
const NAType *
RowSubquery::pushDownType(NAType& desiredType,
enum NABuiltInTypeEnum defaultQualifier)
{
// In the case where the select list of the rowSubquery contains
// a dynamic parameter, we need to change its type..
if ( getDegree() == 1 )
{
RelRoot *sq_root = (RelRoot *) getSubquery();
ValueId outVid = sq_root->compExpr()[0];
if ( outVid.getType().getTypeQualifier() == NA_UNKNOWN_TYPE ||
outVid.getType().getTypeQualifier() == NA_CHARACTER_TYPE
)
outVid.coerceType(desiredType, defaultQualifier);
}
return (NAType *)synthesizeType();
}
const NAType *Exists::synthesizeType()
{
// EXISTS predicate can never evaluate to Unknown
return new HEAP SQLBooleanRelat(FALSE);
}
const NAType *QuantifiedComp::synthesizeType()
{
// Genesis 10-980305-3294
ItemExprList exprList1(child(0).getPtr(), HEAP);
ItemExprList exprList2(getSubquery()->selectList(), HEAP);
NABoolean allowsUnknown;
NABoolean allowIncompatibleComparison = FALSE;
if (CmpCommon::getDefault(ALLOW_INCOMPATIBLE_OPERATIONS) == DF_ON)
allowIncompatibleComparison = TRUE;
if (!synthItemExprLists(exprList1, exprList2, allowIncompatibleComparison,
allowsUnknown, this))
return NULL;
return new HEAP SQLBooleanRelat(HEAP, allowsUnknown);
}
// MV,
const NAType *GenericUpdateOutputFunction::synthesizeType()
{
const NAType *type = NULL;
if( getOperator().match(ITM_JULIANTIMESTAMP) )
{
//
// Type cast any params.
//
ValueId vid = child(0)->getValueId();
SQLTimestamp timestampType(NULL);
vid.coerceType(timestampType);
//
// Check that the operands are compatible.
//
const NAType& operand = vid.getType();
if (operand.getTypeQualifier() != NA_DATETIME_TYPE) {
// 4071 The operand of a JULIANTIMESTAMP function must be a datetime.
*CmpCommon::diags() << DgSqlCode(-4071) << DgString0(getTextUpper());
return NULL;
}
type = new HEAP SQLLargeInt(HEAP, TRUE, operand.supportsSQLnullLogical());
}
else
{
type = new HEAP SQLInt(HEAP, TRUE, FALSE);
}
return type;
}
//++Triggers,
const NAType *UniqueExecuteId::synthesizeType()
{
return new HEAP SQLChar(HEAP, SIZEOF_UNIQUE_EXECUTE_ID, FALSE);
}
const NAType *GetTriggersStatus::synthesizeType()
{
return new HEAP SQLChar(HEAP, TRIGGERS_STATUS_VECTOR_SIZE, FALSE);
}
const NAType *GetBitValueAt::synthesizeType()
{
const NAType *operand1 = &child(0)->getValueId().getType();
const NAType *operand2 = &child(1)->getValueId().getType();
if (operand1->getTypeQualifier() != NA_CHARACTER_TYPE) {
// 4051 Operand 1 must be character.
*CmpCommon::diags() << DgSqlCode(-4051) << DgString0(getTextUpper());
return NULL;
}
if (operand2->getTypeQualifier() != NA_NUMERIC_TYPE) {
// 4052 Operand 2 must be numeric.
*CmpCommon::diags() << DgSqlCode(-4052) << DgString0(getTextUpper());
return NULL;
}
return new HEAP SQLInt(HEAP, FALSE, FALSE);
}
//--Triggers,
const NAType *IsBitwiseAndTrue::synthesizeType()
{
const NAType *operand1 = &child(0)->getValueId().getType();
const NAType *operand2 = &child(1)->getValueId().getType();
if (operand1->getTypeQualifier() != NA_CHARACTER_TYPE) {
// 4051 Operand 1 must be character.
*CmpCommon::diags() << DgSqlCode(-4051) << DgString0(getTextUpper());
return NULL;
}
if (operand1->getTypeQualifier() != NA_CHARACTER_TYPE) {
// 4051 Operand 1 must be character.
*CmpCommon::diags() << DgSqlCode(-4051) << DgString0(getTextUpper());
return NULL;
}
return new HEAP SQLBooleanRelat(FALSE);
}
//--MV
const NAType *ItemList::synthesizeType()
{
const NAType * elementType = &child(0)->getValueId().getType();
SQLRecord *restOfRecord;
if (child(1)->getOperatorType() == ITM_ITEM_LIST)
{
restOfRecord = (SQLRecord *)&child(1)->getValueId().getType();
CMPASSERT(restOfRecord->getTypeQualifier() == NA_RECORD_TYPE);
}
else
{
restOfRecord = new HEAP SQLRecord(HEAP, &child(1)->getValueId().getType(),NULL);
}
return new HEAP SQLRecord(HEAP, elementType,restOfRecord);
}
// -----------------------------------------------------------------------
// member functions for class ItmSeqOffset
// -----------------------------------------------------------------------
const NAType *ItmSeqOffset::synthesizeType()
{
// Verify that child 1 is numeric.
// Return the type of child 0.
const NAType &operand1 = child(0)->getValueId().getType();
if (getArity() > 1) {
const NAType &operand2 = child(1)->getValueId().getType();
if (operand2.getTypeQualifier() != NA_NUMERIC_TYPE) {
// The second operand of an OFFSET function must be numeric.
*CmpCommon::diags() << DgSqlCode(-4052) << DgString0(getTextUpper());
return NULL;
}
}
if (getArity() > 2) {
const NAType &operand3 = child(2)->getValueId().getType();
if (operand3.getTypeQualifier() != NA_NUMERIC_TYPE) {
// The third operand of an OFFSET function must be numeric.
*CmpCommon::diags() << DgSqlCode(-4053) << DgString0(getTextUpper());
return NULL;
}
}
NAType *result = operand1.newCopy(HEAP);
if(nullRowIsZero()) {
result->setNullable(FALSE);
CMPASSERT(result->getTypeQualifier() == NA_NUMERIC_TYPE ||
result->getTypeQualifier() == NA_INTERVAL_TYPE);
} else {
result->setNullable(TRUE);
}
if (isOLAP())
{
result->setNullable(TRUE);
}
return result;
}
const NAType *ItmLagOlapFunction::synthesizeType()
{
// Return the type of child 0.
const NAType &operand1 = child(0)->getValueId().getType();
if (getArity() > 1) {
const NAType &operand2 = child(1)->getValueId().getType();
if (operand2.getTypeQualifier() != NA_NUMERIC_TYPE) {
// The second operand of an OFFSET function must be numeric.
*CmpCommon::diags() << DgSqlCode(-4052) << DgString0(getTextUpper());
return NULL;
}
// check the default expression which should have the same type as the
// child(0).
if (getArity() > 2) {
const NAType& typeForOp0 = child(0)->castToItemExpr()->getValueId().getType();
const NAType& typeForDefault = child(2)->castToItemExpr()->getValueId().getType();
UInt32 flags =
((CmpCommon::getDefault(LIMIT_MAX_NUMERIC_PRECISION) == DF_ON)
? NAType::LIMIT_MAX_NUMERIC_PRECISION : 0);
if ( !(typeForOp0 == typeForDefault) ) {
NATypeSynthRuleEnum rule = SYNTH_RULE_ADD;
if ( typeForOp0.getTypeQualifier() == NA_CHARACTER_TYPE )
rule = SYNTH_RULE_CONCAT;
const NAType* resultType = typeForOp0.synthesizeType(rule,
typeForOp0,
typeForDefault,
HEAP, &flags);
if ( !resultType ) {
*CmpCommon::diags() << DgSqlCode(-4141) << DgString0("LAG");
return NULL;
}
// Set the null attribute of the default value to TRUE.
NAType* newType = typeForDefault.newCopy(HEAP);
newType->setNullable(TRUE);
ValueId vid2 = child(2)->castToItemExpr()->getValueId();
vid2.changeType(newType);
}
}
}
NAType *result = operand1.newCopy(HEAP);
result->setNullable(TRUE);
return result;
}
// -----------------------------------------------------------------------
// member functions for class ItmSeqDiff1
// -----------------------------------------------------------------------
const NAType *ItmSeqDiff1::synthesizeType()
{
// Verify that children are numeric.
// Return the result type of child(0) - child(0).
for (Int32 i = 0; i < getArity(); i++) {
const NAType &operand = child(i)->getValueId().getType();
NABuiltInTypeEnum opType = operand.getTypeQualifier() ;
if ((opType != NA_NUMERIC_TYPE &&
opType != NA_DATETIME_TYPE &&
opType != NA_INTERVAL_TYPE) ||
!operand.isSupportedType()) {
if (i == 0) {
// The first operand of a DIFF1 function must be numeric.
*CmpCommon::diags() << DgSqlCode(-4059) << DgString0(getTextUpper());
}
else {
// The second operand of a DIFF1 function must be numeric.
*CmpCommon::diags() << DgSqlCode(-4052) << DgString0(getTextUpper());
}
return NULL;
} // if not numeric
}
const NAType &operand1 = child(0)->getValueId().getType();
const NAType *result1 = operand1.synthesizeType(SYNTH_RULE_SUB, operand1, operand1, HEAP);
NAType *result;
if (getArity()==2) // will be transformed into: DIFF1(child(0)) / DIFF1(child(1))
{
const NAType &operand2 = child(1)->getValueId().getType();
const NAType *result2 = operand2.synthesizeType(SYNTH_RULE_SUB, operand2, operand2, HEAP);
if (result2->getTypeQualifier() == NA_INTERVAL_TYPE)
{
result2 = new HEAP SQLLargeInt(HEAP, TRUE, FALSE );
}
result = (NAType *)result2->synthesizeType(SYNTH_RULE_DIV, *result1, *result2, HEAP);
}
else
{
result = (NAType *)result1;
}
result->setNullable(TRUE);
return result;
}
// -----------------------------------------------------------------------
// member functions for class ItmSeqDiff2
// -----------------------------------------------------------------------
const NAType *ItmSeqDiff2::synthesizeType()
{
// Verify that children are numeric.
// Return the result type of child(0) - child(0).
for (Int32 i = 0; i < getArity(); i++) {
const NAType &operand = child(i)->getValueId().getType();
NABuiltInTypeEnum opType = operand.getTypeQualifier() ;
if ((opType != NA_NUMERIC_TYPE &&
opType != NA_DATETIME_TYPE &&
opType != NA_INTERVAL_TYPE ) ||
!operand.isSupportedType()) {
if (i == 0) {
// The first operand of a DIFF1 function must be numeric.
*CmpCommon::diags() << DgSqlCode(-4059) << DgString0(getTextUpper());
}
else {
// The second operand of a DIFF1 function must be numeric.
*CmpCommon::diags() << DgSqlCode(-4052) << DgString0(getTextUpper());
}
return NULL;
} // if not numeric
}
const NAType &operand1 = child(0)->getValueId().getType();
const NAType *result1 = operand1.synthesizeType(SYNTH_RULE_SUB, operand1, operand1, HEAP);
NAType *result = (NAType *)result1->synthesizeType(SYNTH_RULE_SUB, *result1, *result1, HEAP);
if (getArity()==2) // will be transformed into: DIFF2(child(0)) / DIFF1(child(1))
{
const NAType &operand2 = child(1)->getValueId().getType();
const NAType *result2 = operand2.synthesizeType(SYNTH_RULE_SUB, operand2, operand2, HEAP);
if (result2->getTypeQualifier() == NA_INTERVAL_TYPE)
{
result2 = new HEAP SQLLargeInt(HEAP, TRUE, FALSE );
}
result = (NAType *)result2->synthesizeType(SYNTH_RULE_DIV, *result, *result2, HEAP);
}
result->setNullable(TRUE);
return result;
}
// -----------------------------------------------------------------------
// member functions for class ItmSeqRunningFunction
// -----------------------------------------------------------------------
const NAType *ItmSeqRunningFunction::synthesizeType()
{
const NAType *result = NULL;
if ((getOperatorType() == ITM_RUNNING_COUNT) ||
(getOperatorType() == ITM_RUNNING_RANK) ||
(getOperatorType() == ITM_RUNNING_DRANK) ||
(getOperatorType() == ITM_RUNNING_CHANGE)) {
result = new HEAP
SQLLargeInt(HEAP, TRUE /* 'long long' on NSK can't be unsigned */,
FALSE /*not null*/);
}
else {
const NAType& operand = child(0)->castToItemExpr()->getValueId().getType();
switch (getOperatorType()) {
case ITM_RUNNING_AVG: { // needs to mimic what will happen after transformation
const NAType *operand1 = synthAvgSum(operand, FALSE);
const NAType *newInt = new HEAP SQLLargeInt(HEAP, TRUE,FALSE);
if (operand1){
result = operand1->synthesizeType(SYNTH_RULE_DIV, *operand1, *newInt, HEAP);
}
}
break;
case ITM_RUNNING_SUM:
result = synthAvgSum(operand, FALSE);
break;
case ITM_LAST_NOT_NULL:
case ITM_RUNNING_MAX:
case ITM_RUNNING_MIN:
result = operand.newCopy(HEAP);
break;
case ITM_RUNNING_SDEV:
case ITM_RUNNING_VARIANCE:
result = new HEAP SQLDoublePrecision(HEAP, TRUE); // See ScalarVariance::synthesizeType()
break;
default:
CMPASSERT("Unknown running function in synthesizeType().");
break;
} // end switch getOperatorType()
if (result){
((NAType *)result)->setNullable(TRUE);
}
} // end else not RUNNINGCOUNT
return result;
}
const NAType *ItmSeqOlapFunction::synthesizeType()
{
const NAType *result = NULL;
if (getOperatorType() == ITM_OLAP_COUNT)
{
result = new HEAP
SQLLargeInt(HEAP, TRUE /* 'long long' on NSK can't be unsigned */,
TRUE /* null*/);
}
else
if (/*(getOperatorType() == ITM_OLAP_COUNT) || */ //-- causes runtime error: ERROR[8421] NULL cannot be assigned to a NOT NULL column.
(getOperatorType() == ITM_OLAP_RANK) ||
(getOperatorType() == ITM_OLAP_DRANK))
{
result = new HEAP
SQLLargeInt(HEAP, TRUE /* 'long long' on NSK can't be unsigned */,
FALSE /*not null*/);
}
else
{
const NAType& operand = child(0)->castToItemExpr()->getValueId().getType();
switch (getOperatorType())
{
case ITM_OLAP_AVG:
{ // needs to mimic what will happen after transformation
const NAType *operand1 = synthAvgSum(operand, FALSE);
const NAType *newInt = new HEAP SQLLargeInt(HEAP, TRUE, TRUE /*FALSE*/);
if (operand1)
{
result = operand1->synthesizeType(SYNTH_RULE_DIV, *operand1, *newInt, HEAP);
}
}
break;
case ITM_OLAP_SUM:
result = synthAvgSum(operand, FALSE);
break;
case ITM_OLAP_MAX:
case ITM_OLAP_MIN:
result = operand.newCopy(HEAP);
break;
case ITM_OLAP_SDEV:
case ITM_OLAP_VARIANCE:
result = new HEAP SQLDoublePrecision(HEAP, TRUE);
break;
default:
CMPASSERT("Unknown running function in synthesizeType().");
break;
} // end switch getOperatorType()
if (result)
{
((NAType *)result)->setNullable(TRUE);
}
} // end else not RUNNINGCOUNT
return result;
}
// -----------------------------------------------------------------------
// member functions for class ItmSeqRowsSince
// -----------------------------------------------------------------------
const NAType *ItmSeqRowsSince::synthesizeType()
{
if (getArity() == 2)
{
const NAType &operand2 = child(1)->getValueId().getType();
if (operand2.getTypeQualifier() != NA_NUMERIC_TYPE) {
// The second operand of a ROWS SINCE function must be numeric.
*CmpCommon::diags() << DgSqlCode(-4052) << DgString0(getTextUpper());
return NULL;
}
}
return new HEAP
SQLInt(HEAP, TRUE /* 'long long' on NSK can't be unsigned */,
TRUE /* nullable */);
}
// -----------------------------------------------------------------------
// member functions for class ItmSeqMovingFunction
// -----------------------------------------------------------------------
const NAType *ItmSeqMovingFunction::synthesizeType()
{
const NAType *result=NULL;
//
// Verify that moving window sizes are numeric values
//
NABoolean child2isOK = TRUE;
const NAType &operand1 = child(1)->getValueId().getType();
if (operand1.getTypeQualifier() != NA_NUMERIC_TYPE) {
// The second operand of a MOVING sequence function must be numeric.
*CmpCommon::diags() << DgSqlCode(-4052) << DgString0(getTextUpper());
return NULL;
}
if (getArity() > 2 ) // check child(2) type
{
const NAType &operand2 = child(2)->getValueId().getType();
if (operand2.getTypeQualifier() != NA_NUMERIC_TYPE) {
// The third operand of a MOVING sequence function must be numeric.
*CmpCommon::diags() << DgSqlCode(-4053) << DgString0(getTextUpper());
return NULL;
}
}
if ((getOperatorType() == ITM_MOVING_COUNT) ||
(getOperatorType() == ITM_MOVING_RANK) ||
(getOperatorType() == ITM_MOVING_DRANK)) {
result = new HEAP
SQLLargeInt(HEAP, TRUE /* 'long long' on NSK can't be unsigned */,
FALSE /*not null*/);
}
else {
const NAType& operand = child(0)->castToItemExpr()->getValueId().getType();
switch (getOperatorType()) {
case ITM_MOVING_AVG: { // needs to mimic what will happen after transformation
const NAType *operand1 = synthAvgSum(operand, FALSE);
const NAType *newInt = new HEAP SQLLargeInt(HEAP, TRUE,FALSE);
if (operand1) {
result = operand1->synthesizeType(SYNTH_RULE_DIV, *operand1, *newInt, HEAP);
}
}
break;
case ITM_MOVING_SUM:
result = synthAvgSum(operand, FALSE);
break;
case ITM_MOVING_MAX:
case ITM_MOVING_MIN:
result = operand.newCopy(HEAP);
break;
case ITM_MOVING_SDEV:
case ITM_MOVING_VARIANCE:
result = new HEAP SQLDoublePrecision(HEAP, TRUE); // See ScalarVariance::synthesizeType()
break;
default:
CMPASSERT("Unknown moving function in synthesizeType().");
break;
} // end switch getOperatorType()
if (result) {
((NAType *)result)->setNullable(TRUE);
}
} // end else not MOVING_COUNT
return result;
}
// -----------------------------------------------------------------------
// member functions for class ItmSeqThisFunction
// -----------------------------------------------------------------------
const NAType *ItmSeqThisFunction::synthesizeType()
{
// Return the type of child
const NAType &operand = child(0)->getValueId().getType();
NAType *result = operand.newCopy(HEAP);
result->setNullable(TRUE);
return result;
}
// -----------------------------------------------------------------------
// member functions for class ItmScalarMinMax
// -----------------------------------------------------------------------
const NAType *ItmScalarMinMax::synthesizeType()
{
// The expression is SCALAR_MIN(<val1>, <val2>) or SCALAR_MAX(<val1>, <val2>)
// The result is the min or max value of the operands.
ValueId valId1 = child(0)->getValueId();
ValueId valId2 = child(1)->getValueId();
//
// Type cast any params.
//
valId1.coerceType(valId2.getType(), NA_NUMERIC_TYPE);
valId2.coerceType(valId1.getType());
//
// Synthesize the result.
//
const NAType& op1 = valId1.getType();
const NAType& op2 = valId2.getType();
UInt32 flags =
((CmpCommon::getDefault(LIMIT_MAX_NUMERIC_PRECISION) == DF_ON)
? NAType::LIMIT_MAX_NUMERIC_PRECISION : 0);
const NAType *result = op1.synthesizeType(SYNTH_RULE_UNION,
op1,
op2,
HEAP,
&flags);
if (result == NULL) {
// 4041 Type $1 cannot be compared with type $2.
emitDyadicTypeSQLnameMsg(-4041, op1, op2);
return NULL;
}
if (result->getTypeQualifier() == NA_CHARACTER_TYPE) {
CharType *ct = (CharType *)result;
propagateCoAndCoToChildren(this, ct->getCollation(), ct->getCoercibility());
}
return result;
}
// -----------------------------------------------------------------------
// member functions for class ItmSeqNotTHISFunction
// -----------------------------------------------------------------------
const NAType *ItmSeqNotTHISFunction::synthesizeType()
{
// Return the type of child
const NAType &operand = child(0)->getValueId().getType();
NAType *result = operand.newCopy(HEAP);
result->setNullable(TRUE);
return result;
}
const NAType * HbaseColumnLookup::synthesizeType()
{
NAType * type = NULL;
if (naType_)
type = (NAType*)naType_;
else
type = new HEAP SQLVarChar(HEAP, 100000);
return type;
}
const NAType * HbaseColumnsDisplay::synthesizeType()
{
NAType * type = new HEAP SQLVarChar(HEAP, displayWidth_);
return type;
}
const NAType * HbaseColumnCreate::synthesizeType()
{
NAType * type = NULL;
if (resultType_)
type = (NAType*)resultType_;
else
type = new HEAP SQLVarChar(HEAP, 100000);
return type;
}
const NAType * SequenceValue::synthesizeType()
{
NAType * type = NULL;
type = new HEAP SQLLargeInt(HEAP, TRUE, FALSE);
return type;
}
const NAType * HbaseTimestamp::synthesizeType()
{
NAType * type = NULL;
type = new HEAP SQLLargeInt(HEAP, TRUE,
col_->getValueId().getType().supportsSQLnull());
return type;
}
const NAType * HbaseVersion::synthesizeType()
{
NAType * type = NULL;
type = new HEAP SQLLargeInt(HEAP, TRUE, FALSE);
return type;
}
const NAType * RowNumFunc::synthesizeType()
{
NAType * type = NULL;
type = new HEAP SQLLargeInt(HEAP, TRUE, FALSE);
return type;
}
const NAType *LOBoper::synthesizeType()
{
// Return blob or clob type
NAType *result = new HEAP SQLBlob(HEAP, ((Int64) CmpCommon::getDefaultNumeric(LOB_MAX_SIZE)*1024*1024));
if (child(0))
{
ValueId vid1 = child(0)->getValueId();
const NAType &typ1 = (NAType&)vid1.getType();
if (typ1.getFSDatatype() == REC_BLOB)
{
result = new HEAP SQLBlob(HEAP, ((Int64) CmpCommon::getDefaultNumeric(LOB_MAX_SIZE)*1024*1024), Lob_Invalid_Storage,
typ1.supportsSQLnull());
}
else if (typ1.getFSDatatype() == REC_CLOB)
{
result = new HEAP SQLClob(HEAP, ((Int64) CmpCommon::getDefaultNumeric(LOB_MAX_SIZE)*1024*1024), Lob_Invalid_Storage,
typ1.supportsSQLnull());
}
}
return result;
}
const NAType *LOBinsert::synthesizeType()
{
// Return blob type
ValueId vid1;
const NAType *typ1 = NULL;
if (child(0))
{
vid1 = child(0)->getValueId();
typ1 = &vid1.getType();
}
if ((obj_ == STRING_) ||
(obj_ == FILE_) ||
(obj_ == EXTERNAL_) ||
(obj_ == LOAD_))
{
if (typ1 && typ1->getTypeQualifier() != NA_CHARACTER_TYPE)
{
if (!lobAsVarchar())
{
// 4221 The operand of a $0~String0 function must be character.
*CmpCommon::diags() << DgSqlCode(-4221) << DgString0("LOBINSERT")
<< DgString1("CHARACTER");
return NULL;
}
}
}
else if (obj_ == LOB_)
{
if (typ1 && typ1->getTypeQualifier() != NA_LOB_TYPE)
{
// 4043 The operand of a $0~String0 function must be blob
*CmpCommon::diags() << DgSqlCode(-4221) << DgString0("LOBINSERT")
<< DgString1("LOB");
return NULL;
}
}
else if (obj_ == BUFFER_)
{
if (typ1 && typ1->getTypeQualifier() != NA_NUMERIC_TYPE)
{
// 4043 The operand of a $0~String0 function must be blob
*CmpCommon::diags() << DgSqlCode(-4221) << DgString0("LOBINSERT")
<< DgString1("LARGEINT");
return NULL;
}
}
else if(obj_ == EMPTY_LOB_)
{
}
else
{
// 4221 The operand of a $0~String0 function must be character.
*CmpCommon::diags() << DgSqlCode(-4221) << DgString0("LOBINSERT")
<< DgString1("BLOB");
return NULL;
}
NAType * result = NULL;
if (lobFsType() == REC_BLOB)
{
result = new HEAP SQLBlob(HEAP, lobSize(), Lob_Invalid_Storage,
(obj_ ==EMPTY_LOB_) ? FALSE:typ1->supportsSQLnull());
}
else if (lobFsType() == REC_CLOB)
{
result = new HEAP SQLClob(HEAP, lobSize(), Lob_Invalid_Storage,
(obj_ == EMPTY_LOB_)? FALSE:typ1->supportsSQLnull());
}
return result;
}
const NAType *LOBupdate::synthesizeType()
{
// Return blob type
ValueId vid1,vid2 ;
const NAType *typ1 = NULL;
const NAType *typ2 = NULL;
if(child(0))
{
vid1= child(0)->getValueId();
typ1 = &vid1.getType();
}
if(child(1))
{
vid2 = child(1)->getValueId();
typ2 = &vid2.getType();
}
if ((obj_ == STRING_) ||
(obj_ == FILE_) ||
(obj_ == EXTERNAL_))
{
if (typ1->getTypeQualifier() != NA_CHARACTER_TYPE)
{
if(!lobAsVarchar())
{
// 4221 The operand of a $0~String0 function must be character.
*CmpCommon::diags() << DgSqlCode(-4221) << DgString0("LOBUPDATE")
<< DgString1("CHARACTER");
return NULL;
}
}
}
else if (obj_ == LOB_)
{
if (typ1->getTypeQualifier() != NA_LOB_TYPE)
{
// 4043 The operand of a $0~String0 function must be blob
*CmpCommon::diags() << DgSqlCode(-4221) << DgString0("LOBUPDATE")
<< DgString1("LOB");
return NULL;
}
}
else if (obj_ == BUFFER_)
{
if (typ1->getTypeQualifier() != NA_NUMERIC_TYPE)
{
// 4043 The operand of a $0~String0 function must be blob
*CmpCommon::diags() << DgSqlCode(-4221) << DgString0("LOBUPDATE")
<< DgString1("LARGEINT");
return NULL;
}
ValueId vid3 = child(2)->getValueId();
const NAType &typ3 = (NAType&)vid3.getType();
if (typ3.getTypeQualifier() != NA_NUMERIC_TYPE)
{
// 4043 The operand of a $0~String0 function must be blob
*CmpCommon::diags() << DgSqlCode(-4221) << DgString0("LOBUPDATE")
<< DgString1("LARGEINT");
return NULL;
}
}
else if (obj_ == EMPTY_LOB_)
{
}
else
{
// 4221 The operand of a $0~String0 function must be character.
*CmpCommon::diags() << DgSqlCode(-4221) << DgString0("LOBUPDATE")
<< DgString1("BLOB");
return NULL;
}
NAType * result = NULL;
if (typ2->getFSDatatype() == REC_BLOB)
{
SQLBlob &blob = (SQLBlob&)*typ2;
result = new HEAP SQLBlob(HEAP, blob.getLobLength(), Lob_Invalid_Storage,
(obj_ ==EMPTY_LOB_) ? FALSE:typ2->supportsSQLnull());
}
else if (typ2->getFSDatatype() == REC_CLOB)
{
SQLClob &clob = (SQLClob&)*typ2;
result = new HEAP SQLClob(HEAP, clob.getLobLength(), Lob_Invalid_Storage,
(obj_ ==EMPTY_LOB_) ? FALSE:typ2->supportsSQLnull());
}
return result;
}
const NAType *LOBconvertHandle::synthesizeType()
{
// Return blob type
ValueId vid1 = child(0)->getValueId();
const NAType &typ1 = (NAType&)vid1.getType();
NAType *result = NULL;
if (obj_ == STRING_)
{
if (typ1.getTypeQualifier() != NA_LOB_TYPE)
{
// 4043 The operand of a $0~String0 function must be character.
*CmpCommon::diags() << DgSqlCode(-4221) << DgString0("LOBCONVERTHANDLE")
<< DgString1("LOB");
return NULL;
}
if (typ1.getFSDatatype() == REC_BLOB)
{
SQLBlob& op1 = (SQLBlob&)vid1.getType();
result = new HEAP SQLBlob(HEAP, op1.getLobLength(), Lob_Invalid_Storage,
typ1.supportsSQLnull(), FALSE,
TRUE);
}
else if (typ1.getFSDatatype() == REC_CLOB)
{
SQLClob& op1 = (SQLClob&)vid1.getType();
result = new HEAP SQLClob(HEAP, op1.getLobLength(), Lob_Invalid_Storage,
typ1.supportsSQLnull(), FALSE,
TRUE);
}
return result;
}
else if (obj_ == LOB_)
{
if (typ1.getTypeQualifier() != NA_CHARACTER_TYPE)
{
// 4221 The operand of a $0~String0 function must be character.
*CmpCommon::diags() << DgSqlCode(-4221) << DgString0("LOBCONVERTHANDLE")
<< DgString1("CHARACTER");
return NULL;
}
result = new HEAP SQLBlob(HEAP, ((Int64) CmpCommon::getDefaultNumeric(LOB_MAX_SIZE)*1024*1024), Lob_Invalid_Storage, typ1.supportsSQLnull(), FALSE,
FALSE);
return result;
}
else
{
*CmpCommon::diags() << DgSqlCode(-4221) << DgString0("LOBCONVERTHANDLE")
<< DgString1("CHARACTER");
return NULL;
}
}
const NAType *LOBconvert::synthesizeType()
{
// Return blob type
ValueId vid1 = child(0)->getValueId();
const NAType &typ1 = (NAType&)vid1.getType();
if (obj_ == STRING_ || obj_ == FILE_)
{
if (typ1.getTypeQualifier() != NA_LOB_TYPE)
{
// 4043 The operand of a $0~String0 function must be blob
*CmpCommon::diags() << DgSqlCode(-4221) << DgString0("LOBCONVERT")
<< DgString1("LOB");
return NULL;
}
SQLlob& op1 = (SQLlob&)vid1.getType();
Lng32 tgtSize = MINOF((Lng32)op1.getLobLength(), tgtSize_);
NAType *result = new HEAP SQLVarChar(HEAP, tgtSize, Lob_Invalid_Storage,
typ1.supportsSQLnull());
return result;
}
else
{
// 4221 The operand of a $0~String0 function must be character.
*CmpCommon::diags() << DgSqlCode(-4221) << DgString0("LOBCONVERT")
<< DgString1("LOB");
return NULL;
}
}
const NAType *LOBextract::synthesizeType()
{
// Return blob type
ValueId vid1 = child(0)->getValueId();
const NAType &typ1 = (NAType&)vid1.getType();
if (typ1.getTypeQualifier() != NA_LOB_TYPE)
{
// 4043 The operand of a $0~String0 function must be blob
*CmpCommon::diags() << DgSqlCode(-4221) << DgString0("LOBEXTRACT")
<< DgString1("LOB");
return NULL;
}
SQLlob& op1 = (SQLlob&)vid1.getType();
Lng32 tgtSize = MINOF((Lng32)op1.getLobLength(), tgtSize_);
NAType *result = new HEAP SQLVarChar(HEAP, tgtSize, Lob_Invalid_Storage,
typ1.supportsSQLnull());
return result;
}
const NAType * ItmLeadOlapFunction::synthesizeType()
{
// check the type of the offset operand, if present
if (getArity() > 1) {
const NAType &operand2 = child(1)->getValueId().getType();
NABoolean isInteger = FALSE;
if (operand2.getTypeQualifier() == NA_NUMERIC_TYPE ) {
const NumericType& nt = (NumericType&)operand2;
if ( nt.isInteger() )
isInteger = TRUE;
}
// The second operand of a LEAD function must be of integer type.
if ( !isInteger ) {
*CmpCommon::diags() << DgSqlCode(-4140) << DgString0(getTextUpper());
return NULL;
}
// check the value of the offset expression constant
NABoolean offsetOK = FALSE;
Int64 value = 0;
if ( getArity() > 1 )
{
ValueId vid1 = child(1)->getValueId();
ItemExpr *offsetExpr = vid1.getItemExpr();
if (offsetExpr) {
if ( offsetExpr->getOperatorType() == ITM_CONSTANT )
{
ConstValue* cv = (ConstValue*)offsetExpr;
if ( cv->canGetExactNumericValue() )
{
value = cv->getExactNumericValue();
if ( value >= 0 ) {
offsetOK = TRUE;
offset_ = (Int32)value;
}
}
} else
offsetOK = TRUE; // delay making the decision. It coud be a row subquery
}
} else {
if ( offset_ >= 0 )
offsetOK = TRUE;
}
if ( !offsetOK ) {
*CmpCommon::diags() << DgSqlCode(-4249) << DgString0("LEAD");
return NULL;
}
}
// check the default expression which should have the same type as the
// child(0).
if (getArity() > 2) {
const NAType& typeForOp0 = child(0)->castToItemExpr()->getValueId().getType();
const NAType& typeForDefault = child(2)->castToItemExpr()->getValueId().getType();
UInt32 flags =
((CmpCommon::getDefault(LIMIT_MAX_NUMERIC_PRECISION) == DF_ON)
? NAType::LIMIT_MAX_NUMERIC_PRECISION : 0);
if ( !(typeForOp0 == typeForDefault) ) {
NATypeSynthRuleEnum rule = SYNTH_RULE_ADD;
if ( typeForOp0.getTypeQualifier() == NA_CHARACTER_TYPE )
rule = SYNTH_RULE_CONCAT;
const NAType* resultType = typeForOp0.synthesizeType(rule,
typeForOp0,
typeForDefault,
HEAP, &flags);
if ( !resultType ) {
*CmpCommon::diags() << DgSqlCode(-4141) << DgString0("LEAD");
return NULL;
}
// Set the null attribute of the default value to TRUE.
NAType* newType = typeForDefault.newCopy(HEAP);
newType->setNullable(TRUE);
ValueId vid2 = child(2)->castToItemExpr()->getValueId();
vid2.changeType(newType);
}
}
// the type of the LEAD() is the type of the 1st argument.
const NAType& operand = child(0)->castToItemExpr()->getValueId().getType();
NAType* result = operand.newCopy(HEAP);
// LEAD can return NULL.
result->setNullable(TRUE);
return result;
}
const NAType * SplitPart::synthesizeType()
{
ValueId vid1 = child(0)->getValueId();
ValueId vid2 = child(1)->getValueId();
ValueId vid3 = child(2)->getValueId();
vid1.coerceType(NA_CHARACTER_TYPE);
vid2.coerceType(NA_CHARACTER_TYPE);
SQLInt si(NULL);
vid3.coerceType(NA_NUMERIC_TYPE);
const NAType *operand1 = &child(0)->getValueId().getType();
const NAType *operand2 = &child(1)->getValueId().getType();
const NAType *operand3 = &child(2)->getValueId().getType();
if ((operand1->getTypeQualifier() != NA_CHARACTER_TYPE)
&& (operand1->getFSDatatype() != REC_CLOB))
{
//4051 The first operand of a split_part function must be character.
*CmpCommon::diags()<<DgSqlCode(-4051) << DgString0(getTextUpper());
return NULL;
}
if ((operand2->getTypeQualifier() != NA_CHARACTER_TYPE)
&& (operand1->getFSDatatype() != REC_CLOB))
{
//4497 The second operand of a split_part function must be character.
*CmpCommon::diags()<<DgSqlCode(-4497) << DgString0("second")
<< DgString1(getTextUpper())
<< DgString2("character");
return NULL;
}
if (operand3->getTypeQualifier() != NA_NUMERIC_TYPE)
{
//4053 The third operand of a split_part function must be numeric.
*CmpCommon::diags() << DgSqlCode(-4053) << DgString0(getTextUpper());
return NULL;
}
const CharType *charOperand = (CharType *)operand1;
Lng32 maxLength_bytes = charOperand->getDataStorageSize();
Lng32 maxLength_chars = charOperand->getPrecisionOrMaxNumChars();
CharInfo::CharSet op1_cs = operand1->getCharSet();
if (maxLength_chars <= 0) //if unlimited
maxLength_chars = maxLength_bytes/CharInfo::minBytesPerChar(op1_cs);
if (operand1->getFSDatatype() == REC_CLOB)
{
return new HEAP SQLClob(HEAP
, maxLength_bytes
, Lob_Invalid_Storage
, operand1->supportsSQLnull()
OR operand2->supportsSQLnull()
OR operand3->supportsSQLnull()
);
}
return new HEAP SQLVarChar(HEAP
, CharLenInfo(maxLength_chars, maxLength_bytes)
, operand1->supportsSQLnull()
OR operand2->supportsSQLnull()
OR operand3->supportsSQLnull()
, charOperand->isUpshifted()
, charOperand->isCaseinsensitive()
, operand1->getCharSet()
, charOperand->getCollation()
, charOperand->getCoercibility()
);
}