blob: 686da8ce75c7b8a9f967d2b7d068c718dcbece6d [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 @@@
**********************************************************************/
/*
******************************************************************************
*
* File: LmParameter.cpp
* Description: LmParameter Class
* Created: 08/22/2003
* Language: C++
*
******************************************************************************
*/
#include "LmParameter.h"
#include "wstr.h"
#ifdef LANGMAN
#include "LmAssert.h"
#include "exp_expr.h"
#include "exp_clause_derived.h"
#endif
//////////////////////////////////////////////////////////////////////
// setOut<type>: The following setOut<type> methods set the contents
// of the outAddr attribute to the respective SQL <type>. Note that
// SQL types such as CHAR and DATE are treated as null-terminated
// strings (COM_VANSI_FSDT) from the LM's perspective.
//////////////////////////////////////////////////////////////////////
LmResult LmParameter::setOutSmallInt(void *dataPtr, short a)
{
if (sizeof(a) > outSize_ )
return LM_PARAM_OVERFLOW;
*(short*) ((char*)dataPtr + outDataOffset_) = a;
return LM_OK;
}
LmResult LmParameter::setOutInteger(void *dataPtr, Int32 a)
{
if (sizeof(a) > outSize_)
return LM_PARAM_OVERFLOW;
*(Int32*) ((char*)dataPtr + outDataOffset_) = a;
return LM_OK;
}
LmResult LmParameter::setOutLargeInt(void *dataPtr, Int64 a)
{
if (sizeof(a) > outSize_)
return LM_PARAM_OVERFLOW;
*(Int64*) ((char*)dataPtr + outDataOffset_) = a;
return LM_OK;
}
LmResult LmParameter::setOutReal(void *dataPtr, float a)
{
if (sizeof(a) > outSize_)
return LM_PARAM_OVERFLOW;
*(float*) ((char*)dataPtr + outDataOffset_) = a;
return LM_OK;
}
LmResult LmParameter::setOutFloat(void *dataPtr, double a)
{
if (sizeof(a) > outSize_)
return LM_PARAM_OVERFLOW;
*(double*) ((char*)dataPtr + outDataOffset_) = a;
return LM_OK;
}
LmResult LmParameter::setOutDouble(void *dataPtr, double a)
{
if (sizeof(a) > outSize_)
return LM_PARAM_OVERFLOW;
*(double*) ((char*)dataPtr + outDataOffset_) = a;
return LM_OK;
}
LmResult LmParameter::setOutNumeric(void *dataPtr,
const char *source,
ComBoolean copyBinary,
CollHeap *heap,
ComDiagsArea *diags)
{
LmResult result = LM_OK;
// Note that this file also gets linked as lmcomp library
// which is used in utilities. But this function gets called
// only when this file is linked into UDR server.
#ifdef LANGMAN
if (copyBinary)
{
NABoolean callerWantsDiags = (diags ? TRUE : FALSE);
ex_expr::exp_return_type expRetcode =
convDoIt((char*)source, str_len(source), REC_BYTE_F_ASCII, 0, 0,
((char*)dataPtr + outDataOffset_), (Lng32)outSize_,
fsType_, prec_, scale_,
NULL, 0, heap, &diags, CONV_ASCII_BIGNUM, NULL, 0);
if (expRetcode == ex_expr::EXPR_ERROR)
result = LM_ERR;
// If the caller did not pass in a diags area, but convDoIt
// generated a new one, we need to release the new one.
if (!callerWantsDiags && diags)
diags->decrRefCount();
}
else
{
result = setOutChar(dataPtr, source, str_len(source));
}
#endif
return result;
}
// Copy the return string without null terminator into outAddr_.
LmResult LmParameter::setOutChar(void *dataPtr,
const char *src,
ComUInt32 lengthInBytes)
{
LmResult result = LM_OK;
#ifdef LANGMAN
if (lengthInBytes > outSize_)
{
lengthInBytes = outSize_;
result = LM_PARAM_OVERFLOW;
}
str_cpy_all((char*)dataPtr + outDataOffset(), src, (Lng32)lengthInBytes);
// Copy length into varchar length indicator
switch (outVCLenIndSize())
{
case 0:
break;
case 2:
{
ComUInt16 tempLen = (ComUInt16) lengthInBytes;
memcpy((char*)dataPtr + outVCLenIndOffset(), &tempLen, sizeof(short));
break;
}
case 4:
memcpy((char*)dataPtr + outVCLenIndOffset(), &lengthInBytes,
sizeof(Int32));
break;
default:
LM_ASSERT1(0, "Unknown varchar indicator length.");
break;
}
// Blank-pad FIXED char types.
if (DFS2REC::isSQLFixedChar(fsType()))
{
if (outSize_ > lengthInBytes)
{
switch (encodingCharSet_)
{
case CharInfo::ISO88591 :
case CharInfo::SJIS :
case CharInfo::UTF8 :
str_pad((char*)dataPtr + outDataOffset_ + lengthInBytes,
(Lng32)(outSize_ - lengthInBytes),
' ');
break;
case CharInfo::UNICODE :
wc_str_pad((NAWchar*)((char*)dataPtr + outDataOffset_ +
lengthInBytes),
(Lng32)(outSize_ - lengthInBytes)/2,
unicode_char_set::space_char());
break;
default :
char msg[256];
sprintf(msg, "Unknown Character set value: %d", encodingCharSet_);
LM_ASSERT1(0, msg);
break;
}
}
}
#endif
return result;
}
LmResult LmParameter::setOutDecimal(void *dataPtr,
const char *source,
CollHeap *heap,
ComDiagsArea *diags)
{
LmResult result = LM_OK;
// Note that this file also gets linked as lmcomp library
// which is used in utilities. But this function gets called
// only when this file is linked into UDR server.
#ifdef LANGMAN
NABoolean callerWantsDiags = (diags ? TRUE : FALSE);
ex_expr::exp_return_type expRetcode =
convDoIt((char*)source, str_len(source), REC_BYTE_F_ASCII, 0, 0,
(char*)dataPtr + outDataOffset() , (Lng32)outSize_, fsType_, prec_,
scale_, NULL, 0, heap, &diags, CONV_ASCII_DEC, NULL, 0);
if (expRetcode == ex_expr::EXPR_ERROR)
result = LM_ERR;
// If the caller did not pass in a diags area, but convDoIt
// generated a new one, we need to release the new one.
if (!callerWantsDiags && diags)
diags->decrRefCount();
#endif
return result;
}
LmResult LmParameter::setOutDate(void *dataPtr, const char *a)
{
return setOutChar(dataPtr, a, str_len(a));
}
LmResult LmParameter::setOutTime(void *dataPtr, const char *val)
{
ComUInt32 valLen = str_len(val);
LmResult result = setOutChar(dataPtr, val, valLen);
if (result != LM_OK)
return result;
// JDBC's Time format is always hh:mm:ss. We need to pad
// .msssss to this format if needed.
// If the target type is Time(0), no padding is needed.
if (outSize_ > valLen)
*((char*)dataPtr + outDataOffset() + valLen) = '.';
for (ComUInt32 index=valLen+1; index<outSize_; index++)
*((char*)dataPtr + outDataOffset() + index) = '0';
return LM_OK;
}
LmResult LmParameter::setOutTimestamp(void *dataPtr, const char *a)
{
// JDBC's Timestamp format is always yyyy-mm-dd hh:mm:ss.fffffffff
// We need to truncate or pad .fffffffff if needed.
// Target Type Action
// +++++++++++ ++++++
// Timestamp(0) Truncate .fffffffff (JDBC returns ".0". We
// raise warning if .fffffffff is not .0)
// Timestamp(n) Pad value if there are fewer than 'n' digits
// after "."
// Timestamp(n) Trucate value(raise warning) if there are more than
// 'n' digits after "." (This is possible becuase
// JDBC precision is greater than SQL precision)
ComUInt32 valLen = str_len(a);
if (valLen > outSize_)
{
// value needs to be truncated.
if (a[valLen-2] == '.' && a[valLen-1] == '0')
{
// The value ends with ".0" No need for warning
return setOutChar(dataPtr, a, valLen-2);
}
else
{
// The returned value does not fit, raise warning
return setOutChar(dataPtr, a, valLen);
}
}
else
{
LmResult result = setOutChar(dataPtr, a, valLen);
if (result != LM_OK)
return result;
// If value needs padding, pad with character '0'.
for (ComUInt32 index=valLen; index<outSize_; index++)
*((char*)dataPtr + outDataOffset() + index) = '0';
return LM_OK;
}
}
LmResult LmParameter::setOutInterval(void *dataPtr,
const char *rawBytes,
ComUInt32 len)
{
LmResult result = LM_OK;
if (len > outSize_)
{
len = outSize_;
result = LM_PARAM_OVERFLOW;
}
Lng32 numOfBlanks = (Lng32) (outSize_ - len);
char *temp = (char*)dataPtr + outDataOffset();
for (Lng32 i = 0; i < numOfBlanks; i++)
{
*temp = ' ';
temp++;
}
str_cpy_all(temp, rawBytes, (Lng32)len);
return result;
}
// This private method should not be called for NOT NULL
// parameters. indOffset is expected to be >= 0.
ComBoolean LmParameter::isNullValue(char *dataRow, ComUInt32 indOffset) const
{
#ifdef LANGMAN
if (((char*)dataRow)[indOffset] & NEG_BIT_MASK)
return TRUE;
#endif
return FALSE;
}
// This private method should not be called for NOT NULL
// parameters. indOffset is expected to be >= 0 and indSize is
// expected to be > 0.
void LmParameter::setNullValue(char *dataRow,
ComUInt32 indOffset, ComUInt32 indSize,
ComBoolean valueIsNull) const
{
#ifdef LANGMAN
str_pad(dataRow + indOffset, indSize, (valueIsNull ? '\377' : '\0'));
#endif
}
ComUInt32
LmParameter::actualInDataSize(void *data) const
{
if (inVCLenIndSize_ == 0)
return inSize();
else
return vcDataSize((char*)data, inVCLenIndOffset_, inVCLenIndSize_);
}
ComUInt32
LmParameter::actualOutDataSize(void *data) const
{
if (outVCLenIndSize_ == 0)
return outSize();
else
return vcDataSize((char*)data, outVCLenIndOffset_, outVCLenIndSize_);
}
ComUInt32
LmParameter::vcDataSize(char *data,
ComSInt32 lenIndOffset,
ComSInt16 lenIndSize) const
{
ComUInt32 len = 0;
#ifdef LANGMAN
switch (lenIndSize)
{
case 0:
break;
case 2: short templen;
memcpy(&templen, data + lenIndOffset, sizeof(short));
len = (ComUInt32) templen;
break;
case 4: memcpy(&len, data + lenIndOffset, sizeof(Int32));
break;
default :
LM_ASSERT1(0, "Unknown varchar indicator length.");
}
#endif
return len;
}
void LmParameter::setParamName(const char *name)
{
if (paramName_)
{
free(paramName_);
paramName_ = NULL;
}
if (name)
{
ComUInt32 len = strlen(name);
paramName_ = (char *) malloc(len + 1);
memcpy(paramName_, name, len + 1);
}
}