blob: ab5b4fa8e20bb336a985caab273376e3672d15c8 [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: NAType.C
* Description: Novel Abstraction for a Type
* Created: 11/16/1994
* Language: C++
*
*
*
*
******************************************************************************
*/
#include "NAType.h"
#include "DatetimeType.h"
#include "ComASSERT.h"
#include "NumericType.h"
#include "CharType.h"
#include "MiscType.h"
#include "CmpCommon.h" /* want to put NAType obj's on statement heap ... */
#include "str.h"
// extern declaration
extern short
convertTypeToText_basic(char * text,
Lng32 fs_datatype,
Lng32 length,
Lng32 precision,
Lng32 scale,
rec_datetime_field datetimestart,
rec_datetime_field datetimeend,
short datetimefractprec,
short intervalleadingprec,
short upshift,
short caseinsensitive,
CharInfo::CharSet charSet,
const char * collation_name,
const char * displaydatatype,
short displayCaseSpecific);
// -----------------------------------------------------------------------
// Methods for class NAType
// -----------------------------------------------------------------------
NAType::NAType (const NAType & rhs, NAMemory * h)
: dataStorageSize_ (rhs.dataStorageSize_),
SQLnullFlag_ (rhs.SQLnullFlag_),
SQLnullHdrSize_ (rhs.SQLnullHdrSize_),
varLenFlag_ (rhs.varLenFlag_),
lengthHdrSize_ (rhs.lengthHdrSize_),
dataAlignment_ (rhs.dataAlignment_),
totalAlignment_ (rhs.totalAlignment_),
typeName_ (rhs.typeName_, h),
qualifier_ (rhs.qualifier_),
displayDataType_ (rhs.displayDataType_, h)
{}
NAType::NAType( NAMemory *h,
const NAString& adtName,
NABuiltInTypeEnum ev,
Lng32 dataStorageSize,
NABoolean nullable,
Lng32 SQLnullHdrSize,
NABoolean varLenFlag,
Lng32 lengthHdrSize,
Lng32 dataAlignment
) : typeName_ (h) // memleak fix
, displayDataType_ (h)
{
// The following assertion is commented out so that zero-length
// strings can be supported.
// ComASSERT(dataStorageSize > 0);
// for now, both null indicator has to be a short and the
// var len size can be a short or a long??
// The following assertion is commented out.
// Records can contain nullable fields and not have a
// null Header. Same for arrays.
// ComASSERT(SQLnullHdrSize == 2 || !nullable);
ComASSERT(lengthHdrSize == 2 || lengthHdrSize == 4 || !varLenFlag);
// supported alignments are none, 2, 4, and 8 bytes
if (dataAlignment == 0) dataAlignment = 1;
ComASSERT((dataAlignment == 1) || (dataAlignment == 2) ||
(dataAlignment == 4) || (dataAlignment == 8));
// Do NOT assert(dataStorageSize>0); that is the NAType::isValid() method.
typeName_ = adtName;
qualifier_ = ev;
dataStorageSize_ = dataStorageSize;
SQLnullFlag_ = nullable ? ALLOWS_NULLS : NOT_NULL_NOT_DROPPABLE;
SQLnullHdrSize_ = nullable ? SQLnullHdrSize : 0;
varLenFlag_ = varLenFlag;
lengthHdrSize_ = varLenFlag_ ? lengthHdrSize : 0;
dataAlignment_ = dataAlignment;
// the total alignment of the type is the max of the alignments of
// the null indicator, the var len field, and the data itself,
// where the former two are aligned as numbers
totalAlignment_ = MAXOF(MAXOF(dataAlignment_,SQLnullHdrSize_),lengthHdrSize_);
} // NAType()
// -- set the nullable flag and recompute the alignment of the type
//
// If physical nulls are not supported, then logical nulls are not either
// (if physicalNulls is False, then logicalNulls is ignored).
//
void NAType::setNullable(NABoolean physicalNulls, NABoolean logicalNulls)
{
if (physicalNulls && !logicalNulls)
SQLnullFlag_ = NOT_NULL_DROPPABLE;
else
SQLnullFlag_ = physicalNulls ? ALLOWS_NULLS : NOT_NULL_NOT_DROPPABLE;
SQLnullHdrSize_ = physicalNulls ? SQL_NULL_HDR_SIZE : 0;
totalAlignment_ = MAXOF(MAXOF(dataAlignment_,SQLnullHdrSize_),lengthHdrSize_);
}
// -- Compute the size of the storage required for this ADT
Lng32 NAType::getTotalAlignedSize() const
{
Lng32 size = SQLnullHdrSize_;
Lng32 align = getDataAlignment(); // must be divisible by data alignment
if (size > 0)
{
size = (((size - 1)/align) + 1) * align;
}
// size = ADJUST(size, getDataAlignment());
size += lengthHdrSize_;
size += dataStorageSize_;
return size;
} // getTotalSize()
Lng32 NAType::getTotalSize() const
{
return dataStorageSize_ + getPrefixSize();
} // getTotalSize()
// -- Compute the total size of null indicator, variable length
// indicator, and fillers between them and the data field
Lng32 NAType::getPrefixSize() const
{
// the result must be the smallest number that is greater or equal
// to SQLnullHdrSize_ + lengthHdrSize_ and that is divisible by
// the data alignment.
Lng32 align = getDataAlignment(); // must be divisible by data alignment
//long prefixLen = SQLnullHdrSize_ + lengthHdrSize_;
// if the var length field has an alignment greater than that of the
// null indicator, there is an extra filler between those two fields
// if (lengthHdrSize_ > 2 AND SQLnullHdrSize_ == 2)
// prefixLen = 2 * lengthHdrSize_;
// return the result
// return (SQLnullHdrSize_ + lengthHdrSize_ + align - 1) / align * align;
// for now (FS2 simulator) there is no alignment:
return (SQLnullHdrSize_ + lengthHdrSize_);
}
Lng32 NAType::getPrefixSizeWithAlignment() const
{
// Previous method does not consider alignment and is used by getTotalSize()
// the result must be the smallest number that is greater or equal
// to SQLnullHdrSize_ + lengthHdrSize_ and that is divisible by
// the data alignment.
Lng32 align = getDataAlignment(); // must be divisible by data alignment
// if the var length field has an alignment greater than that of the
// null indicator, there is an extra filler between those two fields
// for now this method does not handle length indicator > 2 bytes
// if (lengthHdrSize_ > 2 AND SQLnullHdrSize_ == 2)
// prefixLen = 2 * lengthHdrSize_;
// return the result
return (SQLnullHdrSize_ + lengthHdrSize_ + align - 1) / align * align;
}
// -- return the total size of this ADT just like NAType::getTotalSize,
// except add filler bytes such that the size is a multiple of its
// alignment (as returned by getByteAlignment())
// -- Equality comparison
NABoolean NAType::operator==(const NAType& other) const
{
if (typeName_ == other.typeName_ &&
qualifier_ == other.qualifier_ &&
dataStorageSize_ == other.dataStorageSize_ &&
SQLnullFlag_ == other.SQLnullFlag_ &&
varLenFlag_ == other.varLenFlag_)
return TRUE;
else
return FALSE;
} // operator==()
NABoolean NAType::equalIgnoreLength(const NAType& other) const
{
if (typeName_ == other.typeName_ &&
qualifier_ == other.qualifier_ &&
SQLnullFlag_ == other.SQLnullFlag_ &&
varLenFlag_ == other.varLenFlag_)
return TRUE;
else
return FALSE;
}
NABoolean NAType::equalIgnoreNull(const NAType& other) const
{
if (typeName_ == other.typeName_ &&
qualifier_ == other.qualifier_ &&
dataStorageSize_ == other.dataStorageSize_ &&
varLenFlag_ == other.varLenFlag_)
return TRUE;
else
return FALSE;
}
NABoolean NAType::equalPhysical(const NAType& other) const
{
if (typeName_ == other.typeName_ &&
qualifier_ == other.qualifier_ &&
dataStorageSize_ == other.dataStorageSize_ &&
supportsSQLnullPhysical() == other.supportsSQLnullPhysical() &&
varLenFlag_ == other.varLenFlag_)
return TRUE;
else
return FALSE;
}
Lng32 NAType::getEncodedKeyLength() const
{
// by default we assume that a NULL indicator gets prepended to the
// encoded form and that any variable indicators get eliminated and
// the data field is extended up to its maximum length.
// There are no fillers in encoded keys (neither between NULL indicators
// and the data nor between different key columns).
return getSQLnullHdrSize() + getNominalSize();
}
const NAType* NAType::synthesizeNullableType(NAMemory * h) const
{
if (this->supportsSQLnull())
return this;
NAType *result = this->newCopy(h);
result->setNullable(TRUE);
return result;
}
const NAType* NAType::synthesizeType(enum NATypeSynthRuleEnum synthRule,
const NAType& operand1,
const NAType& operand2,
NAMemory * h,
UInt32 *flags) const
{
//
// No type synthesis rule was found for this operand. If this is the first
// operand, try the second operand's rules. Otherwise, the expression is
// invalid. Make sure no endless loop can occur if &operand1 == &operand2.
//
if (this == &operand1 AND this != &operand2)
return operand2.synthesizeType(synthRule, operand1, operand2, h, flags);
return NULL;
}
const NAType* NAType::synthesizeTernary(enum NATypeSynthRuleEnum synthRule,
const NAType& operand1,
const NAType& operand2,
const NAType& operand3,
NAMemory * h) const
{
//
// No type synthesis rule was found for this operand. If this is the first
// operand, try the second operand's rules. If this is the second operand,
// try the third operand's rules. Otherwise, the expression is invalid.
//
if (this == &operand1)
return operand2.synthesizeTernary(synthRule, operand1, operand2, operand3,
h);
if (this == &operand2)
return operand3.synthesizeTernary(synthRule, operand1, operand2, operand3,
h);
return NULL;
}
//Tells us if this is a numeric type
NABoolean NAType::isNumeric() const
{
//Any of the following types imply numeric data
switch(getTypeQualifier())
{
case NA_NUMERIC_TYPE:
return TRUE;
case NA_INTERVAL_TYPE:
return TRUE;
case NA_DATETIME_TYPE:
return TRUE;
default:
break;
}
return FALSE;
}
// ---------------------------------------------------------------------
// Methods that return the binary form of the minimum and the maximum
// representable values.
// ---------------------------------------------------------------------
void NAType::minRepresentableValue(void*, Lng32*, NAString**,
NAMemory * h) const {}
void NAType::maxRepresentableValue(void*, Lng32*, NAString**,
NAMemory * h) const {}
NAString* NAType::convertToString(double v, NAMemory * h) const
{
return NULL;
}
NABoolean NAType::createSQLLiteral(const char * buf,
NAString *&stringLiteral,
NABoolean &isNull,
CollHeap *h) const
{
// the base class can handle the case of a NULL value and
// generate a NULL value, otherwise let the derived class
// generate a literal
if (supportsSQLnull())
{
Int32 nullValue = 0;
switch (getSQLnullHdrSize())
{
case 2:
{
Int16 tmp = *((Int16*) buf);
nullValue = tmp;
}
break;
default:
ComASSERT(FALSE);
}
if (nullValue)
{
stringLiteral = new(h) NAString("NULL", h);
isNull = TRUE;
return TRUE;
}
}
isNull = FALSE;
return FALSE;
}
// keyValue INPUT is the string representation of the current value, then
// keyValue is OUTPUT as the string rep of the very NEXT value, and RETURN TRUE.
// If we're already at the maximum value, keyValue returns empty, RETURN FALSE.
NABoolean NAType::computeNextKeyValue(NAString &keyValue) const
{
keyValue = "";
NAString temp =
"Derived class of NAType needs to define virtual method computeNextKeyValue";
ComASSERT(keyValue == temp);
return FALSE;
}
void NAType::print(FILE* ofd, const char* indent)
{
#ifdef TRACING_ENABLED
fprintf(ofd,"%s nominal size %d, total %d\n",
indent,getNominalSize(),getTotalSize());
#endif
}
// -- The external name for the type (text representation)
NAString NAType::getTypeSQLname(NABoolean) const
{
return "UNSUPPORTED TYPE";
}
void NAType::getTypeSQLnull(NAString& ns, NABoolean ignore) const
{
if (! ignore)
if (supportsSQLnullPhysical())
if (supportsSQLnullLogical())
ns += " ALLOWS NULLS";
else
ns += " NO NULLS DROPPABLE";
else
ns += " NO NULLS";
}
// -- Method for returning the hash key
NAString* NAType::getKey(NAMemory * h) const
{
return new (h) NAString(getTypeSQLname(), h);
}
short NAType::getFSDatatype() const
{
return -1;
}
Lng32 NAType::getPrecision() const
{
return -1;
}
Lng32 NAType::getMagnitude() const
{
return -1;
}
Lng32 NAType::getScale() const
{
return -1;
}
Lng32 NAType::getPrecisionOrMaxNumChars() const
{
return getPrecision();
}
Lng32 NAType::getScaleOrCharset() const
{
return getScale();
}
// Implementation of a pure virtual function.
// Check if a conversion error can occur because of nulls.
NABoolean NAType::errorsCanOccur (const NAType& target, NABoolean lax) const
{
if ((!supportsSQLnull()) || (target.supportsSQLnull()))
return FALSE;
return TRUE;
}
Lng32 NAType::getDisplayLength() const
{
return getDisplayLength(getFSDatatype(),
getNominalSize(),
getPrecision(),
getScale(),
0);
}
// Gets the length that a given data type would use in the display tool
Lng32 NAType::getDisplayLength(Lng32 datatype,
Lng32 length,
Lng32 precision,
Lng32 scale,
Lng32 heading_len) const
{
Lng32 d_len = 0;
Int32 scale_len = 0;
if (scale > 0)
scale_len = 1;
switch (datatype)
{
case REC_BPINT_UNSIGNED:
// Can set the display size based on precision. For now treat it as
// unsigned smallint
d_len = SQL_USMALL_DISPLAY_SIZE;
break;
case REC_BIN8_SIGNED:
d_len = SQL_TINY_DISPLAY_SIZE + scale_len;
break;
case REC_BIN8_UNSIGNED:
d_len = SQL_UTINY_DISPLAY_SIZE + scale_len;
break;
case REC_BIN16_SIGNED:
d_len = SQL_SMALL_DISPLAY_SIZE + scale_len;
break;
case REC_BIN16_UNSIGNED:
d_len = SQL_USMALL_DISPLAY_SIZE + scale_len;
break;
case REC_BIN32_SIGNED:
d_len = SQL_INT_DISPLAY_SIZE + scale_len;
break;
case REC_BIN32_UNSIGNED:
d_len = SQL_UINT_DISPLAY_SIZE + scale_len;
break;
case REC_BIN64_SIGNED:
d_len = SQL_LARGE_DISPLAY_SIZE + scale_len;
break;
case REC_BIN64_UNSIGNED:
d_len = SQL_ULARGE_DISPLAY_SIZE + scale_len;
break;
case REC_BYTE_F_ASCII:
d_len = length;
break;
case REC_BYTE_V_ASCII:
case REC_BYTE_V_ASCII_LONG:
d_len = length;
break;
case REC_DECIMAL_UNSIGNED:
d_len = length + scale_len;
break;
case REC_DECIMAL_LSE:
d_len = length + 1 + scale_len;
break;
case REC_NUM_BIG_SIGNED:
{
SQLBigNum tmp(NULL, precision,scale,FALSE,TRUE,FALSE);
d_len = tmp.getDisplayLength();
}
break;
case REC_NUM_BIG_UNSIGNED:
{
SQLBigNum tmp(NULL, precision,scale,FALSE,FALSE,FALSE);
d_len = tmp.getDisplayLength();
}
break;
case REC_FLOAT32:
d_len = SQL_REAL_DISPLAY_SIZE;
break;
case REC_FLOAT64:
d_len = SQL_DOUBLE_PRECISION_DISPLAY_SIZE;
break;
case REC_DATETIME:
/*
switch (precision) {
case SQLDTCODE_DATE:
{
SQLDate tmp(FALSE);
d_len = tmp.getDisplayLength();
}
break;
case SQLDTCODE_TIME:
{
SQLTime tmp(FALSE, (unsigned) scale);
d_len = tmp.getDisplayLength();
}
break;
case SQLDTCODE_TIMESTAMP:
{
SQLTimestamp tmp(FALSE, (unsigned) scale);
d_len = tmp.getDisplayLength();
}
break;
default:
d_len = length;
break;
}
*/
ComASSERT(FALSE);
break;
case REC_INT_YEAR:
case REC_INT_MONTH:
case REC_INT_YEAR_MONTH:
case REC_INT_DAY:
case REC_INT_HOUR:
case REC_INT_DAY_HOUR:
case REC_INT_MINUTE:
case REC_INT_HOUR_MINUTE:
case REC_INT_DAY_MINUTE:
case REC_INT_SECOND:
case REC_INT_MINUTE_SECOND:
case REC_INT_HOUR_SECOND:
case REC_INT_DAY_SECOND:
case REC_INT_FRACTION: {
rec_datetime_field startField;
rec_datetime_field endField;
getIntervalFields(datatype, startField, endField);
SQLInterval interval(NULL, FALSE,
startField,
(UInt32) precision,
endField,
(UInt32) scale);
d_len = interval.getDisplayLength();
}
break;
case REC_BLOB:
case REC_CLOB:
d_len = length;
break;
case REC_BOOLEAN:
d_len = SQL_BOOLEAN_DISPLAY_SIZE;
break;
default:
d_len = length;
break;
}
if (d_len >= heading_len)
return d_len;
else
return heading_len;
}
// A helper function.
// This method returns a text representation of the datatype
// based on the datatype information input to this method.
// Returns -1 in case of error, 0 if all is ok.
/*static*/
short NAType::convertTypeToText(char * text, // OUTPUT
Lng32 fs_datatype, // all other vars: INPUT
Lng32 length,
Lng32 precision,
Lng32 scale,
rec_datetime_field datetimestart,
rec_datetime_field datetimeend,
short datetimefractprec,
short intervalleadingprec,
short upshift,
short caseinsensitive,
CharInfo::CharSet charSet,
CharInfo::Collation collation,
const char * displaydatatype,
short displayCaseSpecific)
{
return convertTypeToText_basic(text,
fs_datatype,
length,
precision,
scale,
datetimestart,
datetimeend,
datetimefractprec,
intervalleadingprec,
upshift,
caseinsensitive,
charSet,
CharInfo::getCollationName(collation),
displaydatatype,
displayCaseSpecific);
}
short NAType::getMyTypeAsHiveText(NAString * outputStr/*out*/) const
{
Lng32 fs_datatype = getFSDatatype();
switch (fs_datatype)
{
case REC_MIN_F_CHAR_H ... REC_MAX_F_CHAR_H:
{
SQLChar * ct = (SQLChar*)this;
char buf[20];
Int32 size = ct->getStrCharLimit();
str_itoa(size, buf);
*outputStr = "char(";
*outputStr += buf;
*outputStr += ")";
}
break;
case REC_MIN_V_CHAR_H ... REC_MAX_V_CHAR_H:
{
SQLVarChar * ct = (SQLVarChar*)this;
if (ct->wasHiveString())
*outputStr = "string";
else
{
char buf[20];
// Hive doesn't have the "n bytes" notation,
// so just take the overall char limit
Int32 size = ct->getStrCharLimit();
str_itoa(size, buf);
*outputStr = "varchar(";
*outputStr += buf;
*outputStr += ")";
}
}
break;
case REC_BIN8_SIGNED:
case REC_BIN8_UNSIGNED:
*outputStr = "tinyint";
break;
case REC_BIN16_SIGNED:
case REC_BIN16_UNSIGNED:
*outputStr = "smallint";
break;
case REC_BIN32_SIGNED:
case REC_BIN32_UNSIGNED:
*outputStr = "int";
break;
case REC_BIN64_SIGNED:
*outputStr = "bigint";
break;
case REC_MIN_DECIMAL ... REC_MAX_DECIMAL:
if (getPrecision() <= 38)
outputStr->format("decimal(%d,%d)",
getPrecision(),
getScale());
else
*outputStr = "double";
break;
case REC_FLOAT32:
*outputStr = "float";
break;
case REC_FLOAT64:
*outputStr = "double";
break;
case REC_BOOLEAN:
*outputStr = "boolean";
break;
case REC_DATETIME:
{
DatetimeIntervalCommonType & dtiCommonType =
(DatetimeIntervalCommonType &) *this;
ComDateTimeStartEnd dtEndField =
(ComDateTimeStartEnd)dtiCommonType.getEndField();
if ((rec_datetime_field)dtEndField == REC_DATE_SECOND)
*outputStr = "timestamp";
else
*outputStr = "date";
}
break;
default:
*outputStr = "unknown";
break;
} // switch
return 0;
}
short NAType::getMyTypeAsText(NAString * outputStr, // output
NABoolean addNullability,
NABoolean addCollation) const
{
// get the right value for all these
Lng32 fs_datatype = getFSDatatype();
ComSInt32 precision = 0;
ComSInt32 scale = 0;
ComDateTimeStartEnd dtStartField = COM_DTSE_UNKNOWN;
ComDateTimeStartEnd dtEndField = COM_DTSE_UNKNOWN;
ComSInt32 dtTrailingPrecision = 0;
ComSInt32 dtLeadingPrecision = 0;
ComBoolean isUpshifted = FALSE;
ComBoolean isCaseinsensitive = FALSE;
CharInfo::CharSet characterSet = CharInfo::UnknownCharSet;
CharInfo::Collation collationSequence = CharInfo::UNKNOWN_COLLATION;
// Prepare parameters in case of a NUMERIC type
if ( getTypeQualifier() == NA_NUMERIC_TYPE )
{
NumericType & numericType = (NumericType &) *this;
scale = getScale();
if (DFS2REC::isFloat(fs_datatype) ||
fs_datatype == REC_BPINT_UNSIGNED || // all the floats
! numericType.binaryPrecision() ) // or if non binary
{
precision = getPrecision();
}
}
// Prepare parameters in case of INTERVAL / DATETIME type
// Note: ComDateTimeStartEnd is the same enum as rec_datetime_field
// (the latter is defined in /common/dfs2rec.h )
if (getTypeQualifier() == NA_DATETIME_TYPE ||
getTypeQualifier() == NA_INTERVAL_TYPE )
{
DatetimeIntervalCommonType & dtiCommonType =
(DatetimeIntervalCommonType &) *this;
dtStartField = (ComDateTimeStartEnd)dtiCommonType.getStartField();
dtEndField = (ComDateTimeStartEnd)dtiCommonType.getEndField();
dtTrailingPrecision = dtiCommonType.getFractionPrecision();
dtLeadingPrecision = dtiCommonType.getLeadingPrecision();
}
// Prepare parameters in case of a CHARACTER type
CharType & charType = (CharType &) *this;
if ( getTypeQualifier() == NA_CHARACTER_TYPE )
{
isUpshifted = charType.isUpshifted();
isCaseinsensitive = charType.isCaseinsensitive();
characterSet = charType.getCharSet();
if (addCollation)
collationSequence = charType.getCollation();
if ( characterSet == CharInfo::UTF8 /* || (characterSet == CharInfo::SJIS */ )
{
// If byte length limit is EXACTLY (maxBytesPerChar * character limit), then use character limit
if ( charType.getNominalSize() == charType.getStrCharLimit() * charType.getBytesPerChar() )
precision = charType.getStrCharLimit();
// else leave precision as 0
}
}
char text[100];
short rc =
NAType::convertTypeToText(text,
fs_datatype,
getNominalSize(),
precision,
scale,
(rec_datetime_field)dtStartField,
(rec_datetime_field)dtEndField,
(short)dtTrailingPrecision,
(short)dtLeadingPrecision,
(short)isUpshifted,
(short)isCaseinsensitive,
characterSet,
collationSequence,
getDisplayDataType().data(),
0);
if (rc)
return -1;
outputStr->append(text);
if (NOT addNullability)
{
return 0; // do not reach the append null below
}
if (NOT supportsSQLnull())
{
outputStr->append(" NOT NULL NOT DROPPABLE");
}
return 0;
}
Lng32 NAType::getSize() const
{
return sizeof(*this) + typeName_.length();
}
Lng32 NAType::hashKey() const
{
return typeName_.hash();
}
// return true iff it is safe to call NAType::hashKey on me
NABoolean NAType::amSafeToHash() const
{
return typeName_.data() != NULL;
}
NABoolean NAType::useHashInFrequentValue() const
{
return (DFS2REC::isAnyCharacter(getFSDatatype()));
}
NABoolean NAType::useHashRepresentation() const
{
if ( DFS2REC::isAnyCharacter(getFSDatatype()))
return TRUE;
if ( getTypeQualifier() == NA_NUMERIC_TYPE &&
getTypeName() == LiteralNumeric &&
getNominalSize() <= 8 ) // make is consistent with
// ConstValue::computeHashValue()
// (see ItemExpr.cpp).
{
return TRUE; // we want to use hash for SQL NUMERIC
// when it is not inside the freq value list
}
return FALSE;
}
NABoolean NAType::isSkewBusterSupportedType() const
{
if ( DFS2REC::isAnyCharacter(getFSDatatype()) )
return TRUE;
if ( getTypeQualifier() == NA_NUMERIC_TYPE &&
getTypeName() == LiteralNumeric
)
return TRUE;
switch (getFSDatatype()) {
// SQL integer data types can be handled
case REC_BIN16_UNSIGNED:
case REC_BIN16_SIGNED:
case REC_BIN32_UNSIGNED:
case REC_BIN32_SIGNED:
case REC_BIN64_SIGNED:
return TRUE;
default:
break;
}
return FALSE;
}
CharInfo::CharSet NAType::getCharSet() const
{ return CharInfo::UnknownCharSet; };
#define MAX_PRECISION_ALLOWED 18
#define MAX_NUM_LEN 16
NAType* NAType::getNATypeForHive(const char* hiveType, NAMemory* heap)
{
if ( !strcmp(hiveType, "tinyint"))
{
if (CmpCommon::getDefault(TRAF_TINYINT_SUPPORT) == DF_OFF)
return new (heap) SQLSmall(heap, TRUE /* neg */, TRUE /* allow NULL*/);
else
return new (heap) SQLTiny(heap, TRUE /* neg */, TRUE /* allow NULL*/);
}
if ( !strcmp(hiveType, "smallint"))
return new (heap) SQLSmall(heap, TRUE /* neg */, TRUE /* allow NULL*/);
if ( !strcmp(hiveType, "int"))
return new (heap) SQLInt(heap, TRUE /* neg */, TRUE /* allow NULL*/);
if ( !strcmp(hiveType, "bigint"))
return new (heap) SQLLargeInt(heap, TRUE /* neg */, TRUE /* allow NULL*/);
if ( !strcmp(hiveType, "boolean"))
return new (heap) SQLBooleanNative(heap, TRUE);
if ( !strcmp(hiveType, "string"))
{
Int32 lenInBytes = CmpCommon::getDefaultLong(HIVE_MAX_STRING_LENGTH_IN_BYTES);
NAString hiveCharset = CmpCommon::getDefaultString(HIVE_DEFAULT_CHARSET);
// ActiveSchemaDB()->getDefaults().getValue(HIVE_DEFAULT_CHARSET);
hiveCharset.toUpper();
CharInfo::CharSet hiveCharsetEnum = CharInfo::getCharSetEnum(hiveCharset);
Int32 maxNumChars = 0;
Int32 storageLen = lenInBytes;
SQLVarChar * nat =
new (heap) SQLVarChar(heap, CharLenInfo(maxNumChars, storageLen),
TRUE, // allow NULL
FALSE, // not upshifted
FALSE, // not case-insensitive
CharInfo::getCharSetEnum(hiveCharset),
CharInfo::DefaultCollation,
CharInfo::IMPLICIT);
nat->setWasHiveString(TRUE);
return nat;
}
if ( !strcmp(hiveType, "float"))
return new (heap) SQLReal(heap, TRUE /* allow NULL*/);
if ( !strcmp(hiveType, "double"))
return new (heap) SQLDoublePrecision(heap, TRUE /* allow NULL*/);
if ( !strcmp(hiveType, "timestamp"))
return new (heap) SQLTimestamp(heap, TRUE /* allow NULL */ , DatetimeType::MAX_FRACTION_PRECISION);
if ( !strcmp(hiveType, "date"))
return new (heap) SQLDate(heap, TRUE /* allow NULL */);
if ( (!strncmp(hiveType, "varchar", 7)) ||
(!strncmp(hiveType, "char", 4)))
{
char maxLen[32];
memset(maxLen, 0, 32);
int i=0,j=0;
int copyit = 0;
int lenStr = strlen(hiveType);
//get length
for(i = 0; i < lenStr ; i++)
{
if(hiveType[i] == '(') //start
{
copyit=1;
continue;
}
else if(hiveType[i] == ')') //stop
break;
if(copyit > 0)
{
maxLen[j] = hiveType[i];
j++;
}
}
Int32 len = atoi(maxLen);
if(len == 0) return NULL; //cannot parse correctly
NAString hiveCharset = CmpCommon::getDefaultString(HIVE_DEFAULT_CHARSET);
hiveCharset.toUpper();
CharInfo::CharSet hiveCharsetEnum = CharInfo::getCharSetEnum(hiveCharset);
Int32 maxNumChars = 0;
Int32 storageLen = len;
if (CharInfo::isVariableWidthMultiByteCharSet(hiveCharsetEnum))
{
// For Hive VARCHARs, the number specified is the max. number of characters,
// while we count in bytes when using HIVE_MAX_STRING_LENGTH_IN_BYTES for Hive STRING
// columns. Set the max character constraint and also adjust the required storage length.
maxNumChars = len;
storageLen = len * CharInfo::maxBytesPerChar(hiveCharsetEnum);
}
if (!strncmp(hiveType, "char", 4))
return new (heap) SQLChar(heap, CharLenInfo(maxNumChars, storageLen),
TRUE, // allow NULL
FALSE, // not upshifted
FALSE, // not case-insensitive
FALSE, // not varchar
CharInfo::getCharSetEnum(hiveCharset),
CharInfo::DefaultCollation,
CharInfo::IMPLICIT);
else
return new (heap) SQLVarChar(heap, CharLenInfo(maxNumChars, storageLen),
TRUE, // allow NULL
FALSE, // not upshifted
FALSE, // not case-insensitive
CharInfo::getCharSetEnum(hiveCharset),
CharInfo::DefaultCollation,
CharInfo::IMPLICIT);
}
if ( !strncmp(hiveType, "decimal", 7) )
{
const Int16 DisAmbiguate = 0;
Int32 i=0, pstart=-1, pend=-1, sstart=-1, send=-1, p=-1, s = -1;
Int32 hiveTypeLen = strlen(hiveType);
char pstr[MAX_NUM_LEN], sstr[MAX_NUM_LEN];
memset(pstr,0,sizeof(pstr));
memset(sstr,0,sizeof(sstr));
for( i = 0; i < hiveTypeLen; i++ )
{
if(hiveType[i] == '(' )
{
pstart = i+1;
}
else if(hiveType[i] == ',')
{
pend = i;
sstart = i+1;
}
else if(hiveType[i] == ')')
{
send = i;
}
else
continue;
}
if(pend == -1) // no comma found, so no sstart and send
{
pend = send;
send = -1;
s = 0;
}
if(pend - pstart > 0)
{
if( (pend - pstart) >= MAX_NUM_LEN ) // too long
return NULL;
strncpy(pstr,hiveType+pstart, pend-pstart);
p=atoi(pstr);
}
if(send - sstart > 0)
{
if( (send - sstart) >= MAX_NUM_LEN ) // too long
return NULL;
strncpy(sstr,hiveType+sstart,send-sstart);
s=atoi(sstr);
}
if( (p>0) && (p <= MAX_PRECISION_ALLOWED) ) //have precision between 1 - 18
{
if( ( s >=0 ) && ( s<= p) ) //have valid scale
return new (heap) SQLNumeric(heap, TRUE, p, s, DisAmbiguate, TRUE);
else
return NULL;
}
else if( p > MAX_PRECISION_ALLOWED)
{
if ( (s>=0) && ( s<= p ) ) //have valid scale
return new (heap) SQLBigNum(heap, p, s, TRUE, TRUE, TRUE);
else
return NULL;
}
//no p and s given, p and s are all initial value
else if( ( p == -1 ) && ( s == -1 ) )
{
// hive define decimal as decimal ( 10, 0 )
return new (heap) SQLNumeric(heap, TRUE, 10, 0, DisAmbiguate, TRUE);
}
else
{
return NULL;
}
}
return NULL;
}