blob: 1b47f8fe2f7b81456b5047fe4906f76151c816b9 [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: <file>
* Description:
*
*
* Created: 7/10/95
* Language: C++
*
*
*
*
*****************************************************************************
*/
#include "Platform.h"
#include <math.h>
#include <unistd.h>
#include <zlib.h>
#include <openssl/md5.h>
#include <openssl/sha.h>
#include "ComSSL.h"
#define MathSqrt(op, err) sqrt(op)
#include <ctype.h>
#include <string.h>
#include <stdio.h>
#include <uuid/uuid.h>
#include <time.h>
#include "NLSConversion.h"
#include "nawstring.h"
#include "exp_stdh.h"
#include "exp_clause_derived.h"
#include "exp_function.h"
#include "ComDefs.h"
#include "SQLTypeDefs.h"
#include "exp_datetime.h"
#include "exp_interval.h"
#include "exp_bignum.h"
#include "ComSysUtils.h"
#include "wstr.h"
#include "ComDiags.h"
#include "ComAnsiNamePart.h"
#include "ComSqlId.h"
#include "ComCextdecs.h"
#include "ex_globals.h"
#include "NAUserId.h"
#include "ComUser.h"
#include "ExpSeqGen.h"
#include "ComJSON.h"
#undef DllImport
#define DllImport __declspec ( dllimport )
#include "rosetta/rosgen.h"
#define ptimez_h_juliantimestamp
#define ptimez_h_including_section
#include "guardian/ptimez.h"
#ifdef ptimez_h_juliantimestamp
Section missing, generate compiler error
#endif
#define ptimez_h_converttimestamp
#define ptimez_h_including_section
#include "guardian/ptimez.h"
#ifdef ptimez_h_converttimestamp
Section missing, generate compiler error
#endif
#define ptimez_h_interprettimestamp
#define ptimez_h_including_section
#include "guardian/ptimez.h"
#ifdef ptimez_h_interprettimestamp
Section missing, generate compiler error
#endif
#define ptimez_h_computetimestamp
#define ptimez_h_including_section
#include "guardian/ptimez.h"
#ifdef ptimez_h_computetimestamp
Section missing, generate compiler error
#endif
#define psecure_h_including_section
#define psecure_h_security_app_priv_
#define psecure_h_security_psb_get_
#define psecure_h_security_ntuser_set_
#include "security/psecure.h"
#ifndef dsecure_h_INCLUDED
#define dsecure_h_INCLUDED
#include "security/dsecure.h"
#endif
#include "security/uid.h"
#include "security/uid.h"
#include "fs/feerrors.h"
extern char * exClauseGetText(OperatorTypeEnum ote);
void setVCLength(char * VCLen, Lng32 VCLenSize, ULng32 value);
static void ExRaiseJSONError(CollHeap* heap, ComDiagsArea** diagsArea, JsonReturnType type);
//#define TOUPPER(c) (((c >= 'a') && (c <= 'z')) ? (c - 32) : c);
//#define TOLOWER(c) (((c >= 'A') && (c <= 'Z')) ? (c + 32) : c);
// -----------------------------------------------------------------------
// There is currently a bug in the tandem include file sys/time.h that
// prevents us to get the definition of gettimeofday from there.
// -----------------------------------------------------------------------
//extern int gettimeofday(struct timeval *, struct timezone *);
ExFunctionAscii::ExFunctionAscii(){};
ExFunctionChar::ExFunctionChar(){};
ExFunctionConvertHex::ExFunctionConvertHex(){};
ExFunctionRepeat::ExFunctionRepeat(){};
ExFunctionReplace::ExFunctionReplace()
{
collation_ = CharInfo::DefaultCollation;
setArgEncodedLen( 0, 0);//initialize the first child encoded length to 0
setArgEncodedLen( 0, 1);//initialize the second child encoded length to 0
};
ex_function_char_length::ex_function_char_length(){};
ex_function_char_length_doublebyte::ex_function_char_length_doublebyte(){};
ex_function_oct_length::ex_function_oct_length(){};
ex_function_position::ex_function_position(){};
ex_function_position_doublebyte::ex_function_position_doublebyte(){};
ex_function_concat::ex_function_concat(){};
ex_function_lower::ex_function_lower(){};
ex_function_upper::ex_function_upper(){};
ex_function_substring::ex_function_substring(){};
ex_function_trim_char::ex_function_trim_char(){};
ExFunctionTokenStr::ExFunctionTokenStr(){};
ExFunctionReverseStr::ExFunctionReverseStr(){};
ex_function_current::ex_function_current(){};
ex_function_unixtime::ex_function_unixtime(){};
ex_function_sleep::ex_function_sleep(){};
ex_function_unique_execute_id::ex_function_unique_execute_id(){};//Trigger -
ex_function_get_triggers_status::ex_function_get_triggers_status(){};//Trigger -
ex_function_get_bit_value_at::ex_function_get_bit_value_at(){};//Trigger -
ex_function_is_bitwise_and_true::ex_function_is_bitwise_and_true(){};//MV
ex_function_explode_varchar::ex_function_explode_varchar(){};
ex_function_hash::ex_function_hash(){};
ex_function_hivehash::ex_function_hivehash(){};
ExHashComb::ExHashComb(){};
ExHiveHashComb::ExHiveHashComb(){};
ExHDPHash::ExHDPHash(){};
ExHDPHashComb::ExHDPHashComb(){};
ex_function_replace_null::ex_function_replace_null(){};
ex_function_mod::ex_function_mod(){};
ex_function_mask::ex_function_mask(){};
ExFunctionShift::ExFunctionShift(){};
ex_function_converttimestamp::ex_function_converttimestamp(){};
ex_function_dateformat::ex_function_dateformat(){};
ex_function_dayofweek::ex_function_dayofweek(){};
ex_function_extract::ex_function_extract(){};
ex_function_juliantimestamp::ex_function_juliantimestamp(){};
ex_function_exec_count::ex_function_exec_count(){};
ex_function_curr_transid::ex_function_curr_transid(){};
ex_function_ansi_user::ex_function_ansi_user(){};
ex_function_user::ex_function_user(){};
ex_function_nullifzero::ex_function_nullifzero(){};
ex_function_nvl::ex_function_nvl(){};
ex_function_json_object_field_text::ex_function_json_object_field_text(){};
ex_function_split_part::ex_function_split_part(){};
ex_function_queryid_extract::ex_function_queryid_extract(){};
ExFunctionUniqueId::ExFunctionUniqueId(){};
ExFunctionRowNum::ExFunctionRowNum(){};
ExFunctionHbaseColumnLookup::ExFunctionHbaseColumnLookup() {};
ExFunctionHbaseColumnsDisplay::ExFunctionHbaseColumnsDisplay() {};
ExFunctionHbaseColumnCreate::ExFunctionHbaseColumnCreate() {};
ExFunctionCastType::ExFunctionCastType() {};
ExFunctionSequenceValue::ExFunctionSequenceValue() {};
ExFunctionHbaseTimestamp::ExFunctionHbaseTimestamp() {};
ExFunctionHbaseVersion::ExFunctionHbaseVersion() {};
ExFunctionSVariance::ExFunctionSVariance(){};
ExFunctionSStddev::ExFunctionSStddev(){};
ExpRaiseErrorFunction::ExpRaiseErrorFunction(){};
ExFunctionRandomNum::ExFunctionRandomNum(){};
ExFunctionGenericUpdateOutput::ExFunctionGenericUpdateOutput(){}; // MV,
ExFunctionInternalTimestamp::ExFunctionInternalTimestamp(){}; // Triggers
ExFunctionRandomSelection::ExFunctionRandomSelection(){};
ExHash2Distrib::ExHash2Distrib(){};
ExProgDistrib::ExProgDistrib(){};
ExProgDistribKey::ExProgDistribKey(){};
ExPAGroup::ExPAGroup(){};
ExFunctionPack::ExFunctionPack(){};
ExUnPackCol::ExUnPackCol(){};
ExFunctionRangeLookup::ExFunctionRangeLookup(){};
ExFunctionCrc32::ExFunctionCrc32(){};
ExFunctionMd5::ExFunctionMd5(){};
ExFunctionSha::ExFunctionSha(){};
ExFunctionSha2::ExFunctionSha2(){};
ExFunctionIsIP::ExFunctionIsIP(){};
ExFunctionInetAton::ExFunctionInetAton(){};
ExFunctionInetNtoa::ExFunctionInetNtoa(){};
ExFunctionSoundex::ExFunctionSoundex(){};
ExFunctionAESEncrypt::ExFunctionAESEncrypt(){};
ExFunctionAESDecrypt::ExFunctionAESDecrypt(){};
ExFunctionAscii::ExFunctionAscii(OperatorTypeEnum oper_type,
Attributes ** attr, Space * space)
: ex_function_clause(oper_type, 2, attr, space)
{
};
ExFunctionChar::ExFunctionChar(OperatorTypeEnum oper_type,
Attributes ** attr, Space * space)
: ex_function_clause(oper_type, 2, attr, space)
{
};
ExFunctionCrc32::ExFunctionCrc32(OperatorTypeEnum oper_type,
Attributes ** attr, Space * space)
: ex_function_clause(oper_type, 2, attr, space)
{
};
ExFunctionMd5::ExFunctionMd5(OperatorTypeEnum oper_type,
Attributes ** attr, Space * space)
: ex_function_clause(oper_type, 2, attr, space)
{
};
ExFunctionSha::ExFunctionSha(OperatorTypeEnum oper_type,
Attributes ** attr, Space * space)
: ex_function_clause(oper_type, 2, attr, space)
{
};
ExFunctionSha2::ExFunctionSha2(OperatorTypeEnum oper_type,
Attributes ** attr, Space * space, Lng32 mode)
: ex_function_clause(oper_type, 2, attr, space), mode(mode)
{
};
ExFunctionIsIP::ExFunctionIsIP(OperatorTypeEnum oper_type,
Attributes ** attr, Space * space)
: ex_function_clause(oper_type, 2, attr, space)
{
};
ExFunctionInetAton::ExFunctionInetAton(OperatorTypeEnum oper_type,
Attributes ** attr, Space * space)
: ex_function_clause(oper_type, 2, attr, space)
{
};
ExFunctionInetNtoa::ExFunctionInetNtoa(OperatorTypeEnum oper_type,
Attributes ** attr, Space * space)
: ex_function_clause(oper_type, 2, attr, space)
{
};
ExFunctionAESEncrypt::ExFunctionAESEncrypt(OperatorTypeEnum oper_type,
Attributes ** attr, Space * space,
int in_args_num,
Int32 aes_mode )
: ex_function_clause(oper_type, in_args_num + 1, attr, space),
args_num(in_args_num), aes_mode(aes_mode)
{
};
ExFunctionAESDecrypt::ExFunctionAESDecrypt(OperatorTypeEnum oper_type,
Attributes ** attr, Space * space,
int in_args_num, Int32 aes_mode)
: ex_function_clause(oper_type, in_args_num + 1, attr, space),
args_num(in_args_num), aes_mode(aes_mode)
{
};
ExFunctionConvertHex::ExFunctionConvertHex(OperatorTypeEnum oper_type,
Attributes ** attr, Space * space)
: ex_function_clause(oper_type, 2, attr, space)
{
};
ExFunctionRepeat::ExFunctionRepeat(OperatorTypeEnum oper_type,
Attributes ** attr, Space * space)
: ex_function_clause(oper_type, 3, attr, space)
{
};
ExFunctionReplace::ExFunctionReplace(OperatorTypeEnum oper_type,
Attributes ** attr, Space * space)
: ex_function_clause(oper_type, 4, attr, space)
{
collation_ = CharInfo::DefaultCollation;
//set first and second child encoded length
setArgEncodedLen( 0, 0);//initialize the first child encoded length to 0
setArgEncodedLen( 0, 1);//initialize the second child encoded length to 0
};
ex_function_char_length::ex_function_char_length(OperatorTypeEnum oper_type,
Attributes ** attr, Space * space)
: ex_function_clause(oper_type, 2, attr, space)
{
};
ex_function_char_length_doublebyte::ex_function_char_length_doublebyte(
OperatorTypeEnum oper_type,
Attributes ** attr, Space * space)
: ex_function_clause(oper_type, 2, attr, space)
{
};
ex_function_oct_length::ex_function_oct_length(OperatorTypeEnum oper_type,
Attributes ** attr, Space * space)
: ex_function_clause(oper_type, 2, attr, space)
{
};
ex_function_position::ex_function_position(OperatorTypeEnum oper_type,
Attributes ** attr, Space * space,
int in_args_num)
: ex_function_clause(oper_type, in_args_num, attr, space),
args_num(in_args_num)
{
};
ex_function_position_doublebyte::ex_function_position_doublebyte
(
OperatorTypeEnum oper_type,
Attributes ** attr, Space * space, int in_args_num
)
: ex_function_clause(oper_type, in_args_num, attr, space),
args_num(in_args_num)
{
};
ex_function_concat::ex_function_concat(OperatorTypeEnum oper_type,
Attributes ** attr, Space * space)
: ex_function_clause(oper_type, 3, attr, space)
{
};
ex_function_lower::ex_function_lower(OperatorTypeEnum oper_type,
Attributes ** attr, Space * space)
: ex_function_clause(oper_type, 2, attr, space)
{
};
ex_function_upper::ex_function_upper(OperatorTypeEnum oper_type,
Attributes ** attr, Space * space)
: ex_function_clause(oper_type, 2, attr, space)
{
};
ex_function_substring::ex_function_substring(OperatorTypeEnum oper_type,
short num_operands,
Attributes ** attr, Space * space)
: ex_function_clause(oper_type, num_operands, attr, space)
{
};
ex_function_translate::ex_function_translate(OperatorTypeEnum oper_type,
Attributes ** attr,
Space * space,
Int32 conv_type,
Int16 flags)
: ex_function_clause(oper_type, 2 , attr, space)
{
conv_type_= conv_type;
flags_ = flags;
};
ex_function_trim::ex_function_trim(OperatorTypeEnum oper_type,
Attributes ** attr,
Space * space,
Int32 mode)
: ex_function_clause(oper_type, 3 , attr, space)
{
mode_ = mode;
};
ex_function_trim_char::ex_function_trim_char(OperatorTypeEnum oper_type,
Attributes ** attr,
Space * space,
Int32 mode)
: ex_function_trim(oper_type, attr, space, mode)
{
};
ExFunctionTokenStr::ExFunctionTokenStr(OperatorTypeEnum oper_type,
Attributes ** attr, Space * space)
: ex_function_clause(oper_type, 3, attr, space)
{
};
ExFunctionReverseStr::ExFunctionReverseStr(OperatorTypeEnum oper_type,
Attributes ** attr, Space * space)
: ex_function_clause(oper_type, 2, attr, space)
{
};
ex_function_current::ex_function_current(OperatorTypeEnum oper_type,
Attributes ** attr, Space * space)
: ex_function_clause(oper_type, 1, attr, space)
{
};
ex_function_sleep::ex_function_sleep(OperatorTypeEnum oper_type, short numOperands,
Attributes ** attr, Space * space)
: ex_function_clause(oper_type, numOperands, attr, space)
{
};
ex_function_unixtime::ex_function_unixtime(OperatorTypeEnum oper_type, short numOperands,
Attributes ** attr, Space * space)
: ex_function_clause(oper_type, numOperands, attr, space)
{
};
//++ Triggers -
ex_function_unique_execute_id::ex_function_unique_execute_id(OperatorTypeEnum oper_type,
Attributes ** attr, Space * space)
: ex_function_clause(oper_type, 1, attr, space)
{
};
//++ Triggers -
ex_function_get_triggers_status::ex_function_get_triggers_status(OperatorTypeEnum oper_type,
Attributes ** attr, Space * space)
: ex_function_clause(oper_type, 1, attr, space)
{
};
//++ Triggers -
ex_function_get_bit_value_at::ex_function_get_bit_value_at(OperatorTypeEnum oper_type,
Attributes ** attr, Space * space)
: ex_function_clause(oper_type, 3, attr, space)
{
};
//++ MV
ex_function_is_bitwise_and_true::ex_function_is_bitwise_and_true(OperatorTypeEnum oper_type,
Attributes ** attr, Space * space)
: ex_function_clause(oper_type, 3, attr, space)
{
};
ex_function_explode_varchar::ex_function_explode_varchar(OperatorTypeEnum oper_type,
short num_operands,
Attributes ** attr,
Space * space,
NABoolean forInsert)
: ex_function_clause(oper_type, num_operands, attr, space),
forInsert_(forInsert)
{
};
ex_function_hash::ex_function_hash(OperatorTypeEnum oper_type,
Attributes ** attr, Space * space)
: ex_function_clause(oper_type, 2, attr, space)
{
};
ex_function_hivehash::ex_function_hivehash(OperatorTypeEnum oper_type,
Attributes ** attr, Space * space)
: ex_function_clause(oper_type, 2, attr, space)
{
};
ExHashComb::ExHashComb(OperatorTypeEnum oper_type,
Attributes ** attr, Space * space)
: ex_function_clause(oper_type, 3, attr, space)
{
};
ExHiveHashComb::ExHiveHashComb(OperatorTypeEnum oper_type,
Attributes ** attr, Space * space)
: ex_function_clause(oper_type, 3, attr, space)
{
};
ExHDPHash::ExHDPHash(OperatorTypeEnum oper_type,
Attributes ** attr, Space * space)
: ex_function_clause(oper_type, 2, attr, space)
{
};
ExHDPHashComb::ExHDPHashComb(OperatorTypeEnum oper_type,
Attributes ** attr, Space * space)
: ex_function_clause(oper_type, 3, attr, space)
{
};
ex_function_replace_null::ex_function_replace_null(OperatorTypeEnum oper_type,
Attributes ** attr,
Space * space)
: ex_function_clause(oper_type, 4, attr, space)
{
};
ex_function_mod::ex_function_mod(OperatorTypeEnum oper_type,
Attributes ** attr, Space * space)
: ex_function_clause(oper_type, 3, attr, space)
{
};
ex_function_mask::ex_function_mask(OperatorTypeEnum oper_type,
Attributes ** attr, Space * space)
: ex_function_clause(oper_type, 3, attr, space)
{
};
ExFunctionShift::ExFunctionShift(OperatorTypeEnum oper_type,
Attributes ** attr, Space * space)
: ex_function_clause(oper_type, 3, attr, space)
{
};
ex_function_bool::ex_function_bool(OperatorTypeEnum oper_type,
Attributes ** attr, Space * space)
: ex_function_clause(oper_type, 1, attr, space)
{
};
ex_function_converttimestamp::ex_function_converttimestamp
( OperatorTypeEnum oper_type
, Attributes ** attr
, Space * space
)
: ex_function_clause(oper_type, 2, attr, space)
{
};
ex_function_dateformat::ex_function_dateformat(OperatorTypeEnum oper_type,
Attributes ** attr,
Space * space,
Int32 dateformat)
: ex_function_clause(oper_type, 2 , attr, space), dateformat_(dateformat)
{
};
ex_function_dayofweek::ex_function_dayofweek(OperatorTypeEnum oper_type,
Attributes ** attr, Space * space)
: ex_function_clause(oper_type, 2, attr, space)
{
};
ex_function_extract::ex_function_extract(OperatorTypeEnum oper_type,
Attributes ** attr,
Space * space,
rec_datetime_field extractField)
: ex_function_clause(oper_type, 2 , attr, space), extractField_(extractField)
{
};
ex_function_juliantimestamp::ex_function_juliantimestamp
( OperatorTypeEnum oper_type
, Attributes ** attr
, Space * space
)
: ex_function_clause(oper_type, 2, attr, space)
{
};
ex_function_exec_count::ex_function_exec_count
( OperatorTypeEnum oper_type
, Attributes ** attr
, Space * space
)
: ex_function_clause(oper_type, 1, attr, space)
{
execCount_ = 0;
};
ex_function_curr_transid::ex_function_curr_transid
( OperatorTypeEnum oper_type
, Attributes ** attr
, Space * space
)
: ex_function_clause(oper_type, 1, attr, space)
{
};
ex_function_ansi_user::ex_function_ansi_user(OperatorTypeEnum oper_type,
Attributes ** attr, Space * space)
: ex_function_clause(oper_type, 1, attr, space)
{
};
ex_function_user::ex_function_user(OperatorTypeEnum oper_type,
Attributes ** attr, Space * space)
: ex_function_clause(oper_type, 2, attr, space)
{
};
ex_function_nullifzero::ex_function_nullifzero(OperatorTypeEnum oper_type,
Attributes ** attr, Space * space)
: ex_function_clause(oper_type, 2, attr, space)
{
};
ex_function_nvl::ex_function_nvl(OperatorTypeEnum oper_type,
Attributes ** attr, Space * space)
: ex_function_clause(oper_type, 3, attr, space)
{
};
ex_function_json_object_field_text::ex_function_json_object_field_text (OperatorTypeEnum oper_type,
Attributes ** attr, Space * space)
: ex_function_clause(oper_type, 3, attr, space)
{
};
ex_function_queryid_extract::ex_function_queryid_extract(OperatorTypeEnum oper_type,
Attributes ** attr, Space * space)
: ex_function_clause(oper_type, 3, attr, space)
{
};
ExFunctionUniqueId::ExFunctionUniqueId(OperatorTypeEnum oper_type,
Attributes ** attr, Space * space)
: ex_function_clause(oper_type, 1, attr, space)
{
};
ExFunctionRowNum::ExFunctionRowNum(OperatorTypeEnum oper_type,
Attributes ** attr, Space * space)
: ex_function_clause(oper_type, 1, attr, space)
{
};
ExFunctionHbaseColumnLookup::ExFunctionHbaseColumnLookup(OperatorTypeEnum oper_type,
Attributes ** attr,
const char * colName,
Space * space)
: ex_function_clause(oper_type, 2, attr, space)
{
strcpy(colName_, colName);
};
ExFunctionHbaseColumnsDisplay::ExFunctionHbaseColumnsDisplay(OperatorTypeEnum oper_type,
Attributes ** attr,
Lng32 numCols,
char * colNames,
Space * space)
: ex_function_clause(oper_type, 2, attr, space),
numCols_(numCols),
colNames_(colNames)
{
};
ExFunctionHbaseColumnCreate::ExFunctionHbaseColumnCreate(OperatorTypeEnum oper_type,
Attributes ** attr,
short numEntries,
short colNameMaxLen,
Int32 colValMaxLen,
short colValVCIndLen,
Space * space)
: ex_function_clause(oper_type, 1, attr, space),
numEntries_(numEntries),
colNameMaxLen_(colNameMaxLen),
colValMaxLen_(colValMaxLen),
colValVCIndLen_(colValVCIndLen)
{
};
ExFunctionSequenceValue::ExFunctionSequenceValue(OperatorTypeEnum oper_type,
Attributes ** attr,
const SequenceGeneratorAttributes &sga,
Space * space)
: ex_function_clause(oper_type, 1, attr, space),
sga_(sga),
flags_(0)
{
};
ExFunctionHbaseTimestamp::ExFunctionHbaseTimestamp(
OperatorTypeEnum oper_type,
Attributes ** attr,
Lng32 colIndex,
Space * space)
: ex_function_clause(oper_type, 2, attr, space),
colIndex_(colIndex),
flags_(0)
{
};
ExFunctionHbaseVersion::ExFunctionHbaseVersion(
OperatorTypeEnum oper_type,
Attributes ** attr,
Lng32 colIndex,
Space * space)
: ex_function_clause(oper_type, 2, attr, space),
colIndex_(colIndex),
flags_(0)
{
};
ExFunctionCastType::ExFunctionCastType(OperatorTypeEnum oper_type,
Attributes ** attr,
Space * space)
: ex_function_clause(oper_type, 2, attr, space)
{
};
ExFunctionSVariance::ExFunctionSVariance(Attributes **attr, Space *space)
: ex_function_clause(ITM_VARIANCE, 4, attr, space)
{
};
ExFunctionSStddev::ExFunctionSStddev(Attributes **attr, Space *space)
: ex_function_clause(ITM_STDDEV, 4, attr, space)
{
};
ExpRaiseErrorFunction::ExpRaiseErrorFunction (Attributes **attr,
Space *space,
Lng32 sqlCode,
NABoolean raiseError,
const char *constraintName,
const char *tableName,
const NABoolean hasStringExp, // -- Triggers
const char * optionalStr)
: ex_function_clause (ITM_RAISE_ERROR, (hasStringExp ? 2 : 1), attr, space),
theSQLCODE_(sqlCode),
constraintName_((char *)constraintName),
tableName_((char *)tableName)
{
setRaiseError(raiseError);
if (optionalStr)
{
strncpy(optionalStr_, optionalStr, MAX_OPTIONAL_STR_LEN);
optionalStr_[MAX_OPTIONAL_STR_LEN] = 0;
}
else
optionalStr_[0] = 0;
};
ExFunctionRandomNum::ExFunctionRandomNum(OperatorTypeEnum opType,
short num_operands,
NABoolean simpleRandom,
Attributes **attr,
Space *space)
: ex_function_clause(opType, num_operands, attr, space),
flags_(0)
{
seed_ = 0;
if (simpleRandom)
flags_ |= SIMPLE_RANDOM;
}
// MV,
ExFunctionGenericUpdateOutput::ExFunctionGenericUpdateOutput(OperatorTypeEnum oper_type,
Attributes **attr,
Space *space)
: ex_function_clause(oper_type, 1, attr, space)
{}
// Triggers
ExFunctionInternalTimestamp::ExFunctionInternalTimestamp(OperatorTypeEnum oper_type,
Attributes **attr,
Space *space)
: ex_function_clause(oper_type, 1, attr, space)
{}
ExFunctionSoundex::ExFunctionSoundex(OperatorTypeEnum oper_type,
Attributes ** attr, Space * space)
: ex_function_clause(oper_type, 2, attr, space)
{
};
ex_function_split_part::ex_function_split_part(OperatorTypeEnum oper_type
, Attributes **attr
, Space *space)
: ex_function_clause(oper_type, 4, attr, space)
{
}
// Triggers
ex_expr::exp_return_type ex_function_get_bit_value_at::eval(char *op_data[],
CollHeap *heap,
ComDiagsArea** diagsArea)
{
Lng32 buffLen = getOperand(1)->getLength(op_data[1]);
// Get the position from operand 2.
Lng32 pos = *(Lng32 *)op_data[2];
// The character we look into
Lng32 charnum = pos / 8;
// The bit in the character we look into
Lng32 bitnum = 8-(pos % 8)-1;
// Check for error conditions.
if ((charnum >= buffLen) || (charnum < 0))
{
ExRaiseSqlError(heap, diagsArea, EXE_GETBIT_ERROR);
return ex_expr::EXPR_ERROR;
}
unsigned char onechar = *(unsigned char *)(op_data[1] + charnum);
unsigned char mask = 1;
mask = mask<<bitnum;
*((ULng32*)op_data[0]) = (ULng32) (mask & onechar ? 1 : 0);
return ex_expr::EXPR_OK;
}
;
//++ MV
// The function returns True if any of the bits is set in both of the strings
ex_expr::exp_return_type ex_function_is_bitwise_and_true::eval(char *op_data[],
CollHeap *heap,
ComDiagsArea** diagsArea)
{
Lng32 leftSize = getOperand(1)->getLength(op_data[1]);
Lng32 rightSize = getOperand(2)->getLength(op_data[2]);
if (leftSize != rightSize)
{
ExRaiseSqlError(heap, diagsArea, EXE_IS_BITWISE_AND_ERROR);
return ex_expr::EXPR_ERROR;
}
// Iterate through all characters until one "bitwise and" returns TRUE
// Starting with False
*(Lng32 *)op_data[0] = 0;
unsigned char *leftCharPtr = (unsigned char *)(op_data[1]);
unsigned char *rightCharPtr = (unsigned char *)(op_data[2]);
unsigned char *endBarrier = rightCharPtr + rightSize;
for (; rightCharPtr < endBarrier; rightCharPtr++, leftCharPtr++)
{
if ((*leftCharPtr) & (*rightCharPtr))
{
*(Lng32 *)op_data[0] = 1;
break;
}
}
return ex_expr::EXPR_OK;
}
ExFunctionRandomSelection::ExFunctionRandomSelection(OperatorTypeEnum opType,
Attributes **attr,
Space *space,
float selProb)
: ExFunctionRandomNum(opType, 1, FALSE, attr, space)
{
if (selProb < 0)
selProb = 0.0;
selProbability_ = selProb;
difference_ = -1;
}
ExHash2Distrib::ExHash2Distrib(Attributes **attr, Space *space)
: ex_function_clause(ITM_HASH2_DISTRIB, 3, attr, space)
{}
ExProgDistrib::ExProgDistrib(Attributes **attr, Space *space)
: ex_function_clause(ITM_PROGDISTRIB, 3, attr, space)
{}
ExProgDistribKey::ExProgDistribKey(Attributes **attr, Space *space)
: ex_function_clause(ITM_PROGDISTRIBKEY, 4, attr, space)
{}
ExPAGroup::ExPAGroup(Attributes **attr, Space *space)
: ex_function_clause(ITM_PAGROUP, 4, attr, space)
{}
ExUnPackCol::ExUnPackCol(Attributes **attr,
Space *space,
Lng32 width,
Lng32 base,
NABoolean nullsPresent)
: width_(width),
base_(base),
ex_function_clause(ITM_UNPACKCOL, 3, attr, space)
{
setNullsPresent(nullsPresent);
};
ExFunctionRangeLookup::ExFunctionRangeLookup(Attributes** attr,
Space* space,
Lng32 numParts,
Lng32 partKeyLen)
: ex_function_clause(ITM_RANGE_LOOKUP, 3, attr, space),
numParts_(numParts),
partKeyLen_(partKeyLen)
{
}
ex_expr::exp_return_type ex_function_concat::eval(char *op_data[],
CollHeap *heap,
ComDiagsArea** diagsArea)
{
Lng32 len1 = getOperand(1)->getLength(op_data[-MAX_OPERANDS+1]);
Lng32 len2 = getOperand(2)->getLength(op_data[-MAX_OPERANDS+2]);
CharInfo::CharSet cs = ((SimpleType *)getOperand(1))->getCharSet();
if ( cs == CharInfo::UTF8 )
{
Int32 prec1 = ((SimpleType *)getOperand(1))->getPrecision();
len1 = Attributes::trimFillerSpaces( op_data[1], prec1, len1, cs );
Int32 prec2 = ((SimpleType *)getOperand(2))->getPrecision();
len2 = Attributes::trimFillerSpaces( op_data[2], prec2, len2, cs );
}
Lng32 max_len = getOperand(0)->getLength();
if ((len1 + len2) > max_len) {
ExRaiseFunctionSqlError(heap, diagsArea, EXE_STRING_OVERFLOW,
derivedFunction(),
origFunctionOperType());
return ex_expr::EXPR_ERROR;
}
Int32 actual_length = len1+len2;
// If operand 0 is varchar, store the sum of operand 1 length and
// operand 2 length in the varlen area.
getOperand(0)->setVarLength((actual_length), op_data[-MAX_OPERANDS]);
// Now, copy the contents of operand 1 followed by the contents of
// operand 2 into operand 0.
str_cpy_all(op_data[0], op_data[1], len1);
str_cpy_all(&op_data[0][len1], op_data[2], len2);
//
// Blankpad the target (if needed).
//
if ((actual_length) < max_len)
str_pad(&op_data[0][actual_length], max_len - actual_length, ' ');
return ex_expr::EXPR_OK;
};
ex_expr::exp_return_type ExFunctionRepeat::eval(char *op_data[],
CollHeap *heap,
ComDiagsArea** diagsArea)
{
Lng32 repeatCount = *(Lng32 *)op_data[2];
Lng32 len1 = getOperand(1)->getLength(op_data[-MAX_OPERANDS+1]);
CharInfo::CharSet cs = ((SimpleType *)getOperand(1))->getCharSet();
if ( cs == CharInfo::UTF8 )
{
Int32 prec1 = ((SimpleType *)getOperand(1))->getPrecision();
len1 = Attributes::trimFillerSpaces( op_data[1], prec1, len1, cs );
}
Lng32 resultMaxLen = getOperand(0)->getLength();
if ((repeatCount < 0) || ((repeatCount * len1) > resultMaxLen))
{
ExRaiseFunctionSqlError(heap, diagsArea, EXE_STRING_OVERFLOW,
derivedFunction(),
origFunctionOperType());
return ex_expr::EXPR_ERROR;
}
Lng32 currPos = 0;
for (Int32 i = 0; i < repeatCount; i++)
{
str_cpy_all(&op_data[0][currPos], op_data[1], len1);
currPos += len1;
}
// If operand 0 is varchar, store the length.
getOperand(0)->setVarLength(currPos, op_data[-MAX_OPERANDS]);
return ex_expr::EXPR_OK;
};
ex_expr::exp_return_type ExFunctionReplace::eval(char *op_data[],
CollHeap *heap,
ComDiagsArea** diagsArea)
{
CharInfo::CharSet cs = ((SimpleType *)getOperand(0))->getCharSet();
// Note: all lengths are byte lengths.
// source string
Lng32 len1 = getOperand(1)->getLength(op_data[-MAX_OPERANDS+1]);
char * str1 = op_data[1];
if ( cs == CharInfo::UTF8 )
{
Int32 prec1 = ((SimpleType *)getOperand(1))->getPrecision();
len1 = Attributes::trimFillerSpaces( str1, prec1, len1, cs );
}
// if caseinsensitive search is to be done, make a copy of the source
// string and upshift it. This string will be used to do the search.
// The original string will be used to replace.
char * searchStr1 = str1;
if ((caseInsensitiveOperation()) && (heap) && (str1))
{
searchStr1 = new(heap) char[len1];
str_cpy_convert(searchStr1, str1, len1, 1);
}
// string to search for in string1
Lng32 len2 = getOperand(2)->getLength(op_data[-MAX_OPERANDS+2]);
char * str2 = op_data[2];
// string to replace string2 with in string1
Lng32 len3 = getOperand(3)->getLength(op_data[-MAX_OPERANDS+3]);
char * str3 = op_data[3];
if ( cs == CharInfo::UTF8 )
{
Int32 prec2 = ((SimpleType *)getOperand(2))->getPrecision();
len2 = Attributes::trimFillerSpaces( str2, prec2, len2, cs );
Int32 prec3 = ((SimpleType *)getOperand(3))->getPrecision();
len3 = Attributes::trimFillerSpaces( str3, prec3, len3, cs );
}
Lng32 resultMaxLen = getOperand(0)->getLength();
char * result = op_data[0];
char * sourceStr = searchStr1;
char * searchStr = str2;
Int32 lenSourceStr = len1; //getArgEncodedLen(0);
Int32 lenSearchStr = len2; //getArgEncodedLen(1);
Int32 effLenSourceStr = len1; //getArgEncodedLen(0);
Int32 effLenSearchStr = len2; //getArgEncodedLen(1);
Int16 nPasses = 1;
if (CollationInfo::isSystemCollation(getCollation()))
{
nPasses= CollationInfo::getCollationNPasses(getCollation());
lenSourceStr = getArgEncodedLen(0);
lenSearchStr = getArgEncodedLen(1);
assert (heap);
sourceStr = new(heap) char [lenSourceStr];
ex_function_encode::encodeCollationSearchKey(
(UInt8 *) str1,
len1,
(UInt8 *) sourceStr,
lenSourceStr,
(Int32 &) effLenSourceStr,
nPasses,
getCollation(),
TRUE);
searchStr = new(heap) char [lenSearchStr];
ex_function_encode::encodeCollationSearchKey(
(UInt8 *) str2,
len2,
(UInt8 *) searchStr,
lenSearchStr,
(Int32 &)effLenSearchStr,
nPasses,
getCollation(),
TRUE);
}
short bpc = (getOperand(1)->widechar() ? 2 : 1);
NABoolean done = FALSE;
Lng32 position;
Lng32 currPosStr1 = 0;
Lng32 currLenStr1 = len1;
Lng32 currPosResult = 0;
Lng32 currLenResult = 0;
while (! done)
{
position =
ex_function_position::findPosition(&sourceStr[currPosStr1 * nPasses],
currLenStr1 * nPasses,
searchStr,
effLenSearchStr,
bpc,
nPasses,
getCollation(),
0,
cs);
if(position < 0)
{
const char *csname = CharInfo::getCharSetName(cs);
ExRaiseSqlError(heap, diagsArea, EXE_INVALID_CHARACTER);
*(*diagsArea) << DgString0(csname) << DgString1("REPLACE FUNCTION");
return ex_expr::EXPR_ERROR;
}
if (position > 0)
{
position = position - 1;
// copy part of str1 from currPosStr1 till position into result
if ((currLenResult + position) > resultMaxLen) {
if (sourceStr && sourceStr != str1)
NADELETEBASIC(sourceStr,(heap));
if (searchStr && searchStr != str2)
NADELETEBASIC(searchStr,(heap));
ExRaiseFunctionSqlError(heap, diagsArea, EXE_STRING_OVERFLOW,
derivedFunction(),
origFunctionOperType());
return ex_expr::EXPR_ERROR;
}
if (position > 0)
{
str_cpy_all(&result[currPosResult], &str1[currPosStr1],
position);
}
currPosResult += position;
currLenResult += position;
currPosStr1 += (position + len2) ;
currLenStr1 -= (position + len2) ;
// now copy str3 to result. This is the replacement.
if ((currLenResult + len3) > resultMaxLen) {
if (sourceStr && sourceStr != str1)
NADELETEBASIC(sourceStr,(heap));
if (searchStr && searchStr != str2)
NADELETEBASIC(searchStr,(heap));
ExRaiseFunctionSqlError(heap, diagsArea, EXE_STRING_OVERFLOW,
derivedFunction(),
origFunctionOperType());
return ex_expr::EXPR_ERROR;
}
str_cpy_all(&result[currPosResult], str3, len3);
currLenResult += len3;
currPosResult += len3;
}
else
{
done = TRUE;
if ((currLenResult + currLenStr1) > resultMaxLen) {
if (sourceStr && sourceStr != str1)
NADELETEBASIC(sourceStr,(heap));
if (searchStr && searchStr != str2)
NADELETEBASIC(searchStr,(heap));
ExRaiseFunctionSqlError(heap, diagsArea, EXE_STRING_OVERFLOW,
derivedFunction(),
origFunctionOperType());
return ex_expr::EXPR_ERROR;
}
if (currLenStr1 > 0)
str_cpy_all(&result[currPosResult], &str1[currPosStr1], currLenStr1);
currLenResult += currLenStr1;
}
}
// If operand 0 is varchar, store the length.
getOperand(0)->setVarLength(currLenResult, op_data[-MAX_OPERANDS]);
if (sourceStr && sourceStr != str1)
NADELETEBASIC(sourceStr,(heap));
if (searchStr && searchStr != str2)
NADELETEBASIC(searchStr,(heap));
return ex_expr::EXPR_OK;
};
ex_expr::exp_return_type ex_function_substring::eval(char *op_data[],
CollHeap *heap,
ComDiagsArea** diagsArea)
{
Int32 len1_bytes = getOperand(1)->getLength(op_data[-MAX_OPERANDS+1]);
// Get the starting position in characters from operand 2.
// This may be a negative value!
Int32 specifiedCharStartPos = *(Lng32 *)op_data[2];
// Starting position in bytes. It can NOT be a negative value.
Int32 startByteOffset = 0; // Assume beginning of buffer for now.
CharInfo::CharSet cs = ((SimpleType *)getOperand(1))->getCharSet();
// Convert number of character to offset in buffer.
if(specifiedCharStartPos > 1)
{
startByteOffset = Attributes::convertCharToOffset(op_data[1], specifiedCharStartPos, len1_bytes, cs);
if(startByteOffset < 0)
{
const char *csname = CharInfo::getCharSetName(cs);
ExRaiseSqlError(heap, diagsArea, EXE_INVALID_CHARACTER);
*(*diagsArea) << DgString0(csname) << DgString1("SUBSTRING FUNCTION");
return ex_expr::EXPR_ERROR;
}
}
else { /* Leave startByteOffset at 0 */ }
// If operand 3 exists, get the length of substring in characters from operand
// 3. Otherwise, if specifiedCharStartPos > 0, length is from specifiedCharStartPos char to end of buf.
// If specifiedCharStartPos is 0, length is all of buf except last character.
// If specifiedCharStartPos is negative, length is even less (by that negative amount).
Int32 inputLen_bytes = len1_bytes ; // Assume byte count = length of string for now
Int32 specifiedLenInChars = inputLen_bytes ; // Assume char count = byte count for now
Int32 prec1 = 0;
if (getNumOperands() == 4)
specifiedLenInChars = *(Lng32 *)op_data[3]; // Use specified desired length for now
if ( cs == CharInfo::UTF8 )
{
prec1 = ((SimpleType *)getOperand(1))->getPrecision();
if ( prec1 )
inputLen_bytes = Attributes::trimFillerSpaces( op_data[1], prec1, inputLen_bytes, cs );
}
// NOTE: Following formula for lastChar works even if specifiedCharStartPos is 0 or negative.
Int32 lastChar = specifiedLenInChars + (specifiedCharStartPos - 1);
// The end of the substr as a byte offset
Int32 endOff_bytes = inputLen_bytes; // Assume length of input for now.
Int32 actualLenInBytes = 0;
if ( startByteOffset >= inputLen_bytes )
{
// Nothing left in buf to copy, so endOff_bytes and actualLenInBytes are OK as is.
startByteOffset = inputLen_bytes; // IGNORE it if specified start > end of buffer!
;
}
else if (lastChar > 0)
{
endOff_bytes = Attributes::convertCharToOffset (op_data[1], lastChar+1, inputLen_bytes, cs);
if(endOff_bytes < 0)
{
const char *csname = CharInfo::getCharSetName(cs);
ExRaiseSqlError(heap, diagsArea, EXE_INVALID_CHARACTER);
*(*diagsArea) << DgString0(csname) << DgString1("SUBSTRING FUNCTION");
return ex_expr::EXPR_ERROR;
}
}
else endOff_bytes = 0;
// Check for error conditions. endOff_bytes will be less than startByteOffset if length is
// less than 0.
if (endOff_bytes < startByteOffset)
{
ExRaiseFunctionSqlError(heap, diagsArea, EXE_SUBSTRING_ERROR,
derivedFunction(),
origFunctionOperType());
return ex_expr::EXPR_ERROR;
}
actualLenInBytes = endOff_bytes - startByteOffset;
// Now, copy the substring of operand 1 from the starting position into
// operand 0, if actualLenInBytes is greater than 0.
if ( actualLenInBytes > 0)
str_cpy_all(op_data[0], &op_data[1][startByteOffset], actualLenInBytes);
//
// Blankpad the target (if needed).
//
Int32 len0_bytes = getOperand(0)->getLength();
if ( (actualLenInBytes < len0_bytes) && prec1 )
str_pad(&op_data[0][actualLenInBytes], len0_bytes - actualLenInBytes, ' ');
// store the length of substring in the varlen indicator.
if (getOperand(0)->getVCIndicatorLength() > 0)
getOperand(0)->setVarLength( actualLenInBytes, op_data[-MAX_OPERANDS] );
return ex_expr::EXPR_OK;
}
ex_expr::exp_return_type ex_function_trim_char::eval(char *op_data[],
CollHeap *heap,
ComDiagsArea** diagsArea)
{
const Int32 lenSrcStrSmallBuf = 128;
char srcStrSmallBuf[lenSrcStrSmallBuf];
const Int32 lenTrimCharSmallBuf = 8;
char trimCharSmallBuf[lenTrimCharSmallBuf];
// find out the length of trim character.
Lng32 len1 = getOperand(1)->getLength(op_data[-MAX_OPERANDS+1]);
CharInfo::CharSet cs = ((SimpleType *)getOperand(0))->getCharSet();
if ( cs == CharInfo::UTF8 )
{
Int32 prec1 = ((SimpleType *)getOperand(1))->getPrecision();
len1 = Attributes::trimFillerSpaces( op_data[1], prec1, len1, cs );
}
Int32 number_bytes = 0;
number_bytes = Attributes::getFirstCharLength(op_data[1], len1, cs);
if(number_bytes < 0)
{
const char *csname = CharInfo::getCharSetName(cs);
ExRaiseSqlError(heap, diagsArea, EXE_INVALID_CHARACTER);
*(*diagsArea) << DgString0(csname) << DgString1("TRIM FUNCTION");
return ex_expr::EXPR_ERROR;
}
// len1 (length of trim character) must be 1 character. Raise an exception if greater
// than 1.
if (len1 != number_bytes)
{
ExRaiseFunctionSqlError(heap, diagsArea, EXE_TRIM_ERROR,
derivedFunction(),
origFunctionOperType());
return ex_expr::EXPR_ERROR;
}
Lng32 len2 = getOperand(2)->getLength(op_data[-MAX_OPERANDS+2]);
if (cs == CharInfo::UTF8) // If so, must ignore any filler spaces at end of string
{
Int32 prec2 = ((SimpleType *)getOperand(2))->getPrecision();
len2 = Attributes::trimFillerSpaces( op_data[2], prec2, len2, cs );
}
Int16 nPasses = 1;
char * trimChar = op_data[1];
char * srcStr = op_data[2];
Lng32 lenSrcStr = len2;
Lng32 lenTrimChar = len1;
Lng32 effLenSourceStr = len2;
Lng32 effLenTrimChar = len1;
// case of collation --
if (CollationInfo::isSystemCollation(getCollation()))
{
nPasses = CollationInfo::getCollationNPasses(getCollation());
//get the length of the encoded source string
lenSrcStr = getSrcStrEncodedLength();
//get length of encoded trim character
lenTrimChar = getTrimCharEncodedLength();
assert (heap);
if (lenSrcStr <= lenSrcStrSmallBuf)
{
srcStr = srcStrSmallBuf;
}
else
{
srcStr = new(heap) char [lenSrcStr];
}
//get encoded key
ex_function_encode::encodeCollationSearchKey(
(UInt8 *) op_data[2],
len2,
(UInt8 *) srcStr,
lenSrcStr,
(Int32 &) effLenSourceStr,
nPasses,
getCollation(),
FALSE);
if (lenTrimChar <= lenTrimCharSmallBuf)
{
trimChar = trimCharSmallBuf;
}
else
{
trimChar = new(heap) char [lenTrimChar];
}
//get encoded key
ex_function_encode::encodeCollationSearchKey(
(UInt8 *) op_data[1],
len1,
(UInt8 *) trimChar,
lenTrimChar,
(Int32 &) effLenTrimChar,
nPasses,
getCollation(),
FALSE);
}
// Find how many leading characters in operand 2 correspond to the trim
// character.
Lng32 len0 = len2;
Lng32 start = 0;
NABoolean notEqualFlag = 0;
if ((getTrimMode() == 1) || (getTrimMode() == 2))
{
while (start <= len2 - len1)
{
for(Int32 i= 0; i < lenTrimChar; i++)
{
if(trimChar[i] != srcStr[start * nPasses +i])
{
notEqualFlag = 1;
break;
}
}
if (notEqualFlag == 0)
{
start += len1;
len0 -= len1;
}
else
break;
}
}
// Find how many trailing characters in operand 2 correspond to the trim
// character.
Int32 end = len2;
Int32 endt;
Int32 numberOfCharacterInBuf;
Int32 bufferLength = end - start;
const Int32 smallBufSize = 128;
char smallBuf[smallBufSize];
notEqualFlag = 0;
if ((getTrimMode() == 0) || (getTrimMode() == 2))
{
char *charLengthInBuf;
if(bufferLength <= smallBufSize)
charLengthInBuf = smallBuf;
else
charLengthInBuf = new(heap) char[bufferLength];
numberOfCharacterInBuf =
Attributes::getCharLengthInBuf(op_data[2] + start,
op_data[2] + end, charLengthInBuf, cs);
if(numberOfCharacterInBuf < 0)
{
if (srcStr && srcStr != op_data[2])
NADELETEBASIC(srcStr,(heap));
if (trimChar && trimChar != op_data[1])
NADELETEBASIC(trimChar,(heap));
const char *csname = CharInfo::getCharSetName(cs);
ExRaiseSqlError(heap, diagsArea, EXE_INVALID_CHARACTER);
*(*diagsArea) << DgString0(csname) << DgString1("TRIM FUNCTION");
return ex_expr::EXPR_ERROR;
}
while (end >= start + len1)
{
if (charLengthInBuf[--numberOfCharacterInBuf] != len1) break;
endt = end - len1;
for(Int32 i = 0; i < lenTrimChar; i++)
{
if (trimChar[i] != srcStr[endt *nPasses + i])
{
notEqualFlag = 1;
break;
}
}
if(notEqualFlag == 0)
{
end = endt;
len0 -= len1;
}
else
break;
}
if(bufferLength > smallBufSize)
NADELETEBASIC(charLengthInBuf, heap);
}
// Result is always a varchar.
// store the length of trimmed string in the varlen indicator.
getOperand(0)->setVarLength(len0, op_data[-MAX_OPERANDS]);
// Now, copy operand 2 skipping the trim characters into
// operand 0.
if (len0 > 0)
str_cpy_all(op_data[0], &op_data[2][start], len0);
if (srcStr && srcStr != srcStrSmallBuf && srcStr != op_data[2] )
NADELETEBASIC(srcStr,(heap));
if (trimChar && trimChar != trimCharSmallBuf && trimChar != op_data[1])
NADELETEBASIC(trimChar,(heap));
return ex_expr::EXPR_OK;
};
ex_expr::exp_return_type ex_function_lower::eval(char *op_data[],
CollHeap* heap,
ComDiagsArea** diagsArea)
{
Int32 len1 = getOperand(1)->getLength(op_data[-MAX_OPERANDS+1]);
CharInfo::CharSet cs = ((SimpleType *)getOperand(0))->getCharSet();
if ( cs == CharInfo::UTF8 )
{
Int32 prec1 = ((SimpleType *)getOperand(1))->getPrecision();
len1 = Attributes::trimFillerSpaces( op_data[1], prec1, len1, cs );
}
getOperand(0)->setVarLength(len1, op_data[-MAX_OPERANDS]);
cnv_charset charset = convertCharsetEnum(cs);
Int32 number_bytes;
Int32 total_bytes_out = 0;
char tmpBuf[4];
UInt32 UCS4value;
UInt16 UCS2value;
// Now, copy the contents of operand 1 after the case change into operand 0.
Int32 len0 = 0;
if(cs == CharInfo::ISO88591)
{
while (len0 < len1)
{
op_data[0][len0] = TOLOWER(op_data[1][len0]);
++len0;
++total_bytes_out;
}
}
else
{
// If character set is UTF8 or SJIS or ?, convert the string to UCS2,
// call UCS2 lower function and convert the string back.
while (len0 < len1)
{
number_bytes =
LocaleCharToUCS4(op_data[1] + len0, len1 - len0, &UCS4value, charset);
if(number_bytes < 0)
{
const char *csname = CharInfo::getCharSetName(cs);
ExRaiseSqlError(heap, diagsArea, EXE_INVALID_CHARACTER);
*(*diagsArea) << DgString0(csname) << DgString1("LOWER FUNCTION");
return ex_expr::EXPR_ERROR;
}
if(number_bytes == 1 && (op_data[1][len0] & 0x80) == 0)
{
op_data[0][len0] = TOLOWER(op_data[1][len0]);
++len0;
++total_bytes_out;
}
else
{
UCS2value = UCS4value & 0XFFFF;
UCS4value = unicode_char_set::to_lower(*(NAWchar *)&UCS2value);
Int32 number_bytes_out =
UCS4ToLocaleChar((const UInt32 *)&UCS4value, tmpBuf,
CharInfo::maxBytesPerChar(cs), charset);
if(number_bytes_out < 0)
{
const char *csname = CharInfo::getCharSetName(cs);
ExRaiseSqlError(heap, diagsArea, EXE_INVALID_CHARACTER);
*(*diagsArea) << DgString0(csname) << DgString1("LOWER FUNCTION");
return ex_expr::EXPR_ERROR;
}
for (Int32 j = 0; j < number_bytes_out; j++)
{
op_data[0][total_bytes_out] = tmpBuf[j];
total_bytes_out++;
}
len0 += number_bytes;
}
}
}
if (getOperand(0)->getVCIndicatorLength() > 0)
getOperand(0)->setVarLength(total_bytes_out, op_data[-MAX_OPERANDS]);
return ex_expr::EXPR_OK;
};
ex_expr::exp_return_type ex_function_upper::eval(char *op_data[],
CollHeap* heap,
ComDiagsArea** diagsArea)
{
Int32 len1 = getOperand(1)->getLength(op_data[-MAX_OPERANDS+1]);
Int32 len0 = getOperand(0)->getLength();
Int32 in_pos = 0;
Int32 out_pos = 0;
CharInfo::CharSet cs = ((SimpleType *)getOperand(1))->getCharSet();
if ( cs == CharInfo::UTF8 )
{
Int32 prec1 = ((SimpleType *)getOperand(1))->getPrecision();
len1 = Attributes::trimFillerSpaces( op_data[1], prec1, len1, cs );
}
Int32 number_bytes;
UInt32 UCS4value = 0;
UInt16 UCS2value = 0;
// Now, copy the contents of operand 1 after the case change into operand 0.
if(cs == CharInfo::ISO88591)
{
while(in_pos < len1)
{
op_data[0][out_pos] = TOUPPER(op_data[1][in_pos]);
++in_pos;
++out_pos;
}
}
else
{
cnv_charset charset = convertCharsetEnum(cs);
// If character set is UTF8 or SJIS or ?, convert the string to UCS2,
// call UCS2 upper function and convert the string back.
while(in_pos < len1)
{
number_bytes =
LocaleCharToUCS4(op_data[1] + in_pos, len1 - in_pos, &UCS4value, charset);
if(number_bytes < 0)
{
const char *csname = CharInfo::getCharSetName(cs);
ExRaiseSqlError(heap, diagsArea, EXE_INVALID_CHARACTER);
*(*diagsArea) << DgString0(csname) << DgString1("UPPER FUNCTION");
return ex_expr::EXPR_ERROR;
}
if(number_bytes == 1 && (op_data[1][in_pos] & 0x80) == 0)
{
op_data[0][out_pos] = TOUPPER(op_data[1][in_pos]);
++in_pos;
++out_pos;
}
else
{
in_pos += number_bytes;
UCS2value = UCS4value & 0XFFFF;
NAWchar wcUpshift[3];
Int32 charCnt = 1; // Default count to 1
// search against unicode_lower2upper_mapping_table_full
NAWchar* tmpWCP = unicode_char_set::to_upper_full(UCS2value);
if ( tmpWCP )
{
wcUpshift[0] = *tmpWCP++;
wcUpshift[1] = *tmpWCP++;
wcUpshift[2] = *tmpWCP ;
charCnt = (*tmpWCP) ? 3 : 2;
}
else
wcUpshift[0] = unicode_char_set::to_upper(UCS2value);
for (Int32 ii = 0 ; ii < charCnt ; ii++)
{
UInt32 UCS4_val = wcUpshift[ii];
char tmpBuf[8];
Int32 out_bytes = UCS4ToLocaleChar((const UInt32 *)&UCS4_val, tmpBuf,
CharInfo::maxBytesPerChar(cs), charset);
if(out_bytes < 0)
{
const char *csname = CharInfo::getCharSetName(cs);
ExRaiseSqlError(heap, diagsArea, EXE_INVALID_CHARACTER);
*(*diagsArea) << DgString0(csname) << DgString1("UPPER FUNCTION");
return ex_expr::EXPR_ERROR;
}
if (out_pos + out_bytes > len0)
{
ExRaiseFunctionSqlError(heap, diagsArea, EXE_STRING_OVERFLOW,
derivedFunction(),
origFunctionOperType());
return ex_expr::EXPR_ERROR;
}
for (Int32 j = 0; j < out_bytes; j++)
{
op_data[0][out_pos] = tmpBuf[j];
++out_pos;
}
}
}
}
}
getOperand(0)->setVarLength(out_pos, op_data[-MAX_OPERANDS]);
return ex_expr::EXPR_OK;
}
ex_expr::exp_return_type ex_function_oct_length::eval(char *op_data[],
CollHeap*,
ComDiagsArea**)
{
// Move operand's length into result.
// The data type of result is long.
Int32 len1 = getOperand(1)->getLength(op_data[-MAX_OPERANDS+1]);
CharInfo::CharSet cs = ((SimpleType *)getOperand(1))->getCharSet();
if ( cs == CharInfo::UTF8 )
{
Int32 prec1 = ((SimpleType *)getOperand(1))->getPrecision();
len1 = Attributes::trimFillerSpaces( op_data[1], prec1, len1, cs );
}
*(Lng32 *)op_data[0] = len1;
return ex_expr::EXPR_OK;
};
ex_expr::exp_return_type ExFunctionAscii::eval(char *op_data[],CollHeap* heap,
ComDiagsArea** diagsArea)
{
CharInfo::CharSet cs = ((SimpleType *)getOperand(1))->getCharSet();
Int32 len1 = getOperand(1)->getLength(op_data[-MAX_OPERANDS+1]);
if (len1 > 0)
{
switch (getOperType() )
{
case ITM_UNICODE_CODE_VALUE:
{
UInt16 temp;
str_cpy_all((char *)&temp, op_data[1], 2);
*(Lng32 *)op_data[0] = temp;
}
break;
case ITM_NCHAR_MP_CODE_VALUE:
{
UInt16 temp;
#if defined( NA_LITTLE_ENDIAN )
// swap the byte order on little-endian machines as NCHAR_MP charsets are stored
// in multi-byte form (i.e. in big-endian order).
temp = reversebytesUS( *((NAWchar*) op_data[1]) );
#else
str_cpy_all((char *)&temp, op_data[1], 2);
#endif
*(UInt32 *)op_data[0] = temp;
}
break;
case ITM_ASCII:
{
Int32 val = (unsigned char)(op_data[1][0]);
if ( (val > 0x7F) && (cs != CharInfo::ISO88591) )
{
ExRaiseSqlError(heap, diagsArea, EXE_BAD_ARG_TO_MATH_FUNC);
**diagsArea << DgString0("ASCII");
if (derivedFunction())
{
**diagsArea << DgSqlCode(-EXE_MAPPED_FUNCTION_ERROR);
**diagsArea << DgString0(exClauseGetText(origFunctionOperType()));
}
return ex_expr::EXPR_ERROR;
}
*(UInt32 *)op_data[0] = (unsigned char)(op_data[1][0]);
break;
}
case ITM_CODE_VALUE:
default:
{
UInt32 UCS4value = 0;
if ( cs == CharInfo::ISO88591 )
UCS4value = *(unsigned char *)(op_data[1]);
else
{
UInt32 firstCharLen =
LocaleCharToUCS4(op_data[1], len1, &UCS4value, convertCharsetEnum(cs));
if( firstCharLen < 0 )
{
const char *csname = CharInfo::getCharSetName(cs);
ExRaiseSqlError(heap, diagsArea, EXE_INVALID_CHARACTER);
*(*diagsArea) << DgString0(csname) << DgString1("CODE_VALUE FUNCTION");
return ex_expr::EXPR_ERROR;
}
}
*(Int32 *)op_data[0] = UCS4value;
break;
}
}
}
else
*(Int32 *)op_data[0] = 0;
return ex_expr::EXPR_OK;
}
ex_expr::exp_return_type ExFunctionChar::eval(char *op_data[],CollHeap* heap,
ComDiagsArea** diagsArea)
{
UInt32 asciiCode = *(Lng32 *)op_data[1];
Int32 charLength = 1;
CharInfo::CharSet cs = ((SimpleType *)getOperand(0))->getCharSet();
if (getOperType() == ITM_CHAR)
{
if (cs == CharInfo::ISO88591)
{
if (asciiCode < 0 || asciiCode > 0xFF)
{
ExRaiseSqlError(heap, diagsArea, EXE_BAD_ARG_TO_MATH_FUNC);
**diagsArea << DgString0("CHAR");
if (derivedFunction())
{
**diagsArea << DgSqlCode(-EXE_MAPPED_FUNCTION_ERROR);
**diagsArea << DgString0(exClauseGetText(origFunctionOperType()));
}
return ex_expr::EXPR_ERROR;
}
else
{
op_data[0][0] = (char)asciiCode;
getOperand(0)->setVarLength(1, op_data[-MAX_OPERANDS]);
return ex_expr::EXPR_OK;
}
}
else // Must be UTF8 (at least until we support SJIS or some other multi-byte charset)
{
Int32 len0_bytes = getOperand(0)->getLength();
ULng32 * UCS4ptr = (ULng32 *)op_data[1];
Int32 charLength = UCS4ToLocaleChar( UCS4ptr, (char *)op_data[0], len0_bytes, cnv_UTF8 );
if ( charLength < 0 )
{
const char *csname = CharInfo::getCharSetName(cs);
ExRaiseSqlError(heap, diagsArea, EXE_INVALID_CHARACTER);
*(*diagsArea) << DgString0(csname) << DgString1("CHAR FUNCTION");
if (derivedFunction())
{
**diagsArea << DgSqlCode(-EXE_MAPPED_FUNCTION_ERROR);
**diagsArea << DgString0(exClauseGetText(origFunctionOperType()));
}
return ex_expr::EXPR_ERROR;
}
else
{
if ( charLength < len0_bytes )
str_pad(((char *)op_data[0]) + charLength, len0_bytes - charLength, ' ');
getOperand(0)->setVarLength(charLength, op_data[-MAX_OPERANDS]);
}
}
}
else
{
// ITM_UNICODE_CHAR or ITM_NCHAR_MP_CHAR
// check if the code value is legal for UNICODE only. No need
// for KANJI/KSC5601 as both take code-point values with any bit-patterns.
if ( (getOperType() == ITM_UNICODE_CHAR) && (asciiCode < 0 || asciiCode >= 0xFFFE))
{
ExRaiseSqlError(heap, diagsArea, EXE_BAD_ARG_TO_MATH_FUNC);
**diagsArea << DgString0("CHAR");
if (derivedFunction())
{
**diagsArea << DgSqlCode(-EXE_MAPPED_FUNCTION_ERROR);
**diagsArea << DgString0(exClauseGetText(origFunctionOperType()));
}
return ex_expr::EXPR_ERROR;
}
NAWchar wcharCode = (NAWchar)asciiCode;
#if defined( NA_LITTLE_ENDIAN )
// swap the byte order on little-endian machines as NCHAR_MP charsets are stored
// in multi-byte form (i.e. in big-endian order).
if (getOperType() == ITM_NCHAR_MP_CHAR)
{
*(NAWchar*)op_data[0] = reversebytesUS(wcharCode);
} else
*(NAWchar*)op_data[0] = wcharCode;
#else
*(NAWchar*)op_data[0] = wcharCode;
#endif
}
return ex_expr::EXPR_OK;
}
ex_expr::exp_return_type ex_function_char_length::eval(char *op_data[],
CollHeap* heap,
ComDiagsArea** diagsArea)
{
Int32 offset = getOperand(1)->getLength(op_data[-MAX_OPERANDS+1]);
Int32 numOfChar = 0;
CharInfo::CharSet cs = ((SimpleType *)getOperand(1))->getCharSet();
if(CharInfo::maxBytesPerChar(cs) == 1)
{
*(Int32 *)op_data[0] = offset;
return ex_expr::EXPR_OK;
}
if ( cs == CharInfo::UTF8 )
{
Int32 prec1 = ((SimpleType *)getOperand(1))->getPrecision();
offset = Attributes::trimFillerSpaces( op_data[1], prec1, offset, cs );
}
// convert to number of character
numOfChar = Attributes::convertOffsetToChar (op_data[1], offset, cs);
if(numOfChar < 0)
{
const char *csname = CharInfo::getCharSetName(cs);
ExRaiseSqlError(heap, diagsArea, EXE_INVALID_CHARACTER);
*(*diagsArea) << DgString0(csname) << DgString1("CHAR FUNCTION");
return ex_expr::EXPR_ERROR;
}
// Move operand's length into result.
// The data type of result is long.
*(Int32 *)op_data[0] = numOfChar;
return ex_expr::EXPR_OK;
};
ex_expr::exp_return_type ExFunctionConvertHex::eval(char *op_data[],
CollHeap* heap,
ComDiagsArea** diagsArea)
{
static const char HexArray[16] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'};
Lng32 len1 = getOperand(1)->getLength(op_data[-MAX_OPERANDS+1]);
if (getOperType() == ITM_CONVERTTOHEX)
{
Int32 i;
if ( DFS2REC::isDoubleCharacter(getOperand(1)->getDatatype()) )
{
NAWchar *w_p = (NAWchar*)op_data[1];
Int32 w_len = len1 / sizeof(NAWchar);
for (i = 0; i < w_len; i++)
{
op_data[0][4 * i ] = HexArray[0x0F & w_p[i] >> 12];
op_data[0][4 * i + 1] = HexArray[0x0F & w_p[i] >> 8];
op_data[0][4 * i + 2] = HexArray[0x0F & w_p[i] >> 4];
op_data[0][4 * i + 3] = HexArray[0x0F & w_p[i]];
}
} else {
CharInfo::CharSet cs = ((SimpleType *)getOperand(1))->getCharSet();
if ( cs == CharInfo::UTF8 )
{
Int32 prec1 = ((SimpleType *)getOperand(1))->getPrecision();
len1 = Attributes::trimFillerSpaces( op_data[1], prec1, len1, cs );
}
for (i = 0; i < len1; i++)
{
op_data[0][2 * i] = HexArray[0x0F & op_data[1][i] >> 4];
op_data[0][2 * i + 1] = HexArray[0x0F & op_data[1][i]];
}
}
getOperand(0)->setVarLength(2 * len1, op_data[-MAX_OPERANDS]);
}
else
{
// convert from hex.
// make sure that length is an even number.
if ((len1 % 2) != 0)
{
ExRaiseSqlError(heap, diagsArea, EXE_BAD_ARG_TO_MATH_FUNC);
**diagsArea << DgString0("CONVERTFROMHEX");
if (derivedFunction())
{
**diagsArea << DgSqlCode(-EXE_MAPPED_FUNCTION_ERROR);
**diagsArea << DgString0(exClauseGetText(origFunctionOperType()));
}
return ex_expr::EXPR_ERROR;
}
Int32 i = 0;
Int32 j = 0;
while (i < len1)
{
if (((op_data[1][i] >= '0') && (op_data[1][i] <= '9')) ||
((op_data[1][i] >= 'A') && (op_data[1][i] <= 'F')) &&
(((op_data[1][i+1] >= '0') && (op_data[1][i+1] <= '9')) ||
((op_data[1][i+1] >= 'A') && (op_data[1][i+1] <= 'F'))))
{
unsigned char upper4Bits;
unsigned char lower4Bits;
if ((op_data[1][i] >= '0') && (op_data[1][i] <= '9'))
upper4Bits = (unsigned char)(op_data[1][i]) - '0';
else
upper4Bits = (unsigned char)(op_data[1][i]) - 'A' + 10;
if ((op_data[1][i+1] >= '0') && (op_data[1][i+1] <= '9'))
lower4Bits = (unsigned char)(op_data[1][i+1]) - '0';
else
lower4Bits = (unsigned char)(op_data[1][i+1]) - 'A' + 10;
op_data[0][j] = (upper4Bits << 4) | lower4Bits;
i += 2;
j++;
}
else
{
ExRaiseSqlError(heap, diagsArea, EXE_BAD_ARG_TO_MATH_FUNC);
**diagsArea << DgString0("CONVERTFROMHEX");
if (derivedFunction())
{
**diagsArea << DgSqlCode(-EXE_MAPPED_FUNCTION_ERROR);
**diagsArea << DgString0(exClauseGetText(origFunctionOperType()));
}
return ex_expr::EXPR_ERROR;
}
} // while
getOperand(0)->setVarLength(len1 / 2, op_data[-MAX_OPERANDS]);
} // CONVERTFROMHEX
return ex_expr::EXPR_OK;
}
Int32 ex_function_position::findPosition (char* pat,
Int32 patLen,
char* src,
Int32 srcLen,
NABoolean patternInFront)
{
Int32 i, j, k;
// Pattern must be able to "fit" in source string
if (patLen > srcLen)
return 0;
// One time check at beginning of src string if flag indicate so.
if (patternInFront)
return ((str_cmp(pat, src, patLen) == 0) ? 1 : 0);
// Search for pattern throughout the src string
for (i=0; (i + patLen) <= srcLen; i++) {
NABoolean found = TRUE ;
for (j=i, k=0; found && (k < patLen); k++, j++) {
if (src[j] != pat[k])
found = 0;
}
if (found)
return i+1;
}
return 0;
}
Lng32 ex_function_position::findPosition
(char * sourceStr,
Lng32 sourceLen,
char * searchStr,
Lng32 searchLen,
short bytesPerChar,
Int16 nPasses,
CharInfo::Collation collation,
short charOffsetFlag , // 1: char, 0: offset
CharInfo::CharSet cs )
{
// If searchLen is <= 0 or searchLen > sourceLen or
// if searchStr is not present in sourceStr,
// return a position of 0;
// otherwise return the position of searchStr in
// sourceStr.
if (searchLen <= 0)
return 0;
Int32 position = 1;
Int32 collPosition = 1;
Int32 char_count = 1;
Int32 number_bytes;
while (position + searchLen -1 <= sourceLen)
{
if (str_cmp(searchStr, &sourceStr[position-1], (Int32)searchLen) != 0)
if (CollationInfo::isSystemCollation(collation))
{
position += nPasses;
collPosition ++;
}
else
{
number_bytes = Attributes::getFirstCharLength
(&sourceStr[position-1], sourceLen - position + 1, cs);
if(number_bytes <= 0)
return (Lng32)-1;
++char_count;
position += number_bytes;
}
else
{
if (CollationInfo::isSystemCollation(collation))
{
return collPosition;
}
else
{
if(charOffsetFlag)
return char_count;
else
return position;
}
}
}
return 0;
}
ex_expr::exp_return_type
ex_function_char_length_doublebyte::eval(char *op_data[],
CollHeap*,
ComDiagsArea**)
{
// Move operand's length into result.
// The data type of result is long.
*(Lng32 *)op_data[0] =
(getOperand(1)->getLength(op_data[-MAX_OPERANDS+1])) >> 1;
return ex_expr::EXPR_OK;
};
Lng32 ex_function_position::errorChecks(Lng32 startPos, Lng32 occurrence,
CollHeap* heap, ComDiagsArea** diagsArea)
{
// startPos is 1 based. Cannot be <= 0
if (startPos < 0)
{
ExRaiseSqlError(heap, diagsArea, -1572);
*(*diagsArea) << DgString0("START POSITION") << DgString1("INSTR function");
return -1;
}
if (startPos == 0)
{
ExRaiseSqlError(heap, diagsArea, -1571);
*(*diagsArea) << DgString0("START POSITION") << DgString1("INSTR function");
return -1;
}
if (occurrence < 0)
{
ExRaiseSqlError(heap, diagsArea, -1572);
*(*diagsArea) << DgString0("OCCURRENCE") << DgString1("INSTR function");
return -1;
}
if (occurrence == 0)
{
ExRaiseSqlError(heap, diagsArea, -1571);
*(*diagsArea) << DgString0("OCCURRENCE") << DgString1("INSTR function");
return -1;
}
return 0;
}
ex_expr::exp_return_type ex_function_position::eval(char *op_data[],
CollHeap* heap,
ComDiagsArea** diagsArea)
{
CharInfo::CharSet cs = ((SimpleType *)getOperand(1))->getCharSet();
// return value is 1 based. First character position is 1.
// search for operand 1
Lng32 len1 = getOperand(1)->getLength(op_data[-MAX_OPERANDS+1]);
if ( cs == CharInfo::UTF8 )
{
Int32 prec1 = ((SimpleType *)getOperand(1))->getPrecision();
len1 = Attributes::trimFillerSpaces( op_data[1], prec1, len1, cs );
}
// in operand 2
Lng32 len2 = getOperand(2)->getLength(op_data[-MAX_OPERANDS+2]);
if ( cs == CharInfo::UTF8 )
{
Int32 prec2 = ((SimpleType *)getOperand(2))->getPrecision();
len2 = Attributes::trimFillerSpaces( op_data[2], prec2, len2, cs );
}
Int32 startPos = 1;
Int32 occurrence = 1;
if (getNumOperands() >= 4) // start position and optional occurrence specified
{
startPos = *(Int32*)op_data[3];
if (getNumOperands() == 5)
occurrence = *(Int32*)op_data[4];
if (errorChecks(startPos, occurrence, heap, diagsArea))
return ex_expr::EXPR_ERROR;
}
// operand2/srcStr is the string to be searched in.
char * srcStr = &op_data[2][startPos-1];
len2 -= (startPos-1);
char * pat = op_data[1];
Lng32 position = 0;
if (len1 > 0)
{
short nPasses = CollationInfo::getCollationNPasses(getCollation());
for (Int32 occ = 1; occ <= occurrence; occ++)
{
position = findPosition(srcStr,
len2,
pat,
len1,
1,
nPasses,
getCollation(),
1,
cs);
if(position < 0)
{
const char *csname = CharInfo::getCharSetName(cs);
ExRaiseSqlError(heap, diagsArea, EXE_INVALID_CHARACTER);
*(*diagsArea) << DgString0(csname) << DgString1("POSITION FUNCTION");
return ex_expr::EXPR_ERROR;
}
if ((occ < occurrence) &&
(position > 0)) // found a matching string
{
// skip the current matched string and continue
srcStr += (position + len1 - 1);
len2 -= (position + len1 - 1);
startPos += (position + len1 -1);
}
} // for occ
if (position > 0) // found matching string
position += (startPos - 1);
}
else
{
// if len1 <= 0, return position of 1.
position = 1;
}
// Now copy the position into result which is a long.
*(Int32 *)op_data[0] = position;
return ex_expr::EXPR_OK;
};
ex_expr::exp_return_type ex_function_position_doublebyte::eval(char *op_data[],
CollHeap*heap,
ComDiagsArea**diagsArea)
{
// len1 and len2 are character lengths.
// len1 is the pattern length to be searched.
Lng32 len1 = ( getOperand(1)->getLength(op_data[-MAX_OPERANDS+1]) ) / sizeof(NAWchar);
// len2 is the length of string to be seached in.
Lng32 len2 = ( getOperand(2)->getLength(op_data[-MAX_OPERANDS+2]) ) / sizeof(NAWchar);
// startPos is character pos and not byte pos
Int32 startPos = 1;
Int32 occurrence = 1;
if (getNumOperands() >= 4)
{
startPos = *(Int32*)op_data[3];
if (getNumOperands() == 5)
occurrence = *(Int32*)op_data[4];
if (ex_function_position::errorChecks(startPos, occurrence,
heap, diagsArea))
return ex_expr::EXPR_ERROR;
}
// operand2/srcStr is the string to be searched in.
NAWchar * srcStr =
(NAWchar*)&op_data[2][startPos*sizeof(NAWchar) - sizeof(NAWchar)];
NAWchar* pat = (NAWchar*)op_data[1];
// start at specified startPos
Lng32 position = startPos;
// If patter length(len1) > srcStr len(len2), return position of 0
if (len1 > len2)
position = 0;
else if (len1 > 0)
{
// if pat is not present in srcStr, return position of 0;
// otherwise return the position of pat in srcStr for the
// specified occurrence.
short found = 0;
for (Int32 occ = 1; occ <= occurrence; occ++)
{
found = 0;
while (position+len1-1 <= len2 && !found)
{
if (wc_str_cmp(pat, srcStr, (Int32)len1))
{
position++;
srcStr += 1;
}
else
found = 1;
}
if ((occ < occurrence) &&
(found)) // found a matching string
{
srcStr += len1;
position += len1;
}
} // for occ
if (! found) // not found matching string, return 0;
position = 0;
}
else
{
// if len1 <= 0, return position of 1.
position = 1;
}
// Now copy the position into result which is a long.
*(Lng32 *)op_data[0] = position;
return ex_expr::EXPR_OK;
};
static Lng32 findTokenPosition(char * sourceStr, Lng32 sourceLen,
char * searchStr, Lng32 searchLen,
short bytesPerChar)
{
// If searchLen is <= 0 or searchLen > sourceLen or
// if searchStr is not present in sourceStr,
// return a position of 0;
// otherwise return the position of searchStr in
// sourceStr.
Lng32 position = 0;
if (searchLen <= 0)
position = 0;
else
{
NABoolean found = FALSE;
position = 1;
while (position+searchLen-1 <= sourceLen && !found)
{
if (str_cmp(searchStr, &sourceStr[position-1], (Int32)searchLen) != 0)
position += bytesPerChar;
else
found = 1;
}
if (!found) position = 0;
}
return position;
}
ex_expr::exp_return_type ExFunctionTokenStr::eval(char *op_data[],
CollHeap* heap,
ComDiagsArea** diagsArea)
{
CharInfo::CharSet cs = ((SimpleType *)getOperand(1))->getCharSet();
// search for operand 1
Lng32 len1 = getOperand(1)->getLength(op_data[-MAX_OPERANDS+1]);
if ( cs == CharInfo::UTF8 )
{
Int32 prec1 = ((SimpleType *)getOperand(1))->getPrecision();
len1 = Attributes::trimFillerSpaces( op_data[1], prec1, len1, cs );
}
// in operand 2
Lng32 len2 = getOperand(2)->getLength(op_data[-MAX_OPERANDS+2]);
if ( cs == CharInfo::UTF8 )
{
Int32 prec2 = ((SimpleType *)getOperand(2))->getPrecision();
len2 = Attributes::trimFillerSpaces( op_data[2], prec2, len2, cs );
}
Lng32 position;
position = findTokenPosition(op_data[2], len2, op_data[1], len1, 1);
if (position <= 0)
{
ExRaiseFunctionSqlError(heap, diagsArea, EXE_INTERNAL_ERROR,
derivedFunction(),
origFunctionOperType());
return ex_expr::EXPR_ERROR;
}
Lng32 startPos = position + len1 - 1;
Lng32 i;
if (op_data[2][startPos] == '\'')
{
// find the ending single quote.
startPos++;
i = startPos;
while ((i < len2) &&
(op_data[2][i] != '\''))
i++;
}
else
{
// find the ending space character
// startPos++;
i = startPos;
while ((i < len2) &&
(op_data[2][i] != ' '))
i++;
}
/* if (op_data[2][startPos] != '\'')
{
ExRaiseFunctionSqlError(heap, diagsArea, EXE_INTERNAL_ERROR,
derivedFunction(),
origFunctionOperType());
return ex_expr::EXPR_ERROR;
}
if (i == len2)
{
ExRaiseFunctionSqlError(heap, diagsArea, EXE_INTERNAL_ERROR,
derivedFunction(),
origFunctionOperType());
return ex_expr::EXPR_ERROR;
}
*/
str_cpy_all(op_data[0], &op_data[2][startPos], (i - startPos));
if ((i - startPos) <= 0)
{
ExRaiseFunctionSqlError(heap, diagsArea, EXE_INTERNAL_ERROR,
derivedFunction(),
origFunctionOperType());
return ex_expr::EXPR_ERROR;
}
// If result is a varchar, store the length of substring
// in the varlen indicator.
if (getOperand(0)->getVCIndicatorLength() > 0)
getOperand(0)->setVarLength(i - startPos, op_data[-MAX_OPERANDS]);
else
{
ExRaiseFunctionSqlError(heap, diagsArea, EXE_INTERNAL_ERROR,
derivedFunction(),
origFunctionOperType());
return ex_expr::EXPR_ERROR;
}
return ex_expr::EXPR_OK;
};
ex_expr::exp_return_type ExFunctionReverseStr::eval(char *op_data[],
CollHeap* heap,
ComDiagsArea** diagsArea)
{
CharInfo::CharSet cs = ((SimpleType *)getOperand(1))->getCharSet();
Lng32 len1 = getOperand(1)->getLength(op_data[-MAX_OPERANDS+1]);
char * tgt = op_data[0];
char * src = op_data[1];
Lng32 srcPos = 0;
Lng32 tgtPos = 0;
if (cs == CharInfo::ISO88591)
{
tgtPos = len1 - 1;
for (srcPos = 0; srcPos < len1; srcPos++)
{
tgt[tgtPos--] = src[srcPos];
}
}
else if (cs == CharInfo::UCS2)
{
Lng32 bpc = unicode_char_set::bytesPerChar();
srcPos = 0;
tgtPos = len1 - bpc;
while (srcPos < len1)
{
str_cpy_all(&tgt[tgtPos], &src[srcPos], bpc);
tgtPos -= bpc;
srcPos += bpc;
}
}
else if (cs == CharInfo::UTF8)
{
UInt32 UCS4value;
cnv_charset charset = convertCharsetEnum(cs);
Lng32 charLen;
srcPos = 0;
tgtPos = len1;
while(srcPos < len1)
{
charLen = LocaleCharToUCS4(&op_data[1][srcPos],
len1 - srcPos,
&UCS4value,
charset);
if (charLen < 0)
{
const char *csname = CharInfo::getCharSetName(cs);
ExRaiseSqlError(heap, diagsArea, EXE_INVALID_CHARACTER);
*(*diagsArea) << DgString0(csname) << DgString1("REVERSE FUNCTION");
return ex_expr::EXPR_ERROR;
}
tgtPos -= charLen;
str_cpy_all(&tgt[tgtPos], &src[srcPos], charLen);
srcPos += charLen;
}
}
else
{
const char *csname = CharInfo::getCharSetName(cs);
ExRaiseSqlError(heap, diagsArea, EXE_INVALID_CHARACTER);
*(*diagsArea) << DgString0(csname) << DgString1("REVERSE FUNCTION");
return ex_expr::EXPR_ERROR;
}
if (getOperand(0)->getVCIndicatorLength() > 0)
getOperand(0)->setVarLength(len1, op_data[-MAX_OPERANDS]);
return ex_expr::EXPR_OK;
};
ex_expr::exp_return_type ex_function_sleep::eval(char *op_data[],
CollHeap* heap,
ComDiagsArea** diagsArea)
{
Int32 sec = 0;
switch (getOperand(1)->getDatatype())
{
case REC_BIN8_SIGNED:
sec = *(Int8 *)op_data[1] ;
if(sec < 0 )
{
ExRaiseSqlError(heap, diagsArea, EXE_BAD_ARG_TO_MATH_FUNC);
*(*diagsArea) << DgString0("SLEEP");
return ex_expr::EXPR_ERROR;
}
sleep(sec);
*(Int64 *)op_data[0] = 1;
break;
case REC_BIN16_SIGNED:
sec = *(short *)op_data[1] ;
if(sec < 0 )
{
ExRaiseSqlError(heap, diagsArea, EXE_BAD_ARG_TO_MATH_FUNC);
*(*diagsArea) << DgString0("SLEEP");
return ex_expr::EXPR_ERROR;
}
sleep(sec);
*(Int64 *)op_data[0] = 1;
break;
case REC_BIN32_SIGNED:
sec = *(Lng32 *)op_data[1];
if(sec < 0 )
{
ExRaiseSqlError(heap, diagsArea, EXE_BAD_ARG_TO_MATH_FUNC);
*(*diagsArea) << DgString0("SLEEP");
return ex_expr::EXPR_ERROR;
}
sleep(sec);
*(Int64 *)op_data[0] = 1;
break;
case REC_BIN64_SIGNED:
sec = *(Int64 *)op_data[1];
if(sec < 0 )
{
ExRaiseSqlError(heap, diagsArea, EXE_BAD_ARG_TO_MATH_FUNC);
*(*diagsArea) << DgString0("SLEEP");
return ex_expr::EXPR_ERROR;
}
sleep(sec);
*(Int64 *)op_data[0] = 1;
break;
default:
ExRaiseSqlError(heap, diagsArea, EXE_BAD_ARG_TO_MATH_FUNC);
*(*diagsArea) << DgString0("SLEEP");
return ex_expr::EXPR_ERROR;
break;
}
//get the seconds to sleep
return ex_expr::EXPR_OK;
}
ex_expr::exp_return_type ex_function_unixtime::eval(char *op_data[],
CollHeap* heap,
ComDiagsArea** diagsArea)
{
char *opData = op_data[1];
//if there is input value
if( getNumOperands() == 2)
{
struct tm ptr;
if (opData == NULL )
{
ExRaiseSqlError(heap, diagsArea, EXE_BAD_ARG_TO_MATH_FUNC);
*(*diagsArea) << DgString0("UNIX_TIMESTAMP");
return ex_expr::EXPR_ERROR;
}
char* r = strptime(opData, "%Y-%m-%d %H:%M:%S", &ptr);
if( (r == NULL) || (*r != '\0') )
{
ExRaiseSqlError(heap, diagsArea, EXE_BAD_ARG_TO_MATH_FUNC);
*(*diagsArea) << DgString0("UNIX_TIMESTAMP");
return ex_expr::EXPR_ERROR;
}
else
*(Int64 *)op_data[0] = mktime(&ptr);
}
else
{
time_t seconds;
seconds = time((time_t *)NULL);
*(Int64 *)op_data[0] = seconds;
}
return ex_expr::EXPR_OK;
}
ex_expr::exp_return_type ex_function_split_part::eval(char *op_data[]
, CollHeap* heap
, ComDiagsArea** diagsArea)
{
size_t sourceLen = getOperand(1)->getLength(op_data[-MAX_OPERANDS+1]);
size_t patternLen = getOperand(2)->getLength(op_data[-MAX_OPERANDS+2]);
Lng32 indexOfTarget = *(Lng32 *)op_data[3];
if (indexOfTarget <= 0)
{
ExRaiseSqlError(heap, diagsArea, EXE_INVALID_FIELD_POSITION);
*(*diagsArea) << DgInt0(indexOfTarget);
return ex_expr::EXPR_ERROR;
}
NAString source(op_data[1], sourceLen);
NAString pattern(op_data[2], patternLen);
Lng32 patternCnt = 0;
StringPos currentTargetPos = 0;
StringPos pos = 0;
while (patternCnt != indexOfTarget)
{
currentTargetPos = pos;
pos = source.index(pattern, pos);
if (pos == NA_NPOS)
break;
pos = pos + patternLen;
patternCnt++;
}
size_t targetLen = 0;
if ((patternCnt == 0)
||((patternCnt != indexOfTarget)
&& (patternCnt != indexOfTarget - 1)))
op_data[0][0] = '\0';
else
{
if (patternCnt == indexOfTarget)
targetLen = pos - currentTargetPos - patternLen;
else //if (patternLen == indexOfTarget-1)
targetLen = sourceLen - currentTargetPos;
str_cpy_all(op_data[0], op_data[1] + currentTargetPos, targetLen);
}
getOperand(0)->setVarLength(targetLen, op_data[-MAX_OPERANDS]);
return ex_expr::EXPR_OK;
}
ex_expr::exp_return_type ex_function_current::eval(char *op_data[],
CollHeap*,
ComDiagsArea**)
{
if (getOperand())
{
ExpDatetime *datetimeOpType = (ExpDatetime *) getOperand(0);
rec_datetime_field srcStartField;
rec_datetime_field srcEndField;
if (datetimeOpType->getDatetimeFields(datetimeOpType->getPrecision(),
srcStartField,
srcEndField) != 0)
{
return ex_expr::EXPR_ERROR;
}
ExpDatetime::currentTimeStamp(op_data[0],
srcStartField,
srcEndField,
datetimeOpType->getScale());
}
else
{
ExpDatetime::currentTimeStamp(op_data[0],
REC_DATE_YEAR,
REC_DATE_SECOND,
ExpDatetime::MAX_DATETIME_FRACT_PREC);
}
return ex_expr::EXPR_OK;
};
// MV,
ex_expr::exp_return_type ExFunctionGenericUpdateOutput::eval(char *op_data[],
CollHeap* heap,
ComDiagsArea** diagsArea)
{
// We do not set the value here.
// The return value is written into the space allocated for it by the
// executor work method.
// The value is initialized to zero here in case VSBB is rejected by the
// optimizer, so the executor will not override this value.
if (origFunctionOperType() == ITM_VSBBROWCOUNT)
*(Lng32 *)op_data[0] = 1; // Simple Insert RowCount - 1 row.
else
*(Lng32 *)op_data[0] = 0; // Simple Insert RowType is 0.
return ex_expr::EXPR_OK;
}
// Triggers -
ex_expr::exp_return_type ExFunctionInternalTimestamp::eval(char *op_data[],
CollHeap* heap,
ComDiagsArea** diagsArea)
{
ex_function_current currentFun;
return (currentFun.eval(op_data, heap, diagsArea));
}
ex_expr::exp_return_type ex_function_bool::eval(char *op_data[],
CollHeap *heap,
ComDiagsArea** diagsArea)
{
ex_expr::exp_return_type retcode = ex_expr::EXPR_OK;
switch (getOperType())
{
case ITM_RETURN_TRUE:
{
*(Lng32 *)op_data[0] = 1;
}
break;
case ITM_RETURN_FALSE:
{
*(Lng32 *)op_data[0] = 0;
}
break;
case ITM_RETURN_NULL:
{
*(Lng32 *)op_data[0] = -1;
}
break;
default:
{
ExRaiseFunctionSqlError(heap, diagsArea, EXE_INTERNAL_ERROR,
derivedFunction(),
origFunctionOperType());
retcode = ex_expr::EXPR_ERROR;
}
break;
}
return retcode;
}
ex_expr::exp_return_type ex_function_converttimestamp::eval(char *op_data[],
CollHeap *heap,
ComDiagsArea** diagsArea)
{
Int64 juliantimestamp;
str_cpy_all((char *) &juliantimestamp, op_data[1], sizeof(juliantimestamp));
const Int64 minJuliantimestamp = (Int64) 1487311632 * (Int64) 100000000;
const Int64 maxJuliantimestamp = (Int64) 2749273487LL * (Int64) 100000000 +
(Int64) 99999999;
if ((juliantimestamp < minJuliantimestamp) ||
(juliantimestamp > maxJuliantimestamp)) {
char tmpbuf[24];
memset(tmpbuf, 0, sizeof(tmpbuf) );
sprintf(tmpbuf, "%ld", juliantimestamp);
ExRaiseSqlError(heap, diagsArea, EXE_CONVERTTIMESTAMP_ERROR);
if(*diagsArea)
**diagsArea << DgString0(tmpbuf);
if(derivedFunction())
{
**diagsArea << DgSqlCode(-EXE_MAPPED_FUNCTION_ERROR);
**diagsArea << DgString0(exClauseGetText(origFunctionOperType()));
}
return ex_expr::EXPR_ERROR;
}
short timestamp[8];
INTERPRETTIMESTAMP(juliantimestamp, timestamp);
short year = timestamp[0];
char month = (char) timestamp[1];
char day = (char) timestamp[2];
char hour = (char) timestamp[3];
char minute = (char) timestamp[4];
char second = (char) timestamp[5];
Lng32 fraction = timestamp[6] * 1000 + timestamp[7];
char *datetimeOpData = op_data[0];
str_cpy_all(datetimeOpData, (char *) &year, sizeof(year));
datetimeOpData += sizeof(year);
*datetimeOpData++ = month;
*datetimeOpData++ = day;
*datetimeOpData++ = hour;
*datetimeOpData++ = minute;
*datetimeOpData++ = second;
str_cpy_all(datetimeOpData, (char *) &fraction, sizeof(fraction));
return ex_expr::EXPR_OK;
}
ex_expr::exp_return_type ex_function_dateformat::eval(char *op_data[],
CollHeap *heap,
ComDiagsArea** diagsArea)
{
char *opData = op_data[1];
char *formatStr = op_data[2];
char *result = op_data[0];
if ((getDateFormat() == ExpDatetime::DATETIME_FORMAT_NUM1) ||
(getDateFormat() == ExpDatetime::DATETIME_FORMAT_NUM2))
{
// numeric to TIME conversion.
if(ExpDatetime::convNumericTimeToASCII(opData,
result,
getOperand(0)->getLength(),
getDateFormat(),
formatStr,
heap,
diagsArea) < 0) {
ExRaiseFunctionSqlError(heap, diagsArea, EXE_INTERNAL_ERROR,
derivedFunction(),
origFunctionOperType());
return ex_expr::EXPR_ERROR;
}
}
else
{
// Convert the given datetime value to an ASCII string value in the
// given format.
//
if ((DFS2REC::isAnyCharacter(getOperand(1)->getDatatype())) &&
(DFS2REC::isDateTime(getOperand(0)->getDatatype())))
{
Lng32 sourceLen = getOperand(1)->getLength(op_data[-MAX_OPERANDS+1]);
ExpDatetime *datetimeOpType = (ExpDatetime *) getOperand(0);
if(datetimeOpType->convAsciiToDate(opData,
sourceLen,
result,
getOperand(0)->getLength(),
getDateFormat(),
heap,
diagsArea,
0) < 0) {
if (diagsArea &&
(!(*diagsArea) ||
((*diagsArea) &&
(*diagsArea)->getNumber(DgSqlCode::ERROR_) == 0)))
{
// we expect convAsciiToDate to raise a diagnostic; if it
// didn't, raise an internal error here
ExRaiseFunctionSqlError(heap, diagsArea, EXE_INTERNAL_ERROR,
derivedFunction(),
origFunctionOperType());
}
return ex_expr::EXPR_ERROR;
}
}
else
{
ExpDatetime *datetimeOpType = (ExpDatetime *) getOperand(1);
if(datetimeOpType->convDatetimeToASCII(opData,
result,
getOperand(0)->getLength(),
getDateFormat(),
formatStr,
heap,
diagsArea) < 0) {
ExRaiseFunctionSqlError(heap, diagsArea, EXE_INTERNAL_ERROR,
derivedFunction(),
origFunctionOperType());
return ex_expr::EXPR_ERROR;
}
}
}
return ex_expr::EXPR_OK;
}
ex_expr::exp_return_type ex_function_dayofweek::eval(char *op_data[],
CollHeap*,
ComDiagsArea**)
{
Int64 interval;
short year;
char month;
char day;
ExpDatetime *datetimeOpType = (ExpDatetime *) getOperand(1);
char *datetimeOpData = op_data[1];
str_cpy_all((char *) &year, datetimeOpData, sizeof(year));
datetimeOpData += sizeof(year);
month = *datetimeOpData++;
day = *datetimeOpData;
interval = datetimeOpType->getTotalDays(year, month, day);
unsigned short result = (unsigned short)((interval + 1) % 7) + 1;
str_cpy_all(op_data[0], (char *) &result, sizeof(result));
return ex_expr::EXPR_OK;
}
static Int64 lcl_dayofweek(Int64 totaldays)
{
return (unsigned short)((totaldays + 1) % 7) + 1;
}
static Int64 lcl_dayofyear(char year, char month, char day)
{
return (Date2Julian(year,month,day)-Date2Julian(year,1,1)+1);
}
#define DAYS_PER_YEAR 365.25 /*consider leap year every four years*/
#define MONTHS_PER_YEAR 12
#define DAYS_PER_MONTH 30
#define HOURS_PER_DAY 24
#define SECONDS_PER_MINUTE 60
#define SECONDS_PER_HOUR 3600
#define SECONDS_PER_DAY 86400
static Int64 lcl_interval(rec_datetime_field eField, Lng32 eCode, char *opdata, UInt32 nLength)
{
if (!opdata)
return 0;
if ( REC_DATE_DECADE == eField && REC_INT_YEAR == eCode )
{
short nValue;
str_cpy_all((char *) &nValue, opdata, sizeof(nValue));
return nValue / 10;
}
if ( REC_DATE_QUARTER == eField && REC_INT_MONTH == eCode )
{
short nValue;
str_cpy_all((char *) &nValue, opdata, sizeof(nValue));
return (nValue-1)/3+1;
}
if ( REC_DATE_EPOCH == eField )
{
Int64 nVal = 0;
if ( SQL_SMALL_SIZE==nLength )
{
short value;
str_cpy_all((char *) &value, opdata, sizeof(value));
nVal = value;
}
else if ( SQL_INT_SIZE==nLength )
{
Lng32 value;
str_cpy_all((char *) &value, opdata, sizeof(value));
nVal = value;
}
else if ( SQL_LARGE_SIZE==nLength )
{
str_cpy_all((char *) &nVal, opdata, sizeof(nVal));
}
if ( REC_INT_YEAR==eCode )
return nVal*DAYS_PER_YEAR*SECONDS_PER_DAY;
else if ( REC_INT_MONTH==eCode
|| REC_INT_YEAR_MONTH==eCode)
{
double result = (double)(nVal/MONTHS_PER_YEAR) * DAYS_PER_YEAR * SECONDS_PER_DAY;
result += (double)(nVal%MONTHS_PER_YEAR) * DAYS_PER_MONTH * SECONDS_PER_DAY;
return Int64(result);
}
else if ( REC_INT_DAY==eCode )
return nVal*SECONDS_PER_DAY;
else if ( REC_INT_HOUR==eCode
|| REC_INT_DAY_HOUR==eCode )
return nVal*SECONDS_PER_HOUR;
else if ( REC_INT_MINUTE==eCode
|| REC_INT_HOUR_MINUTE==eCode
|| REC_INT_DAY_MINUTE==eCode)
return nVal*SECONDS_PER_MINUTE;
else if ( REC_INT_SECOND==eCode
|| REC_INT_MINUTE_SECOND==eCode
|| REC_INT_HOUR_SECOND==eCode
|| REC_INT_DAY_SECOND==eCode )
return nVal;
}
return 0;
}
Int64 ex_function_extract::getExtraTimeValue(rec_datetime_field eField, Lng32 eCode, char *dateTime)
{
short year;
char month;
char day;
char hour = 0;
char minute = 0;
char second = 0;
char millisencond = 0;
if (eField < REC_DATE_CENTURY || eField > REC_DATE_WOM)
return 0;
if (eCode != REC_DTCODE_DATE && eCode != REC_DTCODE_TIMESTAMP)
return 0;
ExpDatetime *datetimeOpType = (ExpDatetime *) getOperand(1);
if (!datetimeOpType)
return 0;
rec_datetime_field eEndFiled = REC_DATE_DAY;
if ( REC_DTCODE_TIMESTAMP == eCode )
eEndFiled = REC_DATE_SECOND;
size_t n = strlen(dateTime);
for (Int32 field = REC_DATE_YEAR; field <= eEndFiled; field++)
{
switch (field)
{
case REC_DATE_YEAR:
{
str_cpy_all((char *) &year, dateTime, sizeof(year));
dateTime += sizeof(year);
}
break;
case REC_DATE_MONTH:
{
month = *dateTime++;
}
break;
case REC_DATE_DAY:
{
day = *dateTime;
if ( REC_DATE_SECOND == eEndFiled )
dateTime++;
}
break;
case REC_DATE_HOUR:
{
hour = *dateTime++;
}
break;
case REC_DATE_MINUTE:
{
minute = *dateTime++;
}
break;
case REC_DATE_SECOND:
{
second = *dateTime;
if (n>7)// 2018-06-20 20:30:15.12 length = 8
{
dateTime++;
millisencond = *dateTime;
}
}
break;
}
}
switch (eField)
{
case REC_DATE_DOW:
{//same with built-in function dayofweek ex_function_dayofweek::eval
Int64 interval = datetimeOpType->getTotalDays(year, month, day);
return lcl_dayofweek(interval);
}
case REC_DATE_DOY:
{
return lcl_dayofyear(year,month,day);
}
case REC_DATE_WOM:
{
return ((day-1)/7+1);
}
case REC_DATE_CENTURY:
{
return (year+99)/100;
}
case REC_DATE_DECADE:
{
return year/10;
}
case REC_DATE_WEEK:
{//same with built-in function week ITM_WEEK
Int64 interval = datetimeOpType->getTotalDays(year, 1, 1);
Int64 dayofweek = lcl_dayofweek(interval);
Int64 dayofyear = lcl_dayofyear(year,month,day);
return (dayofyear-1+dayofweek-1)/7+1;
}
case REC_DATE_QUARTER:
{
return (month-1)/3+1;
}
case REC_DATE_EPOCH:
{
Int64 ndays = datetimeOpType->getTotalDays(year, month, day);
Int64 nJuliandays = datetimeOpType->getTotalDays(1970, 1, 1);
ndays = ndays - nJuliandays;
Int64 ntimestamp = ndays*86400+hour*3600+minute*60+second;
if ( 0!=millisencond )
ntimestamp = ntimestamp*100+millisencond;
return ntimestamp;
}
}
return 0;
}
ex_expr::exp_return_type ex_function_extract::eval(char *op_data[],
CollHeap *heap,
ComDiagsArea** diagsArea)
{
Int64 result = 0;
if (getOperand(1)->getDatatype() == REC_DATETIME) {
ExpDatetime *datetimeOpType = (ExpDatetime *) getOperand(1);
char *datetimeOpData = op_data[1];
rec_datetime_field opStartField;
rec_datetime_field opEndField;
rec_datetime_field extractStartField = getExtractField();
rec_datetime_field extractEndField = extractStartField;
if ( extractStartField >=REC_DATE_CENTURY && extractStartField<=REC_DATE_WOM )
{
result = getExtraTimeValue(extractStartField, datetimeOpType->getPrecision(), datetimeOpData);
copyInteger (op_data[0], getOperand(0)->getLength(), &result, sizeof(result));
return ex_expr::EXPR_OK;
}
if (extractStartField > REC_DATE_MAX_SINGLE_FIELD) {
extractStartField = REC_DATE_YEAR;
if (extractEndField == REC_DATE_YEARQUARTER_EXTRACT ||
extractEndField == REC_DATE_YEARMONTH_EXTRACT ||
extractEndField == REC_DATE_YEARQUARTER_D_EXTRACT ||
extractEndField == REC_DATE_YEARMONTH_D_EXTRACT)
extractEndField = REC_DATE_MONTH;
else {
ExRaiseFunctionSqlError(heap, diagsArea, EXE_INTERNAL_ERROR,
derivedFunction(),
origFunctionOperType());
return ex_expr::EXPR_ERROR;
}
}
if (datetimeOpType->getDatetimeFields(datetimeOpType->getPrecision(),
opStartField,
opEndField) != 0) {
ExRaiseFunctionSqlError(heap, diagsArea, EXE_INTERNAL_ERROR,
derivedFunction(),
origFunctionOperType());
return ex_expr::EXPR_ERROR;
}
for (Int32 field = opStartField; field <= extractEndField; field++) {
switch (field) {
case REC_DATE_YEAR: {
short value;
if (field >= extractStartField && field <= extractEndField) {
str_cpy_all((char *) &value, datetimeOpData, sizeof(value));
result = value;
}
datetimeOpData += sizeof(value);
break;
}
case REC_DATE_MONTH:
case REC_DATE_DAY:
case REC_DATE_HOUR:
case REC_DATE_MINUTE:
if (field >= extractStartField && field <= extractEndField) {
switch (getExtractField())
{
case REC_DATE_YEARQUARTER_EXTRACT:
// 10*year + quarter - human readable quarter format
result = 10*result + ((*datetimeOpData)+2) / 3;
break;
case REC_DATE_YEARQUARTER_D_EXTRACT:
// 4*year + 0-based quarter - dense quarter format, better for MDAM
result = 4*result + (*datetimeOpData-1) / 3;
break;
case REC_DATE_YEARMONTH_EXTRACT:
// 100*year + month - human readable yearmonth format
result = 100*result + *datetimeOpData;
break;
case REC_DATE_YEARMONTH_D_EXTRACT:
// 12*year + 0-based month - dense month format, better for MDAM
result = 12*result + *datetimeOpData-1;
break;
default:
// regular extract of month, day, hour, minute
result = *datetimeOpData;
break;
}
}
datetimeOpData++;
break;
case REC_DATE_SECOND:
if (field == getExtractField()) {
result = *datetimeOpData;
datetimeOpData++;
short fractionPrecision = datetimeOpType->getScale();
if (fractionPrecision > 0) {
do {
result *= 10;
} while (--fractionPrecision > 0);
Lng32 fraction;
str_cpy_all((char *) &fraction, datetimeOpData, sizeof(fraction));
result += fraction;
}
}
break;
default:
ExRaiseFunctionSqlError(heap, diagsArea, EXE_INTERNAL_ERROR,
derivedFunction(),
origFunctionOperType());
return ex_expr::EXPR_ERROR;
}
}
} else {
if (getExtractField() == REC_DATE_DECADE
|| getExtractField() == REC_DATE_QUARTER
|| getExtractField() == REC_DATE_EPOCH)
{
ExpDatetime *datetimeOpType = (ExpDatetime *) getOperand(1);
result = lcl_interval(getExtractField(),getOperand(1)->getDatatype(),op_data[1],getOperand(1)->getLength());
copyInteger (op_data[0], getOperand(0)->getLength(), &result, sizeof(result));
return ex_expr::EXPR_OK;
}
Int64 interval;
switch (getOperand(1)->getLength()) {
case SQL_SMALL_SIZE: {
short value;
str_cpy_all((char *) &value, op_data[1], sizeof(value));
interval = value;
break;
}
case SQL_INT_SIZE: {
Lng32 value;
str_cpy_all((char *) &value, op_data[1], sizeof(value));
interval = value;
break;
}
case SQL_LARGE_SIZE:
str_cpy_all((char *) &interval, op_data[1], sizeof(interval));
break;
default:
ExRaiseSqlError(heap, diagsArea, EXE_INTERNAL_ERROR);
return ex_expr::EXPR_ERROR;
}
rec_datetime_field startField;
if (ExpInterval::getIntervalStartField(getOperand(1)->getDatatype(), startField) != 0)
return ex_expr::EXPR_ERROR;
if (getExtractField() == startField)
result = interval;
else {
switch (getExtractField()) {
case REC_DATE_MONTH:
//
// The sign of the result of a modulus operation involving a negative
// operand is implementation-dependent according to the C++ reference
// manual. In this case, we prefer the result to be negative.
//
result = interval % 12;
if ((interval < 0) && (result > 0))
result = - result;
break;
case REC_DATE_HOUR:
//
// The sign of the result of a modulus operation involving a negative
// operand is implementation-dependent according to the C++ reference
// manual. In this case, we prefer the result to be negative.
//
result = interval % 24;
if ((interval < 0) && (result > 0))
result = - result;
break;
case REC_DATE_MINUTE:
//
// The sign of the result of a modulus operation involving a negative
// operand is implementation-dependent according to the C++ reference
// manual. In this case, we prefer the result to be negative.
//
result = interval % 60;
if ((interval < 0) && (result > 0))
result = - result;
break;
case REC_DATE_SECOND: {
Lng32 divisor = 60;
for (short fp = getOperand(1)->getScale(); fp > 0; fp--)
divisor *= 10;
result = interval;
interval = result / (Int64) divisor;
result -= interval * (Int64) divisor;
break;
}
default:
ExRaiseSqlError(heap, diagsArea, EXE_INTERNAL_ERROR);
return ex_expr::EXPR_ERROR;
}
}
}
copyInteger (op_data[0], getOperand(0)->getLength(), &result, sizeof(result));
return ex_expr::EXPR_OK;
}
ex_expr::exp_return_type ex_function_juliantimestamp::eval(char *op_data[],
CollHeap *heap,
ComDiagsArea** diagsArea)
{
ex_expr::exp_return_type retcode = ex_expr::EXPR_OK;
Int64 juliantimestamp;
char *datetimeOpData = op_data[1];
short year;
char month;
char day;
char hour;
char minute;
char second;
Lng32 fraction;
str_cpy_all((char *) &year, datetimeOpData, sizeof(year));
datetimeOpData += sizeof(year);
month = *datetimeOpData++;
day = *datetimeOpData++;
hour = *datetimeOpData++;
minute = *datetimeOpData++;
second = *datetimeOpData++;
str_cpy_all((char *) &fraction, datetimeOpData, sizeof(fraction));
short timestamp[] = {
year, month, day, hour, minute, second, (short)(fraction / 1000), (short)(fraction % 1000)
};
short error;
juliantimestamp = COMPUTETIMESTAMP(timestamp, &error);
if (error) {
char tmpbuf[24];
memset(tmpbuf, 0, sizeof(tmpbuf) );
sprintf(tmpbuf, "%ld", juliantimestamp);
ExRaiseSqlError(heap, diagsArea, EXE_JULIANTIMESTAMP_ERROR);
if(*diagsArea)
**diagsArea << DgString0(tmpbuf);
if(derivedFunction())
{
**diagsArea << DgSqlCode(-EXE_MAPPED_FUNCTION_ERROR);
**diagsArea << DgString0(exClauseGetText(origFunctionOperType()));
}
return ex_expr::EXPR_ERROR;
}
str_cpy_all(op_data[0], (char *) &juliantimestamp, sizeof(juliantimestamp));
return retcode;
}
ex_expr::exp_return_type ex_function_exec_count::eval(char *op_data[],
CollHeap *heap,
ComDiagsArea** diagsArea)
{
execCount_++;
str_cpy_all(op_data[0], (char *) &execCount_, sizeof(execCount_));
return ex_expr::EXPR_OK;
}
ex_expr::exp_return_type ex_function_curr_transid::eval(char *op_data[],
CollHeap *heap,
ComDiagsArea** diagsArea)
{
// this function is not used yet anywhere, whoever wants to start using
// it should fill in the missing code here
ExRaiseFunctionSqlError(heap, diagsArea, EXE_USER_FUNCTION_ERROR,
derivedFunction(),
origFunctionOperType());
return ex_expr::EXPR_ERROR;
}
// -----------------------------------------------------------------------
// Helper function for CURRENT_USER and SESSION_USER function.
// Used by exp and UDR code to get the CURRENT_USER and SESSION_USER
// information. SESSION_USER is the user that is logged on to the
// current SQL session. CURRENT_USER is the one with whose privileges
// a SQL statement is executed, With Definer Rights SPJ, the CURRENT_USER is
// the owner of the SPJ while SESSION_USER is the user who invoked the SPJ.
//
// Returns the current login user name as a C-style string (null terminated)
// in inputUserNameBuffer parameter.
// (e.g. returns "Domain1\Administrator" on NT if logged
// in as Domain1\Administrator,
// "role-mgr" on NSK if logged in as alias "role-mgr",
// "ROLE.MGR" on NSK if logged in as Guardian userid ROLE.MGR)
// Returns FEOK as the return value on success, otherwise returns an error status.
// Returns FEBUFTOOSMALL if the input buffer supplied is not big enough to
// accommodate the actual user name.
// Optionally returns the actual length of the user name (in bytes) in
// actualLength parameter. Returns 0 as the actual length if the function returns
// an error code, except for FEBUFTOOSMALL return code in which case it
// returns the actual length so that the caller can get an idea of the minimum
// size of the input buffer to be provided.
// -----------------------------------------------------------------------
short exp_function_get_user(
OperatorTypeEnum userType, // IN - CURRENT_USER or SESSION_USER
char *inputUserNameBuffer, // IN - buffer for returning the user name
Lng32 inputBufferLength, // IN - length(max) of the above buffer in bytes
Lng32 *actualLength) // OUT optional - actual length of the user name
{
if (actualLength)
*actualLength = 0;
short result = FEOK;
Int32 lActualLen = 0;
Int32 userID;
if (userType == ITM_SESSION_USER)
userID = ComUser::getSessionUser();
else
// Default to CURRENT_USER
userID = ComUser::getCurrentUser();
assert (userID != NA_UserIdDefault);
char userName[MAX_USERNAME_LEN+1];
Int16 status = ComUser::getUserNameFromUserID( (Int32) userID
, (char *)&userName
, (Int32) inputBufferLength
, lActualLen );
if (status == FEOK)
{
str_cpy_all(inputUserNameBuffer, userName, lActualLen);
inputUserNameBuffer[lActualLen] = '\0';
}
else
result = FEBUFTOOSMALL;
if (((result == FEOK) || (result == FEBUFTOOSMALL)) && actualLength)
*actualLength = lActualLen;
return result;
}
ex_expr::exp_return_type ex_function_ansi_user::eval(char *op_data[],
CollHeap *heap,
ComDiagsArea** diagsArea)
{
const Lng32 MAX_USER_NAME_LEN = ComSqlId::MAX_LDAP_USER_NAME_LEN;
char username[MAX_USER_NAME_LEN + 1];
Lng32 username_len = 0;
short retcode = FEOK;
retcode = exp_function_get_user ( getOperType(),
username,
MAX_USER_NAME_LEN + 1,
&username_len
);
if (((retcode != FEOK) && (retcode != FENOTFOUND)) ||
((retcode == FEOK) && (username_len == 0)) ) {
ExRaiseFunctionSqlError(heap, diagsArea, EXE_USER_FUNCTION_ERROR,
derivedFunction(),
origFunctionOperType());
return ex_expr::EXPR_ERROR;
}
str_cpy_all(op_data[0], username, username_len);
getOperand(0)->setVarLength(username_len, op_data[-MAX_OPERANDS]);
return ex_expr::EXPR_OK;
}
ex_expr::exp_return_type ex_function_user::eval(char *op_data[],
CollHeap *heap,
ComDiagsArea** diagsArea)
{
Int32 userIDLen = getOperand(1)->getLength(op_data[-MAX_OPERANDS+1]);
Int64 id64;
switch (userIDLen)
{
case SQL_SMALL_SIZE:
id64 = *((short *) op_data[1]);
break;
case SQL_INT_SIZE:
id64 = *((Lng32 *) op_data[1]);
break;
case SQL_LARGE_SIZE:
id64 = *((Int64 *) op_data[1]);
break;
default:
ExRaiseFunctionSqlError(heap, diagsArea, EXE_USER_FUNCTION_ERROR,
derivedFunction(),
origFunctionOperType());
return ex_expr::EXPR_ERROR;
}
if (id64 < -SQL_INT32_MAX || id64 > SQL_INT32_MAX)
{
ExRaiseFunctionSqlError(heap, diagsArea, EXE_USER_FUNCTION_ERROR,
derivedFunction(),
origFunctionOperType());
return ex_expr::EXPR_ERROR;
}
Int32 authID = (Int32)(id64);
// *****************************************************************************
// * *
// * Code to handle functions AUTHNAME and AUTHTYPE. Piggybacked on USER *
// * function code in parser, binder, and optimizer. Perhaps there is a *
// * better way to implement. *
// * *
// * AUTHNAME invokes the porting layer, which calls CLI, as it may be *
// * necessary to read metadata (and therefore have a transaction within *
// * a transaction). *
// * *
// * AUTHTYPE calls Catman directly, as Catman knows the values and ranges *
// * for various types of authentication ID values. Examples include *
// * PUBLIC, SYSTEM, users, and roles. AUTHTYPE returns a single character *
// * that can be used within a case, if, or where clause. *
// * *
// *****************************************************************************
switch (getOperType())
{
case ITM_AUTHNAME:
{
Int16 result;
Int32 authNameLen = 0;
char authName[MAX_AUTHNAME_LEN + 1];
result = ComUser::getAuthNameFromAuthID(authID,
authName,
sizeof(authName),
authNameLen);
if (result != FEOK)
{
ExRaiseFunctionSqlError(heap, diagsArea, EXE_USER_FUNCTION_ERROR,
derivedFunction(),
origFunctionOperType());
return ex_expr::EXPR_ERROR;
}
if (authNameLen > getOperand(0)->getLength())
{
ExRaiseFunctionSqlError(heap, diagsArea, EXE_USER_FUNCTION_ERROR,
derivedFunction(),
origFunctionOperType());
return ex_expr::EXPR_ERROR;
}
getOperand(0)->setVarLength(authNameLen, op_data[-MAX_OPERANDS]);
str_cpy_all(op_data[0], authName, authNameLen);
return ex_expr::EXPR_OK;
}
case ITM_AUTHTYPE:
{
char authType[2];
authType[1] = 0;
authType[0] = ComUser::getAuthType(authID);
getOperand(0)->setVarLength(1, op_data[-MAX_OPERANDS]);
str_cpy_all(op_data[0], authType, 1);
return ex_expr::EXPR_OK;
}
case ITM_USER:
case ITM_USERID:
default:
{
// Drop down to user code
}
}
Int32 userNameLen = 0;
char userName[MAX_USERNAME_LEN+1];
Int16 result = ComUser::getUserNameFromUserID(authID,
(char *)&userName,
MAX_USERNAME_LEN+1,
userNameLen);
if ((result != FEOK) && (result != FENOTFOUND))
{
ExRaiseFunctionSqlError(heap, diagsArea, EXE_USER_FUNCTION_ERROR,
derivedFunction(),
origFunctionOperType());
return ex_expr::EXPR_ERROR;
}
else if (result == FENOTFOUND || userNameLen == 0)
{
// set the user name same as user id
// avoids exceptions if userID not present in USERS table
if (authID < 0)
{
userName[0] = '-';
str_itoa((ULng32)(-authID), &userName[1]);
}
else
{
str_itoa((ULng32)(authID), userName);
}
userNameLen = str_len(userName);
}
if (userNameLen > getOperand(0)->getLength())
{
ExRaiseFunctionSqlError(heap, diagsArea, EXE_USER_FUNCTION_ERROR,
derivedFunction(),
origFunctionOperType());
return ex_expr::EXPR_ERROR;
}
getOperand(0)->setVarLength(userNameLen, op_data[-MAX_OPERANDS]);
str_cpy_all(op_data[0], userName, userNameLen);
return ex_expr::EXPR_OK;
};
////////////////////////////////////////////////////////////////////
//
// encodeKeyValue
//
// This routine encodes key values so that they can be sorted simply
// using binary collation. The routine is called by the executor.
//
// Note: The target MAY point to the source to change the original
// value.
//
////////////////////////////////////////////////////////////////////
void ex_function_encode::encodeKeyValue(Attributes * attr,
const char *source,
const char *varlenPtr,
char *target,
NABoolean isCaseInsensitive,
Attributes * tgtAttr,
char *tgt_varlen_ptr,
const Int32 tgtLength ,
CharInfo::Collation collation,
CollationInfo::CollationType collType)
{
Lng32 fsDatatype = attr->getDatatype();
Lng32 length = attr->getLength();
Lng32 precision = attr->getPrecision();
switch (fsDatatype) {
#if defined( NA_LITTLE_ENDIAN )
case REC_BIN8_SIGNED:
//
// Flip the sign bit.
//
*(UInt8*)target = *(UInt8*)source;
target[0] ^= 0200;
break;
case REC_BIN8_UNSIGNED:
case REC_BOOLEAN:
*(UInt8*)target = *(UInt8*)source;
break;
case REC_BIN16_SIGNED:
//
// Flip the sign bit.
//
*((unsigned short *) target) = reversebytes( *((unsigned short *) source) );
target[0] ^= 0200;
break;
case REC_BPINT_UNSIGNED:
case REC_BIN16_UNSIGNED:
*((unsigned short *) target) = reversebytes( *((unsigned short *) source) );
break;
case REC_BIN32_SIGNED:
//
// Flip the sign bit.
//
*((ULng32 *) target) = reversebytes( *((ULng32 *) source) );
target[0] ^= 0200;
break;
case REC_BIN32_UNSIGNED:
*((ULng32 *) target) = reversebytes( *((ULng32 *) source) );
break;
case REC_BIN64_SIGNED:
//
// Flip the sign bit.
//
*((_int64 *) target) = reversebytes( *((_int64 *) source) );
target[0] ^= 0200;
break;
case REC_BIN64_UNSIGNED:
*((UInt64 *) target) = reversebytes( *((UInt64 *) source) );
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:
switch(length)
{
case 2: // Signed 16 bit
*((unsigned short *) target) = reversebytes( *((unsigned short *) source) );
break;
case 4: // Signed 32 bit
*((ULng32 *) target) = reversebytes( *((ULng32 *) source) );
break;
case 8: // Signed 64 bit
*((_int64 *) target) = reversebytes( *((_int64 *) source) );
break;
default:
assert(FALSE);
break;
}; // switch(length)
target[0] ^= 0200;
break;
case REC_DATETIME: {
// This method has been modified as part of the MP Datetime
// Compatibility project. It has been made more generic so that
// it depends only on the start and end fields of the datetime type.
//
rec_datetime_field startField;
rec_datetime_field endField;
ExpDatetime *dtAttr = (ExpDatetime *)attr;
// Get the start and end fields for this Datetime type.
//
dtAttr->getDatetimeFields(dtAttr->getPrecision(),
startField,
endField);
// Copy all of the source to the destination, then reverse only
// those fields of the target that are longer than 1 byte
//
if (target != source)
str_cpy_all(target, source, length);
// Reverse the YEAR and Fractional precision fields if present.
//
char *ptr = target;
for(Int32 field = startField; field <= endField; field++) {
switch (field) {
case REC_DATE_YEAR:
// convert YYYY from little endian to big endian
//
*((unsigned short *) ptr) = reversebytes( *((unsigned short *) ptr) );
ptr += sizeof(short);
break;
case REC_DATE_MONTH:
case REC_DATE_DAY:
case REC_DATE_HOUR:
case REC_DATE_MINUTE:
// One byte fields are copied as is...
ptr++;
break;
case REC_DATE_SECOND:
ptr++;
// if there is a fraction, make it big endian
// (it is an unsigned long, beginning after the SECOND field)
//
if (dtAttr->getScale() > 0)
*((ULng32 *) ptr) = reversebytes( *((ULng32 *) ptr) );
break;
}
}
break;
}
#else
case REC_BIN8_SIGNED:
case REC_BIN16_SIGNED:
case REC_BIN32_SIGNED:
case REC_BIN64_SIGNED:
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:
//
// Flip the sign bit.
//
if (target != source)
str_cpy_all(target, source, length);
target[0] ^= 0200;
break;
#endif
case REC_DECIMAL_LSE:
//
// If the number is negative, complement all the bytes. Otherwise, set
// the sign bit.
//
if (source[0] & 0200) {
for (Lng32 i = 0; i < length; i++)
target[i] = ~source[i];
} else {
if (target != source)
str_cpy_all(target, source, length);
target[0] |= 0200;
}
break;
case REC_NUM_BIG_UNSIGNED: {
BigNum type(length, precision, 0, 1);
type.encode(source, target);
break;
}
case REC_NUM_BIG_SIGNED: {
BigNum type(length, precision, 0, 0);
type.encode(source, target);
break;
}
case REC_IEEE_FLOAT32: {
//
// unencoded float (IEEE 754 - 1985 standard):
//
// +-+----------+---------------------+
// | | exponent | mantissa |
// | | (8 bits) | (23 bits) |
// +-+----------+---------------------+
// |
// +- Sign bit
//
// Encoded float (IEEE 754 - 1985 standard):
//
// +-+--------+-----------------------+
// | |Exponent| Mantissa |
// | |(8 bits)| (23 bits) |
// +-+--------+-----------------------+
// || |
// |+- Complemented if sign was neg.-+
// |
// +- Sign bit complement
//
// the following code is independent of the "endianess" of the
// architecture. Instead, it assumes IEEE 754 - 1985 standard
// for representation of floats
// source may not be aligned, move it to a temp var.
float floatsource;
str_cpy_all((char*)&floatsource, source, length);
ULng32 *dblword = (ULng32 *) &floatsource;
if (floatsource < 0) // the sign is negative,
*dblword = ~*dblword; // flip all the bits
else
floatsource = -floatsource; // complement the sign bit
// here comes the dependent part
#ifdef NA_LITTLE_ENDIAN
*(ULng32 *) target = reversebytes(*dblword);
#else
// *(unsigned long *) target = *dblword;
str_cpy_all(target, (char*)&floatsource, length);
#endif
break;
}
case REC_IEEE_FLOAT64: {
//
// unencoded double (IEEE 754 - 1985 standard):
//
// +-+--------- -+--------------------+
// | | exponent | mantissa |
// | | (11 bits) | (52 bits) |
// +-+--------- -+--------------------+
// |
// +- Sign bit
//
// Encoded double (IEEE 754 - 1985 standard):
//
// +-+-----------+--------------------+
// | | Exponent | Mantissa |
// | | (11 bits) | (52 bits) |
// +-+-----------+--------------------+
// || |
// |+- Complemented if sign was neg.-+
// |
// +- Sign bit complement
//
// the following code is independent of the "endianess" of the
// archtiecture. Instead, it assumes IEEE 754 - 1985 standard
// for representation of floats
//double doublesource = *(double *) source;
// source may not be aligned, move it to a temp var.
double doublesource;
str_cpy_all((char*)&doublesource, source, length);
Int64 *quadword = (Int64 *) &doublesource;
if (doublesource < 0) // the sign is negative,
*quadword = ~*quadword; // flip all the bits
else
doublesource = -doublesource; // complement the sign bit
// here comes the dependent part
#ifdef NA_LITTLE_ENDIAN
*(Int64 *) target = reversebytes(*quadword);
#else
// *(Int64 *) target = *quadword;
str_cpy_all(target, (char*)&doublesource, length);
#endif
break;
}
case REC_BYTE_F_ASCII: {
if (CollationInfo::isSystemCollation(collation ))
{
Int16 nPasses = CollationInfo::getCollationNPasses(collation);
if (collType == CollationInfo::Sort ||
collType == CollationInfo::Compare)
{
encodeCollationKey(
(const UInt8 *)source,
length,
(UInt8 *)target,
tgtLength,
nPasses,
collation,
TRUE);
}
else //search
{
Int32 effEncodedKeyLength = 0;
encodeCollationSearchKey(
(const UInt8 *)source,
length,
(UInt8 *)target,
tgtLength,
effEncodedKeyLength,
nPasses,
collation,
TRUE);
assert(tgtAttr && tgt_varlen_ptr);
tgtAttr->setVarLength(effEncodedKeyLength, tgt_varlen_ptr);
}
}
else
{
//------------------------------------------
if (target != source)
str_cpy_all(target, source, length);
if (isCaseInsensitive)
{
// upcase target
for (Int32 i = 0; i < length; i++)
{
target[i] = TOUPPER(source[i]);
}
}
//--------------------------
}
}
break;
case REC_BYTE_V_ASCII:
case REC_BYTE_V_ASCII_LONG:
{
Int32 vc_len = attr->getLength(varlenPtr);
if (CollationInfo::isSystemCollation(collation))
{
Int16 nPasses = CollationInfo::getCollationNPasses(collation);
NABoolean rmTspaces = getRmTSpaces(collation);
if (collType == CollationInfo::Sort ||
collType == CollationInfo::Compare)
{
encodeCollationKey(
(UInt8 *)source,
(Int16)vc_len,
(UInt8 *)target,
tgtLength,
nPasses,
collation,
rmTspaces);
}
else
{
Int32 effEncodedKeyLength = 0;
encodeCollationSearchKey(
(UInt8 *)source,
(Int16)vc_len,
(UInt8 *)target,
tgtLength,
effEncodedKeyLength,
nPasses,
collation,
rmTspaces);
assert(tgtAttr && tgt_varlen_ptr);
tgtAttr->setVarLength(effEncodedKeyLength, tgt_varlen_ptr);
}
}
else
{
//
// Copy the source to the target.
//
if (!isCaseInsensitive)
str_cpy_all(target, source, vc_len);
else
{
// upcase target
for (Int32 i = 0; i < vc_len; i++)
{
target[i] = TOUPPER(source[i]);
}
}
//
// Blankpad the target (if needed).
//
if (vc_len < length)
str_pad(&target[vc_len],
(Int32) (length - vc_len), ' ');
}
}
break;
// added for Unicode data type.
case REC_NCHAR_V_UNICODE:
{
Int32 vc_len = attr->getLength(varlenPtr);
//
// Copy the source to the target.
//
str_cpy_all(target, source, vc_len);
//
// Blankpad the target (if needed).
//
if (vc_len < length)
wc_str_pad((NAWchar*)&target[vc_len],
(Int32) (length - vc_len)/sizeof(NAWchar), unicode_char_set::space_char());
#if defined( NA_LITTLE_ENDIAN )
wc_swap_bytes((NAWchar*)target, length/sizeof(NAWchar));
#endif
break;
}
// added for Unicode data type.
case REC_NCHAR_F_UNICODE:
{
if (target != source)
str_cpy_all(target, source, length);
#if defined( NA_LITTLE_ENDIAN )
wc_swap_bytes((NAWchar*)target, length/sizeof(NAWchar));
#endif
break;
}
case REC_BYTE_V_ANSI:
{
short vc_len;
vc_len = strlen(source);
//
// Copy the source to the target.
//
str_cpy_all(target, source, vc_len);
//
// Blankpad the target (if needed).
//
if (vc_len < length)
str_pad(&target[vc_len], (Int32) (length - vc_len), ' ');
}
break;
default:
//
// Encoding is not needed. Just copy the source to the target.
//
if (target != source)
str_cpy_all(target, source, length);
break;
}
}
////////////////////////////////////////////////////////////////////
// class ex_function_encode
////////////////////////////////////////////////////////////////////
ex_function_encode::ex_function_encode(){};
ex_function_encode::ex_function_encode(OperatorTypeEnum oper_type,
Attributes ** attr,
Space * space,
short descFlag)
: ex_function_clause(oper_type, 2, attr, space),
flags_(0),
collation_((Int16) CharInfo::DefaultCollation)
{
if (descFlag)
setIsDesc(TRUE);
else
setIsDesc(FALSE);
setCollEncodingType(CollationInfo::Sort);
};
ex_function_encode::ex_function_encode(OperatorTypeEnum oper_type,
Attributes ** attr,
Space * space,
CharInfo::Collation collation,
short descFlag,
CollationInfo::CollationType collType)
: ex_function_clause(oper_type, 2, attr, space),
flags_(0),
collation_((Int16)collation)
{
if (descFlag)
setIsDesc(TRUE);
else
setIsDesc(FALSE);
setCollEncodingType(collType);
};
ex_expr::exp_return_type ex_function_encode::processNulls(
char * op_data[],
CollHeap *heap,
ComDiagsArea **diagsArea)
{
if ((CollationInfo::isSystemCollation((CharInfo::Collation) collation_)) &&
getCollEncodingType() != CollationInfo::Sort)
{
return ex_clause::processNulls(op_data,heap,diagsArea);
}
else if (regularNullability())
{
return ex_clause::processNulls(op_data,heap,diagsArea);
}
// if value is missing,
// then move max or min value to result.
if (getOperand(1)->getNullFlag() &&
(!op_data[1])) // missing value (is a null value)
{
if (NOT isDesc())
{
// NULLs sort high for ascending comparison.
// Pad result with highest value.
// For SQL/MP tables, DP2 expects missing value columns to be
// 0 padded after the null-indicator.
str_pad(op_data[2 * MAX_OPERANDS],
(Int32)getOperand(0)->getStorageLength(), '\0');
str_pad(op_data[2 * MAX_OPERANDS],
ExpTupleDesc::KEY_NULL_INDICATOR_LENGTH,
'\377');
}
else
{
// NULLs sort low for descending comparison.
// Pad result with lowest value.
str_pad(op_data[2 * MAX_OPERANDS],
(Int32)getOperand(0)->getStorageLength(),
'\377');
str_pad(op_data[2 * MAX_OPERANDS],
ExpTupleDesc::KEY_NULL_INDICATOR_LENGTH,
'\0');
}
return ex_expr::EXPR_NULL;
}
return ex_expr::EXPR_OK;
};
ex_expr::exp_return_type ex_function_encode::evalDecode(char *op_data[],
CollHeap* heap)
{
char * result = op_data[0];
Attributes *srcOp = getOperand(1);
decodeKeyValue(srcOp,
isDesc(),
op_data[1],
op_data[-MAX_OPERANDS+1],
result,
op_data[-MAX_OPERANDS],
FALSE);
return ex_expr::EXPR_OK;
}
ex_expr::exp_return_type ex_function_encode::eval(char *op_data[],
CollHeap* heap,
ComDiagsArea**)
{
if (isDecode())
{
return evalDecode(op_data, heap);
}
Int16 prependedLength = 0;
char * result = op_data[0];
Attributes *tgtOp = getOperand(0);
Attributes *srcOp = getOperand(1);
if ((srcOp->getNullFlag()) && // nullable
(NOT regularNullability()))
{
// If target is aligned format then can't use the 2 byte null here ...
assert( !tgtOp->isSQLMXAlignedFormat() );
// if sort is set for char types with collations (including default)
if (getCollEncodingType() == CollationInfo::Sort)
{
// value cannot be null in this proc. That is handled in process_nulls.
str_pad(result, ExpTupleDesc::KEY_NULL_INDICATOR_LENGTH, '\0');
result += ExpTupleDesc::KEY_NULL_INDICATOR_LENGTH;
prependedLength = ExpTupleDesc::KEY_NULL_INDICATOR_LENGTH;
}
}
if (srcOp->isComplexType())
((ComplexType *)srcOp)->encode(op_data[1], result, isDesc());
else
{
Int32 tgtLength = tgtOp->getLength() - prependedLength ;
encodeKeyValue(srcOp,
op_data[1],
op_data[-MAX_OPERANDS+1],
result,
caseInsensitive(),
tgtOp,
op_data[-MAX_OPERANDS],
tgtLength,
(CharInfo::Collation) collation_,
getCollEncodingType());
}
if (isDesc())
{
// compliment all bytes
for (Lng32 k = 0; k < tgtOp->getLength(); k++)
op_data[0][k] = (char)(~(op_data[0][k]));
}
return ex_expr::EXPR_OK;
}
void ex_function_encode::getCollationWeight(
CharInfo::Collation collation,
Int16 pass,
UInt16 chr,
UInt8 * weightStr,
Int16 & weightStrLen)
{
UChar wght = getCollationWeight(collation, pass, chr);
switch (collation)
{
case CharInfo::CZECH_COLLATION:
case CharInfo::CZECH_COLLATION_CI:
{
if ((CollationInfo::Pass)pass != CollationInfo::SecondPass)
{
if (wght > 0 )
{
weightStr[0] = wght;
weightStrLen = 1;
}
else
{
weightStrLen = 0;
}
}
else
{
if (getCollationWeight(collation, CollationInfo::FirstPass, chr) > 0 )
{
weightStr[0] = wght;
weightStrLen = 1;
}
else
{
weightStr[0] = 0;
weightStr[1] = wght;
weightStrLen = 2;
}
}
}
break;
default:
{
if (wght > 0 )
{
weightStr[0] = wght;
weightStrLen = 1;
}
else
{
weightStrLen = 0;
}
}
}
}
unsigned char ex_function_encode::getCollationWeight(
CharInfo::Collation collation,
Int16 pass,
UInt16 chr)
{
return collParams[CollationInfo::getCollationParamsIndex(collation)].weightTable[pass][chr];
}
Int16 ex_function_encode::getNumberOfDigraphs( const CharInfo::Collation collation)
{
return collParams[CollationInfo::getCollationParamsIndex(collation)].numberOfDigraphs ;
}
UInt8 * ex_function_encode::getDigraph(const CharInfo::Collation collation, const Int32 digraphNum)
{
return (UInt8 *) collParams[CollationInfo::getCollationParamsIndex(collation)].digraphs[digraphNum] ;
}
Int16 ex_function_encode::getDigraphIndex(const CharInfo::Collation collation, const Int32 digraphNum)
{
return collParams[CollationInfo::getCollationParamsIndex(collation)].digraphIdx[digraphNum];
}
NABoolean ex_function_encode::getRmTSpaces(const CharInfo::Collation collation)
{
return collParams[CollationInfo::getCollationParamsIndex(collation)].rmTSpaces;
}
NABoolean ex_function_encode::getNumberOfChars(const CharInfo::Collation collation)
{
return collParams[CollationInfo::getCollationParamsIndex(collation)].numberOfChars;
}
NABoolean ex_function_encode::isOneToOneCollation(const CharInfo::Collation collation)
{
for (UInt16 i =0 ; i < getNumberOfChars(collation); i++)
{
for (UInt16 j =i +1 ; j < getNumberOfChars(collation); j++)
{
NABoolean isOneToOne = FALSE;
for (Int16 pass=0 ; pass < CollationInfo::getCollationNPasses(collation); pass++)
{
if (getCollationWeight(collation,pass,i) != getCollationWeight(collation,pass,j) )
{
isOneToOne = TRUE;
}
}
if (!isOneToOne)
{
return FALSE;
}
}
}
return TRUE;
}
void ex_function_encode::encodeCollationKey(const UInt8 * src,
Int32 srcLength,
UInt8 * encodeKey,
const Int32 encodedKeyLength,
Int16 nPasses,
CharInfo::Collation collation,
NABoolean rmTSpaces )
{
assert (CollationInfo::isSystemCollation(collation));
UInt8 * ptr;
if (src[0] == CollationInfo::getCollationMaxChar(collation))
{
str_pad((char*) encodeKey, srcLength, CollationInfo::getCollationMaxChar(collation));
if (str_cmp((char*)src, (char*)encodeKey, srcLength) == 0)
{
str_pad((char*) encodeKey, encodedKeyLength,'\377' );
return;
}
}
if (src[0] == '\0')
{
str_pad((char*) encodeKey, encodedKeyLength, '\0');
if (str_cmp((char*)src, (char*)encodeKey,srcLength) == 0)
{
return;
}
}
Int16 charNum=0;
NABoolean hasDigraphs = FALSE;
Int32 trailingSpaceLength =0;
UInt8 digraph[2];
digraph[0]=digraph[1]=0;
Int16 weightStrLength=0;
ptr= encodeKey;
/////////////////////////////////////////////
for ( Int32 i = srcLength -1 ; rmTSpaces && i> 0 && src[i]== 0x20; i--)
{
trailingSpaceLength++;
}
for (short i= CollationInfo::FirstPass; i< nPasses; i++)
{
if (i != CollationInfo::FirstPass)
{
*ptr++= 0x0;
}
if ((i == CollationInfo::FirstPass) ||
(i != CollationInfo::FirstPass && hasDigraphs))
{
//loop through the chars in the string, find digraphs an assighn weights
for (Int32 srcIdx = 0; srcIdx < srcLength- trailingSpaceLength; srcIdx++)
{
digraph[0] = digraph[1];
digraph[1] = src[srcIdx];
NABoolean digraphFound = FALSE;
for (Int32 j = 0 ; j < getNumberOfDigraphs(collation); j++)
{
if (digraph[0] == getDigraph(collation, j)[0] &&
digraph[1] == getDigraph(collation, j)[1])
{
digraphFound = hasDigraphs = TRUE;
charNum = getDigraphIndex(collation,j);
ptr--;
break;
}
}
if (!digraphFound)
{
charNum = src[srcIdx];
}
getCollationWeight(collation,i, charNum,ptr,weightStrLength);
ptr = ptr + weightStrLength;
}
}
else
{
for (Int32 srcIdx = 0; srcIdx < srcLength- trailingSpaceLength; srcIdx++)
{
charNum = src[srcIdx];
getCollationWeight(collation, i, charNum,ptr,weightStrLength);
ptr = ptr + weightStrLength;
}
}
}
str_pad( (char *) ptr,(encodeKey - ptr) + encodedKeyLength, '\0');
} // ex_function_encode::encodeCollationKey
void ex_function_encode::encodeCollationSearchKey(const UInt8 * src,
Int32 srcLength,
UInt8 * encodeKey,
const Int32 encodedKeyLength,
Int32 & effEncodedKeyLength,
Int16 nPasses,
CharInfo::Collation collation,
NABoolean rmTSpaces )
{
assert (CollationInfo::isSystemCollation(collation));
UInt8 * ptr;
Int16 charNum=0;
NABoolean hasDigraphs = FALSE;
Int32 trailingSpaceLength =0;
UInt8 digraph[2];
digraph[0]=digraph[1]=0;
ptr= encodeKey;
/////////////////////////////////////////////
for ( Int32 i = srcLength -1 ; rmTSpaces && i> 0 && src[i]== 0x20; i--)
{
trailingSpaceLength++;
}
for (Int32 srcIdx = 0; srcIdx < srcLength- trailingSpaceLength; srcIdx++)
{
digraph[0] = digraph[1];
digraph[1] = src[srcIdx];
NABoolean digraphFound = FALSE;
for (Int32 j = 0 ; j < getNumberOfDigraphs(collation); j++)
{
if (digraph[0] == getDigraph(collation, j)[0] &&
digraph[1] == getDigraph(collation, j)[1])
{
digraphFound = hasDigraphs = TRUE;
charNum = getDigraphIndex(collation,j);
ptr = ptr - nPasses;
break;
}
}
if (!digraphFound)
{
charNum = src[srcIdx];
}
//don't include ignorable characters
short ignorable = 0;
for (short np = 0; np < nPasses ; np++)
{
ptr[np]= getCollationWeight(collation, np, charNum);
if (ptr[np] == '\0')
{
ignorable++;
}
}
if (ignorable != nPasses) //
{
ptr = ptr + nPasses;
}
if (digraphFound &&
ignorable != nPasses)
{
for (short np = CollationInfo::FirstPass; np < nPasses ; np++)
{
ptr[np]= '\0';
}
ptr = ptr + nPasses;
}
}
effEncodedKeyLength = ptr - encodeKey ;
str_pad( (char *) ptr,(encodeKey - ptr) + encodedKeyLength, '\0');
} // ex_function_encode::encodeCollationSearchKey
////////////////////////////////////////////////////////////////////////
// class ex_function_explode_varchar
////////////////////////////////////////////////////////////////////////
ex_expr::exp_return_type ex_function_explode_varchar::processNulls(
char * op_data[],
CollHeap *heap,
ComDiagsArea **diagsArea)
{
Attributes *tgt = getOperand(0);
if (getOperand(1)->getNullFlag() && (!op_data[1])) // missing value (is a null value)
{
if (tgt->getNullFlag()) // if result is nullable
{
// move null value to result
ExpTupleDesc::setNullValue( op_data[0],
tgt->getNullBitIndex(),
tgt->getTupleFormat() );
if (forInsert_)
{
// move 0 to length bytes
tgt->setVarLength(0, op_data[MAX_OPERANDS]);
} // for Insert
else
{
// move maxLength to result length bytes
tgt->setVarLength(tgt->getLength(), op_data[MAX_OPERANDS]);
}
return ex_expr::EXPR_NULL; // indicate that a null input was processed
}
else
{
// Attempt to put NULL into column with NOT NULL NONDROPPABLE constraint.
ExRaiseFunctionSqlError(heap, diagsArea, EXE_ASSIGNING_NULL_TO_NOT_NULL,
derivedFunction(),
origFunctionOperType());
return ex_expr::EXPR_ERROR;
}
} // source is a null value
// first operand is not null -- set null indicator in result if needed
if (tgt->getNullFlag())
{
ExpTupleDesc::clearNullValue( op_data[0],
tgt->getNullBitIndex(),
tgt->getTupleFormat() );
}
return ex_expr::EXPR_OK;
}
ex_expr::exp_return_type ex_function_explode_varchar::eval(char *op_data[],
CollHeap*heap,
ComDiagsArea**diagsArea)
{
if (forInsert_)
{
// move source to target. No blankpadding.
return convDoIt(op_data[1],
getOperand(1)->getLength(op_data[-MAX_OPERANDS + 1]),
getOperand(1)->getDatatype(),
getOperand(1)->getPrecision(),
getOperand(1)->getScale(),
op_data[0],
getOperand(0)->getLength(),
getOperand(0)->getDatatype(),
getOperand(0)->getPrecision(),
getOperand(0)->getScale(),
op_data[-MAX_OPERANDS],
getOperand(0)->getVCIndicatorLength(),
heap,
diagsArea);
}
else
{
// move source to target. Blankpad target to maxLength.
if (convDoIt(op_data[1],
getOperand(1)->getLength(op_data[-MAX_OPERANDS + 1]),
getOperand(0)->getDatatype(),
getOperand(1)->getPrecision(),
getOperand(1)->getScale(),
op_data[0],
getOperand(0)->getLength(),
REC_BYTE_F_ASCII,
getOperand(0)->getPrecision(),
getOperand(0)->getScale(),
NULL,
0,
heap,
diagsArea))
return ex_expr::EXPR_ERROR;
// Move max length to length bytes of target.
getOperand(0)->setVarLength(getOperand(0)->getLength(),
op_data[-MAX_OPERANDS]);
}
return ex_expr::EXPR_OK;
}
////////////////////////////////////////////////////////////////////
// class ex_function_hash
////////////////////////////////////////////////////////////////////
ULng32 ex_function_hash::HashHash(ULng32 inValue) {
// Hashhash -
// input : inValue - double word to be hashed
// output : 30-bit hash values uniformly distributed (mod s) for
// any s < 2**30
// This algorithm creates near-uniform output for arbitrarily distributed
// input by selecting for each fw of the key a quasi-random universal
// hash function from the class of linear functions ax + b (mod p)
// over the field of integers modulo the prime 2**31-1. The output is at
// least comparable in quality to cubics of the form
// ax**3 + bx**2 + cx + d (mod p), and is considerably closer to true
// uniformity than a single linear function chosen once per execution.
// The latter preserve the uniform 2nd central moment of bucket totals,
// and the former the 4th central moment. For probabilistic counting
// applications, the theoretical standard error cannot be achieved with
// less than cubic polynomials, but the present algorithm is approx 3-5x
// in speed. (Cf. histogram doc. for bibliography, but especially:
// Carter and Wegman, "Universal Clases of Hash Functions",
// Journ. Comp. Sys. Sci., 18: April 1979, pp. 145-154
// 22: 1981, pp. 265-279
// Dietzfelbinger, et al., "Polynomial Hash Functions...",
// ICALP '92, pp. 235-246. )
// N.B. - For modular arithmetic the 64-bit product of two 32-bit
// operands must be reduced (mod p). The high-order 32 bits are available
// in hardware but not necessarily through C syntax.
// Two additional optimizations should be noted:
// 1. Instead of processing 3-byte operands, as would be required with
// universal hashing over the field 2**31-1, with alignment delays, we
// process fullwords, and choose distinct 'random' coefficients for
// 2 keys congruent (mod p) using a 32-bit function, and then proceed
// with modular linear hashing over the smaller field.
// 2. For p = 2**c -1 for any c, shifts, and's and or's can be substituted
// for division, as recommended by Carter and Wegman. In addition, the
// output distribution is unaffected (i.e. with probability
// < 1/(2**31-1) if we omit tests for 0 (mod p).
// To reduce a (mod p), create k1 and k2 (<= p) with a = (2**31)k1 + k2,
// and reduce again to (2**31)k3 + k4, where k4 < 2**31 and k3 = 0 or 1.
// Multi-word keys:
// If k = k1||...||kn we compute the quasi-random coefficients c & d using
// ki, but take h(ki) = c*(ki xor h(ki-1)) + d, where h(k0) = 0, and use
// H(k) = h(kn). This precludes the commutative anomaly
// H(k || k') = H(k' || k)
register ULng32 u, v, c, d, k0;
ULng32 a1, a2, b1, b2;
ULng32 c1 = (ULng32)5233452345LL;
ULng32 c2 = (ULng32)8578458478LL;
ULng32 d1 = 1862598173LL;
ULng32 d2 = 3542657857LL;
ULng32 hashValue = 0;
ULng32 k = inValue;
u = (c1 >> 16) * (k >> 16);
v = c1 * k;
c = u ^ v ^ c2;
u = (d1 >> 16) * (k >> 16);
v = d1 * k;
d = u ^ v ^ d2;
c = ((c & 0x80000000) >> 31) + (c & 0x7fffffff);
d = ((d & 0x80000000) >> 31) + (d & 0x7fffffff);
/* compute hash value 1 */
k0 = hashValue ^ k;
/*hmul(c,k0);
u=u0; v=v0;*/
a1 = c >> 16;
a2 = c & 0xffff;
b1 = k0 >> 16;
b2 = k0 & 0xffff;
v = (((a1 * b2) & 0xffff) + ((b1 * a2) & 0xffff));
u = a1 * b1 + (((a1 * b2) >> 16) + ((b1 * a2) >> 16))
+ ((v & 0x10000) >> 16);
v = c * k0;
if (v < (a2 * b2))
u++;
u = u << 1;
u = ((v & 0x80000000) >> 31) | u;
v = v & 0x7fffffff;
v = u + v;
v = ((v & 0x80000000) >> 31) + (v & 0x7fffffff);
/*v = ((v & 0x80000000) >> 31) + (v & 0x7fffffff);
if ( v == 0x7fffffff) v = 0;*/
v = v + d;
v = ((v & 0x80000000) >> 31) + (v & 0x7fffffff);
/*v = ((v & 0x80000000) >> 31) + (v & 0x7fffffff);
if ( v == 0x7fffffff) v = 0;*/
return (v);
};
ex_expr::exp_return_type ex_function_hash::eval(char *op_data[],
CollHeap*,
ComDiagsArea**)
{
Attributes *srcOp = getOperand(1);
ULng32 hashValue = 0;
if (srcOp->getNullFlag() && (! op_data[ -(2 * MAX_OPERANDS) + 1 ]))
{
// operand is a null value. All null values hash to
// the same hash value. Choose any arbitrary constant
// number as the hash value.
hashValue = ExHDPHash::nullHashValue; //;666654765;
}
else
{
// get the actual length stored in the data, or fixed length
Lng32 length = srcOp->getLength(op_data[-MAX_OPERANDS + 1]);
// if VARCHAR, skip trailing blanks and adjust length.
if (srcOp->getVCIndicatorLength() > 0) {
switch ( srcOp->getDatatype() ) {
// added to correctly handle VARNCHAR.
case REC_NCHAR_V_UNICODE:
{
// skip trailing blanks
NAWchar* wstr = (NAWchar*)(op_data[1]);
Lng32 wstr_length = length / sizeof(NAWchar);
while ((wstr_length > 0) &&
( wstr[wstr_length-1] == unicode_char_set::space_char())
)
wstr_length--;
length = sizeof(NAWchar)*wstr_length;
}
break;
default:
//case REC_BYTE_V_ASCII:
// skip trailing blanks
while ((length > 0) &&
(op_data[1][length-1] == ' '))
length--;
break;
}
}
UInt32 flags = ExHDPHash::NO_FLAGS;
switch(srcOp->getDatatype()) {
case REC_NCHAR_V_UNICODE:
case REC_NCHAR_V_ANSI_UNICODE:
flags = ExHDPHash::SWAP_TWO;
break;
}
hashValue = ExHDPHash::hash(op_data[1], flags, length);
};
*(ULng32 *)op_data[0] = hashValue;
return ex_expr::EXPR_OK;
};
Lng32 ex_function_hivehash::hashForCharType(char* data, Lng32 length)
{
// To compute: SUM (i from 0 to n-1) (s(i) * 31^(n-1-i)
ULng32 resultCopy = 0;
ULng32 result = (ULng32)data[0];
for (Lng32 i=1; i<length; i++ ) {
// perform result * 31, optimized as (result <<5 - result)
resultCopy = result;
result <<= 5;
result -= resultCopy;
result += (ULng32)(data[i]);
}
return result;
}
ex_expr::exp_return_type ex_function_hivehash::eval(char *op_data[],
CollHeap*,
ComDiagsArea**)
{
Attributes *srcOp = getOperand(1);
ULng32 hashValue = 0;
Lng32 length;
if (srcOp->getNullFlag() && (! op_data[ -(2 * MAX_OPERANDS) + 1 ]))
{
// operand is a null value. All null values hash to the same hash value.
hashValue = 0; // hive semantics: hash(NULL) = 0
} else
if ( (DFS2REC::isSQLVarChar(srcOp->getDatatype()) ||
DFS2REC::isANSIVarChar(srcOp->getDatatype())) &&
getOperand(1)->getVCIndicatorLength() > 0 )
{
length = srcOp->getLength(op_data[-MAX_OPERANDS + 1]);
hashValue = ex_function_hivehash::hashForCharType(op_data[1],length);
} else
if ( DFS2REC::isSQLFixedChar(srcOp->getDatatype()) ) {
length = srcOp->getLength();
hashValue = ex_function_hivehash::hashForCharType(op_data[1],length);
} else
if ( DFS2REC::isBinary(srcOp->getDatatype()) ) {
hashValue = *(ULng32*)(op_data[1]);
} // TBD: other SQ types
*(ULng32 *)op_data[0] = hashValue;
return ex_expr::EXPR_OK;
}
////////////////////////////////////////////////////////////////////
// class ExHashComb
////////////////////////////////////////////////////////////////////
ex_expr::exp_return_type ExHashComb::eval(char *op_data[],
CollHeap* heap,
ComDiagsArea** diagsArea)
{
// always assume that both operands and result are of the same
// (unsigned) type and length
// with built-in long long type we could also support 8 byte integers
ULng32 op1, op2;
switch (getOperand(0)->getStorageLength())
{
case 4:
op1 = *((ULng32 *) op_data[1]);
op2 = *((ULng32 *) op_data[2]);
*((ULng32 *) op_data[0]) = ((op1 << 1) | (op1 >> 31)) ^ op2;
break;
default:
ExRaiseFunctionSqlError(heap, diagsArea, EXE_INTERNAL_ERROR,
derivedFunction(),
origFunctionOperType());
return ex_expr::EXPR_ERROR;
}
return ex_expr::EXPR_OK;
}
////////////////////////////////////////////////////////////////////
// class ExHiveHashComb
////////////////////////////////////////////////////////////////////
ex_expr::exp_return_type ExHiveHashComb::eval(char *op_data[],
CollHeap* heap,
ComDiagsArea** diagsArea)
{
// always assume that both operands and result are of the same
// (unsigned) type and length
// with built-in long long type we could also support 8 byte integers
ULng32 op1, op2;
switch (getOperand(0)->getStorageLength())
{
case 4:
op1 = *((ULng32 *) op_data[1]);
op2 = *((ULng32 *) op_data[2]);
// compute op1 * 31 + op2, optimized as op1 << 5 - op1 + op2
*((ULng32 *) op_data[0]) = op1 << 5 - op1 + op2;
break;
default:
ExRaiseFunctionSqlError(heap, diagsArea, EXE_INTERNAL_ERROR,
derivedFunction(),
origFunctionOperType());
return ex_expr::EXPR_ERROR;
}
return ex_expr::EXPR_OK;
}
// -------------------------------------------------------------
// Hash Functions used by Hash Partitioning. These functions cannot
// change once Hash Partitioning is released! Defined for all data
// types, returns a 32 bit non-nullable hash value for the data item.
// The ::hash() function uses a loop over the key bytes; the other
// hash2()/hash4()/hash8() are more efficient but are only applicable
// to keys whose sizes are known at compile time: 2/4/8 bytes.
//--------------------------------------------------------------
ULng32 ExHDPHash::hash(const char *data, UInt32 flags, Int32 length)
{
ULng32 hashValue = 0;
unsigned char *valp = (unsigned char *)data;
Int32 iter = 0; // iterator over the key bytes, if needed
switch(flags) {
case NO_FLAGS:
case SWAP_EIGHT:
{
// Speedup for long keys - compute first 8 bytes fast (the rest with a loop)
if ( length >= 8 ) {
hashValue = hash8(data, flags); // do the first 8 bytes fast
// continue with the 9-th byte (only when length > 8 )
valp = (unsigned char *)&data[8];
iter = 8;
}
for(; iter < length; iter++) {
// Make sure the hashValue is sensitive to the byte position.
// One bit circular shift.
hashValue =
(hashValue << 1 | hashValue >> 31) ^ randomHashValues[*valp++];
}
break;
}
case SWAP_TWO:
{
// Speedup for long keys - compute first 8 bytes fast (the rest with a loop)
if ( length >= 8 ) {
hashValue = hash8(data, flags); // do the first 8 bytes fast
// continue with the 9-th byte (only when length > 8 )
valp = (unsigned char *)&data[8];
iter = 8;
}
// Loop over all the bytes of the value and compute the hash value.
for(; iter < length; iter+=2) {
// Make sure the hashValue is sensitive to the byte position.
// One bit circular shift.
hashValue =
(hashValue << 1 | hashValue >> 31) ^ randomHashValues[*(valp+1)];
hashValue =
(hashValue << 1 | hashValue >> 31) ^ randomHashValues[*valp];
valp += 2;
}
break;
}
case SWAP_FOUR:
{
hashValue = hash4(data, flags);
break;
}
case (SWAP_FIRSTTWO | SWAP_LASTFOUR):
case SWAP_FIRSTTWO:
case SWAP_LASTFOUR:
{
if((flags & SWAP_FIRSTTWO) != 0) {
hashValue = randomHashValues[*(valp+1)];
hashValue =
(hashValue << 1 | hashValue >> 31) ^ randomHashValues[*valp];
valp += 2;
iter += 2;
}
if((flags & SWAP_LASTFOUR) != 0) {
length -= 4;
}
for(; iter < length; iter++) {
// Make sure the hashValue is sensitive to the byte position.
// One bit circular shift.
hashValue =
(hashValue << 1 | hashValue >> 31) ^ randomHashValues[*valp++];
}
if((flags & SWAP_LASTFOUR) != 0) {
hashValue =
(hashValue << 1 | hashValue >> 31) ^ randomHashValues[*(valp+3)];
hashValue =
(hashValue << 1 | hashValue >> 31) ^ randomHashValues[*(valp+2)];
hashValue =
(hashValue << 1 | hashValue >> 31) ^ randomHashValues[*(valp+1)];
hashValue =
(hashValue << 1 | hashValue >> 31) ^ randomHashValues[*(valp+0)];
}
break;
}
default:
assert(FALSE);
}
return hashValue;
}
ex_expr::exp_return_type ExHDPHash::eval(char *op_data[],
CollHeap*,
ComDiagsArea**)
{
Attributes *srcOp = getOperand(1);
ULng32 hashValue;
if (srcOp->getNullFlag() && (! op_data[ -(2 * MAX_OPERANDS) + 1 ]))
{
// operand is a null value. All null values hash to
// the same hash value. Choose any arbitrary constant
// number as the hash value.
//
hashValue = ExHDPHash::nullHashValue; //666654765;
}
else {
Int32 length = (Int32)srcOp->getLength(op_data[-MAX_OPERANDS + 1]);
// if VARCHAR, skip trailing blanks and adjust length.
if (srcOp->getVCIndicatorLength() > 0) {
switch ( srcOp->getDatatype() ) {
// added to correctly handle VARNCHAR.
case REC_NCHAR_V_UNICODE:
{
// skip trailing blanks
NAWchar* wstr = (NAWchar*)(op_data[1]);
Int32 wstr_length = length / sizeof(NAWchar);
while ((wstr_length > 0) &&
( wstr[wstr_length-1] == unicode_char_set::space_char()))
wstr_length--;
length = sizeof(NAWchar) * wstr_length;
}
break;
default:
// skip trailing blanks
while ((length > 0) &&
(op_data[1][length-1] == ' '))
length--;
break;
}
}
UInt32 flags = NO_FLAGS;
switch(srcOp->getDatatype()) {
case REC_NUM_BIG_UNSIGNED:
case REC_NUM_BIG_SIGNED:
case REC_BIN16_SIGNED:
case REC_BIN16_UNSIGNED:
case REC_NCHAR_F_UNICODE:
case REC_NCHAR_V_UNICODE:
case REC_NCHAR_V_ANSI_UNICODE:
flags = SWAP_TWO;
break;
case REC_BIN32_SIGNED:
case REC_BIN32_UNSIGNED:
case REC_IEEE_FLOAT32:
flags = SWAP_FOUR;
break;
case REC_BIN64_SIGNED:
case REC_BIN64_UNSIGNED:
case REC_IEEE_FLOAT64:
flags = SWAP_EIGHT;
break;
case REC_DATETIME:
{
rec_datetime_field start;
rec_datetime_field end;
ExpDatetime *datetime = (ExpDatetime*) srcOp;
datetime->getDatetimeFields(srcOp->getPrecision(), start, end);
if(start == REC_DATE_YEAR) {
flags = SWAP_FIRSTTWO;
}
if(end == REC_DATE_SECOND && srcOp->getScale() > 0) {
flags |= SWAP_LASTFOUR;
}
}
break;
default:
if(srcOp->getDatatype() >= REC_MIN_INTERVAL &&
srcOp->getDatatype() <= REC_MAX_INTERVAL) {
if (srcOp->getLength() == 8)
flags = SWAP_EIGHT;
else if (srcOp->getLength() == 4)
flags = SWAP_FOUR;
else if (srcOp->getLength() == 2)
flags = SWAP_TWO;
else
assert(FALSE);
}
}
hashValue = hash(op_data[1], flags, length);
}
*(ULng32 *)op_data[0] = hashValue;
return ex_expr::EXPR_OK;
} // ExHDPHash::eval()
// --------------------------------------------------------------
// 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.
// --------------------------------------------------------------
ex_expr::exp_return_type ExHDPHashComb::eval(char *op_data[],
CollHeap* heap,
ComDiagsArea** diagsArea)
{
// always assume that both operands and result are of the same
// (unsigned) type and length
assert(getOperand(0)->getStorageLength() == 4 &&
getOperand(1)->getStorageLength() == 4 &&
getOperand(2)->getStorageLength() == 4);
ULng32 op1, op2;
op1 = *((ULng32 *) op_data[1]);
op2 = *((ULng32 *) op_data[2]);
// One bit, circular shift
op1 = ((op1 << 1) | (op1 >> 31));
op1 = op1 ^ op2;
*((ULng32 *) op_data[0]) = op1;
return ex_expr::EXPR_OK;
} // ExHDPHashComb::eval()
// ex_function_replace_null
//
ex_expr::exp_return_type
ex_function_replace_null::processNulls(char *op_data[],
CollHeap *heap,
ComDiagsArea **diagsArea)
{
return ex_expr::EXPR_OK;
}
ex_expr::exp_return_type ex_function_replace_null::eval(char *op_data[],
CollHeap*,
ComDiagsArea **) {
Attributes *tgt = getOperand(0);
// Mark the result as non-null
if(tgt->getNullFlag())
ExpTupleDesc::clearNullValue(op_data[ -(2 * MAX_OPERANDS) ],
tgt->getNullBitIndex(),
tgt->getTupleFormat());
// If the input is NULL, replace it with the value in op_data[3]
if (! op_data[ - (2 * MAX_OPERANDS) + 1]) {
for(Lng32 i=0; i < tgt->getStorageLength(); i++)
op_data[0][i] = op_data[3][i];
}
else {
for(Lng32 i=0; i < tgt->getStorageLength(); i++)
op_data[0][i] = op_data[2][i];
}
return ex_expr::EXPR_OK;
}
////////////////////////////////////////////////////////////////////
// class ex_function_mod
////////////////////////////////////////////////////////////////////
ex_expr::exp_return_type ex_function_mod::eval(char *op_data[],
CollHeap *heap,
ComDiagsArea** diagsArea)
{
Int32 lenr = (Int32) getOperand(0)->getLength();
Int32 len1 = (Int32) getOperand(1)->getLength();
Int32 len2 = (Int32) getOperand(2)->getLength();
Int64 op1, op2, result;
switch (len1)
{
case 1:
op1 = *((Int8 *) op_data[1]);
break;
case 2:
op1 = *((short *) op_data[1]);
break;
case 4:
op1 = *((Lng32 *) op_data[1]);
break;
case 8:
op1 = *((Int64 *) op_data[1]);
break;
default:
ExRaiseFunctionSqlError(heap, diagsArea, EXE_INTERNAL_ERROR,
derivedFunction(),
origFunctionOperType());
return ex_expr::EXPR_ERROR;
}
switch (len2)
{
case 1:
op2 = *((Int8 *) op_data[2]);
break;
case 2:
op2 = *((short *) op_data[2]);
break;
case 4:
op2 = *((Lng32 *) op_data[2]);
break;
case 8:
op2 = *((Int64 *) op_data[2]);
break;
default:
ExRaiseSqlError(heap, diagsArea, EXE_INTERNAL_ERROR);
return ex_expr::EXPR_ERROR;
}
if (op2 == 0)
{
ExRaiseFunctionSqlError(heap, diagsArea, EXE_DIVISION_BY_ZERO,
derivedFunction(),
origFunctionOperType());
return ex_expr::EXPR_ERROR;
}
result = op1 % op2;
switch (lenr)
{
case 1:
*((Int8 *) op_data[0]) = (short) result;
break;
case 2:
*((short *) op_data[0]) = (short) result;
break;
case 4:
*((Lng32 *) op_data[0]) = (Lng32)result;
break;
case 8:
*((Int64 *) op_data[0]) = result;
break;
default:
ExRaiseSqlError(heap, diagsArea, EXE_INTERNAL_ERROR);
return ex_expr::EXPR_ERROR;
}
return ex_expr::EXPR_OK;
}
////////////////////////////////////////////////////////////////////
// class ex_function_mask
////////////////////////////////////////////////////////////////////
ex_expr::exp_return_type ex_function_mask::eval(char *op_data[],
CollHeap* heap,
ComDiagsArea** diagsArea)
{
// always assume that both operands and result are of the same
// (unsigned) type and length
// with built-in long long type we could also support 8 byte integers
ULng32 op1, op2, result;
switch (getOperand(0)->getStorageLength())
{
case 1:
op1 = *((UInt8 *) op_data[1]);
op2 = *((UInt8 *) op_data[2]);
if(getOperType() == ITM_MASK_SET) {
result = op1 | op2;
} else {
result = op1 & ~op2;
}
*((unsigned short *) op_data[0]) = (unsigned short) result;
break;
case 2:
op1 = *((unsigned short *) op_data[1]);
op2 = *((unsigned short *) op_data[2]);
if(getOperType() == ITM_MASK_SET) {
result = op1 | op2;
} else {
result = op1 & ~op2;
}
*((unsigned short *) op_data[0]) = (unsigned short) result;
break;
case 4:
op1 = *((ULng32 *) op_data[1]);
op2 = *((ULng32 *) op_data[2]);
if(getOperType() == ITM_MASK_SET) {
result = op1 | op2;
} else {
result = op1 & ~op2;
}
*((ULng32 *) op_data[0]) = result;
break;
case 8:
{
Int64 lop1 = *((Int64 *) op_data[1]);
Int64 lop2 = *((Int64 *) op_data[2]);
Int64 lresult;
if(getOperType() == ITM_MASK_SET) {
lresult = lop1 | lop2;
} else {
lresult = lop1 & ~lop2;
}
*((Int64 *) op_data[0]) = lresult;
break;
}
default:
ExRaiseSqlError(heap, diagsArea, EXE_INTERNAL_ERROR);
return ex_expr::EXPR_ERROR;
}
return ex_expr::EXPR_OK;
}
////////////////////////////////////////////////////////////////////
// class ExFunctionShift
////////////////////////////////////////////////////////////////////
ex_expr::exp_return_type ExFunctionShift::eval(char *op_data[],
CollHeap* heap,
ComDiagsArea** diagsArea)
{
if(getOperand(2)->getStorageLength() != 4) {
ExRaiseSqlError(heap, diagsArea, EXE_INTERNAL_ERROR);
return ex_expr::EXPR_ERROR;
}
ULng32 shift = *((ULng32 *)op_data[2]);
ULng32 value, result;
switch (getOperand(0)->getStorageLength()) {
case 1:
value = *((UInt8 *) op_data[1]);
if(getOperType() == ITM_SHIFT_RIGHT) {
result = value >> shift;
} else {
result = value << shift;
}
*((UInt8 *) op_data[0]) = (UInt8) result;
break;
case 2:
value = *((unsigned short *) op_data[1]);
if(getOperType() == ITM_SHIFT_RIGHT) {
result = value >> shift;
} else {
result = value << shift;
}
*((unsigned short *) op_data[0]) = (unsigned short) result;
break;
case 4:
value = *((ULng32 *) op_data[1]);
if(getOperType() == ITM_SHIFT_RIGHT) {
result = value >> shift;
} else {
result = value << shift;
}
*((ULng32 *) op_data[0]) = result;
break;
case 8:
{
Int64 value = *((Int64 *) op_data[1]);
Int64 result;
if(getOperType() == ITM_SHIFT_RIGHT) {
result = value >> shift;
} else {
result = value << shift;
}
*((Int64 *) op_data[0]) = result;
break;
}
default:
ExRaiseSqlError(heap, diagsArea, EXE_INTERNAL_ERROR);
return ex_expr::EXPR_ERROR;
}
return ex_expr::EXPR_OK;
}
static
ex_expr::exp_return_type getDoubleValue(double *dest,
char *source,
Attributes *operand,
CollHeap *heap,
ComDiagsArea** diagsArea)
{
switch(operand->getDatatype()) {
case REC_FLOAT64:
*dest = *(double *)(source);
return ex_expr::EXPR_OK;
default:
ExRaiseSqlError(heap, diagsArea, EXE_INTERNAL_ERROR);
return ex_expr::EXPR_ERROR;
}
}
static
ex_expr::exp_return_type setDoubleValue(char *dest,
Attributes *operand,
double *source,
CollHeap *heap,
ComDiagsArea** diagsArea)
{
switch(operand->getDatatype()) {
case REC_FLOAT64:
*(double *)dest = *source;
return ex_expr::EXPR_OK;
default:
ExRaiseSqlError(heap, diagsArea, EXE_INTERNAL_ERROR);
return ex_expr::EXPR_ERROR;
}
}
ex_expr::exp_return_type ExFunctionSVariance::eval(char *op_data[],
CollHeap *heap,
ComDiagsArea **diagsArea)
{
double sumOfValSquared = 0;
double sumOfVal = 0;
double countOfVal = 1;
double avgOfVal;
double result = 0;
if(getDoubleValue(&sumOfValSquared, op_data[1], getOperand(1),
heap, diagsArea)) {
return ex_expr::EXPR_ERROR;
}
if(getDoubleValue(&sumOfVal, op_data[2], getOperand(2), heap, diagsArea)) {
return ex_expr::EXPR_ERROR;
}
if(getDoubleValue(&countOfVal, op_data[3], getOperand(3), heap, diagsArea)) {
return ex_expr::EXPR_ERROR;
}
avgOfVal = sumOfVal/countOfVal;
if(countOfVal == 1) {
result = 0.0;
}
else {
result = (sumOfValSquared - (sumOfVal * avgOfVal)) / (countOfVal - 1);
if(result < 0.0) {
result = 0.0;
}
}
if(setDoubleValue(op_data[0], getOperand(0), &result, heap, diagsArea)) {
return ex_expr::EXPR_ERROR;
}
return ex_expr::EXPR_OK;
}
ex_expr::exp_return_type ExFunctionSStddev::eval(char *op_data[],
CollHeap *heap,
ComDiagsArea **diagsArea)
{
double sumOfValSquared = 0;
double sumOfVal = 0;
double countOfVal = 1;
double avgOfVal;
double result = 0;
if(getDoubleValue(&sumOfValSquared, op_data[1], getOperand(1),
heap, diagsArea)) {
return ex_expr::EXPR_ERROR;
}
if(getDoubleValue(&sumOfVal, op_data[2], getOperand(2), heap, diagsArea)) {
return ex_expr::EXPR_ERROR;
}
if(getDoubleValue(&countOfVal, op_data[3], getOperand(3), heap, diagsArea)) {
return ex_expr::EXPR_ERROR;
}
avgOfVal = sumOfVal/countOfVal;
if(countOfVal == 1) {
result = 0.0;
}
else {
short err = 0;
result = (sumOfValSquared - (sumOfVal * avgOfVal)) / (countOfVal - 1);
if(result < 0.0) {
result = 0.0;
} else {
result = MathSqrt(result, err);
}
if (err)
{
ExRaiseSqlError(heap, diagsArea, EXE_BAD_ARG_TO_MATH_FUNC);
**diagsArea << DgString0("SQRT");
ExRaiseSqlError(heap, diagsArea, EXE_MAPPED_FUNCTION_ERROR);
**diagsArea << DgString0("STDDEV");
return ex_expr::EXPR_ERROR;
}
}
if(setDoubleValue(op_data[0], getOperand(0), &result, heap, diagsArea)) {
return ex_expr::EXPR_ERROR;
}
return ex_expr::EXPR_OK;
}
ex_expr::exp_return_type ExpRaiseErrorFunction::eval(char *op_data[],
CollHeap* heap,
ComDiagsArea** diagsArea)
{
char catName[ComAnsiNamePart::MAX_IDENTIFIER_EXT_LEN+1];
char schemaName[ComAnsiNamePart::MAX_IDENTIFIER_EXT_LEN+1];
// Don't do anything with the op[] data
// Create a DiagsArea to return the SQLCODE and the ConstraintName
// and TableName.
if (raiseError())
ExRaiseSqlError(heap, diagsArea, (ExeErrorCode)getSQLCODE(),
NULL, NULL, NULL, NULL,
getOptionalStr());
else
ExRaiseSqlWarning(heap, diagsArea, (ExeErrorCode)getSQLCODE(),
NULL, NULL, NULL, NULL,
getOptionalStr());
// SQLCODE correspoding to Triggered Action Exception
if (getSQLCODE() == ComDiags_TrigActionExceptionSQLCODE)
{
assert(constraintName_ && tableName_);
extractCatSchemaNames(catName, schemaName, constraintName_);
*(*diagsArea) << DgTriggerCatalog(catName);
*(*diagsArea) << DgTriggerSchema(schemaName);
*(*diagsArea) << DgTriggerName(constraintName_);
extractCatSchemaNames(catName, schemaName, tableName_);
*(*diagsArea) << DgCatalogName(catName);
*(*diagsArea) << DgSchemaName(schemaName);
*(*diagsArea) << DgTableName(tableName_);
}
else if (getSQLCODE() == ComDiags_SignalSQLCODE) // Signal Statement
{
if (constraintName_)
*(*diagsArea) << DgString0(constraintName_); // The SQLSTATE
if (getNumOperands()==2)
{
Lng32 len1 = getOperand(1)->getLength(op_data[-MAX_OPERANDS+1]);
op_data[1][len1] = '\0';
*(*diagsArea) << DgString1(op_data[1]); // The string expression
}
else
if (tableName_)
*(*diagsArea) << DgString1(tableName_); // The message
}
else
{
if (constraintName_)
{
extractCatSchemaNames(catName, schemaName, constraintName_);
*(*diagsArea) << DgConstraintCatalog(catName);
*(*diagsArea) << DgConstraintSchema(schemaName);
*(*diagsArea) << DgConstraintName(constraintName_);
}
if (tableName_)
{
extractCatSchemaNames(catName, schemaName, tableName_);
*(*diagsArea) << DgCatalogName(catName);
*(*diagsArea) << DgSchemaName(schemaName);
*(*diagsArea) << DgTableName(tableName_);
}
}
// If it's a warning, we should return a predictable boolean value.
*((ULng32*)op_data[0]) = 0;
if (raiseError())
return ex_expr::EXPR_ERROR;
else
return ex_expr::EXPR_OK;
}
// -----------------------------------------------------------------------
// methods for ExFunctionPack
// -----------------------------------------------------------------------
// Constructor.
ExFunctionPack::ExFunctionPack(Attributes** attr,
Space* space,
Lng32 width,
Lng32 base,
NABoolean nullsPresent)
: ex_function_clause(ITM_PACK_FUNC,3,attr,space),
width_(width), base_(base)
{
setNullsPresent(nullsPresent);
}
// Evaluator.
ex_expr::exp_return_type ExFunctionPack::eval(char* op_data[],
CollHeap* heap,
ComDiagsArea** diagsArea)
{
char guard1 = op_data[0][-1];
char guard2 = op_data[0][getOperand(0)->getLength()];
// Extract no of rows already in the packed record.
Lng32 noOfRows;
str_cpy_all((char*)&noOfRows,op_data[0],sizeof(Lng32));
// Extract the packing factor.
Lng32 pf = *(Lng32 *)op_data[2];
// The clause returns an error for no more slots in the packed record.
if(noOfRows >= pf)
{
ExRaiseSqlError(heap,diagsArea,EXE_INTERNAL_ERROR);
return ex_expr::EXPR_ERROR;
}
// Whether the source is null.
char* nullFlag = op_data[-2*ex_clause::MAX_OPERANDS+1];
// If null bit map is present in the packed record.
if(nullsPresent())
{
// Offset of null bit from the beginning of the null bitmap.
Lng32 nullBitOffsetInBytes = noOfRows >> 3;
// Offset of null bit from the beginning of the byte it is in.
Lng32 nullBitOffsetInBits = noOfRows & 0x7;
// Extract the byte in which the null bit is in.
char* nullByte = op_data[0] + nullBitOffsetInBytes + sizeof(Int32);
// Used to set/unset the null bit.
unsigned char nullByteMask = (1 << nullBitOffsetInBits);
// Turn bit off/on depending on whether operand is null.
if(nullFlag == 0)
*nullByte |= nullByteMask; // set null bit on.
else
*nullByte &= (~nullByteMask); // set null bit off.
}
else if(nullFlag == 0)
{
// Bit map is not present but input is null. We got a problem.
ExRaiseSqlError(heap,diagsArea,EXE_INTERNAL_ERROR);
return ex_expr::EXPR_ERROR;
}
// We have contents to copy only if source is not null.
if(nullFlag != 0)
{
// Width of each packet in the packed record. -ve means in no of bits.
if(width_ < 0)
{
Lng32 widthInBits = -width_;
// Length of data region which has already been occupied in bits.
Lng32 tgtBitsOccupied = (noOfRows * widthInBits);
// Byte offset for data of this packet from beginning of data region.
Lng32 tgtByteOffset = base_ + (tgtBitsOccupied >> 3);
// Bit offset for data of this packet from beginning of its byte.
Lng32 tgtBitOffset = (tgtBitsOccupied & 0x7);
// Byte offset of data source left to be copied.
Lng32 srcByteOffset = 0;
// Bit offset of data source from beginning of its byte to be copied.
Lng32 srcBitOffset = 0;
// No of bits to copy in total.
Lng32 bitsToCopy = widthInBits;
// There are still bits remaining to be copied.
while(bitsToCopy > 0)
{
// Pointer to the target byte.
char* tgtBytePtr = (op_data[0] + tgtByteOffset);
// No of bits left in the target byte.
Lng32 bitsLeftInTgtByte = 8 - tgtBitOffset;
// No of bits left in the source byte.
Lng32 bitsLeftInSrcByte = 8 - srcBitOffset;
Lng32 bitsToCopyThisRound = (bitsLeftInTgtByte > bitsLeftInSrcByte ?
bitsLeftInSrcByte : bitsLeftInTgtByte);
if(bitsToCopyThisRound > bitsToCopy) bitsToCopyThisRound = bitsToCopy;
// Mask has ones in the those positions where bits will be copied to.
unsigned char mask = ((0xFF >> tgtBitOffset) <<
(8 - bitsToCopyThisRound)) >>
(8 - tgtBitOffset - bitsToCopyThisRound);
// Clear target bits. Keep other bits unchanged in the target byte.
(*tgtBytePtr) &= (~mask);
// Align source bits with its the destination. Mask off other bits.
unsigned char srcByte = *(op_data[1] + srcByteOffset);
srcByte = ((srcByte >> srcBitOffset) << tgtBitOffset) & mask;
// Make the copy.
(*tgtBytePtr) |= srcByte;
// Move source byte and bit offsets.
srcBitOffset += bitsToCopyThisRound;
if(srcBitOffset >= 8)
{
srcByteOffset++;
srcBitOffset -= 8;
}
// Move target byte and bit offsets.
tgtBitOffset += bitsToCopyThisRound;
if(tgtBitOffset >= 8)
{
tgtByteOffset++;
tgtBitOffset -= 8;
}
bitsToCopy -= bitsToCopyThisRound;
}
}
else // width_ > 0
{
// Width in bytes: we can copy full strings of bytes.
Lng32 tgtByteOffset = base_ + (noOfRows * width_);
str_cpy_all(op_data[0]+tgtByteOffset,op_data[1],width_);
}
}
// Update the "noOfRows" in the packed record.
noOfRows++;
str_cpy_all(op_data[0],(char*)&noOfRows,sizeof(Lng32));
// $$$ supported as a CHAR rather than a VARCHAR for now.
// getOperand(0)->
// setVarLength(offset+lengthToCopy,op_data[-ex_clause::MAX_OPERANDS]);
if(guard1 != op_data[0][-1] ||
guard2 != op_data[0][getOperand(0)->getLength()]) {
ExRaiseSqlError(heap, diagsArea, EXE_INTERNAL_ERROR);
return ex_expr::EXPR_ERROR;
}
// Signal a completely packed record to the caller.
if(noOfRows == pf) return ex_expr::EXPR_TRUE;
// Signal an incompletely packed record to the caller.
return ex_expr::EXPR_FALSE;
}
// ExUnPackCol::eval() ------------------------------------------
// The ExUnPackCol clause extracts a set of bits from a CHAR value.
// The set of bits to extract is described by a base offset, a width,
// and an index. The offset and width are known at compile time, but
// the index is a run time variable. ExUnPackCol clause also gets
// the null indicator of the result from a bitmap within the CHAR
// field.
//
ex_expr::exp_return_type
ExUnPackCol::eval(char *op_data[], CollHeap *heap, ComDiagsArea **diagsArea)
{
// The width of the extract in BITS.
//
Lng32 width = width_;
// The base offset of the data in BYTES.
//
Lng32 base = base_;
// Boolean indicating if the NULL Bitmap is present.
// If it is present, then it starts at a 4 (sizeof(int)) byte offset.
//
NABoolean np = nullsPresent();
// Which piece of data are we extracting.
//
Lng32 index = *(Lng32 *)op_data[2];
// NULL Processing...
//
if(np) {
// The bit to be extracted.
//
Lng32 bitOffset = index;
// The byte of the CHAR field containing the bit.
//
Lng32 byteOffset = sizeof(Int32) + (bitOffset >> 3);
// The bit of the byte at byteOffset to be extracted.
//
bitOffset = bitOffset & 0x7;
// A pointer to the null indicators of the operands.
//
char **null_data = &op_data[-2 * ex_clause::MAX_OPERANDS];
// The mask used to test the NULL bit.
//
UInt32 mask = 1 << bitOffset;
// The byte containing the NULL Flag.
//
UInt32 byte = op_data[1][byteOffset];
// Is the NULL Bit set?
//
if(byte & mask) {
// The value is NULL, so set the result to NULL, and
// return since we do not need to extract the data.
//
*(short *)null_data[0] = (short)0xFFFF;
return ex_expr::EXPR_OK;
} else {
// The value is non-NULL, so set the indicator,
// continue to extract the data value.
//
*(short *)null_data[0] = 0;
}
}
// Bytes masks used for widths (1-8) of bit extracts.
//
const UInt32 masks[] = {0,1,3,7,15,31,63,127,255};
// Handle some special cases:
// Otherwise do a generic bit extract.
//
if(width == 8 || width == 4 || width == 2 || width == 1) {
// Items per byte for special case widths (1-8).
//
const UInt32 itemsPerBytes[] = {0,8,4,2,2,1,1,1,1};
// Amount to shift the index to get a byte index for the
// special case widths.
//
const UInt32 itemsPerByteShift[] = {0,3,2,1,1,0,0,0,0};
// Extracted value.
//
UInt32 value;
// An even more special case.
//
if(width == 8) {
// Must use unsigned assignment so that sign extension is not done.
// Later when signed bit precision integers are support will have
// to have a special case for those.
//
value = (unsigned char)op_data[1][base + index];
} else {
// The number of items in a byte.
//
UInt32 itemsPerByte = itemsPerBytes[width];
// The amount to shift the index to get a byte offset.
//
UInt32 shift = itemsPerByteShift[width];
// The offset of the byte containing the value.
//
Lng32 byteIndex = index >> shift;
// The index into the byte of the value.
//
Lng32 itemIndex = index & ( itemsPerByte - 1);
// A mask to extract an item of size width.
//
UInt32 mask = masks[width];
// The byte containing the item.
//
value = op_data[1][base + byteIndex];
// Shift the byte, so that the value to be
// extracted is in the least significant bits.
//
value = value >> (width * itemIndex);
// Clear all bits except those of the value.
//
value = value & mask;
}
// Copy value to result.
//
switch(getOperand(0)->getLength()) {
case 1:
*(unsigned char *)op_data[0] = value;
return ex_expr::EXPR_OK;
case 2:
*(unsigned short *)op_data[0] = value;
return ex_expr::EXPR_OK;
case 4:
*(ULng32 *)op_data[0] = value;
return ex_expr::EXPR_OK;
default:
// ERROR - This should never happen.
//
ExRaiseSqlError(heap, diagsArea, EXE_INTERNAL_ERROR);
return ex_expr::EXPR_ERROR;
}
return ex_expr::EXPR_OK;
}
// Handle special case of a Byte copy.
//
if((width % 8) == 0) {
width = width/8;
str_cpy_all(op_data[0], &op_data[1][base + (index * width)], width);
return ex_expr::EXPR_OK;
}
char guard1 = op_data[0][-1];
char guard2 = op_data[0][getOperand(0)->getLength()];
// The general case of arbitrary bit lengths that can span byte boundaries.
//
// The offset to the value in bits.
//
Lng32 bitOffset = index * width;
// The offset to the last bit of the value in bits.
//
Lng32 bitOffsetEnd = bitOffset + width - 1;
// The offset to the byte containing the first bit of the value.
// in bytes.
//
Lng32 byteOffset = base + (bitOffset >> 3);
// The offset to the byte containing the first bit beyond the value.
// in bytes.
//
Lng32 byteOffsetEnd = base + (bitOffsetEnd >> 3);
// The offset of the first bit in the byte.
//
bitOffset = bitOffset & 0x7;
// The amount to shift the byte to the right to align
// the lower portion.
//
Lng32 rshift = bitOffset;
// The amount to shift the byte to the left to align
// the upper portion.
//
Lng32 lshift = 8 - bitOffset;
// An index into the destination.
//
Lng32 dindex = 0;
// Copy all the bits to the destination.
//
Int32 i = byteOffset;
for(; i <= byteOffsetEnd; i++) {
// Get a byte containing bits of the value.
//
unsigned char byte = op_data[1][i];
if(dindex > 0) {
// After the first byte, must copy the upper
// portion of the byte to the previous byte of
// the result. This is the second time writing
// to this byte.
//
op_data[0][dindex - 1] |= byte << lshift;
}
if(dindex < (Lng32) getOperand(0)->getLength()) {
// Copy the lower portion of this byte of the result
// to the destination. This is the first time this
// byte is written to.
//
op_data[0][dindex] = byte >> rshift;
}
dindex++;
}
// Clear all bits of the result that did not come
// from the extracted value.
//
for(i = 0; i < (Lng32) getOperand(0)->getLength(); i++) {
unsigned char mask = (width > 7) ? 0xFF : masks[width];
op_data[0][i] &= mask;
width -= 8;
width = (width < 0) ? 0 : width;
}
if(guard1 != op_data[0][-1] ||
guard2 != op_data[0][getOperand(0)->getLength()]) {
ExRaiseSqlError(heap, diagsArea, EXE_INTERNAL_ERROR);
return ex_expr::EXPR_ERROR;
}
return ex_expr::EXPR_OK;
}
ex_expr::exp_return_type ex_function_translate::eval(char *op_data[],
CollHeap* heap,
ComDiagsArea** diagsArea)
{
Int32 copyLen = 0;
Int32 convertedLen = 0;
Int32 convType = get_conv_type();
Attributes * op0 = getOperand(0);
Attributes * op1 = getOperand(1);
ULng32 convFlags = (flags_ & TRANSLATE_FLAG_ALLOW_INVALID_CODEPOINT ?
CONV_ALLOW_INVALID_CODE_VALUE : 0);
return convDoIt(op_data[1],
op1->getLength(op_data[-MAX_OPERANDS + 1]),
op1->getDatatype(),
op1->getPrecision(),
(convType == CONV_UTF8_F_UCS2_V) ? (Int32)(CharInfo::UTF8) : op1->getScale(),
op_data[0],
op0->getLength(),
op0->getDatatype(),
op0->getPrecision(),
(convType == CONV_UCS2_F_UTF8_V) ? (Int32)(CharInfo::UTF8) : op0->getScale(),
op_data[-MAX_OPERANDS],
op0->getVCIndicatorLength(),
heap,
diagsArea,
(ConvInstruction)convType,
NULL,
convFlags);
}
void ExFunctionRandomNum::initSeed(char *op_data[])
{
if (seed_==0)
{
if (simpleRandom())
{
// start with 1 and go up to max
seed_ = 1;
return;
}
if (getNumOperands() == 2)
{
// seed is specified as an argument. Use it.
seed_ = *(ULng32 *)op_data[1];
return;
}
// Pick an initial seed. According to the reference given below
// (in the eval function), all initial seeds between 1 and
// 2147483647 are equally valid. So, we just need to pick one
// in this range. Do this based on a timestamp.
struct timespec seedTime;
clock_gettime(CLOCK_REALTIME, &seedTime);
seed_ = (Int32) (seedTime.tv_sec % 2147483648);
seed_ ^= (Int32) (seedTime.tv_nsec % 2147483648L);
// Go through one step of a linear congruential random generator.
// (https://en.wikipedia.org/wiki/Linear_congruential_generator).
// This is to avoid seed values that are close to each other when
// we call this method again within a short time. The eval() method
// below doesn't handle seed values that are close to each other
// very well.
seed_ = (((Int64) seed_) * 1664525L + 1013904223L) % 2147483648;
if (seed_<0)
seed_ += 2147483647;
if ( seed_ < 1 ) seed_ = 1;
}
}
void ExFunctionRandomNum::genRand(char *op_data[])
{
// Initialize seed if not already done
initSeed(op_data);
Lng32 t = 0;
const Lng32 M = 2147483647;
if (simpleRandom())
{
t = seed_ + 1;
}
else
{
// Algorithm is taken from "Random Number Generators: Good Ones
// Are Hard To Find", by Stephen K. Park and Keith W. Miller,
// Communications of the ACM, Volume 31, Number 10, Oct 1988.
const Lng32 A = 16807;
const Lng32 Q = 127773;
const Lng32 R = 2836;
Lng32 h = seed_/Q;
Lng32 l = seed_%Q;
t = A*l-R*h;
}
if (t>0)
seed_ = t;
else
seed_ = t + M;
}
ex_expr::exp_return_type ExFunctionRandomNum::eval(char *op_data[],
CollHeap*,
ComDiagsArea**)
{
genRand(op_data); // generates and sets the random number in seed_
*((ULng32*)op_data[0]) = (ULng32) seed_;
return ex_expr::EXPR_OK;
}
void ExFunctionRandomSelection::initDiff()
{
if (difference_ == -1)
{
difference_ = 0;
while (selProbability_ >= 1.0)
{
difference_++;
selProbability_ -= 1.0;
}
// Normalize the selProbability to a 32 bit integer and store in
// normProbability
normProbability_ = (Lng32) (selProbability_ * 0x7fffffff);
// reset the selProbability_ to original value in case this function
// gets called again
selProbability_ += difference_;
}
}
ex_expr::exp_return_type ExFunctionRandomSelection::eval(char *op_data[],
CollHeap*,
ComDiagsArea**)
{
initDiff(); // gets executed only once
genRand(NULL); // generates and sets the random number in seed_
if (getRand() < normProbability_)
*((ULng32*)op_data[0]) = (ULng32) (difference_ + 1);
else
*((ULng32*)op_data[0]) = (ULng32) (difference_);
return ex_expr::EXPR_OK;
}
ex_expr::exp_return_type ExHash2Distrib::eval(char *op_data[],
CollHeap*,
ComDiagsArea**)
{
ULng32 keyValue = *(ULng32*)op_data[1];
ULng32 numParts = *(ULng32*)op_data[2];
ULng32 partNo =
(ULng32)(((Int64)keyValue * (Int64)numParts) >> 32);
*(ULng32*)op_data[0] = partNo;
return ex_expr::EXPR_OK;
}
ex_expr::exp_return_type ExProgDistrib::eval(char *op_data[],
CollHeap*,
ComDiagsArea**)
{
ULng32 keyValue = *(Lng32*)op_data[1];
ULng32 totNumValues = *(Lng32*) op_data[2];
ULng32 resultValue = 1;
ULng32 offset = keyValue;
ULng32 i = 2;
while(offset >= i && i <= totNumValues) {
Lng32 n1 = offset % i;
Lng32 n2 = offset / i;
if (n1 == 0) {
offset = (i-1) * (n2 - 1) + resultValue;
resultValue = i;
i++;
} else {
Lng32 n3 = n2 << 1;
if(n1 > n3) {
Lng32 n = n1/n3 + (n1%n3 != 0);
offset -= n2 * n;
i += n;
} else {
offset -= n2;
i++;
}
}
}
*((ULng32 *)op_data[0]) = resultValue - 1;
return ex_expr::EXPR_OK;
}
ex_expr::exp_return_type ExProgDistribKey::eval(char *op_data[],
CollHeap*,
ComDiagsArea**)
{
ULng32 value = *(ULng32*)op_data[1];
ULng32 offset = *(ULng32*)op_data[2];
ULng32 totNumValues = *(ULng32*)op_data[3];
ULng32 uniqueVal = offset >> 16;
offset = offset & 0x0000FFFF;
value++;
ULng32 i = totNumValues;
while(i >= 2) {
if (value==i) {
value = (ULng32) (offset-1)%(i-1) + 1;
offset = ((offset-1)/(i-1) + 1) * i;
i--;
} else if(offset < i) {
i = (offset>value?offset:value);
} else {
offset = offset + (offset-1)/(i-1);
i--;
}
}
Int64 result = offset;
result = ((result << 16) | uniqueVal) << 16;
*((Int64 *)op_data[0]) = result;
return ex_expr::EXPR_OK;
}
ex_expr::exp_return_type ExPAGroup::eval(char *op_data[],
CollHeap*,
ComDiagsArea**)
{
ULng32 partNum = *(ULng32*)op_data[1];
ULng32 totNumGroups = *(ULng32*) op_data[2];
ULng32 totNumParts = *(ULng32*) op_data[3];
ULng32 scaleFactor = totNumParts / totNumGroups;
ULng32 transPoint = (totNumParts % totNumGroups);
ULng32 groupPart;
if(partNum < (transPoint * (scaleFactor + 1))) {
groupPart = partNum / (scaleFactor + 1);
} else {
groupPart = (partNum - transPoint) / scaleFactor;
}
*((ULng32 *)op_data[0]) = groupPart;
return ex_expr::EXPR_OK;
}
ex_expr::exp_return_type ExFunctionRangeLookup::eval(char *op_data[],
CollHeap*,
ComDiagsArea**)
{
// Two operands get passed to ExFunctionRangeLookup: a pointer to
// the actual, encoded key, and a pointer into a constant array
// that contains the encoded split ranges. The result is a 4 byte
// integer, not NULL, that contains the partition number.
char *encodedKey = op_data[1];
char *sKeys = op_data[2];
Lng32 *result = (Lng32 *) op_data[0];
// Now perform a binary search in sKeys
Lng32 lo = 0;
Lng32 hi = numParts_; // note we have one more entry than parts
Lng32 probe;
Lng32 cresult;
while (hi-lo > 1)
{
// try the element in the middle (may round down)
probe = (lo+hi)/2;
// compare our encoded key with that middle split range
cresult = str_cmp(encodedKey,
&sKeys[probe*partKeyLen_],
partKeyLen_);
if (cresult <= 0)
hi = probe; // search first half, discard second half
if (cresult >= 0)
lo = probe; // search second half, discard first half
}
// Once we have narrowed it down to a difference between lo and hi
// of 0 or 1, we know that lo points to the index of our partition
// because the partition number must be greater or equal to lo and
// less than hi. Remember that we set hi to one more than we had
// partition numbers.
*result = lo;
return ex_expr::EXPR_OK;
}
ExRowsetArrayScan::ExRowsetArrayScan(){};
ExRowsetArrayRowid::ExRowsetArrayRowid(){};
ExRowsetArrayInto::ExRowsetArrayInto(){};
ExRowsetArrayScan::ExRowsetArrayScan(Attributes **attr,
Space *space,
Lng32 maxNumElem,
Lng32 elemSize,
NABoolean elemNullInd)
: maxNumElem_(maxNumElem),
elemSize_(elemSize),
elemNullInd_(elemNullInd),
ex_function_clause(ITM_ROWSETARRAY_SCAN, 3, attr, space)
{
};
ExRowsetArrayRowid::ExRowsetArrayRowid(Attributes **attr,
Space *space,
Lng32 maxNumElem)
: maxNumElem_(maxNumElem),
ex_function_clause(ITM_ROWSETARRAY_ROWID, 3, attr, space)
{
};
ExRowsetArrayInto::ExRowsetArrayInto(Attributes **attr,
Space *space,
Lng32 maxNumElem,
Lng32 elemSize,
NABoolean elemNullInd)
: maxNumElem_(maxNumElem),
numElem_(0),
elemSize_(elemSize),
elemNullInd_(elemNullInd),
ex_function_clause(ITM_ROWSETARRAY_INTO, 3, attr, space)
{
};
// ExRowsetArrayScan::eval() ------------------------------------------
// The ExRowsetArrayScan clause extracts an element of the Rowset array
// The size of the element is known at compile time, but the index is a
// run time variable.
ex_expr::exp_return_type
ExRowsetArrayScan::eval(char *op_data[],
CollHeap *heap,
ComDiagsArea **diagsArea)
{
// op_data[0] points to the result
// op_data[1] points to the array
// op_data[2] points to the index
Lng32 index = *(Lng32 *)op_data[2];
if (index < 0 || index >= maxNumElem_)
{
// The index cannot be greater than the dimension of the array
// It is likely that there was an item expression evaluated at
// execution time to obtain the rowsetSize which is greater than
// the maximum allowed.
ExRaiseSqlError(heap, diagsArea, EXE_ROWSET_INDEX_OUTOF_RANGE);
**diagsArea << DgSqlCode(-EXE_ROWSET_INDEX_OUTOF_RANGE);
return ex_expr::EXPR_ERROR;
}
Attributes *ResultAttr = getOperand(0);
Attributes *SourceAttr = getOperand(1);
Lng32 size = ResultAttr->getStorageLength();
char *SourceElemPtr = &op_data[1][(index * size) + sizeof(Lng32)];
// NULL Processing...
if(elemNullInd_) {
// A pointer to the null indicators of the operands.
char **ResultNullData = &op_data[-2 * ex_clause::MAX_OPERANDS];
char *SourceElemIndPtr = SourceElemPtr;
SourceElemPtr += SourceAttr->getNullIndicatorLength();
// Set the indicator
if (ResultAttr->getNullFlag()) {
str_cpy_all(ResultNullData[0], SourceElemIndPtr,
SourceAttr->getNullIndicatorLength());
}
if ( ExpTupleDesc::isNullValue( SourceElemIndPtr,
SourceAttr->getNullBitIndex(),
SourceAttr->getTupleFormat() ) )
{
// The value is NULL, return since we do not need to extract the data.
return ex_expr::EXPR_NULL;
}
}
// For SQLVarChars, we have to copy both length and value fields.
// op_data[-ex_clause::MAX_OPERANDS] points to the length field of the
// SQLVarChar;
// The size of the field is sizeof(short) for rowset SQLVarChars.
if(SourceAttr->getVCIndicatorLength() > 0){
str_cpy_all((char*)op_data[-ex_clause::MAX_OPERANDS],
(char*)(&op_data[-ex_clause::MAX_OPERANDS+1][index*size]),
SourceAttr->getVCIndicatorLength()); //sizeof(short));
SourceElemPtr += SourceAttr->getVCIndicatorLength();
str_cpy_all(op_data[0], SourceElemPtr, size - SourceAttr->getVCIndicatorLength());
}
else {
// Note we do not have variable length for host variables. But we may not
// need to copy the whole length for strings.
str_cpy_all(op_data[0], SourceElemPtr, size);
}
return ex_expr::EXPR_OK;
}
Long ExRowsetArrayScan::pack(void * space)
{
return packClause(space, sizeof(ExRowsetArrayScan));
}
Long ExRowsetArrayRowid::pack(void * space)
{
return packClause(space, sizeof(ExRowsetArrayRowid));
}
Long ExRowsetArrayInto::pack(void * space)
{
return packClause(space, sizeof(ExRowsetArrayInto));
}
// ExRowsetArrayRowid::eval() ------------------------------------------
// The ExRowsetArrayRowid clause returns the value of the current index
ex_expr::exp_return_type
ExRowsetArrayRowid::eval(char *op_data[], CollHeap *heap,
ComDiagsArea **diagsArea)
{
// op_data[0] points to the result
// op_data[1] points to the array
// op_data[2] points to the index
// The width of each data item in bytes
Lng32 index = *(Lng32 *)op_data[2];
if (index < 0 || index >= maxNumElem_)
{
// The index cannot be greater than the dimension of the array
// It is likely that there was an item expression evaluated at
// execution time to obtain the rowsetSize which is greater than
// the maximum allowed.
ExRaiseSqlError(heap, diagsArea, EXE_ROWSET_INDEX_OUTOF_RANGE);
**diagsArea << DgSqlCode(-EXE_ROWSET_INDEX_OUTOF_RANGE);
return ex_expr::EXPR_ERROR;
}
// Note we do not have variable length for host variables. But we may not
// need to copy the whole length for strings.
str_cpy_all(op_data[0], (char *)&index, sizeof(index));
return ex_expr::EXPR_OK;
}
// ExRowsetArrayInto::eval() ------------------------------------------
// The ExRowsetArrayInto clause appends a value into the Rowset array
// The size of the element is known at compile time
ex_expr::exp_return_type
ExRowsetArrayInto::eval(char *op_data[], CollHeap *heap,
ComDiagsArea **diagsArea)
{
// op_data[0] points to the array (Result)
// op_data[1] points to the value to insert
// op_data[2] points to the rowset size expression
Lng32 runtimeMaxNumElem = *(Lng32 *)op_data[2];
if (numElem_ >= runtimeMaxNumElem || numElem_ >= maxNumElem_) {
// Overflow, we cannot add more elements to this rowset array
ExRaiseSqlError(heap, diagsArea, EXE_ROWSET_OVERFLOW);
**diagsArea << DgSqlCode(-EXE_ROWSET_OVERFLOW);
return ex_expr::EXPR_ERROR;
}
// Get number of rows stored in the array
Lng32 nrows;
str_cpy_all((char*)&nrows,op_data[0],sizeof(Lng32));
if (nrows >= runtimeMaxNumElem || nrows >= maxNumElem_) {
// Overflow, we cannot add more elements to this rowset array
ExRaiseSqlError(heap, diagsArea, EXE_ROWSET_OVERFLOW);
**diagsArea << DgSqlCode(-EXE_ROWSET_OVERFLOW);
return ex_expr::EXPR_ERROR;
}
Attributes *resultAttr = getOperand(0);
NABoolean resultIsNull = FALSE;
char *sourceNullData = op_data[-2 * ex_clause::MAX_OPERANDS + 1];
Attributes *sourceAttr = getOperand(1);
Lng32 elementSize = ((SimpleType *) resultAttr)->getStorageLength();
char *resultElemPtr = &op_data[0][(nrows * elementSize) +
sizeof (Lng32)];
// NULL Processing...
if (elemNullInd_) {
char *resultElemIndPtr = resultElemPtr;
// Set the indicator
if (sourceAttr->getNullFlag() && sourceNullData == 0) {
ExpTupleDesc::setNullValue(resultElemIndPtr,
resultAttr->getNullBitIndex(),
resultAttr->getTupleFormat());
resultIsNull = TRUE;
} else {
ExpTupleDesc::clearNullValue(resultElemIndPtr,
resultAttr->getNullBitIndex(),
resultAttr->getTupleFormat());
}
} else if (sourceAttr->getNullFlag() && sourceNullData == 0) {
// Source is null, but we do not have a way to express it
ExRaiseSqlError(heap, diagsArea, EXE_MISSING_INDICATOR_VARIABLE);
**diagsArea << DgSqlCode(-EXE_MISSING_INDICATOR_VARIABLE);
return ex_expr::EXPR_ERROR;
}
// Copy the result if not null
// For SQLVarChars, copy both val and len fields.
if (resultIsNull == FALSE){
if (DFS2REC::isSQLVarChar(resultAttr->getDatatype())) {
unsigned short VCLen = 0;
str_cpy_all((char *) &VCLen,
(char*)op_data[-ex_clause::MAX_OPERANDS + 1],
resultAttr->getVCIndicatorLength());
str_cpy_all( resultElemPtr+resultAttr->getNullIndicatorLength(),
(char *) &VCLen,
resultAttr->getVCIndicatorLength());
str_cpy_all(
resultElemPtr+resultAttr->getNullIndicatorLength()+
resultAttr->getVCIndicatorLength(),
op_data[1], VCLen);
}
else {
str_cpy_all(resultElemPtr + resultAttr->getNullIndicatorLength(),
op_data[1], resultAttr->getLength());
} // if isSQLVarChar
} // if resultIsNULL
// Update the number of elements in the object associated with the array
// and the array itself
nrows++;
str_cpy_all(op_data[0],(char*)&nrows,sizeof(Lng32));
return ex_expr::EXPR_OK;
}
ex_expr::exp_return_type ex_function_nullifzero::eval(char *op_data[],
CollHeap *heap,
ComDiagsArea** diagsArea)
{
Attributes *tgtOp = getOperand(0);
char * tgt = op_data[0];
char * tgtNull = op_data[-2 * MAX_OPERANDS];
char * src = op_data[1];
Lng32 srcLen = getOperand(1)->getLength();
NABoolean resultIsNull = TRUE;
for (Int32 i = 0; i < srcLen; i++)
{
tgt[i] = src[i];
if (src[i] != 0)
{
resultIsNull = FALSE;
}
}
if (resultIsNull)
{
ExpTupleDesc::setNullValue(tgtNull,
tgtOp->getNullBitIndex(),
tgtOp->getTupleFormat());
}
else
{
ExpTupleDesc::clearNullValue(tgtNull,
tgtOp->getNullBitIndex(),
tgtOp->getTupleFormat());
}
return ex_expr::EXPR_OK;
}
//
// NVL(e1, e2) returns e2 if e1 is NULL otherwise e1. NVL(e1, e2) is
// equivalent to ANSI/ISO
// COALESCE(e1, e2)
// or,
// CASE WHEN e1 IS NULL THEN e2 ELSE e1 END
// Both arguments can be nullable and actually null; they both can
// be constants as well.
// NVL() on CHAR type expressions is mapped to CASE. ISNULL(e1, e2) is
// mapped into NVL(e1, e2)
// Datatypes of e1 and e2 must be comparable/compatible.
//
ex_expr::exp_return_type ex_function_nvl::eval(char *op_data[],
CollHeap *heap,
ComDiagsArea** diagsArea)
{
// Common index into op_data[] to access Null Indicators
Int32 opNullIdx = -2 * MAX_OPERANDS;
Attributes *tgtOp = getOperand(0);
Attributes *arg1 = getOperand(1);
Attributes *arg2 = getOperand(2);
char * tgt = op_data[0];
char * tgtNull = op_data[opNullIdx];
char * src;
UInt32 srcLen;
NABoolean resultIsNull = TRUE;
// As of today, NVL() on CHAR types becomes CASE. So make sure we are
// not dealing with any CHAR types
assert(!DFS2REC::isAnyCharacter(arg1->getDatatype()) &&
!DFS2REC::isAnyCharacter(arg2->getDatatype()));
// Locate the operand that is not null: if both are null
// resultIsNull will still be TRUE and we will just set the
// NULL flag of the result. If any operand is NOT NULL we copy
// that value into result and clear NULL flag of the result.
if (!arg1->getNullFlag() || op_data[opNullIdx + 1])
{
// First operand is either NOT NULLABLE or NON NULL Value.
// This is the result.
src = op_data[1];
srcLen = arg1->getLength();
resultIsNull = FALSE;
}
else
{
// Second operand could be the result, if it is not null.
src = op_data[2];
srcLen = arg2->getLength();
// Second operand is either NOT NULLABLE or NON NULL Value.
// This is the result.
if (!arg2->getNullFlag() || op_data[opNullIdx + 2])
resultIsNull = FALSE;
}
if (resultIsNull)
{
// Result must be nullable
assert(tgtOp->getNullFlag());
ExpTupleDesc::setNullValue(tgtNull,
tgtOp->getNullBitIndex(),
tgtOp->getTupleFormat());
}
else
{
// clear nullflag of result if it is nullable
if (tgtOp->getNullFlag())
ExpTupleDesc::clearNullValue(tgtNull,
tgtOp->getNullBitIndex(),
tgtOp->getTupleFormat());
}
// Copy src to result: this could be NULL
assert((UInt32)(tgtOp->getLength()) >= srcLen);
str_cpy_all(tgt, src, srcLen);
return ex_expr::EXPR_OK;
}
ex_expr::exp_return_type ex_function_json_object_field_text::eval(char *op_data[],
CollHeap *heap,
ComDiagsArea** diagsArea)
{
CharInfo::CharSet cs = ((SimpleType *)getOperand(1))->getCharSet();
// search for operand 1
Lng32 len1 = getOperand(1)->getLength(op_data[-MAX_OPERANDS+1]);
if ( cs == CharInfo::UTF8 )
{
Int32 prec1 = ((SimpleType *)getOperand(1))->getPrecision();
len1 = Attributes::trimFillerSpaces( op_data[1], prec1, len1, cs );
}
// in operand 2
Lng32 len2 = getOperand(2)->getLength(op_data[-MAX_OPERANDS+2]);
if ( cs == CharInfo::UTF8 )
{
Int32 prec2 = ((SimpleType *)getOperand(2))->getPrecision();
len2 = Attributes::trimFillerSpaces( op_data[2], prec2, len2, cs );
}
char *rltStr = NULL;
char jsonStr[len1+1];
char jsonAttr[len2+1];
strncpy(jsonStr, op_data[1], len1);
jsonStr[len1] = '\0';
strncpy(jsonAttr, op_data[2], len2);
jsonAttr[len2] = '\0';
JsonReturnType ret = json_extract_path_text(&rltStr, jsonStr, 1, jsonAttr);
if (ret != JSON_OK)
{
ExRaiseJSONError(heap, diagsArea, ret);
return ex_expr::EXPR_ERROR;
}
if (rltStr != NULL)
{
Lng32 rltLen = str_len(rltStr)+1;
str_cpy_all(op_data[0], rltStr, rltLen);
free(rltStr);
// If result is a varchar, store the length of substring
// in the varlen indicator.
if (getOperand(0)->getVCIndicatorLength() > 0)
getOperand(0)->setVarLength(rltLen, op_data[-MAX_OPERANDS]);
}
else
getOperand(0)->setVarLength(0, op_data[-MAX_OPERANDS]);
return ex_expr::EXPR_OK;
}
//
// Clause used to clear header bytes for both disk formats
// SQLMX_FORMAT and SQLMX_ALIGNED_FORMAT. The number of bytes to clear
// is different for both formats.
// This clause is only generated for insert expressions and update expressions
// (updates that are non-optimized since olt optimized updates do a strcpy
// of the old image and then update the specific columns).
ex_expr::exp_return_type ExHeaderClause::eval(char *op_data[],
CollHeap *heap,
ComDiagsArea **diagsArea)
{
char *tgtData = op_data[0];
Attributes *tgtOp = getOperand(0);
// Clear the entire header (not the VOA area)
str_pad( tgtData, (Int32)adminSz_, '\0' );
if ( bitmapOffset_ > 0 )
((ExpAlignedFormat *)tgtData)->setBitmapOffset( bitmapOffset_ );
// Can not use the tgt attributes offset value here since for the aligned
// format this may not be the first fixed field since the fixed fields
// are re-ordered.
if ( isSQLMXAlignedFormat() )
((ExpAlignedFormat *)tgtData)->setFirstFixedOffset( firstFixedOffset_ );
else
ExpTupleDesc::setFirstFixedOffset( tgtData,
firstFixedOffset_,
tgtOp->getTupleFormat() );
return ex_expr::EXPR_OK;
}
ex_expr::exp_return_type ex_function_queryid_extract::eval(char *op_data[],
CollHeap *heap,
ComDiagsArea** diagsArea)
{
Lng32 retcode = 0;
char * qidStr = op_data[1];
char * attrStr = op_data[2];
Lng32 qidLen = getOperand(1)->getLength();
Lng32 attrLen = getOperand(2)->getLength();
Lng32 attr = -999;
NABoolean isNumeric = FALSE;
// remove trailing blanks from attrStr
while (attrLen && attrStr[attrLen-1] == ' ')
attrLen--;
if (strncmp(attrStr, "SEGMENTNUM", attrLen) == 0)
{
attr = ComSqlId::SQLQUERYID_SEGMENTNUM;
isNumeric = TRUE;
}
else if (strncmp(attrStr, "CPU", attrLen) == 0)
{
attr = ComSqlId::SQLQUERYID_CPUNUM;
isNumeric = TRUE;
}
else if (strncmp(attrStr, "CPUNUM", attrLen) == 0)
{
attr = ComSqlId::SQLQUERYID_CPUNUM;
isNumeric = TRUE;
}
else if (strncmp(attrStr, "PIN", attrLen) == 0)
{
attr = ComSqlId::SQLQUERYID_PIN;
isNumeric = TRUE;
}
else if (strncmp(attrStr, "EXESTARTTIME", attrLen) == 0)
{
attr = ComSqlId::SQLQUERYID_EXESTARTTIME;
isNumeric = TRUE;
}
else if (strncmp(attrStr, "SESSIONID", attrLen) == 0)
{
attr = ComSqlId::SQLQUERYID_SESSIONID;
}
else if (strncmp(attrStr, "SESSIONNUM", attrLen) == 0)
{
attr = ComSqlId::SQLQUERYID_SESSIONNUM;
isNumeric = TRUE;
}
else if (strncmp(attrStr, "USERNAME", attrLen) == 0)
{
attr = ComSqlId::SQLQUERYID_USERNAME;
}
else if (strncmp(attrStr, "SESSIONNAME", attrLen) == 0)
{
attr = ComSqlId::SQLQUERYID_SESSIONNAME;
}
else if (strncmp(attrStr, "QUERYNUM", attrLen) == 0)
{
attr = ComSqlId::SQLQUERYID_QUERYNUM;
isNumeric = TRUE;
}
else if (strncmp(attrStr, "STMTNAME", attrLen) == 0)
{
attr = ComSqlId::SQLQUERYID_STMTNAME;
}
Int64 value;
if (!isNumeric)
value = 99; // set max valueStr length
char valueStr[100];
retcode = ComSqlId::getSqlQueryIdAttr(
attr, qidStr, qidLen, value, valueStr);
if (retcode < 0)
{
ExRaiseFunctionSqlError(heap, diagsArea, (ExeErrorCode)(-retcode),
derivedFunction(),
origFunctionOperType());
return ex_expr::EXPR_ERROR;
}
char * valPtr;
short datatype;
Lng32 length;
if (isNumeric)
{
valPtr = (char*)&value;
datatype = REC_BIN64_SIGNED;
length = 8;
}
else
{
valPtr = valueStr;
datatype = REC_BYTE_V_ANSI;
length = (Lng32)value + 1; // include null terminator
}
if (convDoIt(valPtr, length, datatype, 0, 0,
op_data[0],
getOperand(0)->getLength(),
getOperand(0)->getDatatype(),
getOperand(0)->getPrecision(),
getOperand(0)->getScale(),
op_data[-MAX_OPERANDS],
getOperand(0)->getVCIndicatorLength(),
heap, diagsArea))
return ex_expr::EXPR_ERROR;
return ex_expr::EXPR_OK;
}
ex_expr::exp_return_type ExFunctionUniqueId::eval(char *op_data[],
CollHeap *heap,
ComDiagsArea** diagsArea)
{
Lng32 retcode = 0;
char * result = op_data[0];
if(getOperType() == ITM_UNIQUE_ID)
{
//it is hard to find a common header file for these length
//so hardcode 36 here
//if change, please check the SynthType.cpp for ITM_UNIQUE_ID part as well
//libuuid is global unique, even across computer node
//NOTE: libuuid is avialble on normal CentOS, other system like Ubuntu may need to check
//Trafodion only support RHEL and CentOS as for now
char str[36 + 1];
uuid_t uu;
uuid_generate( uu );
uuid_unparse(uu, str);
str_cpy_all(result, str, 36);
}
else if(getOperType() == ITM_UNIQUE_ID_SYS_GUID)
{
uuid_t uu;
uuid_generate( uu );
str_cpy_all(result, (char*)&uu,sizeof(uu));
}
else //at present , it must be ITM_UUID_SHORT_ID
{
Int64 uniqueUID;
ComUID comUID;
comUID.make_UID();
#if defined( NA_LITTLE_ENDIAN )
uniqueUID = reversebytes(comUID.get_value());
#else
uniqueUID = comUID.get_value();
#endif
//it is safe, since the result is allocated 21 bytes in this case from synthtype,
//max in64 is 19 digits and one for sign, 21 is enough
sprintf(result,"%lu",uniqueUID);
}
return ex_expr::EXPR_OK;
}
ex_expr::exp_return_type ExFunctionRowNum::eval(char *op_data[],
CollHeap *heap,
ComDiagsArea** diagsArea)
{
char * result = op_data[0];
Int64 rowNum = getExeGlobals()->rowNum();
str_cpy_all(result, (char*)&rowNum, sizeof(Int64));
str_pad(&result[sizeof(Int64)], sizeof(Int64), '\0');
return ex_expr::EXPR_OK;
}
short ExFunctionHbaseColumnLookup::extractColFamilyAndName(
const char * input,
short len,
NABoolean isVarchar,
std::string &colFam, std::string &colName)
{
if (! input)
return -1;
Lng32 i = 0;
Lng32 startPos = 0;
if (isVarchar)
{
len = *(short*)input;
startPos = sizeof(len);
}
else if (len == -1)
{
len = strlen(input);
startPos = 0;
}
else
{
startPos = 0;
}
Lng32 j = 0;
i = startPos;
NABoolean colonFound = FALSE;
while ((j < len) && (not colonFound))
{
if (input[i] != ':')
{
i++;
}
else
{
colonFound = TRUE;
}
j++;
}
if (colonFound) // ":" found
{
colFam.assign(&input[startPos], i - startPos);
i++;
if (i < (startPos + len))
{
colName.assign(&input[i], (startPos + len) - i);
}
}
else
{
colName.assign(&input[startPos], i - startPos);
}
return 0;
}
ex_expr::exp_return_type
ExFunctionHbaseColumnLookup::eval(char *op_data[], CollHeap *heap,
ComDiagsArea **diagsArea)
{
// op_data[0] points to result. The result is a varchar.
Attributes *resultAttr = getOperand(0);
Attributes *colDetailAttr = getOperand(1);
char * resultStart = op_data[0];
char * resultNull = op_data[-2 * MAX_OPERANDS];
char * result = resultStart;
char * colDetail = op_data[1];
Lng32 sourceLen = 0;
if (colDetailAttr->getVCIndicatorLength() == sizeof(Lng32))
str_cpy_all((char*)&sourceLen, op_data[-MAX_OPERANDS+1], sizeof(Lng32));
else
{
short tempLen = 0;
str_cpy_all((char*)&tempLen, op_data[-MAX_OPERANDS+1], sizeof(short));
sourceLen = tempLen;
}
char * pos = colDetail;
NABoolean done = FALSE;
NABoolean colFound = FALSE;
while (NOT done)
{
short colNameLen = 0;
Lng32 colValueLen = 0;
memcpy((char*)&colNameLen, pos, sizeof(short));
pos += sizeof(short);
if ((colNameLen == strlen(colName_)) &&
(str_cmp(colName_, pos, colNameLen) == 0))
{
pos += colNameLen;
memcpy((char*)&colValueLen, pos, sizeof(Lng32));
pos += sizeof(Lng32);
NABoolean charType = DFS2REC::isAnyCharacter(resultAttr->getDatatype());
if (! charType)
{
// lengths must match for non-char types
if (colValueLen != resultAttr->getLength())
continue;
}
UInt32 flags = 0;
ex_expr::exp_return_type rc =
convDoIt(pos,
colValueLen,
(charType ? REC_BYTE_F_ASCII : resultAttr->getDatatype()),
(charType ? 0 : resultAttr->getPrecision()),
(charType ? 0 : resultAttr->getScale()),
result,
resultAttr->getLength(),
resultAttr->getDatatype(),
resultAttr->getPrecision(),
resultAttr->getScale(),
NULL,
0,
heap,
diagsArea);
if ((rc != ex_expr::EXPR_OK) ||
((diagsArea) && (*diagsArea) && ((*diagsArea)->getNumber(DgSqlCode::WARNING_)) > 0))
{
if (rc == ex_expr::EXPR_OK)
{
(*diagsArea)->negateAllWarnings();
}
return ex_expr::EXPR_ERROR;
}
getOperand(0)->setVarLength(colValueLen, op_data[-MAX_OPERANDS]);
colFound = TRUE;
done = TRUE;
}
else
{
pos += colNameLen;
memcpy((char*)&colValueLen, pos, sizeof(Lng32));
pos += sizeof(Lng32);
pos += colValueLen;
if (pos >= (colDetail + sourceLen))
{
done = TRUE;
}
}
} // while
if (NOT colFound)
{
// move null value to result
ExpTupleDesc::setNullValue(resultNull,
resultAttr->getNullBitIndex(),
resultAttr->getTupleFormat() );
}
else
{
ExpTupleDesc::clearNullValue(resultNull,
resultAttr->getNullBitIndex(),
resultAttr->getTupleFormat() );
}
return ex_expr::EXPR_OK;
}
NABoolean ExFunctionHbaseColumnsDisplay::toBeDisplayed(
char * colName, Lng32 colNameLen)
{
if ((! colNames()) || (numCols_ == 0))
return TRUE;
char * currColName = colNames();
for (Lng32 i = 0; i < numCols_; i++)
{
short currColNameLen = *(short*)currColName;
currColName += sizeof(short);
if ((colNameLen == currColNameLen) &&
(memcmp(colName, currColName, colNameLen) == 0))
return TRUE;
currColName += currColNameLen;
}
return FALSE;
}
ex_expr::exp_return_type
ExFunctionHbaseColumnsDisplay::eval(char *op_data[], CollHeap *heap,
ComDiagsArea **diagsArea)
{
// op_data[0] points to result. The result is a varchar.
Attributes *resultAttr = getOperand(0);
Attributes *colDetailAttr = getOperand(1);
char * resultStart = op_data[0];
char * result = resultStart;
char * colDetail = op_data[1];
Lng32 sourceLen = 0;
if (colDetailAttr->getVCIndicatorLength() == sizeof(Lng32))
str_cpy_all((char*)&sourceLen, op_data[-MAX_OPERANDS+1], sizeof(Lng32));
else
{
short tempLen = 0;
str_cpy_all((char*)&tempLen, op_data[-MAX_OPERANDS+1], sizeof(short));
sourceLen = tempLen;
}
char * pos = colDetail;
NABoolean done = FALSE;
while (NOT done)
{
short colNameLen = 0;
Lng32 colValueLen = 0;
memcpy((char*)&colNameLen, pos, sizeof(short));
pos += sizeof(short);
memcpy(result, pos, colNameLen);
pos += colNameLen;
// if this col name need to be returned, then return it.
if (NOT toBeDisplayed(result, colNameLen))
{
goto label_continue;
}
result += colNameLen;
memcpy(result, " => ", strlen(" => "));
result += strlen(" => ");
memcpy((char*)&colValueLen, pos, sizeof(Lng32));
pos += sizeof(Lng32);
memcpy(result, pos, colValueLen);
result += colValueLen;
pos += colValueLen;
if (pos < (colDetail + sourceLen))
{
memcpy(result, ", ", strlen(", "));
result += strlen(", ");
}
label_continue:
if (pos >= (colDetail + sourceLen))
{
done = TRUE;
}
}
// store the row length in the varlen indicator.
getOperand(0)->setVarLength((result-resultStart), op_data[-MAX_OPERANDS]);
return ex_expr::EXPR_OK;
}
ex_expr::exp_return_type
ExFunctionHbaseColumnCreate::eval(char *op_data[], CollHeap *heap,
ComDiagsArea **diagsArea)
{
// op_data[0] points to result. The result is a varchar.
// Values in result have already been populated by clauses evaluated
// before this clause is reached.
Attributes *resultAttr = getOperand(0);
char * resultStart = op_data[0];
char * result = resultStart;
str_cpy_all(result, (char*)&numEntries_, sizeof(numEntries_));
result += sizeof(short);
str_cpy_all(result, (char*)&colNameMaxLen_, sizeof(colNameMaxLen_));
result += sizeof(short);
str_cpy_all(result, (char*)&colValVCIndLen_, sizeof(colValVCIndLen_));
result += sizeof(short);
str_cpy_all(result, (char*)&colValMaxLen_, sizeof(colValMaxLen_));
result += sizeof(Int32);
for (Lng32 i = 0; i < numEntries_; i++)
{
// validate that column name is of right format: colfam:colname
std::string colFam;
std::string colNam;
ExFunctionHbaseColumnLookup::extractColFamilyAndName(
result, -1, TRUE/*isVarchar*/, colFam, colNam);
if (colFam.empty())
{
short colNameLen;
str_cpy_all((char*)&colNameLen, result, sizeof(short));
result += sizeof(short);
std::string colNamData(result, colNameLen);
ExRaiseSqlError(heap, diagsArea, (ExeErrorCode)1426, NULL, NULL, NULL, NULL,
colNamData.data());
return ex_expr::EXPR_ERROR;
}
result += sizeof(short);
result += ROUND2(colNameMaxLen_);
// skip the nullable bytes
result += sizeof(short);
if (colValVCIndLen_ == sizeof(short))
result += sizeof(short);
else
{
result = (char*)ROUND4((Int64)result);
result += sizeof(Lng32);
}
result += ROUND2(colValMaxLen_);
}
resultAttr->setVarLength(result - resultStart, op_data[-MAX_OPERANDS]);
return ex_expr::EXPR_OK;
}
ex_expr::exp_return_type
ExFunctionCastType::eval(char *op_data[], CollHeap *heap,
ComDiagsArea **diagsArea)
{
// op_data[0] points to result.
Attributes *resultAttr = getOperand(0);
Attributes *srcAttr = getOperand(1);
char * resultData = op_data[0];
char * srcData = op_data[1];
Lng32 sourceLen = srcAttr->getLength(op_data[-MAX_OPERANDS+1]);
Lng32 resultLen = resultAttr->getLength();
if (sourceLen < resultLen)
{
ExRaiseFunctionSqlError(heap, diagsArea, EXE_STRING_OVERFLOW,
derivedFunction(),
origFunctionOperType());
return ex_expr::EXPR_ERROR;
}
str_cpy_all(resultData, srcData, resultLen);
getOperand(0)->setVarLength(resultLen, op_data[-MAX_OPERANDS]);
return ex_expr::EXPR_OK;
}
ex_expr::exp_return_type
ExFunctionSequenceValue::eval(char *op_data[], CollHeap *heap,
ComDiagsArea **diagsArea)
{
short rc = 0;
// op_data[0] points to result. The result is a varchar.
Attributes *resultAttr = getOperand(0);
char * result = op_data[0];
SequenceValueGenerator * seqValGen = getExeGlobals()->seqGen();
Int64 seqVal = 0;
if (isCurr())
rc = seqValGen->getCurrSeqVal(sga_, seqVal);
else
rc = seqValGen->getNextSeqVal(sga_, seqVal);
if (rc)
{
ExRaiseSqlError(heap, diagsArea, (ExeErrorCode)ABS(rc));
return ex_expr::EXPR_ERROR;
}
*(Int64*)result = seqVal;
return ex_expr::EXPR_OK;
}
ex_expr::exp_return_type
ExFunctionHbaseTimestamp::eval(char *op_data[], CollHeap *heap,
ComDiagsArea **diagsArea)
{
short rc = 0;
// op_data[0] points to result.
Attributes *resultAttr = getOperand(0);
char * result = op_data[0];
Int64 * hbaseTS = (Int64*)op_data[1];
*(Int64*)result = hbaseTS[colIndex_];
return ex_expr::EXPR_OK;
}
ex_expr::exp_return_type
ExFunctionHbaseVersion::eval(char *op_data[], CollHeap *heap,
ComDiagsArea **diagsArea)
{
short rc = 0;
// op_data[0] points to result.
Attributes *resultAttr = getOperand(0);
char * result = op_data[0];
Int64 * hbaseVersion = (Int64*)op_data[1];
*(Int64*)result = hbaseVersion[colIndex_];
return ex_expr::EXPR_OK;
}
////////////////////////////////////////////////////////////////////
//
// decodeKeyValue
//
// This routine decodes an encoded key value.
//
// Note: The target MAY point to the source to change the original
// value.
//
////////////////////////////////////////////////////////////////////
short ex_function_encode::decodeKeyValue(Attributes * attr,
NABoolean isDesc,
char *inSource,
char *varlen_ptr,
char *target,
char *target_varlen_ptr,
NABoolean handleNullability
)
{
Lng32 fsDatatype = attr->getDatatype();
Lng32 length = attr->getLength();
Lng32 precision = attr->getPrecision();
Lng32 encodedKeyLen = length;
if ((handleNullability) &&
(attr->getNullFlag()))
encodedKeyLen += attr->getNullIndicatorLength();
char * source = inSource;
if (isDesc)
{
// compliment all bytes
for (Lng32 k = 0; k < encodedKeyLen; k++)
target[k] = ~(source[k]);
source = target;
}
if ((handleNullability) &&
(attr->getNullFlag()))
{
if (target != source)
str_cpy_all(target, source, attr->getNullIndicatorLength());
source += attr->getNullIndicatorLength();
target += attr->getNullIndicatorLength();
}
switch (fsDatatype) {
#if defined( NA_LITTLE_ENDIAN )
case REC_BIN8_SIGNED:
//
// Flip the sign bit.
//
*(UInt8*)target = *(UInt8*)source;
target[0] ^= 0200;
break;
case REC_BIN8_UNSIGNED:
case REC_BOOLEAN:
*(UInt8*)target = *(UInt8*)source;
break;
case REC_BIN16_SIGNED:
//
// Flip the sign bit.
//
*((unsigned short *) target) = reversebytes( *((unsigned short *) source) );
target[sizeof(short)-1] ^= 0200;
break;
case REC_BPINT_UNSIGNED:
case REC_BIN16_UNSIGNED:
*((unsigned short *) target) = reversebytes( *((unsigned short *) source) );
break;
case REC_BIN32_SIGNED:
//
// Flip the sign bit.
//
*((ULng32 *) target) = reversebytes( *((ULng32 *) source) );
target[sizeof(Lng32)-1] ^= 0200;
break;
case REC_BIN32_UNSIGNED:
*((ULng32 *) target) = reversebytes( *((ULng32 *) source) );
break;
case REC_BIN64_SIGNED:
//
// Flip the sign bit.
//
*((_int64 *) target) = reversebytes( *((_int64 *) source) );
target[sizeof(_int64)-1] ^= 0200;
break;
case REC_BIN64_UNSIGNED:
*((UInt64 *) target) = reversebytes( *((UInt64 *) source) );
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:
switch(length)
{
case 2: // Signed 16 bit
*((unsigned short *) target) = reversebytes( *((unsigned short *) source) );
target[SQL_SMALL_SIZE-1] ^= 0200;
break;
case 4: // Signed 32 bit
*((ULng32 *) target) = reversebytes( *((ULng32 *) source) );
target[SQL_INT_SIZE-1] ^= 0200;
break;
case 8: // Signed 64 bit
*((_int64 *) target) = reversebytes( *((_int64 *) source) );
target[SQL_LARGE_SIZE-1] ^= 0200;
break;
default:
assert(FALSE);
break;
}; // switch(length)
break;
case REC_DATETIME: {
// This method has been modified as part of the MP Datetime
// Compatibility project. It has been made more generic so that
// it depends only on the start and end fields of the datetime type.
//
rec_datetime_field startField;
rec_datetime_field endField;
ExpDatetime *dtAttr = (ExpDatetime *)attr;
// Get the start and end fields for this Datetime type.
//
dtAttr->getDatetimeFields(dtAttr->getPrecision(),
startField,
endField);
// Copy all of the source to the destination, then reverse only
// those fields of the target that are longer than 1 byte
//
if (target != source)
str_cpy_all(target, source, length);
// Reverse the YEAR and Fractional precision fields if present.
//
char *ptr = target;
for(Int32 field = startField; field <= endField; field++) {
switch (field) {
case REC_DATE_YEAR:
// convert YYYY from little endian to big endian
//
*((unsigned short *) ptr) = reversebytes( *((unsigned short *) ptr) );
ptr += sizeof(short);
break;
case REC_DATE_MONTH:
case REC_DATE_DAY:
case REC_DATE_HOUR:
case REC_DATE_MINUTE:
// One byte fields are copied as is...
ptr++;
break;
case REC_DATE_SECOND:
ptr++;
// if there is a fraction, make it big endian
// (it is an unsigned long, beginning after the SECOND field)
//
if (dtAttr->getScale() > 0)
*((ULng32 *) ptr) = reversebytes( *((ULng32 *) ptr) );
break;
}
}
break;
}
#else
case REC_BIN8_SIGNED:
case REC_BIN16_SIGNED:
case REC_BIN32_SIGNED:
case REC_BIN64_SIGNED:
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:
//
// Flip the sign bit.
//
if (target != source)
str_cpy_all(target, source, length);
target[0] ^= 0200;
break;
#endif
case REC_DECIMAL_LSE:
//
// If the number was negative, complement all the bytes. Otherwise, set
// the sign bit.
//
if (NOT(source[0] & 0200)) {
for (Lng32 i = 0; i < length; i++)
target[i] = ~source[i];
} else {
if (target != source)
str_cpy_all(target, source, length);
target[0] &= ~0200;
}
break;
case REC_NUM_BIG_SIGNED:
case REC_NUM_BIG_UNSIGNED: {
BigNum type(length, precision, 0, 0);
type.decode(source, target);
break;
}
case REC_IEEE_FLOAT32: {
//
// Encoded float (IEEE 754 - 1985 standard):
//
// +-+--------+-----------------------+
// | |Exponent| Mantissa |
// | |(8 bits)| (23 bits) |
// +-+--------+-----------------------+
// || |
// |+- Complemented if sign was neg.-+
// |
// +- Sign bit complement
//
// unencoded float (IEEE 754 - 1985 standard):
//
// +-+----------+---------------------+
// | | exponent | mantissa |
// | | (8 bits) | (23 bits) |
// +-+----------+---------------------+
// |
// +- Sign bit
//
// the following code is independent of the "endianess" of the
// archtiecture. Instead, it assumes IEEE 754 - 1985 standard
// for representation of floats
if (source[0] & 0200)
{
// sign bit is on. Indicates this was a positive number.
// Copy to target and clear the sign bit.
if (target != source)
str_cpy_all(target, source, length);
target[0] &= 0177;
}
else
{
// this was a negative number.
// flip all bits.
for (Lng32 i = 0; i < length; i++)
target[i] = ~source[i];
}
// here comes the dependent part
#ifdef NA_LITTLE_ENDIAN
*(ULng32 *) target = reversebytes(*(ULng32 *)target);
#endif
break;
}
case REC_IEEE_FLOAT64: {
//
// Encoded double (IEEE 754 - 1985 standard):
//
// +-+-----------+--------------------+
// | | Exponent | Mantissa |
// | | (11 bits) | (52 bits) |
// +-+-----------+--------------------+
// || |
// |+- Complemented if sign was neg.-+
// |
// +- Sign bit complement
//
// unencoded double (IEEE 754 - 1985 standard):
//
// +-+--------- -+--------------------+
// | | exponent | mantissa |
// | | (11 bits) | (52 bits) |
// +-+--------- -+--------------------+
// |
// +- Sign bit
//
// the following code is independent of the "endianess" of the
// archtiecture. Instead, it assumes IEEE 754 - 1985 standard
// for representation of floats
if (source[0] & 0200)
{
// sign bit is on. Indicates this was a positive number.
// Copy to target and clear the sign bit.
if (target != source)
str_cpy_all(target, source, length);
target[0] &= 0177;
}
else
{
// this was a negative number.
// flip all bits.
for (Lng32 i = 0; i < length; i++)
target[i] = ~source[i];
}
// here comes the dependent part
#ifdef NA_LITTLE_ENDIAN
*(Int64 *) target = reversebytes(*(Int64 *)target);
#endif
break;
}
case REC_BYTE_V_ASCII:
case REC_BYTE_V_ASCII_LONG: {
//
// Copy the source to the target.
//
short vc_len;
// See bug LP 1444134, make this compatible with encoding for
// varchars and remove the VC indicator
assert(attr->getVCIndicatorLength() == sizeof(vc_len));
str_cpy_all((char *) &vc_len, varlen_ptr, attr->getVCIndicatorLength());
if (target != source)
str_cpy_all(target, source, vc_len);
//
// Blankpad the target (if needed).
//
if (vc_len < length)
str_pad(&target[vc_len], (Int32) (length - vc_len), ' ');
//
// Make the length bytes to be the maximum length for this field. This
// will make all encoded varchar keys to have the same length and so the
// comparison will depend on the fixed part of the varchar buffer.
//
vc_len = (short) length;
if (target_varlen_ptr)
str_cpy_all(target_varlen_ptr, (char *) &vc_len, attr->getVCIndicatorLength());
break;
}
case REC_NCHAR_V_UNICODE:
{
//
// Copy the source to the target.
//
// See bug LP 1444134, make this compatible with encoding for
// varchars and remove the VC indicator
short vc_len;
assert(attr->getVCIndicatorLength() == sizeof(vc_len));
str_cpy_all((char *) &vc_len, varlen_ptr, attr->getVCIndicatorLength());
if (target != source)
str_cpy_all(target, source, vc_len);
//
// Blankpad the target (if needed).
//
if (vc_len < length)
wc_str_pad((NAWchar*)&target[attr->getVCIndicatorLength() + vc_len],
(Int32) (length - vc_len)/sizeof(NAWchar), unicode_char_set::space_char());
#if defined( NA_LITTLE_ENDIAN )
wc_swap_bytes((NAWchar*)&target[attr->getVCIndicatorLength()], length/sizeof(NAWchar));
#endif
//
// Make the length bytes to be the maximum length for this field. This
// will make all encoded varchar keys to have the same length and so the
// comparison will depend on the fixed part of the varchar buffer.
//
vc_len = (short) length;
if (target_varlen_ptr)
str_cpy_all(target_varlen_ptr, (char *) &vc_len, attr->getVCIndicatorLength());
break;
}
case REC_NCHAR_F_UNICODE:
{
if (target != source)
str_cpy_all(target, source, length);
#if defined( NA_LITTLE_ENDIAN )
wc_swap_bytes((NAWchar*)target, length/sizeof(NAWchar));
#endif
break;
}
default:
//
// Decoding is not needed. Just copy the source to the target.
//
if (target != source)
str_cpy_all(target, source, length);
break;
}
return 0;
}
static Lng32 convAsciiLength(Attributes * attr)
{
Lng32 d_len = 0;
Int32 scale_len = 0;
Lng32 datatype = attr->getDatatype();
Lng32 length = attr->getLength();
Lng32 precision = attr->getPrecision();
Lng32 scale = attr->getScale();
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_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_NUM_BIG_UNSIGNED:
case REC_NUM_BIG_SIGNED:
d_len = precision + 1 + scale_len; // Precision + sign + decimal point
break;
case REC_BYTE_F_ASCII:
d_len = length;
break;
case REC_NCHAR_F_UNICODE:
case REC_NCHAR_V_UNICODE:
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_FLOAT32:
d_len = SQL_REAL_DISPLAY_SIZE;
break;
case REC_FLOAT64:
d_len = SQL_DOUBLE_PRECISION_DISPLAY_SIZE;
break;
case REC_DATETIME:
switch (precision) {
// add different literals for sqldtcode_date...etc. These literals
// are from sqlcli.h and cannot be included here in this file.
case 1 /*SQLDTCODE_DATE*/:
{
d_len = DATE_DISPLAY_SIZE;
}
break;
case 2 /*SQLDTCODE_TIME*/:
{
d_len = TIME_DISPLAY_SIZE +
(scale > 0 ? (1 + scale) : 0);
}
break;
case 3 /*SQLDTCODE_TIMESTAMP*/:
{
d_len = TIMESTAMP_DISPLAY_SIZE +
(scale > 0 ? (1 + scale) : 0);
}
break;
default:
d_len = length;
break;
}
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: {
rec_datetime_field startField;
rec_datetime_field endField;
ExpInterval::getIntervalStartField(datatype, startField);
ExpInterval::getIntervalEndField(datatype, endField);
// this code is copied from IntervalType::getStringSize in
// w:/common/IntervalType.cpp
d_len = 1 + 1 +
precision +
3/*IntervalFieldStringSize*/ * (endField - startField);
if (scale)
d_len += scale + 1; // 1 for "."
}
break;
default:
d_len = length;
break;
}
return d_len;
}
//helper function, convert a string into IPV4 , if valid, it can support leading and padding space
static Lng32 string2ipv4(char *srcData, Lng32 slen, unsigned int *inet_addr)
{
Int16 i = 0, j = 0 , p=0, leadingspace=0;
char buf[16];
Int16 dot=0;
if(slen < MIN_IPV4_STRING_LEN )
return 0;
unsigned char *ipv4_bytes= (unsigned char *)inet_addr;
if(srcData[0] == ' ')
{
char * next = srcData;
while (*next == ' ')
{
leadingspace++;
next++;
}
}
for(i=leadingspace , j = 0; i < slen ; i++)
{
if(srcData[i] == '.')
{
buf[j]=0;
p = str_atoi(buf, j);
if( p < 0 || p > 255 || j == 0)
{
return 0;
}
else
{
if(ipv4_bytes)
ipv4_bytes[dot] = (unsigned char)p;
}
j = 0;
dot++;
if(dot > 3) return 0;
}
else if(srcData[i] == ' ')
{
break; //space is terminator
}
else
{
if(isdigit(srcData[i]) == 0)
{
return 0;
}
else
buf[j] = srcData[i];
j++;
}
}
Int16 stoppos=i;
// the last part
buf[j]=0; //null terminator
for(i = 0; i < j; i ++) //check for invalid character
{
if(isdigit(buf[i]) == 0)
{
return 0;
}
}
p = str_atoi(buf, j);
if( p < 0 || p > 255 || j == 0) // check for invalid number
{
return 0;
}
else
{
if(ipv4_bytes)
ipv4_bytes[dot] = (unsigned char)p;
}
//if terminated by space
if( stoppos < slen -1)
{
for(j = stoppos ; j < slen; j++)
{
if(srcData[j] != ' ') return 0;
}
}
if(dot != 3)
return 0;
else
return 1;
}
ex_expr::exp_return_type ExFunctionInetAton::eval(char * op_data[],
CollHeap *heap,
ComDiagsArea **diags)
{
char * srcData = op_data[1];
char * resultData = op_data[0];
Attributes *resultAttr = getOperand(0);
Attributes *srcAttr = getOperand(1);
Lng32 slen = srcAttr->getLength(op_data[-MAX_OPERANDS+1]);
Lng32 rlen = resultAttr->getLength();
unsigned int addr;
int ret=string2ipv4(srcData, slen, &addr);
if(ret)
{
*(unsigned int *)op_data[0]=addr;
return ex_expr::EXPR_OK;
}
else
{
ExRaiseSqlError(heap, diags, EXE_INVALID_CHARACTER);
*(*diags) << DgString0("IP format") << DgString1("INET_ATON FUNCTION");
return ex_expr::EXPR_ERROR;
}
}
ex_expr::exp_return_type ExFunctionInetNtoa::eval(char * op_data[],
CollHeap *heap,
ComDiagsArea **diags)
{
char buf[16]; //big enough
unsigned long addr = *(unsigned long*)op_data[1];
char * resultData = op_data[0];
Attributes *resultAttr = getOperand(0);
const unsigned char *ipv4_bytes= (const unsigned char *) &addr;
if( addr > 4294967295 )
{
ExRaiseSqlError(heap, diags, EXE_BAD_ARG_TO_MATH_FUNC);
*(*diags) << DgString0("INET_NTOA");
return ex_expr::EXPR_ERROR;
}
str_sprintf(buf, "%d.%d.%d.%d",
ipv4_bytes[0], ipv4_bytes[1], ipv4_bytes[2], ipv4_bytes[3]);
int slen = str_len(buf);
str_cpy_all(resultData, buf, slen);
getOperand(0)->setVarLength(slen, op_data[-MAX_OPERANDS]);
return ex_expr::EXPR_OK;
}
ex_expr::exp_return_type ExFunctionCrc32::eval(char * op_data[],
CollHeap *heap,
ComDiagsArea **diags)
{
Attributes *resultAttr = getOperand(0);
Attributes *srcAttr = getOperand(1);
Lng32 slen = srcAttr->getLength(op_data[-MAX_OPERANDS+1]);
Lng32 rlen = resultAttr->getLength();
*(ULng32*)op_data[0] = 0;
ULng32 crc = crc32(0L, Z_NULL, 0);
crc = crc32 (crc, (const Bytef*)op_data[1], slen);
*(ULng32*)op_data[0] = crc;
return ex_expr::EXPR_OK;
}
ex_expr::exp_return_type ExFunctionSha2::eval(char * op_data[],
CollHeap *heap,
ComDiagsArea **diags)
{
unsigned char sha[SHA512_DIGEST_LENGTH + 1] = {0};
Attributes *resultAttr = getOperand(0);
Attributes *srcAttr = getOperand(1);
Lng32 slen = srcAttr->getLength(op_data[-MAX_OPERANDS+1]);
// the length of result
Lng32 rlen = SHA512_DIGEST_LENGTH;
switch (mode) {
case 0:
case 256:
SHA256_CTX sha_ctx_256;
if (!SHA256_Init(&sha_ctx_256))
goto sha2_error;
if (!SHA256_Update(&sha_ctx_256, op_data[1], slen))
goto sha2_error;
if (!SHA256_Final((unsigned char *)sha, &sha_ctx_256))
goto sha2_error;
rlen = SHA256_DIGEST_LENGTH;
break;
case 224:
SHA256_CTX sha_ctx_224;
if (!SHA224_Init(&sha_ctx_224))
goto sha2_error;
if (!SHA224_Update(&sha_ctx_224, op_data[1], slen))
goto sha2_error;
if (!SHA224_Final((unsigned char *)sha, &sha_ctx_224))
goto sha2_error;
rlen = SHA224_DIGEST_LENGTH;
break;
case 384:
SHA512_CTX sha_ctx_384;
if (!SHA384_Init(&sha_ctx_384))
goto sha2_error;
if (!SHA384_Update(&sha_ctx_384, op_data[1], slen))
goto sha2_error;
if (!SHA384_Final((unsigned char *)sha, &sha_ctx_384))
goto sha2_error;
rlen = SHA384_DIGEST_LENGTH;
break;
case 512:
SHA512_CTX sha_ctx_512;
if (!SHA512_Init(&sha_ctx_512))
goto sha2_error;
if (!SHA512_Update(&sha_ctx_512, op_data[1], slen))
goto sha2_error;
if (!SHA512_Final((unsigned char *)sha, &sha_ctx_512))
goto sha2_error;
rlen = SHA512_DIGEST_LENGTH;
break;
default:
ExRaiseSqlError(heap, diags, EXE_BAD_ARG_TO_MATH_FUNC);
*(*diags) << DgString0("SHA2");
return ex_expr::EXPR_ERROR;
}
str_pad(op_data[0], rlen, ' ');
char tmp[3];
for(int i=0; i < rlen; i++ )
{
tmp[0]=tmp[1]=tmp[2]='0';
sprintf(tmp, "%.2x", (int)sha[i]);
str_cpy_all(op_data[0]+i*2, tmp, 2);
}
return ex_expr::EXPR_OK;
sha2_error:
ExRaiseFunctionSqlError(heap, diags, EXE_INTERNAL_ERROR,
derivedFunction(),
origFunctionOperType());
return ex_expr::EXPR_ERROR;
}
ex_expr::exp_return_type ExFunctionSha::eval(char * op_data[],
CollHeap *heap,
ComDiagsArea **diags)
{
unsigned char sha[SHA_DIGEST_LENGTH + 1]={0};
Attributes *resultAttr = getOperand(0);
Attributes *srcAttr = getOperand(1);
Lng32 slen = srcAttr->getLength(op_data[-MAX_OPERANDS+1]);
Lng32 rlen = resultAttr->getLength();
str_pad(op_data[0], rlen , ' ');
SHA_CTX sha_ctx;
SHA1_Init(&sha_ctx);
SHA1_Update(&sha_ctx, op_data[1], slen);
SHA1_Final((unsigned char*) sha,&sha_ctx);
char tmp[3];
for(int i=0; i < SHA_DIGEST_LENGTH ; i++ )
{
tmp[0]=tmp[1]=tmp[2]='0';
sprintf(tmp, "%.2x", (int)sha[i]);
str_cpy_all(op_data[0]+i*2, tmp, 2);
}
return ex_expr::EXPR_OK;
}
ex_expr::exp_return_type ExFunctionMd5::eval(char * op_data[],
CollHeap *heap,
ComDiagsArea **diags)
{
unsigned char md5[17]={0};
Attributes *resultAttr = getOperand(0);
Attributes *srcAttr = getOperand(1);
Lng32 slen = srcAttr->getLength(op_data[-MAX_OPERANDS+1]);
Lng32 rlen = resultAttr->getLength();
str_pad(op_data[0], rlen, ' ');
MD5_CTX md5_ctx;
MD5_Init(&md5_ctx);
MD5_Update(&md5_ctx, op_data[1], slen);
MD5_Final((unsigned char*) md5,&md5_ctx);
char tmp[3];
for(int i=0; i < 16; i++ )
{
tmp[0]=tmp[1]=tmp[2]='0';
sprintf(tmp, "%.2x", (int)md5[i]);
str_cpy_all(op_data[0]+i*2, tmp, 2);
}
return ex_expr::EXPR_OK;
}
ex_expr::exp_return_type ExFunctionIsIP::eval(char * op_data[],
CollHeap *heap,
ComDiagsArea **diags)
{
char * resultData = op_data[0];
char * srcData = op_data[1];
Int16 i = 0, j = 0 , p=0;
Attributes *resultAttr = getOperand(0);
Attributes *srcAttr = getOperand(1);
Lng32 slen = srcAttr->getLength(op_data[-MAX_OPERANDS+1]);
Lng32 rlen = resultAttr->getLength();
if(getOperType() == ITM_ISIPV4)
{
if(string2ipv4(srcData, slen, NULL) == 0)
{
*(Int16 *)op_data[0] = 0;
return ex_expr::EXPR_OK;
}
else
{
*(Int16 *)op_data[0] = 1;
return ex_expr::EXPR_OK;
}
}
else
{
Int16 gapcounter = 0 , portidx = 0;;
char portion[IPV6_PARTS_NUM][MAX_IPV6_STRING_LEN + 1];
char trimdata[MAX_IPV6_STRING_LEN + 1];
str_pad(trimdata,MAX_IPV6_STRING_LEN + 1, 0);
if(slen < MIN_IPV6_STRING_LEN )
{
*(Int16 *)op_data[0] = 0;
return ex_expr::EXPR_OK;
}
char *ptr= srcData;
//cannot start with single :
if (*ptr == ':')
{
if (*(ptr+1) != ':')
{
*(Int16 *)op_data[0] = 0;
return ex_expr::EXPR_OK;
}
}
else if (*ptr == ' ')
{
while(*ptr==' ') ptr++;
}
char * start=ptr;
if(slen - (srcData - ptr) > MAX_IPV6_STRING_LEN ) // must be padding space
{
if( start[MAX_IPV6_STRING_LEN] != ' ')
{
*(Int16 *)op_data[0] = 0;
return ex_expr::EXPR_OK;
}
else {
for(j = MAX_IPV6_STRING_LEN; j >=0; j--)
{
if(ptr[j] != ' ') //stop, j is the last non-space char
break;
}
str_cpy_all(trimdata,start, j);
start = trimdata;
}
}
char ipv4[MAX_IPV6_STRING_LEN + 1];
j = 0;
int ipv4idx = 0;
// try to split the string into portions delieted by ':'
// also check '::', call it gap, there is only up to 1 gap
// if there is a gap, portion number can be smaller than 8
// without gap, portion number should be 8
// each portion must be 16 bit integer in HEX format
// leading 0 can be omit
for(i = 0; i< slen; i++)
{
if(start[i] == ':')
{
portion[portidx][j] = 0; //set the terminator
if(start[i+1] == ':')
{
if(j != 0) //some characters are already saved into current portion
portidx++;
gapcounter++;
j = 0; //reset temp buffer pointer
i++;
continue;
}
else
{
//new portion start
if( j == 0 )
{
*(Int16 *)op_data[0] = 0;
return ex_expr::EXPR_OK;
}
portidx++;
j=0;
continue;
}
}
else if( start[i] == '.') //ipv4 mixed format
{
if( ipv4idx > 0 )
{
*(Int16 *)op_data[0] = 0;
return ex_expr::EXPR_OK;
}
str_cpy_all(ipv4, portion[portidx],str_len(portion[portidx]));
if(strlen(start+i) < MAX_IPV4_STRING_LEN) //15 is the maximum IPV4 string length
str_cat((const char*)ipv4, start+i, ipv4);
else
{
*(Int16 *)op_data[0] = 0;
return ex_expr::EXPR_OK;
}
if(string2ipv4(ipv4, strlen(ipv4), NULL) == 0)
{
*(Int16 *)op_data[0] = 0;
return ex_expr::EXPR_OK;
}
else
{
ipv4idx = 2; //ipv4 use 2 portions, 32 bits
break; // ipv4 string must be the last portion
}
}
portion[portidx][j] = start[i];
j++;
}
if(gapcounter > 1 || portidx > IPV6_PARTS_NUM - 1)
{
*(Int16 *)op_data[0] = 0;
return ex_expr::EXPR_OK;
}
else if(gapcounter ==0 && portidx+ipv4idx < IPV6_PARTS_NUM - 1)
{
*(Int16 *)op_data[0] = 0;
return ex_expr::EXPR_OK;
}
//check each IPV6 portion
for(i =0; i < portidx ; i++)
{
int len = strlen(portion[i]);
if( len > 4) //IPV4 portion can be longer than 4 chars
{
if(ipv4idx == 0 || ((ipv4idx == 2) && ( i != portidx -1) ) ) // no IPV4 portion, or this is not the IPV4 portion
{
*(Int16 *)op_data[0] = 0;
return ex_expr::EXPR_OK;
}
}
for(j = 0; j < len; j++)
{
if( (portion[i][j] >= 'A' && portion[i][j] <= 'F') ||
(portion[i][j] >= 'a' && portion[i][j] <= 'f') ||
(portion[i][j] >= '0' && portion[i][j] <= '9')
) //good
continue;
else
{
*(Int16 *)op_data[0] = 0;
return ex_expr::EXPR_OK;
}
}
}
//everything is good, this is IPV6
*(Int16 *)op_data[0] = 1;
return ex_expr::EXPR_OK;
}
}
// Parse json errors
static void ExRaiseJSONError(CollHeap* heap, ComDiagsArea** diagsArea, JsonReturnType type)
{
switch(type)
{
case JSON_INVALID_TOKEN:
ExRaiseSqlError(heap, diagsArea, EXE_JSON_INVALID_TOKEN);
break;
case JSON_INVALID_VALUE:
ExRaiseSqlError(heap, diagsArea, EXE_JSON_INVALID_VALUE);
break;
case JSON_INVALID_STRING:
ExRaiseSqlError(heap, diagsArea, EXE_JSON_INVALID_STRING);
break;
case JSON_INVALID_ARRAY_START:
ExRaiseSqlError(heap, diagsArea, EXE_JSON_INVALID_ARRAY_START);
break;
case JSON_INVALID_ARRAY_NEXT:
ExRaiseSqlError(heap, diagsArea, EXE_JSON_INVALID_ARRAY_NEXT);
break;
case JSON_INVALID_OBJECT_START:
ExRaiseSqlError(heap, diagsArea, EXE_JSON_INVALID_OBJECT_START);
break;
case JSON_INVALID_OBJECT_LABEL:
ExRaiseSqlError(heap, diagsArea, EXE_JSON_INVALID_OBJECT_LABEL);
break;
case JSON_INVALID_OBJECT_NEXT:
ExRaiseSqlError(heap, diagsArea, EXE_JSON_INVALID_OBJECT_NEXT);
break;
case JSON_INVALID_OBJECT_COMMA:
ExRaiseSqlError(heap, diagsArea, EXE_JSON_INVALID_OBJECT_COMMA);
break;
case JSON_INVALID_END:
ExRaiseSqlError(heap, diagsArea, EXE_JSON_INVALID_END);
break;
case JSON_END_PREMATURELY:
ExRaiseSqlError(heap, diagsArea, EXE_JSON_END_PREMATURELY);
break;
default:
ExRaiseSqlError(heap, diagsArea, EXE_JSON_UNEXPECTED_ERROR);
break;
}
}
/*
* SOUNDEX(str) returns a character string containing the phonetic
* representation of the input string. It lets you compare words that
* are spelled differently, but sound alike in English.
* The phonetic representation is defined in "The Art of Computer Programming",
* Volume 3: Sorting and Searching, by Donald E. Knuth, as follows:
*
* 1. Retain the first letter of the string and remove all other occurrences
* of the following letters: a, e, h, i, o, u, w, y.
*
* 2. Assign numbers to the remaining letters (after the first) as follows:
* b, f, p, v = 1
* c, g, j, k, q, s, x, z = 2
* d, t = 3
* l = 4
* m, n = 5
* r = 6
*
* 3. If two or more letters with the same number were adjacent in the original
* name (before step 1), or adjacent except for any intervening h and w, then
* omit all but the first.
*
* 4. Return the first four bytes padded with 0.
* */
ex_expr::exp_return_type ExFunctionSoundex::eval(char *op_data[],
CollHeap *heap,
ComDiagsArea** diagsArea)
{
ULng32 previous = 0;
ULng32 current = 0;
char *srcStr = op_data[1];
char *tgtStr = op_data[0];
Lng32 srcLen = getOperand(1)->getLength(op_data[-MAX_OPERANDS+1]);
Lng32 tgtLen = getOperand(0)->getLength();
CharInfo::CharSet cs = ((SimpleType *)getOperand(1))->getCharSet();
str_pad(tgtStr, tgtLen, '\0');
tgtStr[0] = toupper(srcStr[0]); // Retain the first letter, convert to capital anyway
Int16 setLen = 1; // The first character is set already
for(int i=1; i < srcLen; ++i)
{
char chr = toupper(srcStr[i]);
switch(chr)
{
case 'A':
case 'E':
case 'H':
case 'I':
case 'O':
case 'U':
case 'W':
case 'Y':
current = 0;
break;
case 'B':
case 'F':
case 'P':
case 'V':
current = 1;
break;
case 'C':
case 'G':
case 'J':
case 'K':
case 'Q':
case 'S':
case 'X':
case 'Z':
current = 2;
break;
case 'D':
case 'T':
current = 3;
break;
case 'L':
current = 4;
break;
case 'M':
case 'N':
current = 5;
break;
case 'R':
current = 6;
break;
default:
break;
}
if(current) // Only non-zero valued letter shall ve retained, 0 will be discarded
{
if(previous != current)
{
str_itoa(current, &tgtStr[setLen]);
setLen++; // A new character is set in target
}
}
previous = current;
if(setLen == tgtLen) // Don't overhit the target string
break;
} // end of for loop
if(setLen < tgtLen)
str_pad(tgtStr+setLen, (tgtLen - setLen), '0');
return ex_expr::EXPR_OK;
}
ex_expr::exp_return_type ExFunctionAESEncrypt::eval(char * op_data[],
CollHeap *heap,
ComDiagsArea **diagsArea)
{
CharInfo::CharSet cs = ((SimpleType *)getOperand(0))->getCharSet();
Attributes *tgt = getOperand(0);
Lng32 source_len = getOperand(1)->getLength(op_data[-MAX_OPERANDS + 1]);
char * source = op_data[1];
Lng32 key_len = getOperand(2)->getLength(op_data[-MAX_OPERANDS + 2]);
unsigned char * key = (unsigned char *)op_data[2];
unsigned char * result = (unsigned char *)op_data[0];
unsigned char rkey[EVP_MAX_KEY_LENGTH];
int u_len, f_len;
EVP_CIPHER_CTX ctx;
const EVP_CIPHER * cipher = aes_algorithm_type[aes_mode];
int iv_len_need = EVP_CIPHER_iv_length(cipher);
unsigned char * iv = NULL;
if (iv_len_need) {
if (args_num == 3) {
Lng32 iv_len_input = getOperand(3)->getLength(op_data[-MAX_OPERANDS + 3]);
if (iv_len_input == 0 || iv_len_input < iv_len_need) {
// the length of iv is too short
ExRaiseSqlError(heap, diagsArea, EXE_AES_INVALID_IV);
*(*diagsArea) << DgInt0(iv_len_input) << DgInt1(iv_len_need);
return ex_expr::EXPR_ERROR;
}
iv = (unsigned char *)op_data[3];
}
else {
// it does not have iv argument, but the algorithm need iv
ExRaiseSqlError(heap, diagsArea,EXE_ERR_PARAMCOUNT_FOR_FUNC);
*(*diagsArea) << DgString0("AES_ENCRYPT");
return ex_expr::EXPR_ERROR;
}
}
else {
if (args_num == 3) {
// the algorithm doesn't need iv, give a warning
ExRaiseSqlWarning(heap, diagsArea, EXE_OPTION_IGNORED);
*(*diagsArea) << DgString0("IV");
}
}
aes_create_key(key, key_len, rkey, aes_mode);
if (!EVP_EncryptInit(&ctx, cipher, (const unsigned char*)rkey, iv))
goto aes_encrypt_error;
if (!EVP_CIPHER_CTX_set_padding(&ctx, true))
goto aes_encrypt_error;
if (!EVP_EncryptUpdate(&ctx, result, &u_len, (const unsigned char *)source, source_len))
goto aes_encrypt_error;
if (!EVP_EncryptFinal(&ctx, result + u_len, &f_len))
goto aes_encrypt_error;
EVP_CIPHER_CTX_cleanup(&ctx);
tgt->setVarLength(u_len + f_len, op_data[-MAX_OPERANDS]);
return ex_expr::EXPR_OK;
aes_encrypt_error:
ERR_clear_error();
EVP_CIPHER_CTX_cleanup(&ctx);
ExRaiseSqlError(heap, diagsArea, EXE_OPENSSL_ERROR);
*(*diagsArea) << DgString0("AES_ENCRYPT FUNCTION");
return ex_expr::EXPR_ERROR;
}
ex_expr::exp_return_type ExFunctionAESDecrypt::eval(char * op_data[],
CollHeap *heap,
ComDiagsArea **diagsArea)
{
Attributes * tgt = getOperand(0);
Lng32 source_len = getOperand(1)->getLength(op_data[-MAX_OPERANDS + 1]);
const unsigned char * source = (unsigned char *)op_data[1];
Lng32 key_len = getOperand(2)->getLength(op_data[-MAX_OPERANDS + 2]);
const unsigned char * key = (unsigned char *)op_data[2];
Lng32 maxLength = getOperand(0)->getLength();
unsigned char * result = (unsigned char *) op_data[0];
unsigned char rkey[EVP_MAX_KEY_LENGTH] = {0};
int u_len, f_len;
EVP_CIPHER_CTX ctx;
const EVP_CIPHER * cipher = aes_algorithm_type[aes_mode];
int iv_len_need = EVP_CIPHER_iv_length(cipher);
unsigned char * iv = NULL;
if (iv_len_need) {
if (args_num == 3) {
Lng32 iv_len_input = getOperand(3)->getLength(op_data[-MAX_OPERANDS + 3]);
if (iv_len_input == 0 || iv_len_input < iv_len_need) {
// the length of iv is too short
ExRaiseSqlError(heap, diagsArea, EXE_AES_INVALID_IV);
*(*diagsArea) << DgInt0(iv_len_input) << DgInt1(iv_len_need);
return ex_expr::EXPR_ERROR;
}
iv = (unsigned char *)op_data[3];
}
else {
// it does not have iv argument, but the algorithm need iv
ExRaiseSqlError(heap, diagsArea, EXE_ERR_PARAMCOUNT_FOR_FUNC);
*(*diagsArea) << DgString0("AES_DECRYPT");
return ex_expr::EXPR_ERROR;
}
}
else {
if (args_num == 3) {
// the algorithm doesn't need iv, give a warning
ExRaiseSqlWarning(heap, diagsArea, EXE_OPTION_IGNORED);
*(*diagsArea) << DgString0("IV");
}
}
aes_create_key(key, key_len, rkey, aes_mode);
if (!EVP_DecryptInit(&ctx, cipher, rkey, iv))
goto aes_decrypt_error;
if (!EVP_CIPHER_CTX_set_padding(&ctx, true))
goto aes_decrypt_error;
if (!EVP_DecryptUpdate(&ctx, result, &u_len, source, source_len))
goto aes_decrypt_error;
if (!EVP_DecryptFinal_ex(&ctx, result + u_len, &f_len))
goto aes_decrypt_error;
EVP_CIPHER_CTX_cleanup(&ctx);
tgt->setVarLength(u_len + f_len, op_data[-MAX_OPERANDS]);
return ex_expr::EXPR_OK;
aes_decrypt_error:
ERR_clear_error();
EVP_CIPHER_CTX_cleanup(&ctx);
ExRaiseSqlError(heap, diagsArea, EXE_OPENSSL_ERROR);
*(*diagsArea) << DgString0("AES_DECRYPT FUNCTION");
return ex_expr::EXPR_ERROR;
}