mariadb/storage/connect/value.cpp
Alexander Barkov 4f9e09efb4 Fixing ODBC related compilation failures:
- without ODBC: adding a few "#ifdef CONNECT_SUPPORT"
- with ODBC on Linux: conflicting definitions for DWORD
  in sql.h (unixODBC) vs global.h.
  Using "typedef unsigned int DWORD", as this is how MS SQK defines it
  and matches unixODBC definition.

Removing sqlutil.h. value.cpp now uses sql.h and sqlext.h instead.


removed:
  storage/connect/sqlutil.h
modified:
  storage/connect/global.h
  storage/connect/value.cpp
  storage/connect/value.h
2013-01-28 13:42:14 +04:00

4924 lines
159 KiB
C++
Raw Blame History

/************* Value C++ Functions Source Code File (.CPP) *************/
/* Name: VALUE.CPP Version 2.0 */
/* */
/* (C) Copyright to the author Olivier BERTRAND 2001-2013 */
/* */
/* This file contains the VALUE and derived classes family functions. */
/* These classes contain values of different types. They are used so */
/* new object types can be defined and added to the processing simply */
/* (hopefully) adding their specific functions in this file. */
/* First family is VALUE that represent single typed objects. It is */
/* used by columns (COLBLK), SELECT and FILTER (derived) objects. */
/* Second family is VALBLK, representing simple suballocated arrays */
/* of values treated sequentially by FIX, BIN and VCT tables and */
/* columns, as well for min/max blocks as for VCT column blocks. */
/* Q&A: why not using only one family ? Simple values are arrays that */
/* have only one element and arrays could have functions for all kind */
/* of processing. The answer is a-because historically it was simpler */
/* to do that way, b-because of performance on single values, and c- */
/* to avoid too complicated classes and unuseful duplication of many */
/* functions used on one family only. The drawback is that for new */
/* types of objects, we shall have more classes to update. */
/* Currently the only implemented types are STRING, int, DOUBLE and */
/* DATE. Shortly we should add at least int VARCHAR and LONGLONG. */
/***********************************************************************/
#ifndef __VALUE_H
#define __VALUE_H
/***********************************************************************/
/* Include relevant MariaDB header file. */
/***********************************************************************/
#include "my_global.h"
#if defined(WIN32)
//#include <windows.h>
#else // !WIN32
#include <string.h>
#endif // !WIN32
#include <math.h>
#ifdef ODBC_SUPPORT
#include <sql.h>
#include <sqlext.h>
#endif
#undef DOMAIN // Was defined in math.h
/***********************************************************************/
/* Include required application header files */
/* global.h is header containing all global Plug declarations. */
/* plgdbsem.h is header containing the DB applic. declarations. */
/***********************************************************************/
#include "global.h"
#include "plgdbsem.h"
#include "preparse.h" // For DATPAR
//#include "value.h"
#include "valblk.h"
#define NO_FUNC // Already defined in ODBConn
#include "plgcnx.h" // For DB types
/***********************************************************************/
/* Check macro's. */
/***********************************************************************/
#if defined(_DEBUG)
#define CheckType(V) if (Type != V->GetType()) { \
PGLOBAL& g = Global; \
strcpy(g->Message, MSG(VALTYPE_NOMATCH)); \
longjmp(g->jumper[g->jump_level], Type); }
#else
#define CheckType(V)
#endif
#define FOURYEARS 126230400 // Four years in seconds (1 leap)
/***********************************************************************/
/* Static variables. */
/***********************************************************************/
static char *list =
" ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789/.*-<2D>abcdefghijklmnopqrstuv"; //wxyz<79>'
//" ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyz.";
extern "C" int trace;
/***********************************************************************/
/* Initialize the DTVAL static member. */
/***********************************************************************/
int DTVAL::Shift = 0;
/***********************************************************************/
/* Routines called externally. */
/***********************************************************************/
bool PlugEvalLike(PGLOBAL, LPCSTR, LPCSTR, bool);
#if !defined(WIN32)
extern "C" {
PSZ strupr(PSZ s);
PSZ strlwr(PSZ s);
}
#endif // !WIN32
/***********************************************************************/
/* Returns the bitmap representing the conditions that must not be */
/* met when returning from TestValue for a given operator. */
/* Bit one is EQ, bit 2 is LT, and bit 3 is GT. */
/***********************************************************************/
BYTE OpBmp(PGLOBAL g, OPVAL opc)
{
BYTE bt;
switch (opc) {
case OP_IN:
case OP_EQ: bt = 0x06; break;
case OP_NE: bt = 0x01; break;
case OP_GT: bt = 0x03; break;
case OP_GE: bt = 0x02; break;
case OP_LT: bt = 0x05; break;
case OP_LE: bt = 0x04; break;
case OP_EXIST: bt = 0x00; break;
default:
sprintf(g->Message, MSG(BAD_FILTER_OP), opc);
longjmp(g->jumper[g->jump_level], 777);
} // endswitch opc
return bt;
} // end of OpBmp
/***********************************************************************/
/* GetTypeName: returns the PlugDB internal type name. */
/***********************************************************************/
PSZ GetTypeName(int type)
{
PSZ name = "UNKNOWN";
switch (type) {
case TYPE_STRING: name = "CHAR"; break;
case TYPE_SHORT: name = "SMALLINT"; break;
case TYPE_INT: name = "INTEGER"; break;
case TYPE_BIGINT: name = "BIGINT"; break;
case TYPE_DATE: name = "DATE"; break;
case TYPE_FLOAT: name = "FLOAT"; break;
} // endswitch type
return name;
} // end of GetTypeName
/***********************************************************************/
/* GetTypeSize: returns the PlugDB internal type size. */
/***********************************************************************/
int GetTypeSize(int type, int len)
{
switch (type) {
case TYPE_STRING: len = len * sizeof(char); break;
case TYPE_SHORT: len = sizeof(short); break;
case TYPE_INT: len = sizeof(int); break;
case TYPE_BIGINT: len = sizeof(longlong); break;
case TYPE_DATE: len = sizeof(int); break;
case TYPE_FLOAT: len = sizeof(double); break;
break;
default: len = 0;
} // endswitch type
return len;
} // end of GetTypeSize
/***********************************************************************/
/* GetPLGType: returns the PlugDB type corresponding to a DB type. */
/***********************************************************************/
int GetPLGType(int type)
{
int tp;
switch (type) {
case DB_CHAR:
case DB_STRING: tp = TYPE_STRING; break;
case DB_SHORT: tp = TYPE_SHORT; break;
case DB_INT: tp = TYPE_INT; break;
case DB_DOUBLE: tp = TYPE_FLOAT; break;
case DB_DATE: tp = TYPE_DATE; break;
default: tp = TYPE_ERROR;
} // endswitch type
return tp;
} // end of GetPLGType
/***********************************************************************/
/* GetDBType: returns the DB type corresponding to a PlugDB type. */
/***********************************************************************/
int GetDBType(int type)
{
int tp;
switch (type) {
case TYPE_STRING: tp = DB_CHAR; break;
case TYPE_SHORT: tp = DB_SHORT; break;
case TYPE_INT: tp = DB_INT; break;
case TYPE_BIGINT:
case TYPE_FLOAT: tp = DB_DOUBLE; break;
case TYPE_DATE: tp = DB_DATE; break;
default: tp = DB_ERROR;
} // endswitch type
return tp;
} // end of GetPLGType
#if ODBC_SUPPORT
/***********************************************************************/
/* GetSQLType: returns the SQL_TYPE corresponding to a PLG type. */
/***********************************************************************/
short GetSQLType(int type)
{
short tp = SQL_TYPE_NULL;
switch (type) {
case TYPE_STRING: tp = SQL_CHAR; break;
case TYPE_SHORT: tp = SQL_SMALLINT; break;
case TYPE_INT: tp = SQL_INTEGER; break;
case TYPE_DATE: tp = SQL_TIMESTAMP; break;
case TYPE_BIGINT: tp = SQL_BIGINT; break; // (-5)
case TYPE_FLOAT: tp = SQL_DOUBLE; break;
} // endswitch type
return tp;
} // end of GetSQLType
/***********************************************************************/
/* GetSQLCType: returns the SQL_C_TYPE corresponding to a PLG type. */
/***********************************************************************/
int GetSQLCType(int type)
{
int tp = SQL_TYPE_NULL;
switch (type) {
case TYPE_STRING: tp = SQL_C_CHAR; break;
case TYPE_SHORT: tp = SQL_C_SHORT; break;
case TYPE_INT: tp = SQL_C_LONG; break;
case TYPE_DATE: tp = SQL_C_TIMESTAMP; break;
case TYPE_BIGINT: tp = SQL_C_SBIGINT; break;
case TYPE_FLOAT: tp = SQL_C_DOUBLE; break;
} // endswitch type
return tp;
} // end of GetSQLCType
#endif /* ODBC_SUPPORT */
/***********************************************************************/
/* GetFormatType: returns the FORMAT character(s) according to type. */
/***********************************************************************/
char *GetFormatType(int type)
{
char *c = "X";
switch (type) {
case TYPE_STRING: c = "C"; break;
case TYPE_SHORT: c = "S"; break;
case TYPE_INT: c = "N"; break;
case TYPE_BIGINT: c = "L"; break;
case TYPE_FLOAT: c = "F"; break;
case TYPE_DATE: c = "D"; break;
} // endswitch type
return c;
} // end of GetFormatType
/***********************************************************************/
/* GetFormatType: returns the FORMAT type according to character. */
/***********************************************************************/
int GetFormatType(char c)
{
int type = TYPE_ERROR;
switch (c) {
case 'C': type = TYPE_STRING; break;
case 'S': type = TYPE_SHORT; break;
case 'N': type = TYPE_INT; break;
case 'L': type = TYPE_BIGINT; break;
case 'F': type = TYPE_FLOAT; break;
case 'D': type = TYPE_DATE; break;
} // endswitch type
return type;
} // end of GetFormatType
#ifdef ODBC_SUPPORT
/***********************************************************************/
/* TranslateSQLType: translate a SQL Type to a PLG type. */
/***********************************************************************/
int TranslateSQLType(int stp, int prec, int& len)
{
int type;
switch (stp) {
case SQL_CHAR: // 1
case SQL_VARCHAR: // 12
type = TYPE_STRING;
break;
case SQL_LONGVARCHAR: // (-1)
type = TYPE_STRING;
len = min(abs(len), 255);
break;
case SQL_NUMERIC: // 2
case SQL_DECIMAL: // 3
type = (prec) ? TYPE_FLOAT
: (len > 10) ? TYPE_BIGINT : TYPE_INT;
break;
case SQL_INTEGER: // 4
type = TYPE_INT;
break;
case SQL_SMALLINT: // 5
case SQL_TINYINT: // (-6)
case SQL_BIT: // (-7)
type = TYPE_SHORT;
break;
case SQL_FLOAT: // 6
case SQL_REAL: // 7
case SQL_DOUBLE: // 8
type = TYPE_FLOAT;
break;
case SQL_DATETIME: // 9
// case SQL_DATE: // 9
type = TYPE_DATE;
len = 10;
break;
case SQL_INTERVAL: // 10
// case SQL_TIME: // 10
type = TYPE_STRING;
len = 8 + ((prec) ? (prec+1) : 0);
break;
case SQL_TIMESTAMP: // 11
type = TYPE_DATE;
len = 19 + ((prec) ? (prec+1) : 0);
break;
case SQL_BIGINT: // (-5)
type = TYPE_BIGINT;
break;
case SQL_UNKNOWN_TYPE: // 0
case SQL_BINARY: // (-2)
case SQL_VARBINARY: // (-3)
case SQL_LONGVARBINARY: // (-4)
// case SQL_BIT: // (-7)
case SQL_GUID: // (-11)
default:
type = TYPE_ERROR;
len = 0;
} // endswitch type
return type;
} // end of TranslateSQLType
#endif ODBC_SUPPORT
/***********************************************************************/
/* IsTypeChar: returns true for character type(s). */
/***********************************************************************/
bool IsTypeChar(int type)
{
switch (type) {
case TYPE_STRING:
return true;
} // endswitch type
return false;
} // end of IsTypeChar
/***********************************************************************/
/* IsTypeNum: returns true for numeric types. */
/***********************************************************************/
bool IsTypeNum(int type)
{
switch (type) {
case TYPE_INT:
case TYPE_BIGINT:
case TYPE_DATE:
case TYPE_FLOAT:
case TYPE_SHORT:
case TYPE_NUM:
return true;
} // endswitch type
return false;
} // end of IsTypeNum
/***********************************************************************/
/* ConvertType: what this function does is to determine the type to */
/* which should be converted a value so no precision would be lost. */
/* This can be a numeric type if num is true or non numeric if false. */
/* Note: this is an ultra simplified version of this function that */
/* should become more and more complex as new types are added. */
/* Not evaluated types (TYPE_VOID or TYPE_UNDEF) return false from */
/* IsType... functions so match does not prevent correct setting. */
/***********************************************************************/
int ConvertType(int target, int type, CONV kind, bool match)
{
switch (kind) {
case CNV_CHAR:
if (match && (!IsTypeChar(target) || !IsTypeChar(type)))
return TYPE_ERROR;
return TYPE_STRING;
case CNV_NUM:
if (match && (!IsTypeNum(target) || !IsTypeNum(type)))
return TYPE_ERROR;
return (target == TYPE_FLOAT || type == TYPE_FLOAT) ? TYPE_FLOAT
: (target == TYPE_DATE || type == TYPE_DATE) ? TYPE_DATE
: (target == TYPE_BIGINT || type == TYPE_BIGINT) ? TYPE_BIGINT
: (target == TYPE_INT || type == TYPE_INT) ? TYPE_INT
: TYPE_SHORT;
default:
if (!target || target == type)
return type;
if (match && ((IsTypeChar(target) && !IsTypeChar(type)) ||
(IsTypeNum(target) && !IsTypeNum(type))))
return TYPE_ERROR;
return (target == TYPE_FLOAT || type == TYPE_FLOAT) ? TYPE_FLOAT
: (target == TYPE_DATE || type == TYPE_DATE) ? TYPE_DATE
: (target == TYPE_BIGINT || type == TYPE_BIGINT) ? TYPE_BIGINT
: (target == TYPE_INT || type == TYPE_INT) ? TYPE_INT
: (target == TYPE_SHORT || type == TYPE_SHORT) ? TYPE_SHORT
: (target == TYPE_STRING || type == TYPE_STRING) ? TYPE_STRING
: TYPE_ERROR;
} // endswitch kind
} // end of ConvertType
/***********************************************************************/
/* AllocateConstant: allocates a constant Value. */
/***********************************************************************/
PVAL AllocateValue(PGLOBAL g, void *value, short type)
{
PVAL valp;
if (trace)
htrc("AllocateConstant: value=%p type=%hd\n", value, type);
switch (type) {
case TYPE_STRING: valp = new(g) STRING((PSZ)value); break;
case TYPE_SHORT: valp = new(g) SHVAL(*(short*)value); break;
case TYPE_INT: valp = new(g) INTVAL(*(int*)value); break;
case TYPE_BIGINT: valp = new(g) BIGVAL(*(longlong*)value); break;
case TYPE_FLOAT: valp = new(g) DFVAL(*(double *)value); break;
default:
sprintf(g->Message, MSG(BAD_VALUE_TYPE), type);
return NULL;
} // endswitch Type
valp->SetGlobal(g);
return valp;
} // end of AllocateValue
/***********************************************************************/
/* Allocate a variable Value according to type, length and precision. */
/***********************************************************************/
PVAL AllocateValue(PGLOBAL g, int type, int len, int prec,
PSZ dom, PCATLG cat)
{
PVAL valp;
switch (type) {
case TYPE_STRING: valp = new(g) STRING(g, (PSZ)NULL, len, prec);
break;
case TYPE_DATE: valp = new(g) DTVAL(g, len, prec, dom); break;
case TYPE_INT: valp = new(g) INTVAL((int)0); break;
case TYPE_BIGINT: valp = new(g) BIGVAL((longlong)0); break;
case TYPE_SHORT: valp = new(g) SHVAL((short)0); break;
case TYPE_FLOAT: valp = new(g) DFVAL(0.0, prec); break;
default:
sprintf(g->Message, MSG(BAD_VALUE_TYPE), type);
return NULL;
} // endswitch type
valp->SetGlobal(g);
return valp;
} // end of AllocateValue
/***********************************************************************/
/* Allocate a constant Value converted to newtype. */
/* Can also be used to copy a Value eventually converted. */
/***********************************************************************/
PVAL AllocateValue(PGLOBAL g, PVAL valp, int newtype)
{
PSZ p, sp;
if (newtype == TYPE_VOID) // Means allocate a value of the same type
newtype = valp->GetType();
switch (newtype) {
case TYPE_STRING:
p = (PSZ)PlugSubAlloc(g, NULL, 1 + valp->GetValLen());
if ((sp = valp->GetCharString(p)) != p)
strcpy (p, sp);
valp = new(g) STRING(g, p, valp->GetValLen(), valp->GetValPrec());
break;
case TYPE_SHORT: valp = new(g) SHVAL(valp->GetShortValue()); break;
case TYPE_INT: valp = new(g) INTVAL(valp->GetIntValue()); break;
case TYPE_BIGINT: valp = new(g) BIGVAL(valp->GetBigintValue()); break;
case TYPE_DATE: valp = new(g) DTVAL(g, valp->GetIntValue()); break;
case TYPE_FLOAT: valp = new(g) DFVAL(valp->GetFloatValue()); break;
default:
sprintf(g->Message, MSG(BAD_VALUE_TYPE), newtype);
return NULL;
} // endswitch type
valp->SetGlobal(g);
return valp;
} // end of AllocateValue
/* -------------------------- Class VALUE ---------------------------- */
/***********************************************************************/
/* ShowTypedValue: send back the value formatted according to parms. */
/* buf: is a pointer to a buffer large enough for big double values. */
/* typ: is the type wanted for the value character representation. */
/* n: is the field length (needed for right justification. */
/* p: is the precision (for float representations). */
/* Note: this fonction is currently not used anymore. */
/***********************************************************************/
char *VALUE::ShowTypedValue(PGLOBAL g, char *buf, int typ, int n, int p)
{
switch (typ) {
case TYPE_STRING:
buf = GetCharString(buf);
break;
case TYPE_INT:
case TYPE_DATE:
buf = GetIntString(buf, n);
break;
case TYPE_FLOAT:
buf = GetFloatString(buf, n, p);
break;
case TYPE_SHORT:
buf = GetShortString(buf, n);
break;
case TYPE_BIGINT:
buf = GetBigintString(buf, n);
break;
default:
// More should be added for additional values.
if (trace)
htrc("Invalid col format type %d\n", typ);
sprintf(g->Message, MSG(BAD_COL_FORMAT), typ);
longjmp(g->jumper[g->jump_level], 31);
} // endswitch Type
return buf;
} // end of ShowTypedValue
/***********************************************************************/
/* Returns a BYTE indicating the comparison between two values. */
/* Bit 1 indicates equality, Bit 2 less than, and Bit3 greater than. */
/* More than 1 bit can be set only in the case of TYPE_LIST. */
/***********************************************************************/
BYTE VALUE::TestValue(PVAL vp)
{
int n = CompareValue(vp);
return (n > 0) ? 0x04 : (n < 0) ? 0x02 : 0x01;
} // end of TestValue
/* -------------------------- Class STRING --------------------------- */
/***********************************************************************/
/* STRING public constructor from a constant string. */
/***********************************************************************/
STRING::STRING(PSZ s) : VALUE(TYPE_STRING)
{
Strp = s;
Len = strlen(s);
Clen = Len;
Ci = false;
} // end of STRING constructor
/***********************************************************************/
/* STRING public constructor from char. */
/***********************************************************************/
STRING::STRING(PGLOBAL g, PSZ s, int n, int c) : VALUE(TYPE_STRING)
{
Len = n;
if (!s) {
Strp = (char *)PlugSubAlloc(g, NULL, Len + 1);
Strp[Len] = '\0';
} else
Strp = s;
Clen = Len;
Ci = (c != 0);
} // end of STRING constructor
/***********************************************************************/
/* STRING public constructor from short. */
/***********************************************************************/
STRING::STRING(PGLOBAL g, short i) : VALUE(TYPE_STRING)
{
Strp = (char *)PlugSubAlloc(g, NULL, 12);
Len = sprintf(Strp, "%hd", i);
Clen = Len;
Ci = false;
} // end of STRING constructor
/***********************************************************************/
/* STRING public constructor from int. */
/***********************************************************************/
STRING::STRING(PGLOBAL g, int n) : VALUE(TYPE_STRING)
{
Strp = (char *)PlugSubAlloc(g, NULL, 12);
Len = sprintf(Strp, "%d", n);
Clen = Len;
Ci = false;
} // end of STRING constructor
/***********************************************************************/
/* STRING public constructor from bigint. */
/***********************************************************************/
STRING::STRING(PGLOBAL g, longlong n) : VALUE(TYPE_STRING)
{
Strp = (char *)PlugSubAlloc(g, NULL, 12);
Len = sprintf(Strp, "%lld", n);
Clen = Len;
Ci = false;
} // end of STRING constructor
/***********************************************************************/
/* STRING public constructor from double. */
/***********************************************************************/
STRING::STRING(PGLOBAL g, double f) : VALUE(TYPE_STRING)
{
Strp = (char *)PlugSubAlloc(g, NULL, 32);
Len = sprintf(Strp, "%lf", f);
Clen = Len;
Ci = false;
} // end of STRING constructor
/***********************************************************************/
/* STRING SetValue: copy the value of another Value object. */
/***********************************************************************/
bool STRING::SetValue_pval(PVAL valp, bool chktype)
{
if (chktype && (valp->GetType() != Type || valp->GetSize() > Len))
return true;
char buf[32];
strncpy(Strp, valp->GetCharString(buf), Len);
return false;
} // end of SetValue_pval
/***********************************************************************/
/* STRING SetValue: fill string with chars extracted from a line. */
/***********************************************************************/
void STRING::SetValue_char(char *p, int n)
{
n = min(n, Len);
strncpy(Strp, p, n);
for (p = Strp + n - 1; (*p == ' ' || *p == '\0') && p >= Strp; p--) ;
*(++p) = '\0';
if (trace)
htrc(" Setting string to: '%s'\n", Strp);
} // end of SetValue_char
/***********************************************************************/
/* STRING SetValue: fill string with another string. */
/***********************************************************************/
void STRING::SetValue_psz(PSZ s)
{
strncpy(Strp, s, Len);
} // end of SetValue_psz
/***********************************************************************/
/* STRING SetValue: fill string with a string extracted from a block. */
/***********************************************************************/
void STRING::SetValue_pvblk(PVBLK blk, int n)
{
strncpy(Strp, blk->GetCharValue(n), Len);
} // end of SetValue_pvblk
/***********************************************************************/
/* STRING SetValue: get the character representation of a short int. */
/***********************************************************************/
void STRING::SetValue(short n)
{
SetValue((int)n);
} // end of SetValue
/***********************************************************************/
/* STRING SetValue: get the character representation of an integer. */
/***********************************************************************/
void STRING::SetValue(int n)
{
char buf[16];
PGLOBAL& g = Global;
int k = sprintf(buf, "%d", n);
if (k > Len) {
sprintf(g->Message, MSG(VALSTR_TOO_LONG), buf, Len);
longjmp(g->jumper[g->jump_level], 138);
} else
SetValue_psz(buf);
} // end of SetValue
/***********************************************************************/
/* STRING SetValue: get the character representation of a big integer.*/
/***********************************************************************/
void STRING::SetValue(longlong n)
{
char buf[24];
PGLOBAL& g = Global;
int k = sprintf(buf, "%lld", n);
if (k > Len) {
sprintf(g->Message, MSG(VALSTR_TOO_LONG), buf, Len);
longjmp(g->jumper[g->jump_level], 138);
} else
SetValue_psz(buf);
} // end of SetValue
/***********************************************************************/
/* STRING SetValue: get the character representation of a double. */
/***********************************************************************/
void STRING::SetValue(double f)
{
char *p, buf[32];
PGLOBAL& g = Global;
int k = sprintf(buf, "%lf", f);
for (p = buf + k - 1; p >= buf; p--)
if (*p == '0') {
*p = 0;
k--;
} else
break;
if (k > Len) {
sprintf(g->Message, MSG(VALSTR_TOO_LONG), buf, Len);
longjmp(g->jumper[g->jump_level], 138);
} else
SetValue_psz(buf);
} // end of SetValue
/***********************************************************************/
/* STRING SetBinValue: fill string with chars extracted from a line. */
/***********************************************************************/
void STRING::SetBinValue(void *p)
{
SetValue_char((char *)p, Len);
} // end of SetBinValue
/***********************************************************************/
/* GetBinValue: fill a buffer with the internal binary value. */
/* This function checks whether the buffer length is enough and */
/* returns true if not. Actual filling occurs only if go is true. */
/* Currently used by WriteColumn of binary files. */
/***********************************************************************/
bool STRING::GetBinValue(void *buf, int buflen, bool go)
{
int len = strlen(Strp);
if (len > buflen)
return true;
else if (go) {
memset(buf, ' ', buflen);
memcpy(buf, Strp, len);
} // endif go
return false;
} // end of GetBinValue
/***********************************************************************/
/* GetBinValue: used by SELECT when called from QUERY and KINDEX. */
/* This is a fast implementation that does not do any checking. */
/***********************************************************************/
void STRING::GetBinValue(void *buf, int buflen)
{
assert(buflen >= (signed)strlen(Strp));
memset(buf, ' ', buflen);
memcpy(buf, Strp, buflen);
} // end of GetBinValue
/***********************************************************************/
/* STRING ShowValue: get string representation of a char value. */
/***********************************************************************/
char *STRING::ShowValue(char *buf, int len)
{
return Strp;
} // end of ShowValue
/***********************************************************************/
/* STRING GetCharString: get string representation of a char value. */
/***********************************************************************/
char *STRING::GetCharString(char *p)
{
return Strp;
} // end of GetCharString
/***********************************************************************/
/* STRING GetShortString: get short representation of a char value. */
/***********************************************************************/
char *STRING::GetShortString(char *p, int n)
{
sprintf(p, "%*hd", n, (short)atoi(Strp));
return p;
} // end of GetShortString
/***********************************************************************/
/* STRING GetIntString: get int representation of a char value. */
/***********************************************************************/
char *STRING::GetIntString(char *p, int n)
{
sprintf(p, "%*d", n, atol(Strp));
return p;
} // end of GetIntString
/***********************************************************************/
/* STRING GetIntString: get big int representation of a char value. */
/***********************************************************************/
char *STRING::GetBigintString(char *p, int n)
{
sprintf(p, "%*lld", n, atol(Strp));
return p;
} // end of GetBigintString
/***********************************************************************/
/* STRING GetFloatString: get double representation of a char value. */
/***********************************************************************/
char *STRING::GetFloatString(char *p, int n, int prec)
{
sprintf(p, "%*.*lf", n, (prec < 0) ? 2 : prec, atof(Strp));
return p;
} // end of GetFloatString
/***********************************************************************/
/* STRING compare value with another Value. */
/***********************************************************************/
bool STRING::IsEqual(PVAL vp, bool chktype)
{
if (this == vp)
return true;
else if (chktype && Type != vp->GetType())
return false;
else if (Ci || vp->IsCi())
return !stricmp(Strp, vp->GetCharValue());
else // (!Ci)
return !strcmp(Strp, vp->GetCharValue());
} // end of IsEqual
/***********************************************************************/
/* Compare values and returns 1, 0 or -1 according to comparison. */
/* This function is used for evaluation of character filters. */
/***********************************************************************/
int STRING::CompareValue(PVAL vp)
{
int n;
//assert(vp->GetType() == Type);
if (trace)
htrc(" Comparing: val='%s','%s'\n", Strp, vp->GetCharValue());
// Process filtering on character strings.
if (Ci || vp->IsCi())
n = stricmp(Strp, vp->GetCharValue());
else
n = strcmp(Strp, vp->GetCharValue());
#if defined(WIN32)
if (n == _NLSCMPERROR)
return n; // Here we should raise an error
#endif // WIN32
return (n > 0) ? 1 : (n < 0) ? -1 : 0;
} // end of CompareValue
/***********************************************************************/
/* Returns a BYTE indicating the comparison between two values. */
/* Bit 1 indicates equality, Bit 2 less than, and Bit3 greater than. */
/* More than 1 bit are set only in the case of error. */
/***********************************************************************/
BYTE STRING::TestValue(PVAL vp)
{
// Process filtering on character strings.
bool ci = (Ci || vp->IsCi());
int n = (ci) ? stricmp(Strp, vp->GetCharValue())
: strcmp(Strp, vp->GetCharValue());
#if defined(WIN32)
if (n == _NLSCMPERROR)
return 0x07; // Here we could raise an error
#endif // WIN32
return (n > 0) ? 0x04 : (n < 0) ? 0x02 : 0x01;
} // end of TestValue
/***********************************************************************/
/* Compute a function on a string. */
/***********************************************************************/
bool STRING::Compute(PGLOBAL g, PVAL *vp, int np, OPVAL op)
{
assert(np <= 3);
if (op == OP_SUBST) {
/*******************************************************************/
/* SUBSTR: this functions have 1 STRING parameter followed by */
/* 1 or 2 int parameters. */
/*******************************************************************/
char *p, *s, buf[32];
int i, n, len;
assert(np >= 2);
s = vp[0]->GetCharString(buf);
i = (int)vp[1]->GetIntValue(); // Starting point
n = (np > 2) ? (int)vp[2]->GetIntValue(): 0;
len = strlen(s);
*Strp = '\0';
if (i > len || i < -len || i == 0 || n < 0)
p = NULL;
else if (i > 0)
p = s + i - 1;
else
p = s + len + i;
if (p) {
/******************************************************************/
/* This should not happen if the result size has been set */
/* accurately, and this test could be placed under trace. */
/******************************************************************/
if (((n > 0) ? min(n, (signed)strlen(p)) : (signed)strlen(p)) > Len) {
strcpy(g->Message, MSG(SUB_RES_TOO_LNG));
return true;
} // endif
/******************************************************************/
/* Do the actual Substr operation. */
/******************************************************************/
if (n > 0)
strncat(Strp, p, n);
else
strcpy(Strp, p);
} // endif p
if (trace)
htrc("SUBSTR result=%s val=%s,%d,%d", Strp, s, i, n);
} else if (op == OP_LTRIM || op == OP_RTRIM) {
/*******************************************************************/
/* Trimming functions have one STRING parameter followed by one */
/* CHAR parameter (one chararacter). */
/*******************************************************************/
char *p, buf[32], c = ' ';
PSZ strg;
int len;
assert(np > 0);
strg = vp[0]->GetCharString(buf);
len = strlen(strg);
strg = strcpy(Strp, strg);
if (len > 0) {
if (np > 1) {
// Character value may have been entered as an integer
if (vp[1]->GetType() == TYPE_INT)
c = (char)vp[1]->GetIntValue();
else if (IsTypeChar(vp[1]->GetType()))
c = *vp[1]->GetCharValue();
else {
strcpy(g->Message, MSG(BAD_TRIM_ARGTYP));
return true;
} // endelse
} // endif 2 args
if (op == OP_LTRIM) {
for (p = strg; *p == c; p++) ;
if (p != strg)
do {
*(strg++) = *p;
} while (*(p++)); /* enddo */
} else // OP_RTRIM:
for (p = strg + len - 1; *p == c && p >= strg; p--)
*p = '\0';
} // endif len
} else if (op == OP_LPAD || op == OP_RPAD ||
op == OP_LJUST || op == OP_RJUST || op == OP_CJUST) {
/*******************************************************************/
/* Pad and justify functions have 3 arguments char, NUM and C. */
/*******************************************************************/
PSZ strg;
int i, n1, n2, len;
int n = 0;
char buf[32], c = ' ';
assert(np > 0);
strg = vp[0]->GetCharString(buf);
len = strlen(strg);
strg = strcpy(Strp, strg);
if (np > 1) {
n = vp[1]->GetIntValue();
if (n > Len) {
sprintf(g->Message, MSG(OP_RES_TOO_LONG), op);
return true;
} // endif
if (np > 2) {
// Character value may have been entered as an integer
if (vp[2]->GetType() == TYPE_INT)
c = (char)vp[2]->GetIntValue();
else if (IsTypeChar(vp[2]->GetType()))
c = *vp[2]->GetCharValue();
else {
strcpy(g->Message, MSG(BAD_PAD_ARGTYP));
return true;
} // endelse
} // endif 3 args
} // endif 2 args
if (n == 0)
n = Len;
if ((n = (n - (int)len)) > 0) {
switch (op) {
case OP_RPAD:
case OP_LJUST:
n1 = 0;
n2 = (int)n;
break;
case OP_LPAD:
case OP_RJUST:
n1 = (int)n;
n2 = 0;
break;
case OP_CJUST:
n1 = (int)n / 2;
n2 = (int)n - n1;
break;
default:
sprintf(g->Message, MSG(INVALID_OPER), op, "Compute");
return true;
} // endswitch op
if (n1 > 0) {
for (i = len; i >= 0; i--)
*(strg + i + n1) = *(strg + i);
for (i = 0; i < n1; i++)
*(strg + i) = c;
len += n1;
} // endif n1
if (n2 > 0) {
for (i = len; i < len + n2; i++)
*(strg + i) = c;
*(strg + len + n2) = '\0';
} // endif n2
} // endif n
if (trace)
htrc(" function result=%s\n", strg);
} else if (op == OP_SNDX) {
/*******************************************************************/
/* SOUNDEX function: one string argument. */
/* In addition to Knuth standard algorithm, we accept and ignore */
/* all non alpha characters. */
/*******************************************************************/
static int t[27] =
{0,1,2,3,0,1,2,0,0,2,2,4,5,5,0,1,2,6,2,3,0,1,0,2,0,2,0};
// A B C D E F G H I J K L M N O P Q R S T U V W X Y Z [
char *p, s[65];
int i, n;
bool b = false;
assert(np == 1);
p = vp[0]->GetCharValue();
for (i = 0; i < 64; p++)
if (isalpha(*p)) {
s[i++] = toupper(*p);
b = true;
} else if (!*p)
break;
else
s[i++] = 'Z' + 1;
if (b) {
s[i] = '\0';
Strp[0] = *s;
} else {
strcpy(Strp, " "); // Null string
return false;
} // endif i
for (i = 1, p = s + 1; *p && i < 4; p++)
if ((n = t[*p - 'A'])) {
Strp[i] = '0' + n;
if (!b || Strp[i] != Strp[i - 1]) {
b = true;
i++;
} // endif dup
} else
b = false;
for (; i < 4; i++)
Strp[i] = '0';
// Strp[4] = '\0';
} else {
/*******************************************************************/
/* All other functions have STRING parameter(s). */
/*******************************************************************/
char *p[3], val[3][32];
int i;
for (i = 0; i < np; i++)
p[i] = vp[i]->GetCharString(val[i]);
switch (op) {
case OP_LOWER:
assert(np == 1);
strlwr(strcpy(Strp, p[0]));
break;
case OP_UPPER:
assert(np == 1);
strupr(strcpy(Strp, p[0]));
break;
case OP_CNC:
assert(np == 2);
strncat(strncpy(Strp, p[0], Len), p[1], Len);
break;
case OP_MIN:
assert(np == 2);
strcpy(Strp, (strcmp(p[0], p[1]) < 0) ? p[0] : p[1]);
break;
case OP_MAX:
assert(np == 2);
strcpy(Strp, (strcmp(p[0], p[1]) > 0) ? p[0] : p[1]);
break;
case OP_REPL:
{char *pp;
int i, len;
if (np == 2) {
p[2] = "";
np = 3;
} else
assert(np == 3);
if ((len = strlen(p[1]))) {
*Strp = '\0';
do {
if ((pp = strstr(p[0], p[1]))) {
i = strlen(Strp) + (pp - p[0]) + strlen(p[2]);
if (i > Len) {
if (trace)
htrc(" error len=%d R_Length=%d\n", i, Len);
sprintf(g->Message, MSG(OP_RES_TOO_LONG), op);
return true;
} // endif
strncat(Strp, p[0], pp - p[0]);
strcat(Strp, p[2]);
p[0] = pp + len;
} else
strcat(Strp, p[0]);
} while (pp); // enddo
} else
strcpy(Strp, p[0]);
}break;
case OP_TRANSL:
{unsigned char *p0, *p1, *p2, cp[256];
unsigned int k, n = strlen(p[1]);
assert(np == 3 && n == strlen(p[2]));
p0 = (unsigned char *)p[0];
p1 = (unsigned char *)p[1];
p2 = (unsigned char *)p[2];
for (k = 0; k < 256; k++)
cp[k] = k;
for (k = 0; k < n; k++)
cp[p1[k]] = p2[k];
for (k = 0; k < strlen(p[0]); k++)
Strp[k] = cp[p0[k]];
Strp[k] = 0;
}break;
case OP_FDISK:
case OP_FPATH:
case OP_FNAME:
case OP_FTYPE:
// if (!ExtractFromPath(g, Strp, p[0], op))
// return true;
// break;
default:
sprintf(g->Message, MSG(BAD_EXP_OPER), op);
return true;
} // endswitch op
if (trace) {
htrc("Compute result=%s val=%s", Strp, p[0]);
for (i = 1; i < np; i++)
htrc(",%s", p[i]);
htrc(" op=%d\n", op);
} // endif trace
} // endif op
return false;
} // end of Compute
/***********************************************************************/
/* GetTime: extract the time from a string of format hh:mm:ss */
/***********************************************************************/
int STRING::GetTime(PGLOBAL g, PVAL *vp, int np)
{
int hh, mm, ss;
hh = mm = ss = 0;
sscanf(Strp, " %d : %d : %d", &hh, &mm, &ss);
return ((hh * 3600) + (mm * 60) + ss);
} // end of GetTime
/***********************************************************************/
/* FormatValue: This function set vp (a STRING value) to the string */
/* constructed from its own value formated using the fmt format. */
/* This function assumes that the format matches the value type. */
/***********************************************************************/
bool STRING::FormatValue(PVAL vp, char *fmt)
{
char *buf = (char*)vp->GetTo_Val(); // Should be big enough
int n = sprintf(buf, fmt, Strp);
return (n > vp->GetValLen());
} // end of FormatValue
/***********************************************************************/
/* SetMin: used by the aggregate function MIN. */
/***********************************************************************/
void STRING::SetMin(PVAL vp)
{
char *val = vp->GetCharValue();
assert(strlen(val) <= (unsigned)Len);
if (((Ci) ? stricmp(val, Strp) : strcmp(val, Strp)) < 0)
strcpy(Strp, val);
} // end of SetMin
/***********************************************************************/
/* SetMin: used by QUERY for the aggregate function MIN. */
/***********************************************************************/
void STRING::SetMin(PVBLK vbp, int i)
{
char *val = vbp->GetCharValue(i);
if (((Ci) ? stricmp(val, Strp) : strcmp(val, Strp)) < 0)
strcpy(Strp, val);
} // end of SetMin
/***********************************************************************/
/* SetMin: used by QUERY for the aggregate function MIN. */
/***********************************************************************/
void STRING::SetMin(PVBLK vbp, int j, int k)
{
char *val;
for (register int i = j; i < k; i++) {
val = vbp->GetCharValue(i);
if (((Ci) ? stricmp(val, Strp) : strcmp(val, Strp)) < 0)
strcpy(Strp, val);
} // endfor i
} // end of SetMin
/***********************************************************************/
/* SetMin: used by QUERY for the aggregate function MIN. */
/***********************************************************************/
void STRING::SetMin(PVBLK vbp, int *x, int j, int k)
{
char *val;
for (register int i = j; i < k; i++) {
val = vbp->GetCharValue(x[i]);
if (((Ci) ? stricmp(val, Strp) : strcmp(val, Strp)) < 0)
strcpy(Strp, val);
} // endfor i
} // end of SetMin
/***********************************************************************/
/* SetMax: used by the aggregate function MAX. */
/***********************************************************************/
void STRING::SetMax(PVAL vp)
{
char *val = vp->GetCharValue();
assert(strlen(val) <= (unsigned)Len);
if (((Ci) ? stricmp(val, Strp) : strcmp(val, Strp)) > 0)
strcpy(Strp, val);
} // end of SetMax
/***********************************************************************/
/* SetMin: used by QUERY for the aggregate function MIN. */
/***********************************************************************/
void STRING::SetMax(PVBLK vbp, int i)
{
char *val = vbp->GetCharValue(i);
if (((Ci) ? stricmp(val, Strp) : strcmp(val, Strp)) > 0)
strcpy(Strp, val);
} // end of SetMin
/***********************************************************************/
/* SetMin: used by QUERY for the aggregate function MIN. */
/***********************************************************************/
void STRING::SetMax(PVBLK vbp, int j, int k)
{
char *val;
for (register int i = j; i < k; i++) {
val = vbp->GetCharValue(i);
if (((Ci) ? stricmp(val, Strp) : strcmp(val, Strp)) > 0)
strcpy(Strp, val);
} // endfor i
} // end of SetMin
/***********************************************************************/
/* SetMin: used by QUERY for the aggregate function MIN. */
/***********************************************************************/
void STRING::SetMax(PVBLK vbp, int *x, int j, int k)
{
char *val;
for (register int i = j; i < k; i++) {
val = vbp->GetCharValue(x[i]);
if (((Ci) ? stricmp(val, Strp) : strcmp(val, Strp)) > 0)
strcpy(Strp, val);
} // endfor i
} // end of SetMin
/***********************************************************************/
/* STRING SetFormat function (used to set SELECT output format). */
/***********************************************************************/
bool STRING::SetConstFormat(PGLOBAL g, FORMAT& fmt)
{
fmt.Type[0] = 'C';
fmt.Length = Len;
fmt.Prec = 0;
return false;
} // end of SetConstFormat
/***********************************************************************/
/* Make file output of a STRING object. */
/***********************************************************************/
void STRING::Print(PGLOBAL g, FILE *f, uint n)
{
char m[64];
memset(m, ' ', n); /* Make margin string */
m[n] = '\0';
fprintf(f, "%s%s\n", m, Strp);
} // end of Print
/***********************************************************************/
/* Make string output of a STRING object. */
/***********************************************************************/
void STRING::Print(PGLOBAL g, char *ps, uint z)
{
sprintf(ps, "'%.*s'", z-3, Strp);
} // end of Print
/* -------------------------- Class SHVAL ---------------------------- */
/***********************************************************************/
/* SHVAL public constructor from char. */
/***********************************************************************/
SHVAL::SHVAL(PSZ s) : VALUE(TYPE_SHORT)
{
Sval = atoi(s);
Clen = sizeof(short);
} // end of SHVAL constructor
/***********************************************************************/
/* SHVAL public constructor from short. */
/***********************************************************************/
SHVAL::SHVAL(short i) : VALUE(TYPE_SHORT)
{
Sval = i;
Clen = sizeof(short);
} // end of SHVAL constructor
/***********************************************************************/
/* SHVAL public constructor from int. */
/***********************************************************************/
SHVAL::SHVAL(int n) : VALUE(TYPE_SHORT)
{
Sval = (short)n;
Clen = sizeof(short);
} // end of SHVAL constructor
/***********************************************************************/
/* SHVAL public constructor from big int. */
/***********************************************************************/
SHVAL::SHVAL(longlong n) : VALUE(TYPE_SHORT)
{
Sval = (short)n;
Clen = sizeof(short);
} // end of SHVAL constructor
/***********************************************************************/
/* SHVAL public constructor from double. */
/***********************************************************************/
SHVAL::SHVAL(double f) : VALUE(TYPE_SHORT)
{
Sval = (short)f;
Clen = sizeof(short);
} // end of SHVAL constructor
/***********************************************************************/
/* SHVAL GetValLen: returns the print length of the short object. */
/***********************************************************************/
int SHVAL::GetValLen(void)
{
char c[16];
return sprintf(c, "%hd", Sval);
} // end of GetValLen
/***********************************************************************/
/* SHVAL SetValue: copy the value of another Value object. */
/* This function allows conversion if chktype is false. */
/***********************************************************************/
bool SHVAL::SetValue_pval(PVAL valp, bool chktype)
{
if (chktype && Type != valp->GetType())
return true;
Sval = valp->GetShortValue();
return false;
} // end of SetValue
/***********************************************************************/
/* SHVAL SetValue: convert chars extracted from a line to short value */
/***********************************************************************/
void SHVAL::SetValue_char(char *p, int n)
{
char *p2;
bool minus;
// if (trace) wrong because p can be not null terminated
// htrc("SHVAL_char: p='%s' n=%d\n", p, n);
for (p2 = p + n; p < p2 && *p == ' '; p++) ;
for (Sval = 0, minus = false; p < p2; p++)
switch (*p) {
case '-':
minus = true;
case '+':
break;
case '0': Sval = Sval * 10; break;
case '1': Sval = Sval * 10 + 1; break;
case '2': Sval = Sval * 10 + 2; break;
case '3': Sval = Sval * 10 + 3; break;
case '4': Sval = Sval * 10 + 4; break;
case '5': Sval = Sval * 10 + 5; break;
case '6': Sval = Sval * 10 + 6; break;
case '7': Sval = Sval * 10 + 7; break;
case '8': Sval = Sval * 10 + 8; break;
case '9': Sval = Sval * 10 + 9; break;
default:
p = p2;
} // endswitch *p
if (minus && Sval)
Sval = - Sval;
if (trace)
htrc(" setting short to: %hd\n", Sval);
} // end of SetValue
/***********************************************************************/
/* SHVAL SetValue: fill a short value from a string. */
/***********************************************************************/
void SHVAL::SetValue_psz(PSZ s)
{
Sval = atoi(s);
} // end of SetValue
/***********************************************************************/
/* SHVAL SetValue: set value with a short extracted from a block. */
/***********************************************************************/
void SHVAL::SetValue_pvblk(PVBLK blk, int n)
{
Sval = blk->GetShortValue(n);
} // end of SetValue
/***********************************************************************/
/* SHVAL SetBinValue: with bytes extracted from a line. */
/***********************************************************************/
void SHVAL::SetBinValue(void *p)
{
Sval = *(short *)p;
} // end of SetBinValue
/***********************************************************************/
/* GetBinValue: fill a buffer with the internal binary value. */
/* This function checks whether the buffer length is enough and */
/* returns true if not. Actual filling occurs only if go is true. */
/* Currently used by WriteColumn of binary files. */
/***********************************************************************/
bool SHVAL::GetBinValue(void *buf, int buflen, bool go)
{
// Test on length was removed here until a variable in column give the
// real field length. For BIN files the field length logically cannot
// be different from the variable length because no conversion is done.
// Therefore this test is useless anyway.
//#if defined(_DEBUG)
// if (sizeof(short) > buflen)
// return true;
//#endif
if (go)
*(short *)buf = Sval;
return false;
} // end of GetBinValue
/***********************************************************************/
/* GetBinValue: used by SELECT when called from QUERY and KINDEX. */
/* This is a fast implementation that does not do any checking. */
/***********************************************************************/
void SHVAL::GetBinValue(void *buf, int buflen)
{
assert(buflen == sizeof(short));
*(short *)buf = Sval;
} // end of GetBinValue
/***********************************************************************/
/* SHVAL ShowValue: get string representation of a short value. */
/***********************************************************************/
char *SHVAL::ShowValue(char *buf, int len)
{
sprintf(buf, "%*hd", len, Sval);
return buf;
} // end of ShowValue
/***********************************************************************/
/* SHVAL GetCharString: get string representation of a short value. */
/***********************************************************************/
char *SHVAL::GetCharString(char *p)
{
sprintf(p, "%hd", Sval);
return p;
} // end of GetCharString
/***********************************************************************/
/* SHVAL GetShortString: get short representation of a short value. */
/***********************************************************************/
char *SHVAL::GetShortString(char *p, int n)
{
sprintf(p, "%*hd", n, Sval);
return p;
} // end of GetShortString
/***********************************************************************/
/* SHVAL GetIntString: get int representation of a short value. */
/***********************************************************************/
char *SHVAL::GetIntString(char *p, int n)
{
sprintf(p, "%*d", n, (int)Sval);
return p;
} // end of GetIntString
/***********************************************************************/
/* SHVAL GetBigintString: get big int representation of a short value.*/
/***********************************************************************/
char *SHVAL::GetBigintString(char *p, int n)
{
sprintf(p, "%*lld", n, (longlong)Sval);
return p;
} // end of GetBigintString
/***********************************************************************/
/* SHVAL GetFloatString: get double representation of a short value. */
/***********************************************************************/
char *SHVAL::GetFloatString(char *p, int n, int prec)
{
sprintf(p, "%*.*lf", n, (prec < 0) ? 2 : prec, (double)Sval);
return p;
} // end of GetFloatString
/***********************************************************************/
/* SHVAL compare value with another Value. */
/***********************************************************************/
bool SHVAL::IsEqual(PVAL vp, bool chktype)
{
if (this == vp)
return true;
else if (chktype && Type != vp->GetType())
return false;
else
return (Sval == vp->GetShortValue());
} // end of IsEqual
/***********************************************************************/
/* Compare values and returns 1, 0 or -1 according to comparison. */
/* This function is used for evaluation of short integer filters. */
/***********************************************************************/
int SHVAL::CompareValue(PVAL vp)
{
//assert(vp->GetType() == Type);
// Process filtering on short integers.
short n = vp->GetShortValue();
if (trace > 1)
htrc(" Comparing: val=%hd,%hd\n", Sval, n);
return (Sval > n) ? 1 : (Sval < n) ? (-1) : 0;
} // end of CompareValue
/***********************************************************************/
/* SafeAdd: adds a value and test whether overflow/underflow occured. */
/***********************************************************************/
short SHVAL::SafeAdd(short n1, short n2)
{
PGLOBAL& g = Global;
short n = n1 + n2;
if ((n2 > 0) && (n < n1)) {
// Overflow
strcpy(g->Message, MSG(FIX_OVFLW_ADD));
longjmp(g->jumper[g->jump_level], 138);
} else if ((n2 < 0) && (n > n1)) {
// Underflow
strcpy(g->Message, MSG(FIX_UNFLW_ADD));
longjmp(g->jumper[g->jump_level], 138);
} // endif's n2
return n;
} // end of SafeAdd
/***********************************************************************/
/* SafeMult: multiply values and test whether overflow occured. */
/***********************************************************************/
short SHVAL::SafeMult(short n1, short n2)
{
PGLOBAL& g = Global;
double n = (double)n1 * (double)n2;
if (n > 32767.0) {
// Overflow
strcpy(g->Message, MSG(FIX_OVFLW_TIMES));
longjmp(g->jumper[g->jump_level], 138);
} else if (n < -32768.0) {
// Underflow
strcpy(g->Message, MSG(FIX_UNFLW_TIMES));
longjmp(g->jumper[g->jump_level], 138);
} // endif's n2
return (short)n;
} // end of SafeMult
/***********************************************************************/
/* Compute a function on a int integers. */
/***********************************************************************/
bool SHVAL::Compute(PGLOBAL g, PVAL *vp, int np, OPVAL op)
{
if (op == OP_LEN) {
assert(np == 1);
char buf[32];
char *p = vp[0]->GetCharString(buf);
Sval = strlen(p);
if (trace)
htrc("Compute result=%hd val=%s op=%d\n", Sval, p, op);
} else if (op == OP_INSTR || op == OP_LIKE || op == OP_CNTIN) {
char *p, *tp = g->Message;
char *p1, val1[32];
char *p2, val2[32];
bool b = (vp[0]->IsCi() || vp[1]->IsCi());
assert(np == 2);
p1 = vp[0]->GetCharString(val1);
p2 = vp[1]->GetCharString(val2);
if (op != OP_LIKE) {
if (!strcmp(p2, "\\t"))
p2 = "\t";
if (b) { // Case insensitive
if (strlen(p1) + strlen(p2) + 1 >= MAX_STR &&
!(tp = new char[strlen(p1) + strlen(p2) + 2])) {
strcpy(g->Message, MSG(NEW_RETURN_NULL));
return true;
} // endif p
// Make a lower case copy of p1 and p2
p1 = strlwr(strcpy(tp, p1));
p2 = strlwr(strcpy(tp + strlen(p1) + 1, p2));
} // endif Ci
if (op == OP_CNTIN) {
size_t t2 = strlen(p2);
for (Sval = 0; (p = strstr(p1, p2)); Sval++, p1 = p + t2) ;
} else // OP_INSTR
Sval = (p = strstr(p1, p2)) ? 1 + (short)(p - p1) : 0;
if (tp != g->Message) // If working space was obtained
delete [] tp; // by the use of new, delete it.
} else // OP_LIKE
Sval = (PlugEvalLike(g, p1, p2, b)) ? 1 : 0;
if (trace)
htrc("Compute result=%hd val=%s,%s op=%d\n", Sval, p1, p2, op);
} else {
short val[2];
assert(np <= 2);
for (int i = 0; i < np; i++)
val[i] = vp[i]->GetShortValue();
switch (op) {
case OP_ABS:
assert(np == 1);
Sval = abs(*val);
break;
case OP_SIGN:
assert(np == 1);
Sval = (*val < 0) ? (-1) : 1;
break;
case OP_CEIL:
case OP_FLOOR:
assert(np == 1);
Sval = *val;
break;
case OP_ADD:
assert(np == 2);
Sval = SafeAdd(val[0], val[1]);
break;
case OP_SUB:
assert(np == 2);
Sval = SafeAdd(val[0], -val[1]);
break;
case OP_MULT:
assert(np == 2);
Sval = SafeMult(val[0], val[1]);
break;
case OP_MIN:
assert(np == 2);
Sval = min(val[0], val[1]);
break;
case OP_MAX:
assert(np == 2);
Sval = max(val[0], val[1]);
break;
case OP_DIV:
assert(np == 2);
if (!val[1]) {
strcpy(g->Message, MSG(ZERO_DIVIDE));
return true;
} // endif
Sval = val[0] / val[1];
break;
case OP_MOD:
assert(np == 2);
if (!val[1]) {
strcpy(g->Message, MSG(ZERO_DIVIDE));
return true;
} // endif
Sval = val[0] % val[1];
break;
case OP_BITAND:
assert(np == 2);
Sval = val[0] & val[1];
break;
case OP_BITOR:
assert(np == 2);
Sval = val[0] | val[1];
break;
case OP_BITXOR:
assert(np == 2);
Sval = val[0] ^ val[1];
break;
case OP_BITNOT:
assert(np == 1);
Sval = ~val[0];
break;
case OP_DELTA:
// assert(np == 1);
Sval = val[0] - Sval;
break;
default:
sprintf(g->Message, MSG(BAD_EXP_OPER), op);
return true;
} // endswitch op
if (trace)
if (np = 1)
htrc(" result=%hd val=%hd op=%d\n", Sval, val[0], op);
else
htrc(" result=%hd val=%hd,%hd op=%d\n",
Sval, val[0], val[1], op);
} // endif op
return false;
} // end of Compute
/***********************************************************************/
/* Divide: used by aggregate functions when calculating average. */
/***********************************************************************/
void SHVAL::Divide(int cnt)
{
Sval /= (short)cnt;
} // end of Divide
/***********************************************************************/
/* StdVar: used by aggregate functions for Stddev and Variance. */
/***********************************************************************/
void SHVAL::StdVar(PVAL vp, int cnt, bool b)
{
short lv2 = vp->GetShortValue(), scnt = (short)cnt;
Sval = (scnt == 1) ? 0
: (SafeAdd(lv2, -(SafeMult(Sval, Sval) / scnt)) / (scnt - 1));
if (b) // Builtin == FNC_STDDEV
Sval = (short)sqrt((double)Sval);
} // end of StdVar
/***********************************************************************/
/* Times: used by aggregate functions for Stddev and Variance. */
/***********************************************************************/
void SHVAL::Times(PVAL vp)
{
Sval = SafeMult(Sval, vp->GetShortValue());
} // end of Times
/***********************************************************************/
/* Add: used by aggregate functions for Sum and other functions. */
/***********************************************************************/
void SHVAL::Add(PVAL vp)
{
Sval = SafeAdd(Sval, vp->GetShortValue());
} // end of Add
/***********************************************************************/
/* Add: used by QUERY for function Sum and other functions. */
/***********************************************************************/
void SHVAL::Add(PVBLK vbp, int i)
{
Sval = SafeAdd(Sval, vbp->GetShortValue(i));
} // end of Add
/***********************************************************************/
/* Add: used by QUERY for function Sum and other functions. */
/***********************************************************************/
void SHVAL::Add(PVBLK vbp, int j, int k)
{
CheckType(vbp)
short *lp = (short *)vbp->GetValPointer();
for (register int i = j; i < k; i++)
Sval = SafeAdd(Sval, lp[i]);
} // end of Add
/***********************************************************************/
/* Add: used by QUERY for function Sum and other functions. */
/***********************************************************************/
void SHVAL::Add(PVBLK vbp, int *x, int j, int k)
{
CheckType(vbp)
short *lp = (short *)vbp->GetValPointer();
for (register int i = j; i < k; i++)
Sval = SafeAdd(Sval, lp[x[i]]);
} // end of Add
/***********************************************************************/
/* AddSquare: used by aggregate functions for Stddev and Variance. */
/***********************************************************************/
void SHVAL::AddSquare(PVAL vp)
{
short val = vp->GetShortValue();
Sval = SafeAdd(Sval, SafeMult(val, val));
} // end of AddSquare
/***********************************************************************/
/* AddSquare: used by QUERY for functions Stddev and Variance. */
/***********************************************************************/
void SHVAL::AddSquare(PVBLK vbp, int i)
{
short val = vbp->GetShortValue(i);
Sval = SafeAdd(Sval, SafeMult(val, val));
} // end of AddSquare
/***********************************************************************/
/* AddSquare: used by QUERY for functions Stddev and Variance. */
/***********************************************************************/
void SHVAL::AddSquare(PVBLK vbp, int j, int k)
{
CheckType(vbp)
short *lp = (short *)vbp->GetValPointer();
for (register int i = j; i < k; i++)
Sval = SafeAdd(Sval, SafeMult(lp[i], lp[i]));
} // end of AddSquare
/***********************************************************************/
/* FormatValue: This function set vp (a STRING value) to the string */
/* constructed from its own value formated using the fmt format. */
/* This function assumes that the format matches the value type. */
/***********************************************************************/
bool SHVAL::FormatValue(PVAL vp, char *fmt)
{
char *buf = (char*)vp->GetTo_Val(); // Should be big enough
int n = sprintf(buf, fmt, Sval);
return (n > vp->GetValLen());
} // end of FormatValue
/***********************************************************************/
/* SetMin: used by the aggregate function MIN. */
/***********************************************************************/
void SHVAL::SetMin(PVAL vp)
{
short val = vp->GetShortValue();
if (val < Sval)
Sval = val;
} // end of SetMin
/***********************************************************************/
/* SetMin: used by QUERY for the aggregate function MIN. */
/***********************************************************************/
void SHVAL::SetMin(PVBLK vbp, int i)
{
short val = vbp->GetShortValue(i);
if (val < Sval)
Sval = val;
} // end of SetMin
/***********************************************************************/
/* SetMin: used by QUERY for the aggregate function MIN. */
/***********************************************************************/
void SHVAL::SetMin(PVBLK vbp, int j, int k)
{
CheckType(vbp)
short *lp = (short *)vbp->GetValPointer();
for (register int i = j; i < k; i++)
if (lp[i] < Sval)
Sval = lp[i];
} // end of SetMin
/***********************************************************************/
/* SetMin: used by QUERY for the aggregate function MIN. */
/***********************************************************************/
void SHVAL::SetMin(PVBLK vbp, int *x, int j, int k)
{
CheckType(vbp)
short val;
short *lp = (short *)vbp->GetValPointer();
for (register int i = j; i < k; i++) {
val = lp[x[i]];
if (val < Sval)
Sval = val;
} // endfor i
} // end of SetMin
/***********************************************************************/
/* SetMax: used by the aggregate function MAX. */
/***********************************************************************/
void SHVAL::SetMax(PVAL vp)
{
short val = vp->GetShortValue();
if (val > Sval)
Sval = val;
} // end of SetMax
/***********************************************************************/
/* SetMax: used by QUERY for the aggregate function MAX. */
/***********************************************************************/
void SHVAL::SetMax(PVBLK vbp, int i)
{
short val = vbp->GetShortValue(i);
if (val > Sval)
Sval = val;
} // end of SetMax
/***********************************************************************/
/* SetMax: used by QUERY for the aggregate function MAX. */
/***********************************************************************/
void SHVAL::SetMax(PVBLK vbp, int j, int k)
{
CheckType(vbp)
short *lp = (short *)vbp->GetValPointer();
for (register int i = j; i < k; i++)
if (lp[i] > Sval)
Sval = lp[i];
} // end of SetMax
/***********************************************************************/
/* SetMax: used by QUERY for the aggregate function MIN. */
/***********************************************************************/
void SHVAL::SetMax(PVBLK vbp, int *x, int j, int k)
{
CheckType(vbp)
short val;
short *lp = (short *)vbp->GetValPointer();
for (register int i = j; i < k; i++) {
val = lp[x[i]];
if (val > Sval)
Sval = val;
} // endfor i
} // end of SetMax
/***********************************************************************/
/* SHVAL SetFormat function (used to set SELECT output format). */
/***********************************************************************/
bool SHVAL::SetConstFormat(PGLOBAL g, FORMAT& fmt)
{
char c[16];
fmt.Type[0] = 'S';
fmt.Length = sprintf(c, "%hd", Sval);
fmt.Prec = 0;
return false;
} // end of SetConstFormat
/***********************************************************************/
/* Make file output of a short object. */
/***********************************************************************/
void SHVAL::Print(PGLOBAL g, FILE *f, uint n)
{
char m[64];
memset(m, ' ', n); /* Make margin string */
m[n] = '\0';
fprintf(f, "%s%hd\n", m, Sval);
} /* end of Print */
/***********************************************************************/
/* Make string output of a short object. */
/***********************************************************************/
void SHVAL::Print(PGLOBAL g, char *ps, uint z)
{
sprintf(ps, "%hd", Sval);
} /* end of Print */
/* -------------------------- Class INTVAL ---------------------------- */
/***********************************************************************/
/* INTVAL public constructor from char. */
/***********************************************************************/
INTVAL::INTVAL(PSZ s) : VALUE(TYPE_INT)
{
Ival = atol(s);
Clen = sizeof(int);
} // end of INTVAL constructor
/***********************************************************************/
/* INTVAL public constructor from short. */
/***********************************************************************/
INTVAL::INTVAL(short n) : VALUE(TYPE_INT)
{
Ival = (int)n;
Clen = sizeof(int);
} // end of INTVAL constructor
/***********************************************************************/
/* INTVAL public constructor from int. */
/***********************************************************************/
INTVAL::INTVAL(int n) : VALUE(TYPE_INT)
{
Ival = n;
Clen = sizeof(int);
} // end of INTVAL constructor
/***********************************************************************/
/* INTVAL public constructor from big int. */
/***********************************************************************/
INTVAL::INTVAL(longlong n) : VALUE(TYPE_INT)
{
Ival = (int)n;
Clen = sizeof(int);
} // end of INTVAL constructor
/***********************************************************************/
/* INTVAL public constructor from double. */
/***********************************************************************/
INTVAL::INTVAL(double f) : VALUE(TYPE_INT)
{
Ival = (int)f;
Clen = sizeof(int);
} // end of INTVAL constructor
/***********************************************************************/
/* INTVAL GetValLen: returns the print length of the int object. */
/***********************************************************************/
int INTVAL::GetValLen(void)
{
char c[16];
return sprintf(c, "%d", Ival);
} // end of GetValLen
/***********************************************************************/
/* INTVAL SetValue: copy the value of another Value object. */
/* This function allows conversion if chktype is false. */
/***********************************************************************/
bool INTVAL::SetValue_pval(PVAL valp, bool chktype)
{
if (chktype && Type != valp->GetType())
return true;
Ival = valp->GetIntValue();
return false;
} // end of SetValue
/***********************************************************************/
/* INTVAL SetValue: convert chars extracted from a line to int value. */
/***********************************************************************/
void INTVAL::SetValue_char(char *p, int n)
{
char *p2;
bool minus;
for (p2 = p + n; p < p2 && *p == ' '; p++) ;
for (Ival = 0, minus = false; p < p2; p++)
switch (*p) {
case '-':
minus = true;
case '+':
break;
case '0': Ival = Ival * 10; break;
case '1': Ival = Ival * 10 + 1; break;
case '2': Ival = Ival * 10 + 2; break;
case '3': Ival = Ival * 10 + 3; break;
case '4': Ival = Ival * 10 + 4; break;
case '5': Ival = Ival * 10 + 5; break;
case '6': Ival = Ival * 10 + 6; break;
case '7': Ival = Ival * 10 + 7; break;
case '8': Ival = Ival * 10 + 8; break;
case '9': Ival = Ival * 10 + 9; break;
default:
p = p2;
} // endswitch *p
if (minus && Ival)
Ival = - Ival;
if (trace)
htrc(" setting int to: %d\n", Ival);
} // end of SetValue
/***********************************************************************/
/* INTVAL SetValue: fill a int value from a string. */
/***********************************************************************/
void INTVAL::SetValue_psz(PSZ s)
{
Ival = atol(s);
} // end of SetValue
/***********************************************************************/
/* INTVAL SetValue: set value with a int extracted from a block. */
/***********************************************************************/
void INTVAL::SetValue_pvblk(PVBLK blk, int n)
{
Ival = blk->GetIntValue(n);
} // end of SetValue
/***********************************************************************/
/* INTVAL SetBinValue: with bytes extracted from a line. */
/***********************************************************************/
void INTVAL::SetBinValue(void *p)
{
Ival = *(int *)p;
} // end of SetBinValue
/***********************************************************************/
/* GetBinValue: fill a buffer with the internal binary value. */
/* This function checks whether the buffer length is enough and */
/* returns true if not. Actual filling occurs only if go is true. */
/* Currently used by WriteColumn of binary files. */
/***********************************************************************/
bool INTVAL::GetBinValue(void *buf, int buflen, bool go)
{
// Test on length was removed here until a variable in column give the
// real field length. For BIN files the field length logically cannot
// be different from the variable length because no conversion is done.
// Therefore this test is useless anyway.
//#if defined(_DEBUG)
// if (sizeof(int) > buflen)
// return true;
//#endif
if (go)
*(int *)buf = Ival;
return false;
} // end of GetBinValue
/***********************************************************************/
/* GetBinValue: used by SELECT when called from QUERY and KINDEX. */
/* This is a fast implementation that does not do any checking. */
/***********************************************************************/
void INTVAL::GetBinValue(void *buf, int buflen)
{
assert(buflen == sizeof(int));
*(int *)buf = Ival;
} // end of GetBinValue
/***********************************************************************/
/* INTVAL ShowValue: get string representation of a int value. */
/***********************************************************************/
char *INTVAL::ShowValue(char *buf, int len)
{
sprintf(buf, "%*d", len, Ival);
return buf;
} // end of ShowValue
/***********************************************************************/
/* INTVAL GetCharString: get string representation of a int value. */
/***********************************************************************/
char *INTVAL::GetCharString(char *p)
{
sprintf(p, "%d", Ival);
return p;
} // end of GetCharString
/***********************************************************************/
/* INTVAL GetShortString: get short representation of a int value. */
/***********************************************************************/
char *INTVAL::GetShortString(char *p, int n)
{
sprintf(p, "%*hd", n, (short)Ival);
return p;
} // end of GetShortString
/***********************************************************************/
/* INTVAL GetIntString: get int representation of a int value. */
/***********************************************************************/
char *INTVAL::GetIntString(char *p, int n)
{
sprintf(p, "%*d", n, Ival);
return p;
} // end of GetIntString
/***********************************************************************/
/* INTVAL GetBigintString: get big int representation of a int value. */
/***********************************************************************/
char *INTVAL::GetBigintString(char *p, int n)
{
sprintf(p, "%*lld", n, (longlong)Ival);
return p;
} // end of GetBigintString
/***********************************************************************/
/* INTVAL GetFloatString: get double representation of a int value. */
/***********************************************************************/
char *INTVAL::GetFloatString(char *p, int n, int prec)
{
sprintf(p, "%*.*lf", n, (prec < 0) ? 2 : prec, (double)Ival);
return p;
} // end of GetFloatString
/***********************************************************************/
/* INTVAL compare value with another Value. */
/***********************************************************************/
bool INTVAL::IsEqual(PVAL vp, bool chktype)
{
if (this == vp)
return true;
else if (chktype && Type != vp->GetType())
return false;
else
return (Ival == vp->GetIntValue());
} // end of IsEqual
/***********************************************************************/
/* Compare values and returns 1, 0 or -1 according to comparison. */
/* This function is used for evaluation of int integer filters. */
/***********************************************************************/
int INTVAL::CompareValue(PVAL vp)
{
//assert(vp->GetType() == Type);
// Process filtering on int integers.
int n = vp->GetIntValue();
if (trace > 1)
htrc(" Comparing: val=%d,%d\n", Ival, n);
return (Ival > n) ? 1 : (Ival < n) ? (-1) : 0;
} // end of CompareValue
/***********************************************************************/
/* SafeAdd: adds a value and test whether overflow/underflow occured. */
/***********************************************************************/
int INTVAL::SafeAdd(int n1, int n2)
{
PGLOBAL& g = Global;
int n = n1 + n2;
if ((n2 > 0) && (n < n1)) {
// Overflow
strcpy(g->Message, MSG(FIX_OVFLW_ADD));
longjmp(g->jumper[g->jump_level], 138);
} else if ((n2 < 0) && (n > n1)) {
// Underflow
strcpy(g->Message, MSG(FIX_UNFLW_ADD));
longjmp(g->jumper[g->jump_level], 138);
} // endif's n2
return n;
} // end of SafeAdd
/***********************************************************************/
/* SafeMult: multiply values and test whether overflow occured. */
/***********************************************************************/
int INTVAL::SafeMult(int n1, int n2)
{
PGLOBAL& g = Global;
double n = (double)n1 * (double)n2;
if (n > 2147483647.0) {
// Overflow
strcpy(g->Message, MSG(FIX_OVFLW_TIMES));
longjmp(g->jumper[g->jump_level], 138);
} else if (n < -2147483648.0) {
// Underflow
strcpy(g->Message, MSG(FIX_UNFLW_TIMES));
longjmp(g->jumper[g->jump_level], 138);
} // endif's n2
return (int)n;
} // end of SafeMult
/***********************************************************************/
/* Compute a function on a int integers. */
/***********************************************************************/
bool INTVAL::Compute(PGLOBAL g, PVAL *vp, int np, OPVAL op)
{
if (op == OP_LEN) {
assert(np == 1);
char buf[32];
char *p = vp[0]->GetCharString(buf);
Ival = strlen(p);
if (trace)
htrc("Compute result=%d val=%s op=%d\n", Ival, p, op);
} else if (op == OP_INSTR || op == OP_LIKE || op == OP_CNTIN) {
char *p, *tp = g->Message;
char *p1, val1[32];
char *p2, val2[32];
bool b = (vp[0]->IsCi() || vp[1]->IsCi());
assert(np == 2);
p1 = vp[0]->GetCharString(val1);
p2 = vp[1]->GetCharString(val2);
if (op != OP_LIKE) {
if (!strcmp(p2, "\\t"))
p2 = "\t";
if (b) { // Case insensitive
if (strlen(p1) + strlen(p2) + 1 >= MAX_STR &&
!(tp = new char[strlen(p1) + strlen(p2) + 2])) {
strcpy(g->Message, MSG(NEW_RETURN_NULL));
return true;
} // endif p
// Make a lower case copy of p1 and p2
p1 = strlwr(strcpy(tp, p1));
p2 = strlwr(strcpy(tp + strlen(p1) + 1, p2));
} // endif b
if (op == OP_CNTIN) {
size_t t2 = strlen(p2);
for (Ival = 0; (p = strstr(p1, p2)); Ival++, p1 = p + t2) ;
} else // OP_INSTR
Ival = (p = strstr(p1, p2)) ? 1 + (int)(p - p1) : 0;
if (tp != g->Message) // If working space was obtained
delete [] tp; // by the use of new, delete it.
} else // OP_LIKE
Ival = (PlugEvalLike(g, p1, p2, b)) ? 1 : 0;
if (trace)
htrc("Compute result=%d val=%s,%s op=%d\n", Ival, p1, p2, op);
} else if (op == OP_MDAY || op == OP_MONTH || op == OP_YEAR ||
op == OP_WDAY || op == OP_QUART || op == OP_YDAY) {
assert(np == 1 && vp[0]->GetType() == TYPE_DATE);
if (((DTVAL*)vp[0])->GetTmMember(op, Ival)) {
sprintf(g->Message, MSG(COMPUTE_ERROR), op);
return true;
} // endif
} else if (op == OP_NWEEK) {
// Week number of the year for the internal date value
assert((np == 1 || np == 2) && vp[0]->GetType() == TYPE_DATE);
// Start of the week SUN=0, MON=1, etc.
Ival = (np == 2) ? vp[1]->GetIntValue() : 1;
// This function sets Ival to nweek
if (((DTVAL*)vp[0])->WeekNum(g, Ival))
return true;
} else if (op == OP_DBTWN || op == OP_MBTWN || op == OP_YBTWN) {
assert(np == 2 && vp[0]->GetType() == TYPE_DATE
&& vp[1]->GetType() == TYPE_DATE);
if (((DTVAL*)vp[0])->DateDiff((DTVAL*)vp[1], op, Ival)) {
sprintf(g->Message, MSG(COMPUTE_ERROR), op);
return true;
} // endif
} else if (op == OP_TIME) {
Ival = vp[0]->GetTime(g, (np == 1) ? NULL : vp + 1, np - 1);
} else {
int val[2];
assert(np <= 2);
for (int i = 0; i < np; i++)
val[i] = vp[i]->GetIntValue();
switch (op) {
case OP_ABS:
assert(np == 1);
Ival = labs(*val);
break;
case OP_SIGN:
assert(np == 1);
Ival = (*val < 0) ? (-1) : 1;
break;
case OP_CEIL:
case OP_FLOOR:
assert(np == 1);
Ival = *val;
break;
case OP_ADD:
assert(np == 2);
Ival = SafeAdd(val[0], val[1]);
break;
case OP_SUB:
assert(np == 2);
Ival = SafeAdd(val[0], -val[1]);
break;
case OP_MULT:
assert(np == 2);
Ival = SafeMult(val[0], val[1]);
break;
case OP_MIN:
assert(np == 2);
Ival = min(val[0], val[1]);
break;
case OP_MAX:
assert(np == 2);
Ival = max(val[0], val[1]);
break;
case OP_DIV:
assert(np == 2);
if (!val[1]) {
strcpy(g->Message, MSG(ZERO_DIVIDE));
return true;
} // endif
Ival = val[0] / val[1];
break;
case OP_MOD:
assert(np == 2);
if (!val[1]) {
strcpy(g->Message, MSG(ZERO_DIVIDE));
return true;
} // endif
Ival = val[0] % val[1];
break;
case OP_BITAND:
assert(np == 2);
Ival = val[0] & val[1];
break;
case OP_BITOR:
assert(np == 2);
Ival = val[0] | val[1];
break;
case OP_BITXOR:
assert(np == 2);
Ival = val[0] ^ val[1];
break;
case OP_BITNOT:
assert(np == 1);
Ival = ~val[0];
break;
case OP_DELTA:
// assert(np == 1);
Ival = val[0] - Ival;
break;
default:
sprintf(g->Message, MSG(BAD_EXP_OPER), op);
return true;
} // endswitch op
if (trace)
if (np = 1)
htrc(" result=%d val=%d op=%d\n", Ival, val[0], op);
else
htrc(" result=%d val=%d,%d op=%d\n",
Ival, val[0], val[1], op);
} // endif op
return false;
} // end of Compute
/***********************************************************************/
/* GetTime: convert HR/MIN/SEC in a number of seconds. */
/***********************************************************************/
int INTVAL::GetTime(PGLOBAL g, PVAL *vp, int np)
{
int sec = Ival;
for (int i = 0; i < 2; i++) {
sec *= 60;
if (np > i)
sec += vp[i]->GetIntValue();
} // endfor i
return sec;
} // end of GetTime
/***********************************************************************/
/* Divide: used by aggregate functions when calculating average. */
/***********************************************************************/
void INTVAL::Divide(int cnt)
{
Ival /= cnt;
} // end of Divide
/***********************************************************************/
/* StdVar: used by aggregate functions for Stddev and Variance. */
/***********************************************************************/
void INTVAL::StdVar(PVAL vp, int cnt, bool b)
{
int lv2 = vp->GetIntValue();
Ival = (cnt == 1) ? 0
: (SafeAdd(lv2, -(SafeMult(Ival, Ival) / cnt)) / (cnt - 1));
if (b) // Builtin == FNC_STDDEV
Ival = (int)sqrt((double)Ival);
} // end of StdVar
/***********************************************************************/
/* Times: used by aggregate functions for Stddev and Variance. */
/***********************************************************************/
void INTVAL::Times(PVAL vp)
{
Ival = SafeMult(Ival, vp->GetIntValue());
} // end of Times
/***********************************************************************/
/* Add: used by aggregate functions for Sum and other functions. */
/***********************************************************************/
void INTVAL::Add(PVAL vp)
{
Ival = SafeAdd(Ival, vp->GetIntValue());
} // end of Add
/***********************************************************************/
/* Add: used by QUERY for function Sum and other functions. */
/***********************************************************************/
void INTVAL::Add(PVBLK vbp, int i)
{
Ival = SafeAdd(Ival, vbp->GetIntValue(i));
} // end of Add
/***********************************************************************/
/* Add: used by QUERY for function Sum and other functions. */
/***********************************************************************/
void INTVAL::Add(PVBLK vbp, int j, int k)
{
CheckType(vbp)
int *lp = (int *)vbp->GetValPointer();
for (register int i = j; i < k; i++)
Ival = SafeAdd(Ival, lp[i]);
} // end of Add
/***********************************************************************/
/* Add: used by QUERY for function Sum and other functions. */
/***********************************************************************/
void INTVAL::Add(PVBLK vbp, int *x, int j, int k)
{
CheckType(vbp)
int *lp = (int *)vbp->GetValPointer();
for (register int i = j; i < k; i++)
Ival = SafeAdd(Ival, lp[x[i]]);
} // end of Add
/***********************************************************************/
/* AddSquare: used by aggregate functions for Stddev and Variance. */
/***********************************************************************/
void INTVAL::AddSquare(PVAL vp)
{
int val = vp->GetIntValue();
Ival = SafeAdd(Ival, SafeMult(val, val));
} // end of AddSquare
/***********************************************************************/
/* AddSquare: used by QUERY for functions Stddev and Variance. */
/***********************************************************************/
void INTVAL::AddSquare(PVBLK vbp, int i)
{
int val = vbp->GetIntValue(i);
Ival = SafeAdd(Ival, SafeMult(val, val));
} // end of AddSquare
/***********************************************************************/
/* AddSquare: used by QUERY for functions Stddev and Variance. */
/***********************************************************************/
void INTVAL::AddSquare(PVBLK vbp, int j, int k)
{
CheckType(vbp)
int *lp = (int *)vbp->GetValPointer();
for (register int i = j; i < k; i++)
Ival = SafeAdd(Ival, SafeMult(lp[i], lp[i]));
} // end of AddSquare
/***********************************************************************/
/* FormatValue: This function set vp (a STRING value) to the string */
/* constructed from its own value formated using the fmt format. */
/* This function assumes that the format matches the value type. */
/***********************************************************************/
bool INTVAL::FormatValue(PVAL vp, char *fmt)
{
char *buf = (char*)vp->GetTo_Val(); // Should be big enough
int n = sprintf(buf, fmt, Ival);
return (n > vp->GetValLen());
} // end of FormatValue
/***********************************************************************/
/* SetMin: used by the aggregate function MIN. */
/***********************************************************************/
void INTVAL::SetMin(PVAL vp)
{
int val = vp->GetIntValue();
if (val < Ival)
Ival = val;
} // end of SetMin
/***********************************************************************/
/* SetMin: used by QUERY for the aggregate function MIN. */
/***********************************************************************/
void INTVAL::SetMin(PVBLK vbp, int i)
{
int val = vbp->GetIntValue(i);
if (val < Ival)
Ival = val;
} // end of SetMin
/***********************************************************************/
/* SetMin: used by QUERY for the aggregate function MIN. */
/***********************************************************************/
void INTVAL::SetMin(PVBLK vbp, int j, int k)
{
CheckType(vbp)
int *lp = (int *)vbp->GetValPointer();
for (register int i = j; i < k; i++)
if (lp[i] < Ival)
Ival = lp[i];
} // end of SetMin
/***********************************************************************/
/* SetMin: used by QUERY for the aggregate function MIN. */
/***********************************************************************/
void INTVAL::SetMin(PVBLK vbp, int *x, int j, int k)
{
CheckType(vbp)
register int val;
int *lp = (int *)vbp->GetValPointer();
for (register int i = j; i < k; i++) {
val = lp[x[i]];
if (val < Ival)
Ival = val;
} // endfor i
} // end of SetMin
/***********************************************************************/
/* SetMax: used by the aggregate function MAX. */
/***********************************************************************/
void INTVAL::SetMax(PVAL vp)
{
int val = vp->GetIntValue();
if (val > Ival)
Ival = val;
} // end of SetMax
/***********************************************************************/
/* SetMax: used by QUERY for the aggregate function MAX. */
/***********************************************************************/
void INTVAL::SetMax(PVBLK vbp, int i)
{
int val = vbp->GetIntValue(i);
if (val > Ival)
Ival = val;
} // end of SetMax
/***********************************************************************/
/* SetMax: used by QUERY for the aggregate function MAX. */
/***********************************************************************/
void INTVAL::SetMax(PVBLK vbp, int j, int k)
{
CheckType(vbp)
int *lp = (int *)vbp->GetValPointer();
for (register int i = j; i < k; i++)
if (lp[i] > Ival)
Ival = lp[i];
} // end of SetMax
/***********************************************************************/
/* SetMax: used by QUERY for the aggregate function MIN. */
/***********************************************************************/
void INTVAL::SetMax(PVBLK vbp, int *x, int j, int k)
{
CheckType(vbp)
register int val;
int *lp = (int *)vbp->GetValPointer();
for (register int i = j; i < k; i++) {
val = lp[x[i]];
if (val > Ival)
Ival = val;
} // endfor i
} // end of SetMax
/***********************************************************************/
/* INTVAL SetFormat function (used to set SELECT output format). */
/***********************************************************************/
bool INTVAL::SetConstFormat(PGLOBAL g, FORMAT& fmt)
{
char c[16];
fmt.Type[0] = 'N';
fmt.Length = sprintf(c, "%d", Ival);
fmt.Prec = 0;
return false;
} // end of SetConstFormat
/***********************************************************************/
/* Make file output of a int object. */
/***********************************************************************/
void INTVAL::Print(PGLOBAL g, FILE *f, uint n)
{
char m[64];
memset(m, ' ', n); /* Make margin string */
m[n] = '\0';
fprintf(f, "%s%d\n", m, Ival);
} /* end of Print */
/***********************************************************************/
/* Make string output of a int object. */
/***********************************************************************/
void INTVAL::Print(PGLOBAL g, char *ps, uint z)
{
sprintf(ps, "%d", Ival);
} /* end of Print */
/* -------------------------- Class DTVAL ---------------------------- */
/***********************************************************************/
/* DTVAL public constructor for new void values. */
/***********************************************************************/
DTVAL::DTVAL(PGLOBAL g, int n, int prec, PSZ fmt) : INTVAL((int)0)
{
if (!fmt) {
Pdtp = NULL;
Sdate = NULL;
DefYear = 0;
Len = n;
} else
SetFormat(g, fmt, n, prec);
Type = TYPE_DATE;
} // end of DTVAL constructor
/***********************************************************************/
/* DTVAL public constructor from char. */
/***********************************************************************/
DTVAL::DTVAL(PGLOBAL g, PSZ s, int n) : INTVAL((s) ? s : (char *)"0")
{
Pdtp = NULL;
Len = n;
Type = TYPE_DATE;
Sdate = NULL;
DefYear = 0;
} // end of DTVAL constructor
/***********************************************************************/
/* DTVAL public constructor from short. */
/***********************************************************************/
DTVAL::DTVAL(PGLOBAL g, short n) : INTVAL((int)n)
{
Pdtp = NULL;
Len = 19;
Type = TYPE_DATE;
Sdate = NULL;
DefYear = 0;
} // end of DTVAL constructor
/***********************************************************************/
/* DTVAL public constructor from int. */
/***********************************************************************/
DTVAL::DTVAL(PGLOBAL g, int n) : INTVAL(n)
{
Pdtp = NULL;
Len = 19;
Type = TYPE_DATE;
Sdate = NULL;
DefYear = 0;
} // end of DTVAL constructor
/***********************************************************************/
/* DTVAL public constructor from double. */
/***********************************************************************/
DTVAL::DTVAL(PGLOBAL g, double f) : INTVAL(f)
{
Pdtp = NULL;
Len = 19;
Type = TYPE_DATE;
Sdate = NULL;
DefYear = 0;
} // end of DTVAL constructor
/***********************************************************************/
/* Set format so formatted dates can be converted on input/output. */
/***********************************************************************/
bool DTVAL::SetFormat(PGLOBAL g, PSZ fmt, int len, int year)
{
Pdtp = MakeDateFormat(g, fmt, true, true, (year > 9999) ? 1 : 0);
Sdate = (char*)PlugSubAlloc(g, NULL, len + 1);
DefYear = (int)((year > 9999) ? (year - 10000) : year);
Len = len;
return false;
} // end of SetFormat
/***********************************************************************/
/* Set format from the format of another date value. */
/***********************************************************************/
bool DTVAL::SetFormat(PGLOBAL g, PVAL valp)
{
DTVAL *vp;
if (valp->GetType() != TYPE_DATE) {
sprintf(g->Message, MSG(NO_FORMAT_TYPE), valp->GetType());
return true;
} else
vp = (DTVAL*)valp;
Len = vp->Len;
Pdtp = vp->Pdtp;
Sdate = (char*)PlugSubAlloc(g, NULL, Len + 1);
DefYear = vp->DefYear;
return false;
} // end of SetFormat
/***********************************************************************/
/* We need TimeShift because the mktime C function does a correction */
/* for local time zone that we want to override for DB operations. */
/***********************************************************************/
void DTVAL::SetTimeShift(void)
{
struct tm dtm = {0,0,0,2,0,70,0,0,0};
Shift = (int)mktime(&dtm) - 86400;
if (trace)
htrc("DTVAL Shift=%d\n", Shift);
} // end of SetTimeShift
/***********************************************************************/
/* GetGmTime: returns a pointer to a static tm structure obtained */
/* though the gmtime C function. The purpose of this function is to */
/* extend the range of valid dates by accepting negative time values. */
/***********************************************************************/
struct tm *DTVAL::GetGmTime(void)
{
struct tm *datm;
time_t t = (time_t)Ival;
if (Ival < 0) {
int n;
for (n = 0; t < 0; n += 4)
t += FOURYEARS;
datm = gmtime(&t);
if (datm)
datm->tm_year -= n;
} else
datm = gmtime((const time_t *)&t);
return datm;
} // end of GetGmTime
/***********************************************************************/
/* MakeTime: calculates a date value from a tm structures using the */
/* mktime C function. The purpose of this function is to extend the */
/* range of valid dates by accepting to set negative time values. */
/***********************************************************************/
bool DTVAL::MakeTime(struct tm *ptm)
{
int n, y = ptm->tm_year;
time_t t = mktime(ptm);
if (trace)
htrc("MakeTime from (%d,%d,%d,%d,%d,%d)\n",
ptm->tm_year, ptm->tm_mon, ptm->tm_mday,
ptm->tm_hour, ptm->tm_min, ptm->tm_sec);
if (t == -1) {
if (y < 1 || y > 71)
return true;
for (n = 0; t == -1 && n < 20; n++) {
ptm->tm_year += 4;
t = mktime(ptm);
} // endfor t
if (t == -1)
return true;
if ((t -= (n * FOURYEARS + Shift)) > 2000000000)
return true;
Ival = (int)t;
} else
Ival = (int)t - Shift;
if (trace)
htrc("MakeTime Ival=%d\n", Ival);
return false;
} // end of MakeTime
/***********************************************************************/
/* Make a time_t datetime from its components (YY, MM, DD, hh, mm, ss) */
/***********************************************************************/
bool DTVAL::MakeDate(PGLOBAL g, int *val, int nval)
{
int i, m;
int n;
bool rc = false;
struct tm datm = {0,0,0,1,0,70,0,0,0};
if (trace)
htrc("MakeDate from(%d,%d,%d,%d,%d,%d) nval=%d\n",
val[0], val[1], val[2], val[3], val[4], val[5], nval);
for (i = 0; i < nval; i++) {
n = val[i];
// if (trace > 1)
// htrc("i=%d n=%d\n", i, n);
switch (i) {
case 0:
if (n >= 1900)
n -= 1900;
datm.tm_year = n;
// if (trace > 1)
// htrc("n=%d tm_year=%d\n", n, datm.tm_year);
break;
case 1:
// If mktime handles apparently correctly large or negative
// day values, it is not the same for months. Therefore we
// do the ajustment here, thus mktime has not to do it.
if (n > 0) {
m = (n - 1) % 12;
n = (n - 1) / 12;
} else {
m = 11 + n % 12;
n = n / 12 - 1;
} // endfi n
datm.tm_mon = m;
datm.tm_year += n;
// if (trace > 1)
// htrc("n=%d m=%d tm_year=%d tm_mon=%d\n", n, m, datm.tm_year, datm.tm_mon);
break;
case 2:
// For days, big or negative values may also cause problems
m = n % 1461;
n = 4 * (n / 1461);
if (m < 0) {
m += 1461;
n -= 4;
} // endif m
datm.tm_mday = m;
datm.tm_year += n;
// if (trace > 1)
// htrc("n=%d m=%d tm_year=%d tm_mon=%d\n", n, m, datm.tm_year, datm.tm_mon);
break;
case 3: datm.tm_hour = n; break;
case 4: datm.tm_min = n; break;
case 5: datm.tm_sec = n; break;
} // endswitch i
} // endfor i
if (trace)
htrc("MakeDate datm=(%d,%d,%d,%d,%d,%d)\n",
datm.tm_year, datm.tm_mon, datm.tm_mday,
datm.tm_hour, datm.tm_min, datm.tm_sec);
// Pass g to have an error return or NULL to set invalid dates to 0
if (MakeTime(&datm))
if (g) {
strcpy(g->Message, MSG(BAD_DATETIME));
rc = true;
} else
Ival = 0;
return rc;
} // end of MakeDate
/***********************************************************************/
/* DTVAL SetValue: copy the value of another Value object. */
/* This function allows conversion if chktype is false. */
/***********************************************************************/
bool DTVAL::SetValue_pval(PVAL valp, bool chktype)
{
if (chktype && Type != valp->GetType())
return true;
if (Pdtp && !valp->IsTypeNum()) {
int ndv;
int dval[6];
ndv = ExtractDate(valp->GetCharValue(), Pdtp, DefYear, dval);
MakeDate(NULL, dval, ndv);
} else
Ival = valp->GetIntValue();
return false;
} // end of SetValue
/***********************************************************************/
/* SetValue: convert chars extracted from a line to date value. */
/***********************************************************************/
void DTVAL::SetValue_char(char *p, int n)
{
if (Pdtp) {
char *p2;
int ndv;
int dval[6];
// Trim trailing blanks
for (p2 = p + n -1; p < p2 && *p2 == ' '; p2--) ;
n = min(p2 - p + 1, Len);
memcpy(Sdate, p, n);
Sdate[n] = '\0';
ndv = ExtractDate(Sdate, Pdtp, DefYear, dval);
MakeDate(NULL, dval, ndv);
if (trace)
htrc(" setting date: '%s' -> %d\n", Sdate, Ival);
} else
INTVAL::SetValue_char(p, n);
} // end of SetValue
/***********************************************************************/
/* SetValue: convert a char string to date value. */
/***********************************************************************/
void DTVAL::SetValue_psz(PSZ p)
{
if (Pdtp) {
int ndv;
int dval[6];
strncpy(Sdate, p, Len);
Sdate[Len] = '\0';
ndv = ExtractDate(Sdate, Pdtp, DefYear, dval);
MakeDate(NULL, dval, ndv);
if (trace)
htrc(" setting date: '%s' -> %d\n", Sdate, Ival);
} else
INTVAL::SetValue_psz(p);
} // end of SetValue
/***********************************************************************/
/* DTVAL SetValue: set value with a value extracted from a block. */
/***********************************************************************/
void DTVAL::SetValue_pvblk(PVBLK blk, int n)
{
if (Pdtp && !::IsTypeNum(blk->GetType())) {
int ndv;
int dval[6];
ndv = ExtractDate(blk->GetCharValue(n), Pdtp, DefYear, dval);
MakeDate(NULL, dval, ndv);
} else
Ival = blk->GetIntValue(n);
} // end of SetValue
/***********************************************************************/
/* DTVAL GetCharString: get string representation of a date value. */
/***********************************************************************/
char *DTVAL::GetCharString(char *p)
{
if (Pdtp) {
size_t n = 0;
struct tm *ptm = GetGmTime();
if (ptm)
n = strftime(Sdate, Len + 1, Pdtp->OutFmt, ptm);
if (!n) {
*Sdate = '\0';
strncat(Sdate, "Error", Len + 1);
} // endif n
return Sdate;
} else
sprintf(p, "%d", Ival);
return p;
} // end of GetCharString
/***********************************************************************/
/* DTVAL ShowValue: get string representation of a date value. */
/***********************************************************************/
char *DTVAL::ShowValue(char *buf, int len)
{
if (Pdtp) {
char *p;
size_t m, n = 0;
struct tm *ptm = GetGmTime();
if (Len < len) {
p = buf;
m = len;
} else {
p = Sdate;
m = Len + 1;
} // endif Len
if (ptm)
n = strftime(p, m, Pdtp->OutFmt, ptm);
if (!n) {
*p = '\0';
strncat(p, "Error", m);
} // endif n
return p;
} else
return INTVAL::ShowValue(buf, len);
} // end of ShowValue
/***********************************************************************/
/* Compute a function on a date time stamp. */
/***********************************************************************/
bool DTVAL::Compute(PGLOBAL g, PVAL *vp, int np, OPVAL op)
{
bool rc = false;
if (op == OP_DATE) {
int val[6];
int nval = min(np, 6);
for (int i = 0; i < nval; i++)
val[i] = vp[i]->GetIntValue();
rc = MakeDate(g, val, nval);
} else if (op == OP_ADDAY || op == OP_ADDMTH ||
op == OP_ADDYR || op == OP_NXTDAY) {
struct tm *ptm;
int n = (op != OP_NXTDAY) ? (int)vp[1]->GetIntValue() : 1;
INTVAL::SetValue_pval(vp[0], true);
Ival -= Shift;
ptm = GetGmTime();
switch (op) {
case OP_ADDAY:
case OP_NXTDAY:
ptm->tm_mday += n;
break;
case OP_ADDMTH:
ptm->tm_mon += n;
break;
case OP_ADDYR:
ptm->tm_year += n;
break;
default:
sprintf(g->Message, MSG(BAD_DATE_OPER), op);
return true;
} // endswitch op
if (MakeTime(ptm)) {
strcpy(g->Message, MSG(BAD_DATETIME));
rc = true;
} // endif MakeTime
} else if (op == OP_SYSDT) {
Ival = (int)time(NULL) - Shift;
} else if (op == OP_CURDT) {
Ival = (((int)time(NULL) - Shift) / 86400) * 86400;
} else
rc = INTVAL::Compute(g, vp, np, op);
return rc;
} // end of Compute
/***********************************************************************/
/* GetTime: extract the time info from a date stamp. */
/***********************************************************************/
int DTVAL::GetTime(PGLOBAL g, PVAL *vp, int np)
{
return (Ival % 86400);
} // end of GetTime
/***********************************************************************/
/* Returns a member of the struct tm representation of the date. */
/***********************************************************************/
bool DTVAL::GetTmMember(OPVAL op, int& mval)
{
bool rc = false;
struct tm *ptm = GetGmTime();
switch (op) {
case OP_MDAY: mval = ptm->tm_mday; break;
case OP_MONTH: mval = ptm->tm_mon + 1; break;
case OP_YEAR: mval = ptm->tm_year + 1900; break;
case OP_WDAY: mval = ptm->tm_wday + 1; break;
case OP_YDAY: mval = ptm->tm_yday + 1; break;
case OP_QUART: mval = ptm->tm_mon / 3 + 1; break;
default:
rc = true;
} // endswitch op
return rc;
} // end of GetTmMember
/***********************************************************************/
/* Calculates the week number of the year for the internal date value.*/
/* The International Standard ISO 8601 has decreed that Monday shall */
/* be the first day of the week. A week that lies partly in one year */
/* and partly in another is assigned a number in the year in which */
/* most of its days lie. That means that week number 1 of any year is */
/* the week that contains the January 4th. */
/***********************************************************************/
bool DTVAL::WeekNum(PGLOBAL g, int& nval)
{
// w is the start of the week SUN=0, MON=1, etc.
int m, n, w = nval % 7;
struct tm *ptm = GetGmTime();
// Which day is January 4th of this year?
m = (367 + ptm->tm_wday - ptm->tm_yday) % 7;
// When does the first week begins?
n = 3 - (7 + m - w) % 7;
// Now calculate the week number
if (!(nval = (7 + ptm->tm_yday - n) / 7))
nval = 52;
// Everything should be Ok
return false;
} // end of WeekNum
/***********************************************************************/
/* This covers days, months and years between two dates. */
/***********************************************************************/
bool DTVAL::DateDiff(DTVAL *dtp, OPVAL op, int& tdif)
{
bool rc = false;
int lv1, lv2, t1, t2;
int s = CompareValue(dtp);
struct tm dat1, dat2, *ptm = dtp->GetGmTime();
if (!ptm)
return true;
if (s == 0) {
// Dates are equal
tdif = 0;
return rc;
} else if (s > 0) {
// This Date is greater than dtp->Date
dat1 = *ptm;
lv1 = dtp->GetIntValue();
lv2 = Ival;
if ((ptm = GetGmTime()))
dat2 = *ptm;
} else {
// This Date is less than dtp->Date
dat2 = *ptm;
lv2 = dtp->GetIntValue();
lv1 = Ival;
if ((ptm = GetGmTime()))
dat1 = *ptm;
} // endif's s
if (!ptm)
return true;
// Both dates are valid and dat2 is greater than dat1
t1 = lv1 % 86400; if (t1 < 0) t1 += 86400;
t2 = lv2 % 86400; if (t2 < 0) t2 += 86400;
if (t1 > t2) {
lv1 += 86400;
dat1.tm_mday++;
} // endif
if (dat1.tm_mday > dat2.tm_mday)
dat1.tm_mon++;
switch (op) {
case OP_DBTWN:
tdif = (lv2 / 86400) - (lv1 / 86400);
break;
case OP_MBTWN:
tdif = (dat2.tm_year - dat1.tm_year) * 12
+ (dat2.tm_mon - dat1.tm_mon);
break;
case OP_YBTWN:
if (dat1.tm_mon > dat2.tm_mon)
dat1.tm_year++;
tdif = dat2.tm_year - dat1.tm_year;
break;
default:
rc = true;
} // endswitch op
if (!rc && s < 0)
tdif = -tdif;
return rc;
} // end of DateDiff
/***********************************************************************/
/* FormatValue: This function set vp (a STRING value) to the string */
/* constructed from its own value formated using the fmt format. */
/* This function assumes that the format matches the value type. */
/***********************************************************************/
bool DTVAL::FormatValue(PVAL vp, char *fmt)
{
char *buf = (char*)vp->GetTo_Val(); // Should be big enough
struct tm *ptm = GetGmTime();
if (trace)
htrc("FormatValue: ptm=%p len=%d\n", ptm, vp->GetValLen());
if (ptm) {
size_t n = strftime(buf, vp->GetValLen(), fmt, ptm);
if (trace)
htrc("strftime: n=%d buf=%s\n", n, (n) ? buf : "???");
return (n == 0);
} else
return true;
} // end of FormatValue
/* -------------------------- Class BIGVAL ---------------------------- */
/***********************************************************************/
/* BIGVAL public constructor from char. */
/***********************************************************************/
BIGVAL::BIGVAL(PSZ s) : VALUE(TYPE_BIGINT)
{
Lval = atoll(s);
Clen = sizeof(longlong);
} // end of BIGVAL constructor
/***********************************************************************/
/* BIGVAL public constructor from short. */
/***********************************************************************/
BIGVAL::BIGVAL(short n) : VALUE(TYPE_BIGINT)
{
Lval = (longlong)n;
Clen = sizeof(longlong);
} // end of BIGVAL constructor
/***********************************************************************/
/* BIGVAL public constructor from int. */
/***********************************************************************/
BIGVAL::BIGVAL(int n) : VALUE(TYPE_BIGINT)
{
Lval = (longlong)n;
Clen = sizeof(longlong);
} // end of BIGVAL constructor
/***********************************************************************/
/* BIGVAL public constructor from big int. */
/***********************************************************************/
BIGVAL::BIGVAL(longlong n) : VALUE(TYPE_BIGINT)
{
Lval = n;
Clen = sizeof(longlong);
} // end of BIGVAL constructor
/***********************************************************************/
/* BIGVAL public constructor from double. */
/***********************************************************************/
BIGVAL::BIGVAL(double f) : VALUE(TYPE_BIGINT)
{
Lval = (longlong)f;
Clen = sizeof(longlong);
} // end of BIGVAL constructor
/***********************************************************************/
/* BIGVAL GetValLen: returns the print length of the int object. */
/***********************************************************************/
int BIGVAL::GetValLen(void)
{
char c[24];
return sprintf(c, "%lld", Lval);
} // end of GetValLen
/***********************************************************************/
/* BIGVAL SetValue: copy the value of another Value object. */
/* This function allows conversion if chktype is false. */
/***********************************************************************/
bool BIGVAL::SetValue_pval(PVAL valp, bool chktype)
{
if (chktype && Type != valp->GetType())
return true;
Lval = valp->GetBigintValue();
return false;
} // end of SetValue
/***********************************************************************/
/* BIGVAL SetValue: convert chars extracted from a line to a big int. */
/***********************************************************************/
void BIGVAL::SetValue_char(char *p, int n)
{
char *p2;
bool minus;
for (p2 = p + n; p < p2 && *p == ' '; p++) ;
for (Lval = 0LL, minus = false; p < p2; p++)
switch (*p) {
case '-':
minus = true;
case '+':
break;
case '0': Lval = Lval * 10LL; break;
case '1': Lval = Lval * 10LL + 1LL; break;
case '2': Lval = Lval * 10LL + 2LL; break;
case '3': Lval = Lval * 10LL + 3LL; break;
case '4': Lval = Lval * 10LL + 4LL; break;
case '5': Lval = Lval * 10LL + 5LL; break;
case '6': Lval = Lval * 10LL + 6LL; break;
case '7': Lval = Lval * 10LL + 7LL; break;
case '8': Lval = Lval * 10LL + 8LL; break;
case '9': Lval = Lval * 10LL + 9LL; break;
default:
p = p2;
} // endswitch *p
if (minus && Lval)
Lval = - Lval;
if (trace)
htrc(" setting big int to: %lld\n", Lval);
} // end of SetValue
/***********************************************************************/
/* BIGVAL SetValue: fill a big int value from a string. */
/***********************************************************************/
void BIGVAL::SetValue_psz(PSZ s)
{
Lval = atoll(s);
} // end of SetValue
/***********************************************************************/
/* BIGVAL SetValue: set value with a int extracted from a block. */
/***********************************************************************/
void BIGVAL::SetValue_pvblk(PVBLK blk, int n)
{
Lval = blk->GetBigintValue(n);
} // end of SetValue
/***********************************************************************/
/* BIGVAL SetBinValue: with bytes extracted from a line. */
/***********************************************************************/
void BIGVAL::SetBinValue(void *p)
{
Lval = *(longlong *)p;
} // end of SetBinValue
/***********************************************************************/
/* GetBinValue: fill a buffer with the internal binary value. */
/* This function checks whether the buffer length is enough and */
/* returns true if not. Actual filling occurs only if go is true. */
/* Currently used by WriteColumn of binary files. */
/***********************************************************************/
bool BIGVAL::GetBinValue(void *buf, int buflen, bool go)
{
// Test on length was removed here until a variable in column give the
// real field length. For BIN files the field length logically cannot
// be different from the variable length because no conversion is done.
// Therefore this test is useless anyway.
//#if defined(_DEBUG)
// if (sizeof(int) > buflen)
// return true;
//#endif
if (go)
*(longlong *)buf = Lval;
return false;
} // end of GetBinValue
/***********************************************************************/
/* GetBinValue: used by SELECT when called from QUERY and KINDEX. */
/* This is a fast implementation that does not do any checking. */
/***********************************************************************/
void BIGVAL::GetBinValue(void *buf, int buflen)
{
assert(buflen == sizeof(longlong));
*(longlong *)buf = Lval;
} // end of GetBinValue
/***********************************************************************/
/* BIGVAL ShowValue: get string representation of a big int value. */
/***********************************************************************/
char *BIGVAL::ShowValue(char *buf, int len)
{
sprintf(buf, "%*lld", len, Lval);
return buf;
} // end of ShowValue
/***********************************************************************/
/* BIGVAL GetCharString: get string representation of a big int value.*/
/***********************************************************************/
char *BIGVAL::GetCharString(char *p)
{
sprintf(p, "%lld", Lval);
return p;
} // end of GetCharString
/***********************************************************************/
/* BIGVAL GetShortString: get short representation of a int value. */
/***********************************************************************/
char *BIGVAL::GetShortString(char *p, int n)
{
sprintf(p, "%*hd", n, (short)Lval);
return p;
} // end of GetShortString
/***********************************************************************/
/* BIGVAL GetIntString: get int representation of a int value. */
/***********************************************************************/
char *BIGVAL::GetIntString(char *p, int n)
{
sprintf(p, "%*d", n, (int)Lval);
return p;
} // end of GetIntString
/***********************************************************************/
/* BIGVAL GetBigintString: get big int representation of a int value. */
/***********************************************************************/
char *BIGVAL::GetBigintString(char *p, int n)
{
sprintf(p, "%*lld", n, Lval);
return p;
} // end of GetBigintString
/***********************************************************************/
/* BIGVAL GetFloatString: get double representation of a int value. */
/***********************************************************************/
char *BIGVAL::GetFloatString(char *p, int n, int prec)
{
sprintf(p, "%*.*lf", n, (prec < 0) ? 2 : prec, (double)Lval);
return p;
} // end of GetFloatString
/***********************************************************************/
/* BIGVAL compare value with another Value. */
/***********************************************************************/
bool BIGVAL::IsEqual(PVAL vp, bool chktype)
{
if (this == vp)
return true;
else if (chktype && Type != vp->GetType())
return false;
else
return (Lval == vp->GetBigintValue());
} // end of IsEqual
/***********************************************************************/
/* Compare values and returns 1, 0 or -1 according to comparison. */
/* This function is used for evaluation of big int integer filters. */
/***********************************************************************/
int BIGVAL::CompareValue(PVAL vp)
{
//assert(vp->GetType() == Type);
// Process filtering on big int integers.
longlong n = vp->GetBigintValue();
if (trace > 1)
htrc(" Comparing: val=%lld,%lld\n", Lval, n);
return (Lval > n) ? 1 : (Lval < n) ? (-1) : 0;
} // end of CompareValue
/***********************************************************************/
/* SafeAdd: adds a value and test whether overflow/underflow occured. */
/***********************************************************************/
longlong BIGVAL::SafeAdd(longlong n1, longlong n2)
{
PGLOBAL& g = Global;
longlong n = n1 + n2;
if ((n2 > 0LL) && (n < n1)) {
// Overflow
strcpy(g->Message, MSG(FIX_OVFLW_ADD));
longjmp(g->jumper[g->jump_level], 138);
} else if ((n2 < 0LL) && (n > n1)) {
// Underflow
strcpy(g->Message, MSG(FIX_UNFLW_ADD));
longjmp(g->jumper[g->jump_level], 138);
} // endif's n2
return n;
} // end of SafeAdd
/***********************************************************************/
/* SafeMult: multiply values and test whether overflow occured. */
/***********************************************************************/
longlong BIGVAL::SafeMult(longlong n1, longlong n2)
{
PGLOBAL& g = Global;
double n = (double)n1 * (double)n2;
if (n > LLONG_MAX) {
// Overflow
strcpy(g->Message, MSG(FIX_OVFLW_TIMES));
longjmp(g->jumper[g->jump_level], 138);
} else if (n < LLONG_MIN) {
// Underflow
strcpy(g->Message, MSG(FIX_UNFLW_TIMES));
longjmp(g->jumper[g->jump_level], 138);
} // endif's n2
return n1 * n2;
} // end of SafeMult
/***********************************************************************/
/* Compute a function on a int integers. */
/***********************************************************************/
bool BIGVAL::Compute(PGLOBAL g, PVAL *vp, int np, OPVAL op)
{
if (op == OP_LEN) {
assert(np == 1);
char buf[32];
char *p = vp[0]->GetCharString(buf);
Lval = strlen(p);
if (trace)
htrc("Compute result=%lld val=%s op=%d\n", Lval, p, op);
} else if (op == OP_INSTR || op == OP_LIKE || op == OP_CNTIN) {
char *p, *tp = g->Message;
char *p1, val1[32];
char *p2, val2[32];
bool b = (vp[0]->IsCi() || vp[1]->IsCi());
assert(np == 2);
p1 = vp[0]->GetCharString(val1);
p2 = vp[1]->GetCharString(val2);
if (op != OP_LIKE) {
if (!strcmp(p2, "\\t"))
p2 = "\t";
if (b) { // Case insensitive
if (strlen(p1) + strlen(p2) + 1 >= MAX_STR &&
!(tp = new char[strlen(p1) + strlen(p2) + 2])) {
strcpy(g->Message, MSG(NEW_RETURN_NULL));
return true;
} // endif p
// Make a lower case copy of p1 and p2
p1 = strlwr(strcpy(tp, p1));
p2 = strlwr(strcpy(tp + strlen(p1) + 1, p2));
} // endif b
if (op == OP_CNTIN) {
size_t t2 = strlen(p2);
for (Lval = 0LL; (p = strstr(p1, p2)); Lval++, p1 = p + t2) ;
} else // OP_INSTR
Lval = (p = strstr(p1, p2)) ? 1LL + (longlong)(p - p1) : 0LL;
if (tp != g->Message) // If working space was obtained
delete [] tp; // by the use of new, delete it.
} else // OP_LIKE
Lval = (PlugEvalLike(g, p1, p2, b)) ? 1LL : 0LL;
if (trace)
htrc("Compute result=%lld val=%s,%s op=%d\n", Lval, p1, p2, op);
} else {
longlong val[2];
assert(np <= 2);
for (int i = 0; i < np; i++)
val[i] = vp[i]->GetBigintValue();
switch (op) {
case OP_ABS:
assert(np == 1);
Lval = (*val >= 0LL) ? *val : -*val;
break;
case OP_SIGN:
assert(np == 1);
Lval = (*val < 0LL) ? (-1) : 1;
break;
case OP_CEIL:
case OP_FLOOR:
assert(np == 1);
Lval = *val;
break;
case OP_ADD:
assert(np == 2);
Lval = SafeAdd(val[0], val[1]);
break;
case OP_SUB:
assert(np == 2);
Lval = SafeAdd(val[0], -val[1]);
break;
case OP_MULT:
assert(np == 2);
Lval = SafeMult(val[0], val[1]);
break;
case OP_MIN:
assert(np == 2);
Lval = min(val[0], val[1]);
break;
case OP_MAX:
assert(np == 2);
Lval = max(val[0], val[1]);
break;
case OP_DIV:
assert(np == 2);
if (!val[1]) {
strcpy(g->Message, MSG(ZERO_DIVIDE));
return true;
} // endif
Lval = val[0] / val[1];
break;
case OP_MOD:
assert(np == 2);
if (!val[1]) {
strcpy(g->Message, MSG(ZERO_DIVIDE));
return true;
} // endif
Lval = val[0] % val[1];
break;
case OP_BITAND:
assert(np == 2);
Lval = val[0] & val[1];
break;
case OP_BITOR:
assert(np == 2);
Lval = val[0] | val[1];
break;
case OP_BITXOR:
assert(np == 2);
Lval = val[0] ^ val[1];
break;
case OP_BITNOT:
assert(np == 1);
Lval = ~val[0];
break;
case OP_DELTA:
// assert(np == 1);
Lval = val[0] - Lval;
break;
default:
sprintf(g->Message, MSG(BAD_EXP_OPER), op);
return true;
} // endswitch op
if (trace)
if (np = 1)
htrc(" result=%lld val=%lld op=%d\n", Lval, val[0], op);
else
htrc(" result=%lld val=%lld,%lld op=%d\n",
Lval, val[0], val[1], op);
} // endif op
return false;
} // end of Compute
/***********************************************************************/
/* Divide: used by aggregate functions when calculating average. */
/***********************************************************************/
void BIGVAL::Divide(int cnt)
{
Lval /= cnt;
} // end of Divide
/***********************************************************************/
/* StdVar: used by aggregate functions for Stddev and Variance. */
/***********************************************************************/
void BIGVAL::StdVar(PVAL vp, int cnt, bool b)
{
longlong lv2 = vp->GetBigintValue();
Lval = (cnt == 1) ? 0
: (SafeAdd(lv2, -(SafeMult(Lval, Lval) / cnt)) / (cnt - 1));
if (b) // Builtin == FNC_STDDEV
Lval = (longlong)sqrt((double)Lval);
} // end of StdVar
/***********************************************************************/
/* Times: used by aggregate functions for Stddev and Variance. */
/***********************************************************************/
void BIGVAL::Times(PVAL vp)
{
Lval = SafeMult(Lval, vp->GetBigintValue());
} // end of Times
/***********************************************************************/
/* Add: used by aggregate functions for Sum and other functions. */
/***********************************************************************/
void BIGVAL::Add(PVAL vp)
{
Lval = SafeAdd(Lval, vp->GetBigintValue());
} // end of Add
/***********************************************************************/
/* Add: used by QUERY for function Sum and other functions. */
/***********************************************************************/
void BIGVAL::Add(PVBLK vbp, int i)
{
Lval = SafeAdd(Lval, vbp->GetBigintValue(i));
} // end of Add
/***********************************************************************/
/* Add: used by QUERY for function Sum and other functions. */
/***********************************************************************/
void BIGVAL::Add(PVBLK vbp, int j, int k)
{
CheckType(vbp)
longlong *lp = (longlong *)vbp->GetValPointer();
for (register int i = j; i < k; i++)
Lval = SafeAdd(Lval, lp[i]);
} // end of Add
/***********************************************************************/
/* Add: used by QUERY for function Sum and other functions. */
/***********************************************************************/
void BIGVAL::Add(PVBLK vbp, int *x, int j, int k)
{
CheckType(vbp)
longlong *lp = (longlong *)vbp->GetValPointer();
for (register int i = j; i < k; i++)
Lval = SafeAdd(Lval, lp[x[i]]);
} // end of Add
/***********************************************************************/
/* AddSquare: used by aggregate functions for Stddev and Variance. */
/***********************************************************************/
void BIGVAL::AddSquare(PVAL vp)
{
longlong val = vp->GetBigintValue();
Lval = SafeAdd(Lval, SafeMult(val, val));
} // end of AddSquare
/***********************************************************************/
/* AddSquare: used by QUERY for functions Stddev and Variance. */
/***********************************************************************/
void BIGVAL::AddSquare(PVBLK vbp, int i)
{
longlong val = vbp->GetBigintValue(i);
Lval = SafeAdd(Lval, SafeMult(val, val));
} // end of AddSquare
/***********************************************************************/
/* AddSquare: used by QUERY for functions Stddev and Variance. */
/***********************************************************************/
void BIGVAL::AddSquare(PVBLK vbp, int j, int k)
{
CheckType(vbp)
longlong *lp = (longlong *)vbp->GetValPointer();
for (register int i = j; i < k; i++)
Lval = SafeAdd(Lval, SafeMult(lp[i], lp[i]));
} // end of AddSquare
/***********************************************************************/
/* FormatValue: This function set vp (a STRING value) to the string */
/* constructed from its own value formated using the fmt format. */
/* This function assumes that the format matches the value type. */
/***********************************************************************/
bool BIGVAL::FormatValue(PVAL vp, char *fmt)
{
char *buf = (char*)vp->GetTo_Val(); // Should be big enough
int n = sprintf(buf, fmt, Lval);
return (n > vp->GetValLen());
} // end of FormatValue
/***********************************************************************/
/* SetMin: used by the aggregate function MIN. */
/***********************************************************************/
void BIGVAL::SetMin(PVAL vp)
{
longlong val = vp->GetBigintValue();
if (val < Lval)
Lval = val;
} // end of SetMin
/***********************************************************************/
/* SetMin: used by QUERY for the aggregate function MIN. */
/***********************************************************************/
void BIGVAL::SetMin(PVBLK vbp, int i)
{
longlong val = vbp->GetBigintValue(i);
if (val < Lval)
Lval = val;
} // end of SetMin
/***********************************************************************/
/* SetMin: used by QUERY for the aggregate function MIN. */
/***********************************************************************/
void BIGVAL::SetMin(PVBLK vbp, int j, int k)
{
CheckType(vbp)
longlong *lp = (longlong *)vbp->GetValPointer();
for (register int i = j; i < k; i++)
if (lp[i] < Lval)
Lval = lp[i];
} // end of SetMin
/***********************************************************************/
/* SetMin: used by QUERY for the aggregate function MIN. */
/***********************************************************************/
void BIGVAL::SetMin(PVBLK vbp, int *x, int j, int k)
{
CheckType(vbp)
longlong val;
longlong *lp = (longlong *)vbp->GetValPointer();
for (register int i = j; i < k; i++) {
val = lp[x[i]];
if (val < Lval)
Lval = val;
} // endfor i
} // end of SetMin
/***********************************************************************/
/* SetMax: used by the aggregate function MAX. */
/***********************************************************************/
void BIGVAL::SetMax(PVAL vp)
{
longlong val = vp->GetBigintValue();
if (val > Lval)
Lval = val;
} // end of SetMax
/***********************************************************************/
/* SetMax: used by QUERY for the aggregate function MAX. */
/***********************************************************************/
void BIGVAL::SetMax(PVBLK vbp, int i)
{
longlong val = vbp->GetBigintValue(i);
if (val > Lval)
Lval = val;
} // end of SetMax
/***********************************************************************/
/* SetMax: used by QUERY for the aggregate function MAX. */
/***********************************************************************/
void BIGVAL::SetMax(PVBLK vbp, int j, int k)
{
CheckType(vbp)
longlong *lp = (longlong *)vbp->GetValPointer();
for (register int i = j; i < k; i++)
if (lp[i] > Lval)
Lval = lp[i];
} // end of SetMax
/***********************************************************************/
/* SetMax: used by QUERY for the aggregate function MIN. */
/***********************************************************************/
void BIGVAL::SetMax(PVBLK vbp, int *x, int j, int k)
{
CheckType(vbp)
longlong val;
longlong *lp = (longlong *)vbp->GetValPointer();
for (register int i = j; i < k; i++) {
val = lp[x[i]];
if (val > Lval)
Lval = val;
} // endfor i
} // end of SetMax
/***********************************************************************/
/* BIGVAL SetFormat function (used to set SELECT output format). */
/***********************************************************************/
bool BIGVAL::SetConstFormat(PGLOBAL g, FORMAT& fmt)
{
char c[16];
fmt.Type[0] = 'L';
fmt.Length = sprintf(c, "%lld", Lval);
fmt.Prec = 0;
return false;
} // end of SetConstFormat
/***********************************************************************/
/* Make file output of a big int object. */
/***********************************************************************/
void BIGVAL::Print(PGLOBAL g, FILE *f, uint n)
{
char m[64];
memset(m, ' ', n); /* Make margin string */
m[n] = '\0';
fprintf(f, "%s%lld\n", m, Lval);
} /* end of Print */
/***********************************************************************/
/* Make string output of a int object. */
/***********************************************************************/
void BIGVAL::Print(PGLOBAL g, char *ps, uint z)
{
sprintf(ps, "%lld", Lval);
} /* end of Print */
/* -------------------------- Class DFVAL ---------------------------- */
/***********************************************************************/
/* DFVAL public constructor from char. */
/***********************************************************************/
DFVAL::DFVAL(PSZ s, int prec) : VALUE(TYPE_FLOAT)
{
Fval = atof(s);
Prec = prec;
Clen = sizeof(double);
} // end of DFVAL constructor
/***********************************************************************/
/* DFVAL public constructor from short. */
/***********************************************************************/
DFVAL::DFVAL(short n, int prec) : VALUE(TYPE_FLOAT)
{
Fval = (double)n;
Prec = prec;
Clen = sizeof(double);
} // end of DFVAL constructor
/***********************************************************************/
/* DFVAL public constructor from int. */
/***********************************************************************/
DFVAL::DFVAL(int n, int prec) : VALUE(TYPE_FLOAT)
{
Fval = (double)n;
Prec = prec;
Clen = sizeof(double);
} // end of DFVAL constructor
/***********************************************************************/
/* DFVAL public constructor from double. */
/***********************************************************************/
DFVAL::DFVAL(double f, int prec) : VALUE(TYPE_FLOAT)
{
Fval = f;
Prec = prec;
Clen = sizeof(double);
} // end of DFVAL constructor
/***********************************************************************/
/* DFVAL GetValLen: returns the print length of the double object. */
/***********************************************************************/
int DFVAL::GetValLen(void)
{
char c[32];
return sprintf(c, "%.*lf", Prec, Fval);
} // end of GetValLen
/***********************************************************************/
/* DFVAL SetValue: copy the value of another Value object. */
/* This function allows conversion if chktype is false. */
/***********************************************************************/
bool DFVAL::SetValue_pval(PVAL valp, bool chktype)
{
if (chktype && Type != valp->GetType())
return true;
Fval = valp->GetFloatValue();
return false;
} // end of SetValue
/***********************************************************************/
/* SetValue: convert chars extracted from a line to double value. */
/***********************************************************************/
void DFVAL::SetValue_char(char *p, int n)
{
char *p2, buf[32];
for (p2 = p + n; p < p2 && *p == ' '; p++) ;
n = min(p2 - p, 31);
memcpy(buf, p, n);
buf[n] = '\0';
Fval = atof(buf);
if (trace)
htrc(" setting double: '%s' -> %lf\n", buf, Fval);
} // end of SetValue
/***********************************************************************/
/* DFVAL SetValue: fill a double float value from a string. */
/***********************************************************************/
void DFVAL::SetValue_psz(PSZ s)
{
Fval = atof(s);
} // end of SetValue
/***********************************************************************/
/* DFVAL SetValue: set value with a double extracted from a block. */
/***********************************************************************/
void DFVAL::SetValue_pvblk(PVBLK blk, int n)
{
Fval = blk->GetFloatValue(n);
} // end of SetValue
/***********************************************************************/
/* SetBinValue: with bytes extracted from a line. */
/***********************************************************************/
void DFVAL::SetBinValue(void *p)
{
Fval = *(double *)p;
} // end of SetBinValue
/***********************************************************************/
/* GetBinValue: fill a buffer with the internal binary value. */
/* This function checks whether the buffer length is enough and */
/* returns true if not. Actual filling occurs only if go is true. */
/* Currently used by WriteColumn of binary files. */
/***********************************************************************/
bool DFVAL::GetBinValue(void *buf, int buflen, bool go)
{
// Test on length was removed here until a variable in column give the
// real field length. For BIN files the field length logically cannot
// be different from the variable length because no conversion is done.
// Therefore this test is useless anyway.
//#if defined(_DEBUG)
// if (sizeof(double) > buflen)
// return true;
//#endif
if (go)
*(double *)buf = Fval;
return false;
} // end of GetBinValue
/***********************************************************************/
/* GetBinValue: used by SELECT when called from QUERY and KINDEX. */
/* This is a fast implementation that does not do any checking. */
/* Note: type is not needed here and just kept for compatibility. */
/***********************************************************************/
void DFVAL::GetBinValue(void *buf, int buflen)
{
assert(buflen == sizeof(double));
*(double *)buf = Fval;
} // end of GetBinValue
/***********************************************************************/
/* DFVAL ShowValue: get string representation of a double value. */
/***********************************************************************/
char *DFVAL::ShowValue(char *buf, int len)
{
// TODO: use snprintf to avoid possible overflow
sprintf(buf, "%*.*lf", len, Prec, Fval);
return buf;
} // end of ShowValue
/***********************************************************************/
/* DFVAL GetCharString: get string representation of a double value. */
/***********************************************************************/
char *DFVAL::GetCharString(char *p)
{
sprintf(p, "%.*lf", Prec, Fval);
return p;
} // end of GetCharString
/***********************************************************************/
/* DFVAL GetShortString: get short representation of a double value. */
/***********************************************************************/
char *DFVAL::GetShortString(char *p, int n)
{
sprintf(p, "%*hd", n, (short)Fval);
return p;
} // end of GetShortString
/***********************************************************************/
/* DFVAL GetIntString: get int representation of a double value. */
/***********************************************************************/
char *DFVAL::GetIntString(char *p, int n)
{
sprintf(p, "%*ld", n, (int)Fval);
return p;
} // end of GetIntString
/***********************************************************************/
/* DFVAL GetBigintString: get big int representation of a double val. */
/***********************************************************************/
char *DFVAL::GetBigintString(char *p, int n)
{
sprintf(p, "%*lld", n, (longlong)Fval);
return p;
} // end of GetBigintString
/***********************************************************************/
/* DFVAL GetFloatString: get double representation of a double value. */
/***********************************************************************/
char *DFVAL::GetFloatString(char *p, int n, int prec)
{
sprintf(p, "%*.*lf", n, (prec < 0) ? Prec : prec, Fval);
return p;
} // end of GetFloatString
/***********************************************************************/
/* DFVAL compare value with another Value. */
/***********************************************************************/
bool DFVAL::IsEqual(PVAL vp, bool chktype)
{
if (this == vp)
return true;
else if (chktype && Type != vp->GetType())
return false;
else
return (Fval == vp->GetFloatValue());
} // end of IsEqual
/***********************************************************************/
/* Compare values and returns 1, 0 or -1 according to comparison. */
/* This function is used for evaluation of double float filters. */
/***********************************************************************/
int DFVAL::CompareValue(PVAL vp)
{
//assert(vp->GetType() == Type);
// Process filtering on int integers.
double d = vp->GetFloatValue();
if (trace)
htrc(" Comparing: val=%.2f,%.2f\n", Fval, d);
return (Fval > d) ? 1 : (Fval < d) ? (-1) : 0;
} // end of CompareValue
/***********************************************************************/
/* Compute a function on double floats. */
/***********************************************************************/
bool DFVAL::Compute(PGLOBAL g, PVAL *vp, int np, OPVAL op)
{
double val[2];
assert(np <= 2);
for (int i = 0; i < np; i++)
val[i] = vp[i]->GetFloatValue();
switch (op) {
case OP_ABS:
assert(np == 1);
Fval = fabs(*val);
break;
case OP_CEIL:
assert(np == 1);
Fval = ceil(*val);
break;
case OP_FLOOR:
assert(np == 1);
Fval = floor(*val);
break;
case OP_SIGN:
assert(np == 1);
Fval = (*val < 0.0) ? (-1.0) : 1.0;
break;
case OP_ADD:
assert(np == 2);
Fval = val[0] + val[1];
break;
case OP_SUB:
assert(np == 2);
Fval = val[0] - val[1];
break;
case OP_MULT:
assert(np == 2);
Fval = val[0] * val[1];
break;
case OP_MIN:
assert(np == 2);
Fval = min(val[0], val[1]);
break;
case OP_MAX:
assert(np == 2);
Fval = max(val[0], val[1]);
break;
case OP_DIV:
assert(np == 2);
if (!val[1]) {
strcpy(g->Message, MSG(ZERO_DIVIDE));
return true;
} // endif
Fval = val[0] / val[1];
break;
case OP_MOD:
assert(np == 2);
Fval = fmod(val[0], val[1]);
break;
case OP_SQRT:
assert(np == 1);
Fval = sqrt(*val);
break;
case OP_LN:
assert(np == 1);
Fval = log(*val);
break;
case OP_EXP:
assert(np == 1);
Fval = exp(*val);
break;
case OP_COS:
assert(np == 1);
Fval = cos(*val);
break;
case OP_SIN:
assert(np == 1);
Fval = sin(*val);
break;
case OP_TAN:
assert(np == 1);
Fval = tan(*val);
break;
case OP_COSH:
assert(np == 1);
Fval = cosh(*val);
break;
case OP_SINH:
assert(np == 1);
Fval = sinh(*val);
break;
case OP_TANH:
assert(np == 1);
Fval = tanh(*val);
break;
case OP_LOG:
assert(np > 0);
if (np > 1 && val[1] != 10.0) {
strcpy(g->Message, MSG(ONLY_LOG10_IMPL));
return true;
} // endif Numarg
Fval = log10(val[0]);
break;
case OP_POWER:
assert(np == 2);
Fval = pow(val[0], val[1]);
break;
case OP_ROUND:
assert(np > 0);
if (np > 1) {
double dx, dy = val[1];
modf(dy, &dx); // Get integral part of arg
dx = pow(10.0, dx);
modf(val[0] * dx + 0.5, &dy);
Fval = dy / dx;
} else
modf(val[0] + 0.5, &Fval);
break;
case OP_DELTA:
// assert(np == 1);
Fval = val[0] - Fval;
break;
default:
sprintf(g->Message, MSG(BAD_EXP_OPER), op);
return true;
} // endswitch op
if (trace)
if (np == 1)
htrc("Compute result=%lf val=%lf op=%d\n", Fval, val[0], op);
else
htrc("Compute result=%lf val=%lf,%lf op=%d\n",
Fval, val[0], val[1], op);
return false;
} // end of Compute
/***********************************************************************/
/* GetTime: convert HR/MIN/SEC in a number of seconds. */
/***********************************************************************/
int DFVAL::GetTime(PGLOBAL g, PVAL *vp, int np)
{
double sec = Fval;
for (int i = 0; i < 2; i++) {
sec *= 60.0;
if (np > i)
sec += vp[i]->GetFloatValue();
} // endfor i
return (int)sec;
} // end of GetTime
/***********************************************************************/
/* Divide: used by aggregate functions when calculating average. */
/***********************************************************************/
void DFVAL::Divide(int cnt)
{
Fval /= (double)cnt;
} // end of Divide
/***********************************************************************/
/* StdVar: used by aggregate functions for Stddev and Variance. */
/***********************************************************************/
void DFVAL::StdVar(PVAL vp, int cnt, bool b)
{
double fv2 = vp->GetFloatValue();
double cnd = (double)cnt;
Fval = (cnt == 1) ? 0.0 : ((fv2 - (Fval * Fval) / cnd) / (cnd - 1.0));
if (b) // Builtin == FNC_STDDEV
Fval = sqrt(Fval);
} // end of StdVar
/***********************************************************************/
/* Times: used by aggregate functions for Stddev and Variance. */
/***********************************************************************/
void DFVAL::Times(PVAL vp)
{
Fval *= vp->GetFloatValue();
} // end of Times
/***********************************************************************/
/* Add: used by aggregate functions for Sum and other functions. */
/***********************************************************************/
void DFVAL::Add(PVAL vp)
{
Fval += vp->GetFloatValue();
} // end of Add
/***********************************************************************/
/* Add: used by aggregate functions for Sum and other functions. */
/***********************************************************************/
void DFVAL::Add(PVBLK vbp, int i)
{
Fval += vbp->GetFloatValue(i);
} // end of Add
/***********************************************************************/
/* Add: used by aggregate functions for Sum and other functions. */
/***********************************************************************/
void DFVAL::Add(PVBLK vbp, int j, int k)
{
CheckType(vbp)
double *dp = (double *)vbp->GetValPointer();
for (register int i = j; i < k; i++)
Fval += dp[i];
} // end of Add
/***********************************************************************/
/* Add: used by aggregate functions for Sum and other functions. */
/***********************************************************************/
void DFVAL::Add(PVBLK vbp, int *x, int j, int k)
{
CheckType(vbp)
double *dp = (double *)vbp->GetValPointer();
for (register int i = j; i < k; i++)
Fval += dp[x[i]];
} // end of Add
/***********************************************************************/
/* AddSquare: used by aggregate functions for Stddev and Variance. */
/***********************************************************************/
void DFVAL::AddSquare(PVAL vp)
{
double val = vp->GetFloatValue();
Fval += (val * val);
} // end of AddSquare
/***********************************************************************/
/* AddSquare: used by aggregate functions for Stddev and Variance. */
/***********************************************************************/
void DFVAL::AddSquare(PVBLK vbp, int i)
{
double val = vbp->GetFloatValue(i);
Fval += (val * val);
} // end of AddSquare
/***********************************************************************/
/* AddSquare: used by aggregate functions for Stddev and Variance. */
/***********************************************************************/
void DFVAL::AddSquare(PVBLK vbp, int j, int k)
{
CheckType(vbp)
double *dp = (double *)vbp->GetValPointer();
for (register int i = j; i < k; i++)
Fval += (dp[i] * dp[i]);
} // end of AddSquare
/***********************************************************************/
/* FormatValue: This function set vp (a STRING value) to the string */
/* constructed from its own value formated using the fmt format. */
/* This function assumes that the format matches the value type. */
/***********************************************************************/
bool DFVAL::FormatValue(PVAL vp, char *fmt)
{
char *buf = (char*)vp->GetTo_Val(); // Should be big enough
int n = sprintf(buf, fmt, Fval);
return (n > vp->GetValLen());
} // end of FormatValue
/***********************************************************************/
/* SetMin: used by the aggregate function MIN. */
/***********************************************************************/
void DFVAL::SetMin(PVAL vp)
{
double val = vp->GetFloatValue();
if (val < Fval)
Fval = val;
} // end of SetMin
/***********************************************************************/
/* SetMin: used by QUERY for the aggregate function MIN. */
/***********************************************************************/
void DFVAL::SetMin(PVBLK vbp, int i)
{
double val = vbp->GetFloatValue(i);
if (val < Fval)
Fval = val;
} // end of SetMin
/***********************************************************************/
/* SetMin: used by QUERY for the aggregate function MIN. */
/***********************************************************************/
void DFVAL::SetMin(PVBLK vbp, int j, int k)
{
CheckType(vbp)
double *dp = (double *)vbp->GetValPointer();
for (register int i = j; i < k; i++)
if (dp[i] < Fval)
Fval = dp[i];
} // end of SetMin
/***********************************************************************/
/* SetMax: used by QUERY for the aggregate function MIN. */
/***********************************************************************/
void DFVAL::SetMin(PVBLK vbp, int *x, int j, int k)
{
CheckType(vbp)
register double val;
double *dp = (double *)vbp->GetValPointer();
for (register int i = j; i < k; i++) {
val = dp[x[i]];
if (val < Fval)
Fval = val;
} // endfor i
} // end of SetMin
/***********************************************************************/
/* SetMax: used by the aggregate function MAX. */
/***********************************************************************/
void DFVAL::SetMax(PVAL vp)
{
double val = vp->GetFloatValue();
if (val > Fval)
Fval = val;
} // end of SetMax
/***********************************************************************/
/* SetMax: used by QUERY for the aggregate function MAX. */
/***********************************************************************/
void DFVAL::SetMax(PVBLK vbp, int i)
{
double val = vbp->GetFloatValue(i);
if (val > Fval)
Fval = val;
} // end of SetMax
/***********************************************************************/
/* SetMax: used by QUERY for the aggregate function MIN. */
/***********************************************************************/
void DFVAL::SetMax(PVBLK vbp, int j, int k)
{
CheckType(vbp)
double *dp = (double *)vbp->GetValPointer();
for (register int i = j; i < k; i++)
if (dp[i] > Fval)
Fval = dp[i];
} // end of SetMax
/***********************************************************************/
/* SetMax: used by QUERY for the aggregate function MIN. */
/***********************************************************************/
void DFVAL::SetMax(PVBLK vbp, int *x, int j, int k)
{
CheckType(vbp)
register double val;
double *dp = (double *)vbp->GetValPointer();
for (register int i = j; i < k; i++) {
val = dp[x[i]];
if (val > Fval)
Fval = val;
} // endfor i
} // end of SetMax
/***********************************************************************/
/* DFVAL SetFormat function (used to set SELECT output format). */
/***********************************************************************/
bool DFVAL::SetConstFormat(PGLOBAL g, FORMAT& fmt)
{
char c[32];
fmt.Type[0] = 'F';
fmt.Length = sprintf(c, "%.*lf", Prec, Fval);
fmt.Prec = Prec;
return false;
} // end of SetConstFormat
/***********************************************************************/
/* Make file output of a double object. */
/***********************************************************************/
void DFVAL::Print(PGLOBAL g, FILE *f, uint n)
{
char m[64];
memset(m, ' ', n); /* Make margin string */
m[n] = '\0';
fprintf(f, "%s%.*lf\n", m, Prec, Fval);
} /* end of Print */
/***********************************************************************/
/* Make string output of a double object. */
/***********************************************************************/
void DFVAL::Print(PGLOBAL g, char *ps, uint z)
{
sprintf(ps, "%.*lf", Prec, Fval);
} /* end of Print */
#endif // __VALUE_H
/* -------------------------- End of Value --------------------------- */