mirror of
https://github.com/MariaDB/server.git
synced 2025-01-17 20:42:30 +01:00
0219ac1e98
have been created by the last addition of new CONNECT features. The version previous to this one is a preliminary test version and should not be distributed. - Handle indexed UPDATE/DELETE. Previously this was just tested and an error message send when it could not be done. Now CONNECT can do it in all the cases. It is done by a MRR like tchnique by making a list of all update or delete to do, sort them, then execute them. modified: storage/connect/array.cpp storage/connect/array.h storage/connect/filamap.cpp storage/connect/filamap.h storage/connect/filamdbf.cpp storage/connect/filamfix.cpp storage/connect/filamfix.h storage/connect/filamtxt.cpp storage/connect/filamtxt.h storage/connect/filamvct.cpp storage/connect/filamvct.h storage/connect/filamzip.cpp storage/connect/filamzip.h storage/connect/global.h storage/connect/ha_connect.cc storage/connect/ha_connect.h - Differenciate Cardinality that returns a true or estimated table size and GetMaxSize that return a value equal or greater than the table row number. This fixes the errors of non matching opt files. modified: storage/connect/connect.cc storage/connect/tabdos.cpp storage/connect/tabdos.h storage/connect/tabfix.cpp storage/connect/table.cpp storage/connect/tabmac.h storage/connect/tabmysql.cpp storage/connect/tabmysql.h storage/connect/tabodbc.cpp storage/connect/tabodbc.h storage/connect/tabpivot.h storage/connect/tabtbl.cpp storage/connect/tabtbl.h storage/connect/tabutil.cpp storage/connect/tabutil.h storage/connect/tabwmi.h storage/connect/xtable.h - Fix some errors and issues when making index and opt files. Erase opt and index files for void tables. Fix wrong calculation of Block and Last in MakeBlockValues. Invalidate indexes before making opt file. Fully handle blocked variable tables. Make opt file for blocked variable tables even when they have no optimised colums. modified: storage/connect/tabdos.cpp storage/connect/xindex.h - Fix some errors making index Return an error when the allocation is too small (should not really occur now that GetMaxSize is sure) Don't use XXROW index for DBF tables because of soft deleted lines. modified: storage/connect/xindex.cpp - Typo modified: storage/connect/macutil.cpp storage/connect/tabdos.h storage/connect/tabsys.cpp storage/connect/tabsys.h
2638 lines
83 KiB
C++
2638 lines
83 KiB
C++
/************* Value C++ Functions Source Code File (.CPP) *************/
|
|
/* Name: VALUE.CPP Version 2.5 */
|
|
/* */
|
|
/* (C) Copyright to the author Olivier BERTRAND 2001-2014 */
|
|
/* */
|
|
/* 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, SHORT, TINY, */
|
|
/* DATE and LONGLONG. Recently we added some UNSIGNED types. */
|
|
/***********************************************************************/
|
|
|
|
/***********************************************************************/
|
|
/* Include relevant MariaDB header file. */
|
|
/***********************************************************************/
|
|
#include "my_global.h"
|
|
#include "sql_class.h"
|
|
#include "sql_time.h"
|
|
|
|
#if defined(WIN32)
|
|
//#include <windows.h>
|
|
#else // !WIN32
|
|
#include <string.h>
|
|
#endif // !WIN32
|
|
|
|
#include <math.h>
|
|
|
|
#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
|
|
#include "osutil.h"
|
|
|
|
/***********************************************************************/
|
|
/* 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. */
|
|
/***********************************************************************/
|
|
|
|
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], TYPE_ARRAY);
|
|
} // endswitch opc
|
|
|
|
return bt;
|
|
} // end of OpBmp
|
|
|
|
/***********************************************************************/
|
|
/* Get a long long number from its character representation. */
|
|
/* IN p: Pointer to the numeric string */
|
|
/* IN n: The string length */
|
|
/* IN maxval: The number max value */
|
|
/* IN un: True if the number must be unsigned */
|
|
/* OUT rc: Set to TRUE for out of range value */
|
|
/* OUT minus: Set to true if the number is negative */
|
|
/* Returned val: The resulting number */
|
|
/***********************************************************************/
|
|
ulonglong CharToNumber(char *p, int n, ulonglong maxval,
|
|
bool un, bool *minus, bool *rc)
|
|
{
|
|
char *p2;
|
|
uchar c;
|
|
ulonglong val;
|
|
|
|
if (minus) *minus = false;
|
|
if (rc) *rc = false;
|
|
|
|
// Eliminate leading blanks or 0
|
|
for (p2 = p + n; p < p2 && (*p == ' ' || *p == '0'); p++) ;
|
|
|
|
// Get an eventual sign character
|
|
switch (*p) {
|
|
case '-':
|
|
if (un) {
|
|
if (rc) *rc = true;
|
|
return 0;
|
|
} else {
|
|
maxval++;
|
|
if (minus) *minus = true;
|
|
} // endif Unsigned
|
|
|
|
case '+':
|
|
p++;
|
|
break;
|
|
} // endswitch *p
|
|
|
|
for (val = 0; p < p2 && (c = (uchar)(*p - '0')) < 10; p++)
|
|
if (val > (maxval - c) / 10) {
|
|
val = maxval;
|
|
if (rc) *rc = true;
|
|
break;
|
|
} else
|
|
val = val * 10 + c;
|
|
|
|
return val;
|
|
} // end of CharToNumber
|
|
|
|
/***********************************************************************/
|
|
/* GetTypeName: returns the PlugDB internal type name. */
|
|
/***********************************************************************/
|
|
PSZ GetTypeName(int type)
|
|
{
|
|
PSZ name;
|
|
|
|
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_DOUBLE: name = "DOUBLE"; break;
|
|
case TYPE_TINY: name = "TINY"; break;
|
|
case TYPE_DECIM: name = "DECIMAL"; break;
|
|
case TYPE_BIN: name = "BINARY"; break;
|
|
case TYPE_PCHAR: name = "PCHAR"; break;
|
|
default: name = "UNKNOWN"; 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_DECIM:
|
|
case TYPE_BIN:
|
|
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_DOUBLE: len = sizeof(double); break;
|
|
case TYPE_TINY: len = sizeof(char); break;
|
|
case TYPE_PCHAR: len = sizeof(char*); break;
|
|
default: len = 0;
|
|
} // endswitch type
|
|
|
|
return len;
|
|
} // end of GetTypeSize
|
|
|
|
/***********************************************************************/
|
|
/* 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_DOUBLE: c = "F"; break;
|
|
case TYPE_DATE: c = "D"; break;
|
|
case TYPE_TINY: c = "T"; break;
|
|
case TYPE_DECIM: c = "M"; break;
|
|
case TYPE_BIN: c = "B"; break;
|
|
case TYPE_PCHAR: c = "P"; 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_DOUBLE; break;
|
|
case 'D': type = TYPE_DATE; break;
|
|
case 'T': type = TYPE_TINY; break;
|
|
case 'M': type = TYPE_DECIM; break;
|
|
case 'B': type = TYPE_BIN; break;
|
|
case 'P': type = TYPE_PCHAR; break;
|
|
} // endswitch type
|
|
|
|
return type;
|
|
} // end of GetFormatType
|
|
|
|
/***********************************************************************/
|
|
/* IsTypeChar: returns true for character type(s). */
|
|
/***********************************************************************/
|
|
bool IsTypeChar(int type)
|
|
{
|
|
switch (type) {
|
|
case TYPE_STRING:
|
|
case TYPE_DECIM:
|
|
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_DOUBLE:
|
|
case TYPE_SHORT:
|
|
case TYPE_NUM:
|
|
case TYPE_TINY:
|
|
case TYPE_DECIM:
|
|
return true;
|
|
} // endswitch type
|
|
|
|
return false;
|
|
} // end of IsTypeNum
|
|
|
|
/***********************************************************************/
|
|
/* GetFmt: returns the format to use with a typed value. */
|
|
/***********************************************************************/
|
|
const char *GetFmt(int type, bool un)
|
|
{
|
|
const char *fmt;
|
|
|
|
switch (type) {
|
|
case TYPE_DECIM:
|
|
case TYPE_STRING: fmt = "%s"; break;
|
|
case TYPE_SHORT: fmt = (un) ? "%hu" : "%hd"; break;
|
|
case TYPE_BIGINT: fmt = (un) ? "%llu" : "%lld"; break;
|
|
case TYPE_DOUBLE: fmt = "%.*lf"; break;
|
|
case TYPE_BIN: fmt = "%*x"; break;
|
|
default: fmt = (un) ? "%u" : "%d"; break;
|
|
} // endswitch Type
|
|
|
|
return fmt;
|
|
} // end of GetFmt
|
|
|
|
/***********************************************************************/
|
|
/* 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_DOUBLE || type == TYPE_DOUBLE) ? TYPE_DOUBLE
|
|
: (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
|
|
: TYPE_TINY;
|
|
default:
|
|
if (target == TYPE_ERROR || target == type)
|
|
return type;
|
|
|
|
if (match && ((IsTypeChar(target) && !IsTypeChar(type)) ||
|
|
(IsTypeNum(target) && !IsTypeNum(type))))
|
|
return TYPE_ERROR;
|
|
|
|
return (target == TYPE_DOUBLE || type == TYPE_DOUBLE) ? TYPE_DOUBLE
|
|
: (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
|
|
: (target == TYPE_TINY || type == TYPE_TINY) ? TYPE_TINY
|
|
: 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) TYPVAL<PSZ>((PSZ)value);
|
|
break;
|
|
case TYPE_SHORT:
|
|
valp = new(g) TYPVAL<short>(*(short*)value, TYPE_SHORT);
|
|
break;
|
|
case TYPE_INT:
|
|
valp = new(g) TYPVAL<int>(*(int*)value, TYPE_INT);
|
|
break;
|
|
case TYPE_BIGINT:
|
|
valp = new(g) TYPVAL<longlong>(*(longlong*)value, TYPE_BIGINT);
|
|
break;
|
|
case TYPE_DOUBLE:
|
|
valp = new(g) TYPVAL<double>(*(double *)value, TYPE_DOUBLE, 2);
|
|
break;
|
|
case TYPE_TINY:
|
|
valp = new(g) TYPVAL<char>(*(char *)value, TYPE_TINY);
|
|
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,
|
|
bool uns, PSZ fmt)
|
|
{
|
|
PVAL valp;
|
|
|
|
switch (type) {
|
|
case TYPE_STRING:
|
|
valp = new(g) TYPVAL<PSZ>(g, (PSZ)NULL, len, prec);
|
|
break;
|
|
case TYPE_DATE:
|
|
valp = new(g) DTVAL(g, len, prec, fmt);
|
|
break;
|
|
case TYPE_INT:
|
|
if (uns)
|
|
valp = new(g) TYPVAL<uint>((uint)0, TYPE_INT, 0, true);
|
|
else
|
|
valp = new(g) TYPVAL<int>((int)0, TYPE_INT);
|
|
|
|
break;
|
|
case TYPE_BIGINT:
|
|
if (uns)
|
|
valp = new(g) TYPVAL<ulonglong>((ulonglong)0, TYPE_BIGINT, 0, true);
|
|
else
|
|
valp = new(g) TYPVAL<longlong>((longlong)0, TYPE_BIGINT);
|
|
|
|
break;
|
|
case TYPE_SHORT:
|
|
if (uns)
|
|
valp = new(g) TYPVAL<ushort>((ushort)0, TYPE_SHORT, 0, true);
|
|
else
|
|
valp = new(g) TYPVAL<short>((short)0, TYPE_SHORT);
|
|
|
|
break;
|
|
case TYPE_DOUBLE:
|
|
valp = new(g) TYPVAL<double>(0.0, TYPE_DOUBLE, prec);
|
|
break;
|
|
case TYPE_TINY:
|
|
if (uns)
|
|
valp = new(g) TYPVAL<uchar>((uchar)0, TYPE_TINY, 0, true);
|
|
else
|
|
valp = new(g) TYPVAL<char>((char)0, TYPE_TINY);
|
|
|
|
break;
|
|
case TYPE_DECIM:
|
|
valp = new(g) DECVAL(g, (PSZ)NULL, len, prec, uns);
|
|
break;
|
|
case TYPE_BIN:
|
|
valp = new(g) BINVAL(g, (void*)NULL, len, 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, int uns)
|
|
{
|
|
PSZ p, sp;
|
|
bool un = (uns < 0) ? false : (uns > 0) ? true : valp->IsUnsigned();
|
|
|
|
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) TYPVAL<PSZ>(g, p, valp->GetValLen(), valp->GetValPrec());
|
|
break;
|
|
case TYPE_SHORT:
|
|
if (un)
|
|
valp = new(g) TYPVAL<ushort>(valp->GetUShortValue(),
|
|
TYPE_SHORT, 0, true);
|
|
else
|
|
valp = new(g) TYPVAL<short>(valp->GetShortValue(), TYPE_SHORT);
|
|
|
|
break;
|
|
case TYPE_INT:
|
|
if (un)
|
|
valp = new(g) TYPVAL<uint>(valp->GetUIntValue(), TYPE_INT, 0, true);
|
|
else
|
|
valp = new(g) TYPVAL<int>(valp->GetIntValue(), TYPE_INT);
|
|
|
|
break;
|
|
case TYPE_BIGINT:
|
|
if (un)
|
|
valp = new(g) TYPVAL<ulonglong>(valp->GetUBigintValue(),
|
|
TYPE_BIGINT, 0, true);
|
|
else
|
|
valp = new(g) TYPVAL<longlong>(valp->GetBigintValue(), TYPE_BIGINT);
|
|
|
|
break;
|
|
case TYPE_DATE:
|
|
valp = new(g) DTVAL(g, valp->GetIntValue());
|
|
break;
|
|
case TYPE_DOUBLE:
|
|
valp = new(g) TYPVAL<double>(valp->GetFloatValue(), TYPE_DOUBLE,
|
|
valp->GetValPrec());
|
|
break;
|
|
case TYPE_TINY:
|
|
if (un)
|
|
valp = new(g) TYPVAL<uchar>(valp->GetUTinyValue(),
|
|
TYPE_TINY, 0, true);
|
|
else
|
|
valp = new(g) TYPVAL<char>(valp->GetTinyValue(), TYPE_TINY);
|
|
|
|
break;
|
|
default:
|
|
sprintf(g->Message, MSG(BAD_VALUE_TYPE), newtype);
|
|
return NULL;
|
|
} // endswitch type
|
|
|
|
valp->SetGlobal(g);
|
|
return valp;
|
|
} // end of AllocateValue
|
|
|
|
/* -------------------------- Class VALUE ---------------------------- */
|
|
|
|
/***********************************************************************/
|
|
/* Class VALUE protected constructor. */
|
|
/***********************************************************************/
|
|
VALUE::VALUE(int type, bool un) : Type(type)
|
|
{
|
|
Null = false;
|
|
Nullable = false;
|
|
Unsigned = un;
|
|
Clen = 0;
|
|
Prec = 0;
|
|
Fmt = GetFmt(Type, Unsigned);
|
|
Xfmt = GetXfmt();
|
|
} // end of VALUE constructor
|
|
|
|
/***********************************************************************/
|
|
/* VALUE GetXfmt: returns the extended format to use with typed value. */
|
|
/***********************************************************************/
|
|
const char *VALUE::GetXfmt(void)
|
|
{
|
|
const char *fmt;
|
|
|
|
switch (Type) {
|
|
case TYPE_DECIM:
|
|
case TYPE_STRING: fmt = "%*s"; break;
|
|
case TYPE_SHORT: fmt = (Unsigned) ? "%*hu" : "%*hd"; break;
|
|
case TYPE_BIGINT: fmt = (Unsigned) ? "%*llu" : "%*lld"; break;
|
|
case TYPE_DOUBLE: fmt = "%*.*lf"; break;
|
|
case TYPE_BIN: fmt = "%*x"; break;
|
|
default: fmt = (Unsigned) ? "%*u" : "%*d"; break;
|
|
} // endswitch Type
|
|
|
|
return fmt;
|
|
} // end of GetFmt
|
|
|
|
/***********************************************************************/
|
|
/* 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 TYPVAL ---------------------------- */
|
|
|
|
/***********************************************************************/
|
|
/* TYPVAL public constructor from a constant typed value. */
|
|
/***********************************************************************/
|
|
template <class TYPE>
|
|
TYPVAL<TYPE>::TYPVAL(TYPE n, int type, int prec, bool un)
|
|
: VALUE(type, un)
|
|
{
|
|
Tval = n;
|
|
Clen = sizeof(TYPE);
|
|
Prec = prec;
|
|
} // end of TYPVAL constructor
|
|
|
|
/***********************************************************************/
|
|
/* Return unsigned max value for the type. */
|
|
/***********************************************************************/
|
|
template <class TYPE>
|
|
ulonglong TYPVAL<TYPE>::MaxVal(void) {DBUG_ASSERT(false); return 0;}
|
|
|
|
template <>
|
|
ulonglong TYPVAL<short>::MaxVal(void) {return INT_MAX16;}
|
|
|
|
template <>
|
|
ulonglong TYPVAL<ushort>::MaxVal(void) {return UINT_MAX16;}
|
|
|
|
template <>
|
|
ulonglong TYPVAL<int>::MaxVal(void) {return INT_MAX32;}
|
|
|
|
template <>
|
|
ulonglong TYPVAL<uint>::MaxVal(void) {return UINT_MAX32;}
|
|
|
|
template <>
|
|
ulonglong TYPVAL<char>::MaxVal(void) {return INT_MAX8;}
|
|
|
|
template <>
|
|
ulonglong TYPVAL<uchar>::MaxVal(void) {return UINT_MAX8;}
|
|
|
|
template <>
|
|
ulonglong TYPVAL<longlong>::MaxVal(void) {return INT_MAX64;}
|
|
|
|
template <>
|
|
ulonglong TYPVAL<ulonglong>::MaxVal(void) {return ULONGLONG_MAX;}
|
|
|
|
/***********************************************************************/
|
|
/* TYPVAL GetValLen: returns the print length of the typed object. */
|
|
/***********************************************************************/
|
|
template <class TYPE>
|
|
int TYPVAL<TYPE>::GetValLen(void)
|
|
{
|
|
char c[32];
|
|
|
|
return sprintf(c, Fmt, Tval);
|
|
} // end of GetValLen
|
|
|
|
template <>
|
|
int TYPVAL<double>::GetValLen(void)
|
|
{
|
|
char c[32];
|
|
|
|
return sprintf(c, Fmt, Prec, Tval);
|
|
} // end of GetValLen
|
|
|
|
/***********************************************************************/
|
|
/* TYPVAL SetValue: copy the value of another Value object. */
|
|
/* This function allows conversion if chktype is false. */
|
|
/***********************************************************************/
|
|
template <class TYPE>
|
|
bool TYPVAL<TYPE>::SetValue_pval(PVAL valp, bool chktype)
|
|
{
|
|
if (chktype && Type != valp->GetType())
|
|
return true;
|
|
|
|
if (!(Null = valp->IsNull() && Nullable))
|
|
Tval = GetTypedValue(valp);
|
|
else
|
|
Reset();
|
|
|
|
return false;
|
|
} // end of SetValue
|
|
|
|
template <>
|
|
short TYPVAL<short>::GetTypedValue(PVAL valp)
|
|
{return valp->GetShortValue();}
|
|
|
|
template <>
|
|
ushort TYPVAL<ushort>::GetTypedValue(PVAL valp)
|
|
{return valp->GetUShortValue();}
|
|
|
|
template <>
|
|
int TYPVAL<int>::GetTypedValue(PVAL valp)
|
|
{return valp->GetIntValue();}
|
|
|
|
template <>
|
|
uint TYPVAL<uint>::GetTypedValue(PVAL valp)
|
|
{return valp->GetUIntValue();}
|
|
|
|
template <>
|
|
longlong TYPVAL<longlong>::GetTypedValue(PVAL valp)
|
|
{return valp->GetBigintValue();}
|
|
|
|
template <>
|
|
ulonglong TYPVAL<ulonglong>::GetTypedValue(PVAL valp)
|
|
{return valp->GetUBigintValue();}
|
|
|
|
template <>
|
|
double TYPVAL<double>::GetTypedValue(PVAL valp)
|
|
{return valp->GetFloatValue();}
|
|
|
|
template <>
|
|
char TYPVAL<char>::GetTypedValue(PVAL valp)
|
|
{return valp->GetTinyValue();}
|
|
|
|
template <>
|
|
uchar TYPVAL<uchar>::GetTypedValue(PVAL valp)
|
|
{return valp->GetUTinyValue();}
|
|
|
|
/***********************************************************************/
|
|
/* TYPVAL SetValue: convert chars extracted from a line to TYPE value.*/
|
|
/***********************************************************************/
|
|
template <class TYPE>
|
|
bool TYPVAL<TYPE>::SetValue_char(char *p, int n)
|
|
{
|
|
bool rc, minus;
|
|
ulonglong maxval = MaxVal();
|
|
ulonglong val = CharToNumber(p, n, maxval, Unsigned, &minus, &rc);
|
|
|
|
if (minus && val < maxval)
|
|
Tval = (TYPE)(-(signed)val);
|
|
else
|
|
Tval = (TYPE)val;
|
|
|
|
if (trace > 1) {
|
|
char buf[64];
|
|
htrc(strcat(strcat(strcpy(buf, " setting %s to: "), Fmt), "\n"),
|
|
GetTypeName(Type), Tval);
|
|
} // endif trace
|
|
|
|
Null = false;
|
|
return rc;
|
|
} // end of SetValue
|
|
|
|
template <>
|
|
bool TYPVAL<double>::SetValue_char(char *p, int n)
|
|
{
|
|
if (p) {
|
|
char buf[64];
|
|
|
|
for (; n > 0 && *p == ' '; p++)
|
|
n--;
|
|
|
|
memcpy(buf, p, MY_MIN(n, 31));
|
|
buf[n] = '\0';
|
|
Tval = atof(buf);
|
|
|
|
if (trace > 1)
|
|
htrc(" setting double: '%s' -> %lf\n", buf, Tval);
|
|
|
|
Null = false;
|
|
} else {
|
|
Reset();
|
|
Null = Nullable;
|
|
} // endif p
|
|
|
|
return false;
|
|
} // end of SetValue
|
|
|
|
/***********************************************************************/
|
|
/* TYPVAL SetValue: fill a typed value from a string. */
|
|
/***********************************************************************/
|
|
template <class TYPE>
|
|
void TYPVAL<TYPE>::SetValue_psz(PSZ s)
|
|
{
|
|
if (s) {
|
|
SetValue_char(s, (int)strlen(s));
|
|
Null = false;
|
|
} else {
|
|
Reset();
|
|
Null = Nullable;
|
|
} // endif p
|
|
|
|
} // end of SetValue
|
|
|
|
/***********************************************************************/
|
|
/* TYPVAL SetValue: set value with a TYPE extracted from a block. */
|
|
/***********************************************************************/
|
|
template <class TYPE>
|
|
void TYPVAL<TYPE>::SetValue_pvblk(PVBLK blk, int n)
|
|
{
|
|
Tval = GetTypedValue(blk, n);
|
|
Null = false;
|
|
} // end of SetValue
|
|
|
|
template <>
|
|
int TYPVAL<int>::GetTypedValue(PVBLK blk, int n)
|
|
{return blk->GetIntValue(n);}
|
|
|
|
template <>
|
|
uint TYPVAL<uint>::GetTypedValue(PVBLK blk, int n)
|
|
{return blk->GetUIntValue(n);}
|
|
|
|
template <>
|
|
short TYPVAL<short>::GetTypedValue(PVBLK blk, int n)
|
|
{return blk->GetShortValue(n);}
|
|
|
|
template <>
|
|
ushort TYPVAL<ushort>::GetTypedValue(PVBLK blk, int n)
|
|
{return blk->GetUShortValue(n);}
|
|
|
|
template <>
|
|
longlong TYPVAL<longlong>::GetTypedValue(PVBLK blk, int n)
|
|
{return blk->GetBigintValue(n);}
|
|
|
|
template <>
|
|
ulonglong TYPVAL<ulonglong>::GetTypedValue(PVBLK blk, int n)
|
|
{return blk->GetUBigintValue(n);}
|
|
|
|
template <>
|
|
double TYPVAL<double>::GetTypedValue(PVBLK blk, int n)
|
|
{return blk->GetFloatValue(n);}
|
|
|
|
template <>
|
|
char TYPVAL<char>::GetTypedValue(PVBLK blk, int n)
|
|
{return blk->GetTinyValue(n);}
|
|
|
|
template <>
|
|
uchar TYPVAL<uchar>::GetTypedValue(PVBLK blk, int n)
|
|
{return blk->GetUTinyValue(n);}
|
|
|
|
/***********************************************************************/
|
|
/* TYPVAL SetBinValue: with bytes extracted from a line. */
|
|
/***********************************************************************/
|
|
template <class TYPE>
|
|
void TYPVAL<TYPE>::SetBinValue(void *p)
|
|
{
|
|
Tval = *(TYPE *)p;
|
|
Null = false;
|
|
} // 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. */
|
|
/***********************************************************************/
|
|
template <class TYPE>
|
|
bool TYPVAL<TYPE>::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(TYPE) > buflen)
|
|
// return true;
|
|
//#endif
|
|
|
|
if (go)
|
|
*(TYPE *)buf = Tval;
|
|
|
|
Null = false;
|
|
return false;
|
|
} // end of GetBinValue
|
|
|
|
/***********************************************************************/
|
|
/* TYPVAL ShowValue: get string representation of a typed value. */
|
|
/***********************************************************************/
|
|
template <class TYPE>
|
|
char *TYPVAL<TYPE>::ShowValue(char *buf, int len)
|
|
{
|
|
sprintf(buf, Xfmt, len, Tval);
|
|
return buf;
|
|
} // end of ShowValue
|
|
|
|
template <>
|
|
char *TYPVAL<double>::ShowValue(char *buf, int len)
|
|
{
|
|
// TODO: use snprintf to avoid possible overflow
|
|
sprintf(buf, Xfmt, len, Prec, Tval);
|
|
return buf;
|
|
} // end of ShowValue
|
|
|
|
/***********************************************************************/
|
|
/* TYPVAL GetCharString: get string representation of a typed value. */
|
|
/***********************************************************************/
|
|
template <class TYPE>
|
|
char *TYPVAL<TYPE>::GetCharString(char *p)
|
|
{
|
|
sprintf(p, Fmt, Tval);
|
|
return p;
|
|
} // end of GetCharString
|
|
|
|
template <>
|
|
char *TYPVAL<double>::GetCharString(char *p)
|
|
{
|
|
sprintf(p, Fmt, Prec, Tval);
|
|
return p;
|
|
} // end of GetCharString
|
|
|
|
#if 0
|
|
/***********************************************************************/
|
|
/* TYPVAL GetShortString: get short representation of a typed value. */
|
|
/***********************************************************************/
|
|
template <class TYPE>
|
|
char *TYPVAL<TYPE>::GetShortString(char *p, int n)
|
|
{
|
|
sprintf(p, "%*hd", n, (short)Tval);
|
|
return p;
|
|
} // end of GetShortString
|
|
|
|
/***********************************************************************/
|
|
/* TYPVAL GetIntString: get int representation of a typed value. */
|
|
/***********************************************************************/
|
|
template <class TYPE>
|
|
char *TYPVAL<TYPE>::GetIntString(char *p, int n)
|
|
{
|
|
sprintf(p, "%*d", n, (int)Tval);
|
|
return p;
|
|
} // end of GetIntString
|
|
|
|
/***********************************************************************/
|
|
/* TYPVAL GetBigintString: get big int representation of a TYPE value.*/
|
|
/***********************************************************************/
|
|
template <class TYPE>
|
|
char *TYPVAL<TYPE>::GetBigintString(char *p, int n)
|
|
{
|
|
sprintf(p, "%*lld", n, (longlong)Tval);
|
|
return p;
|
|
} // end of GetBigintString
|
|
|
|
/***********************************************************************/
|
|
/* TYPVAL GetFloatString: get double representation of a typed value. */
|
|
/***********************************************************************/
|
|
template <class TYPE>
|
|
char *TYPVAL<TYPE>::GetFloatString(char *p, int n, int prec)
|
|
{
|
|
sprintf(p, "%*.*lf", n, (prec < 0) ? 2 : prec, (double)Tval);
|
|
return p;
|
|
} // end of GetFloatString
|
|
|
|
/***********************************************************************/
|
|
/* TYPVAL GetTinyString: get char representation of a typed value. */
|
|
/***********************************************************************/
|
|
template <class TYPE>
|
|
char *TYPVAL<TYPE>::GetTinyString(char *p, int n)
|
|
{
|
|
sprintf(p, "%*d", n, (int)(char)Tval);
|
|
return p;
|
|
} // end of GetIntString
|
|
#endif // 0
|
|
|
|
/***********************************************************************/
|
|
/* TYPVAL compare value with another Value. */
|
|
/***********************************************************************/
|
|
template <class TYPE>
|
|
bool TYPVAL<TYPE>::IsEqual(PVAL vp, bool chktype)
|
|
{
|
|
if (this == vp)
|
|
return true;
|
|
else if (chktype && Type != vp->GetType())
|
|
return false;
|
|
else if (chktype && Unsigned != vp->IsUnsigned())
|
|
return false;
|
|
else if (Null || vp->IsNull())
|
|
return false;
|
|
else
|
|
return (Tval == GetTypedValue(vp));
|
|
|
|
} // end of IsEqual
|
|
|
|
/***********************************************************************/
|
|
/* Compare values and returns 1, 0 or -1 according to comparison. */
|
|
/* This function is used for evaluation of numeric filters. */
|
|
/***********************************************************************/
|
|
template <class TYPE>
|
|
int TYPVAL<TYPE>::CompareValue(PVAL vp)
|
|
{
|
|
//assert(vp->GetType() == Type);
|
|
|
|
// Process filtering on numeric values.
|
|
TYPE n = GetTypedValue(vp);
|
|
|
|
//if (trace)
|
|
// htrc(" Comparing: val=%d,%d\n", Tval, n);
|
|
|
|
return (Tval > n) ? 1 : (Tval < n) ? (-1) : 0;
|
|
} // end of CompareValue
|
|
|
|
/***********************************************************************/
|
|
/* 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. */
|
|
/***********************************************************************/
|
|
template <class TYPE>
|
|
bool TYPVAL<TYPE>::FormatValue(PVAL vp, char *fmt)
|
|
{
|
|
char *buf = (char*)vp->GetTo_Val(); // Should be big enough
|
|
int n = sprintf(buf, fmt, Tval);
|
|
|
|
return (n > vp->GetValLen());
|
|
} // end of FormatValue
|
|
|
|
/***********************************************************************/
|
|
/* TYPVAL SetFormat function (used to set SELECT output format). */
|
|
/***********************************************************************/
|
|
template <class TYPE>
|
|
bool TYPVAL<TYPE>::SetConstFormat(PGLOBAL g, FORMAT& fmt)
|
|
{
|
|
char c[32];
|
|
|
|
fmt.Type[0] = *GetFormatType(Type);
|
|
fmt.Length = sprintf(c, Fmt, Tval);
|
|
fmt.Prec = Prec;
|
|
return false;
|
|
} // end of SetConstFormat
|
|
|
|
/***********************************************************************/
|
|
/* Make file output of a typed object. */
|
|
/***********************************************************************/
|
|
template <class TYPE>
|
|
void TYPVAL<TYPE>::Print(PGLOBAL g, FILE *f, uint n)
|
|
{
|
|
char m[64], buf[12];
|
|
|
|
memset(m, ' ', n); /* Make margin string */
|
|
m[n] = '\0';
|
|
|
|
if (Null)
|
|
fprintf(f, "%s<null>\n", m);
|
|
else
|
|
fprintf(f, strcat(strcat(strcpy(buf, "%s"), Fmt), "\n"), m, Tval);
|
|
|
|
} /* end of Print */
|
|
|
|
/***********************************************************************/
|
|
/* Make string output of a int object. */
|
|
/***********************************************************************/
|
|
template <class TYPE>
|
|
void TYPVAL<TYPE>::Print(PGLOBAL g, char *ps, uint z)
|
|
{
|
|
if (Null)
|
|
strcpy(ps, "<null>");
|
|
else
|
|
sprintf(ps, Fmt, Tval);
|
|
|
|
} /* end of Print */
|
|
|
|
/* -------------------------- Class STRING --------------------------- */
|
|
|
|
/***********************************************************************/
|
|
/* STRING public constructor from a constant string. */
|
|
/***********************************************************************/
|
|
TYPVAL<PSZ>::TYPVAL(PSZ s) : VALUE(TYPE_STRING)
|
|
{
|
|
Strp = s;
|
|
Len = strlen(s);
|
|
Clen = Len;
|
|
Ci = false;
|
|
} // end of STRING constructor
|
|
|
|
/***********************************************************************/
|
|
/* STRING public constructor from char. */
|
|
/***********************************************************************/
|
|
TYPVAL<PSZ>::TYPVAL(PGLOBAL g, PSZ s, int n, int c)
|
|
: VALUE(TYPE_STRING)
|
|
{
|
|
Len = (g) ? n : strlen(s);
|
|
|
|
if (!s) {
|
|
if (g) {
|
|
Strp = (char *)PlugSubAlloc(g, NULL, Len + 1);
|
|
Strp[Len] = '\0';
|
|
} else
|
|
assert(false);
|
|
|
|
} else
|
|
Strp = s;
|
|
|
|
Clen = Len;
|
|
Ci = (c != 0);
|
|
} // end of STRING constructor
|
|
|
|
/***********************************************************************/
|
|
/* Get the tiny value represented by the Strp string. */
|
|
/***********************************************************************/
|
|
char TYPVAL<PSZ>::GetTinyValue(void)
|
|
{
|
|
bool m;
|
|
ulonglong val = CharToNumber(Strp, strlen(Strp), INT_MAX8, false, &m);
|
|
|
|
return (m && val < INT_MAX8) ? (char)(-(signed)val) : (char)val;
|
|
} // end of GetTinyValue
|
|
|
|
/***********************************************************************/
|
|
/* Get the unsigned tiny value represented by the Strp string. */
|
|
/***********************************************************************/
|
|
uchar TYPVAL<PSZ>::GetUTinyValue(void)
|
|
{
|
|
return (uchar)CharToNumber(Strp, strlen(Strp), UINT_MAX8, true);
|
|
} // end of GetUTinyValue
|
|
|
|
/***********************************************************************/
|
|
/* Get the short value represented by the Strp string. */
|
|
/***********************************************************************/
|
|
short TYPVAL<PSZ>::GetShortValue(void)
|
|
{
|
|
bool m;
|
|
ulonglong val = CharToNumber(Strp, strlen(Strp), INT_MAX16, false, &m);
|
|
|
|
return (m && val < INT_MAX16) ? (short)(-(signed)val) : (short)val;
|
|
} // end of GetShortValue
|
|
|
|
/***********************************************************************/
|
|
/* Get the unsigned short value represented by the Strp string. */
|
|
/***********************************************************************/
|
|
ushort TYPVAL<PSZ>::GetUShortValue(void)
|
|
{
|
|
return (ushort)CharToNumber(Strp, strlen(Strp), UINT_MAX16, true);
|
|
} // end of GetUshortValue
|
|
|
|
/***********************************************************************/
|
|
/* Get the integer value represented by the Strp string. */
|
|
/***********************************************************************/
|
|
int TYPVAL<PSZ>::GetIntValue(void)
|
|
{
|
|
bool m;
|
|
ulonglong val = CharToNumber(Strp, strlen(Strp), INT_MAX32, false, &m);
|
|
|
|
return (m && val < INT_MAX32) ? (int)(-(signed)val) : (int)val;
|
|
} // end of GetIntValue
|
|
|
|
/***********************************************************************/
|
|
/* Get the unsigned integer value represented by the Strp string. */
|
|
/***********************************************************************/
|
|
uint TYPVAL<PSZ>::GetUIntValue(void)
|
|
{
|
|
return (uint)CharToNumber(Strp, strlen(Strp), UINT_MAX32, true);
|
|
} // end of GetUintValue
|
|
|
|
/***********************************************************************/
|
|
/* Get the big integer value represented by the Strp string. */
|
|
/***********************************************************************/
|
|
longlong TYPVAL<PSZ>::GetBigintValue(void)
|
|
{
|
|
bool m;
|
|
ulonglong val = CharToNumber(Strp, strlen(Strp), INT_MAX64, false, &m);
|
|
|
|
return (m && val < INT_MAX64) ? (-(signed)val) : (longlong)val;
|
|
} // end of GetBigintValue
|
|
|
|
/***********************************************************************/
|
|
/* Get the unsigned big integer value represented by the Strp string. */
|
|
/***********************************************************************/
|
|
ulonglong TYPVAL<PSZ>::GetUBigintValue(void)
|
|
{
|
|
return CharToNumber(Strp, strlen(Strp), ULONGLONG_MAX, true);
|
|
} // end of GetUBigintValue
|
|
|
|
/***********************************************************************/
|
|
/* STRING SetValue: copy the value of another Value object. */
|
|
/***********************************************************************/
|
|
bool TYPVAL<PSZ>::SetValue_pval(PVAL valp, bool chktype)
|
|
{
|
|
if (chktype && (valp->GetType() != Type || valp->GetSize() > Len))
|
|
return true;
|
|
|
|
char buf[64];
|
|
|
|
if (!(Null = valp->IsNull() && Nullable))
|
|
strncpy(Strp, valp->GetCharString(buf), Len);
|
|
else
|
|
Reset();
|
|
|
|
return false;
|
|
} // end of SetValue_pval
|
|
|
|
/***********************************************************************/
|
|
/* STRING SetValue: fill string with chars extracted from a line. */
|
|
/***********************************************************************/
|
|
bool TYPVAL<PSZ>::SetValue_char(char *p, int n)
|
|
{
|
|
bool rc;
|
|
|
|
if (p) {
|
|
rc = n > Len;
|
|
|
|
if ((n = MY_MIN(n, Len))) {
|
|
strncpy(Strp, p, n);
|
|
|
|
// for (p = Strp + n - 1; p >= Strp && (*p == ' ' || *p == '\0'); p--) ;
|
|
for (p = Strp + n - 1; p >= Strp; p--)
|
|
if (*p && *p != ' ')
|
|
break;
|
|
|
|
*(++p) = '\0';
|
|
|
|
if (trace > 1)
|
|
htrc(" Setting string to: '%s'\n", Strp);
|
|
|
|
} else
|
|
Reset();
|
|
|
|
Null = false;
|
|
} else {
|
|
rc = false;
|
|
Reset();
|
|
Null = Nullable;
|
|
} // endif p
|
|
|
|
return rc;
|
|
} // end of SetValue_char
|
|
|
|
/***********************************************************************/
|
|
/* STRING SetValue: fill string with another string. */
|
|
/***********************************************************************/
|
|
void TYPVAL<PSZ>::SetValue_psz(PSZ s)
|
|
{
|
|
if (s) {
|
|
strncpy(Strp, s, Len);
|
|
Null = false;
|
|
} else {
|
|
Reset();
|
|
Null = Nullable;
|
|
} // endif s
|
|
|
|
} // end of SetValue_psz
|
|
|
|
/***********************************************************************/
|
|
/* STRING SetValue: fill string with a string extracted from a block. */
|
|
/***********************************************************************/
|
|
void TYPVAL<PSZ>::SetValue_pvblk(PVBLK blk, int n)
|
|
{
|
|
// STRBLK's can return a NULL pointer
|
|
PSZ vp = blk->GetCharString(Strp, n);
|
|
|
|
if (vp != Strp)
|
|
SetValue_psz(vp);
|
|
|
|
} // end of SetValue_pvblk
|
|
|
|
/***********************************************************************/
|
|
/* STRING SetValue: get the character representation of an integer. */
|
|
/***********************************************************************/
|
|
void TYPVAL<PSZ>::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);
|
|
|
|
Null = false;
|
|
} // end of SetValue
|
|
|
|
/***********************************************************************/
|
|
/* STRING SetValue: get the character representation of an uint. */
|
|
/***********************************************************************/
|
|
void TYPVAL<PSZ>::SetValue(uint n)
|
|
{
|
|
char buf[16];
|
|
PGLOBAL& g = Global;
|
|
int k = sprintf(buf, "%u", n);
|
|
|
|
if (k > Len) {
|
|
sprintf(g->Message, MSG(VALSTR_TOO_LONG), buf, Len);
|
|
longjmp(g->jumper[g->jump_level], 138);
|
|
} else
|
|
SetValue_psz(buf);
|
|
|
|
Null = false;
|
|
} // end of SetValue
|
|
|
|
/***********************************************************************/
|
|
/* STRING SetValue: get the character representation of a short int. */
|
|
/***********************************************************************/
|
|
void TYPVAL<PSZ>::SetValue(short i)
|
|
{
|
|
SetValue((int)i);
|
|
Null = false;
|
|
} // end of SetValue
|
|
|
|
/***********************************************************************/
|
|
/* STRING SetValue: get the character representation of a ushort int. */
|
|
/***********************************************************************/
|
|
void TYPVAL<PSZ>::SetValue(ushort i)
|
|
{
|
|
SetValue((uint)i);
|
|
Null = false;
|
|
} // end of SetValue
|
|
|
|
/***********************************************************************/
|
|
/* STRING SetValue: get the character representation of a big integer.*/
|
|
/***********************************************************************/
|
|
void TYPVAL<PSZ>::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);
|
|
|
|
Null = false;
|
|
} // end of SetValue
|
|
|
|
/***********************************************************************/
|
|
/* STRING SetValue: get the character representation of a big integer.*/
|
|
/***********************************************************************/
|
|
void TYPVAL<PSZ>::SetValue(ulonglong n)
|
|
{
|
|
char buf[24];
|
|
PGLOBAL& g = Global;
|
|
int k = sprintf(buf, "%llu", n);
|
|
|
|
if (k > Len) {
|
|
sprintf(g->Message, MSG(VALSTR_TOO_LONG), buf, Len);
|
|
longjmp(g->jumper[g->jump_level], 138);
|
|
} else
|
|
SetValue_psz(buf);
|
|
|
|
Null = false;
|
|
} // end of SetValue
|
|
|
|
/***********************************************************************/
|
|
/* STRING SetValue: get the character representation of a double. */
|
|
/***********************************************************************/
|
|
void TYPVAL<PSZ>::SetValue(double f)
|
|
{
|
|
char *p, buf[64];
|
|
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);
|
|
|
|
Null = false;
|
|
} // end of SetValue
|
|
|
|
/***********************************************************************/
|
|
/* STRING SetValue: get the character representation of a tiny int. */
|
|
/***********************************************************************/
|
|
void TYPVAL<PSZ>::SetValue(char c)
|
|
{
|
|
SetValue((int)c);
|
|
Null = false;
|
|
} // end of SetValue
|
|
|
|
/***********************************************************************/
|
|
/* STRING SetValue: get the character representation of a tiny int. */
|
|
/***********************************************************************/
|
|
void TYPVAL<PSZ>::SetValue(uchar c)
|
|
{
|
|
SetValue((uint)c);
|
|
Null = false;
|
|
} // end of SetValue
|
|
|
|
/***********************************************************************/
|
|
/* STRING SetBinValue: fill string with chars extracted from a line. */
|
|
/***********************************************************************/
|
|
void TYPVAL<PSZ>::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 TYPVAL<PSZ>::GetBinValue(void *buf, int buflen, bool go)
|
|
{
|
|
int len = (Null) ? 0 : strlen(Strp);
|
|
|
|
if (len > buflen)
|
|
return true;
|
|
else if (go) {
|
|
memset(buf, ' ', buflen);
|
|
memcpy(buf, Strp, len);
|
|
} // endif go
|
|
|
|
return false;
|
|
} // end of GetBinValue
|
|
|
|
/***********************************************************************/
|
|
/* STRING ShowValue: get string representation of a char value. */
|
|
/***********************************************************************/
|
|
char *TYPVAL<PSZ>::ShowValue(char *buf, int len)
|
|
{
|
|
return Strp;
|
|
} // end of ShowValue
|
|
|
|
/***********************************************************************/
|
|
/* STRING GetCharString: get string representation of a char value. */
|
|
/***********************************************************************/
|
|
char *TYPVAL<PSZ>::GetCharString(char *p)
|
|
{
|
|
return Strp;
|
|
} // end of GetCharString
|
|
|
|
/***********************************************************************/
|
|
/* STRING compare value with another Value. */
|
|
/***********************************************************************/
|
|
bool TYPVAL<PSZ>::IsEqual(PVAL vp, bool chktype)
|
|
{
|
|
if (this == vp)
|
|
return true;
|
|
else if (chktype && Type != vp->GetType())
|
|
return false;
|
|
else if (Null || vp->IsNull())
|
|
return false;
|
|
|
|
char buf[64];
|
|
|
|
if (Ci || vp->IsCi())
|
|
return !stricmp(Strp, vp->GetCharString(buf));
|
|
else // (!Ci)
|
|
return !strcmp(Strp, vp->GetCharString(buf));
|
|
|
|
} // end of IsEqual
|
|
|
|
/***********************************************************************/
|
|
/* Compare values and returns 1, 0 or -1 according to comparison. */
|
|
/* This function is used for evaluation of numeric filters. */
|
|
/***********************************************************************/
|
|
int TYPVAL<PSZ>::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
|
|
|
|
/***********************************************************************/
|
|
/* 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 TYPVAL<PSZ>::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
|
|
|
|
/***********************************************************************/
|
|
/* STRING SetFormat function (used to set SELECT output format). */
|
|
/***********************************************************************/
|
|
bool TYPVAL<PSZ>::SetConstFormat(PGLOBAL g, FORMAT& fmt)
|
|
{
|
|
fmt.Type[0] = 'C';
|
|
fmt.Length = Len;
|
|
fmt.Prec = 0;
|
|
return false;
|
|
} // end of SetConstFormat
|
|
|
|
/* -------------------------- Class DECIMAL -------------------------- */
|
|
|
|
/***********************************************************************/
|
|
/* DECIMAL public constructor from a constant string. */
|
|
/***********************************************************************/
|
|
DECVAL::DECVAL(PSZ s) : TYPVAL<PSZ>(s)
|
|
{
|
|
if (s) {
|
|
char *p = strchr(Strp, '.');
|
|
|
|
Prec = (p) ? Len - (p - Strp) : 0;
|
|
} // endif s
|
|
|
|
Type = TYPE_DECIM;
|
|
} // end of DECVAL constructor
|
|
|
|
/***********************************************************************/
|
|
/* DECIMAL public constructor from char. */
|
|
/***********************************************************************/
|
|
DECVAL::DECVAL(PGLOBAL g, PSZ s, int n, int prec, bool uns)
|
|
: TYPVAL<PSZ>(g, s, n + (prec ? 1 : 0) + (uns ? 0 : 1), 0)
|
|
{
|
|
Prec = prec;
|
|
Unsigned = uns;
|
|
Type = TYPE_DECIM;
|
|
} // end of DECVAL constructor
|
|
|
|
/***********************************************************************/
|
|
/* DECIMAL: Check whether the numerica value is equal to 0. */
|
|
/***********************************************************************/
|
|
bool DECVAL::IsZero(void)
|
|
{
|
|
for (int i = 0; Strp[i]; i++)
|
|
if (!strchr("0 +-.", Strp[i]))
|
|
return false;
|
|
|
|
return true;
|
|
} // end of IsZero
|
|
|
|
/***********************************************************************/
|
|
/* DECIMAL: Reset value to zero. */
|
|
/***********************************************************************/
|
|
void DECVAL::Reset(void)
|
|
{
|
|
int i = 0;
|
|
|
|
Strp[i++] = '0';
|
|
|
|
if (Prec) {
|
|
Strp[i++] = '.';
|
|
|
|
do {
|
|
Strp[i++] = '0';
|
|
} while (i < Prec + 2);
|
|
|
|
} // endif Prec
|
|
|
|
Strp[i] = 0;
|
|
} // end of Reset
|
|
|
|
/***********************************************************************/
|
|
/* DECIMAL ShowValue: get string representation right justified. */
|
|
/***********************************************************************/
|
|
char *DECVAL::ShowValue(char *buf, int len)
|
|
{
|
|
sprintf(buf, Xfmt, len, Strp);
|
|
return buf;
|
|
} // end of ShowValue
|
|
|
|
/***********************************************************************/
|
|
/* 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 DECVAL::GetBinValue(void *buf, int buflen, bool go)
|
|
{
|
|
int len = (Null) ? 0 : strlen(Strp);
|
|
|
|
if (len > buflen)
|
|
return true;
|
|
else if (go) {
|
|
memset(buf, ' ', buflen - len);
|
|
memcpy((char*)buf + buflen - len, Strp, len);
|
|
} // endif go
|
|
|
|
return false;
|
|
} // end of GetBinValue
|
|
|
|
#if 0
|
|
/***********************************************************************/
|
|
/* DECIMAL SetValue: copy the value of another Value object. */
|
|
/***********************************************************************/
|
|
bool DECVAL::SetValue_pval(PVAL valp, bool chktype)
|
|
{
|
|
if (chktype && (valp->GetType() != Type || valp->GetSize() > Len))
|
|
return true;
|
|
|
|
char buf[64];
|
|
|
|
if (!(Null = valp->IsNull() && Nullable))
|
|
strncpy(Strp, valp->GetCharString(buf), Len);
|
|
else
|
|
Reset();
|
|
|
|
return false;
|
|
} // end of SetValue_pval
|
|
|
|
/***********************************************************************/
|
|
/* DECIMAL SetValue: fill string with chars extracted from a line. */
|
|
/***********************************************************************/
|
|
bool DECVAL::SetValue_char(char *p, int n)
|
|
{
|
|
bool rc;
|
|
|
|
if (p) {
|
|
rc = n > Len;
|
|
|
|
if ((n = MY_MIN(n, Len))) {
|
|
strncpy(Strp, p, n);
|
|
|
|
// for (p = Strp + n - 1; p >= Strp && (*p == ' ' || *p == '\0'); p--) ;
|
|
for (p = Strp + n - 1; p >= Strp; p--)
|
|
if (*p && *p != ' ')
|
|
break;
|
|
|
|
*(++p) = '\0';
|
|
|
|
if (trace > 1)
|
|
htrc(" Setting string to: '%s'\n", Strp);
|
|
|
|
} else
|
|
Reset();
|
|
|
|
Null = false;
|
|
} else {
|
|
rc = false;
|
|
Reset();
|
|
Null = Nullable;
|
|
} // endif p
|
|
|
|
return rc;
|
|
} // end of SetValue_char
|
|
|
|
/***********************************************************************/
|
|
/* DECIMAL SetValue: fill string with another string. */
|
|
/***********************************************************************/
|
|
void DECVAL::SetValue_psz(PSZ s)
|
|
{
|
|
if (s) {
|
|
strncpy(Strp, s, Len);
|
|
Null = false;
|
|
} else {
|
|
Reset();
|
|
Null = Nullable;
|
|
} // endif s
|
|
|
|
} // end of SetValue_psz
|
|
|
|
/***********************************************************************/
|
|
/* DECIMAL SetValue: fill string with a string extracted from a block.*/
|
|
/***********************************************************************/
|
|
void DECVAL::SetValue_pvblk(PVBLK blk, int n)
|
|
{
|
|
// STRBLK's can return a NULL pointer
|
|
SetValue_psz(blk->GetCharValue(n));
|
|
} // end of SetValue_pvblk
|
|
|
|
/***********************************************************************/
|
|
/* DECIMAL SetBinValue: fill string with chars extracted from a line. */
|
|
/***********************************************************************/
|
|
void DECVAL::SetBinValue(void *p)
|
|
{
|
|
SetValue_char((char *)p, Len);
|
|
} // end of SetBinValue
|
|
|
|
/***********************************************************************/
|
|
/* DECIMAL GetCharString: get string representation of a char value. */
|
|
/***********************************************************************/
|
|
char *DECVAL::GetCharString(char *p)
|
|
{
|
|
return Strp;
|
|
} // end of GetCharString
|
|
#endif // 0
|
|
|
|
/***********************************************************************/
|
|
/* DECIMAL compare value with another Value. */
|
|
/***********************************************************************/
|
|
bool DECVAL::IsEqual(PVAL vp, bool chktype)
|
|
{
|
|
if (this == vp)
|
|
return true;
|
|
else if (chktype && Type != vp->GetType())
|
|
return false;
|
|
else if (Null || vp->IsNull())
|
|
return false;
|
|
|
|
char buf[64];
|
|
|
|
return !strcmp(Strp, vp->GetCharString(buf));
|
|
} // end of IsEqual
|
|
|
|
/***********************************************************************/
|
|
/* Compare values and returns 1, 0 or -1 according to comparison. */
|
|
/* This function is used for evaluation of numeric filters. */
|
|
/***********************************************************************/
|
|
int DECVAL::CompareValue(PVAL vp)
|
|
{
|
|
//assert(vp->GetType() == Type);
|
|
|
|
// Process filtering on numeric values.
|
|
double f = atof(Strp), n = vp->GetFloatValue();
|
|
|
|
//if (trace)
|
|
// htrc(" Comparing: val=%d,%d\n", f, n);
|
|
|
|
return (f > n) ? 1 : (f < n) ? (-1) : 0;
|
|
} // end of CompareValue
|
|
|
|
#if 0
|
|
/***********************************************************************/
|
|
/* 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 DECVAL::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
|
|
|
|
/***********************************************************************/
|
|
/* DECIMAL SetFormat function (used to set SELECT output format). */
|
|
/***********************************************************************/
|
|
bool DECVAL::SetConstFormat(PGLOBAL g, FORMAT& fmt)
|
|
{
|
|
fmt.Type[0] = 'C';
|
|
fmt.Length = Len;
|
|
fmt.Prec = 0;
|
|
return false;
|
|
} // end of SetConstFormat
|
|
#endif // 0
|
|
|
|
/* -------------------------- Class BINVAL --------------------------- */
|
|
|
|
/***********************************************************************/
|
|
/* BINVAL public constructor from bytes. */
|
|
/***********************************************************************/
|
|
BINVAL::BINVAL(PGLOBAL g, void *p, int cl, int n) : VALUE(TYPE_BIN)
|
|
{
|
|
assert(g);
|
|
Len = n;
|
|
Clen = cl;
|
|
Binp = PlugSubAlloc(g, NULL, Clen + 1);
|
|
memset(Binp, 0, Clen + 1);
|
|
|
|
if (p)
|
|
memcpy(Binp, p, Len);
|
|
|
|
Chrp = NULL;
|
|
} // end of BINVAL constructor
|
|
|
|
/***********************************************************************/
|
|
/* BINVAL: Check whether the hexadecimal value is equal to 0. */
|
|
/***********************************************************************/
|
|
bool BINVAL::IsZero(void)
|
|
{
|
|
for (int i = 0; i < Len; i++)
|
|
if (((char*)Binp)[i] != 0)
|
|
return false;
|
|
|
|
return true;
|
|
} // end of IsZero
|
|
|
|
/***********************************************************************/
|
|
/* BINVAL: Reset value to zero. */
|
|
/***********************************************************************/
|
|
void BINVAL::Reset(void)
|
|
{
|
|
memset(Binp, 0, Clen);
|
|
Len = 0;
|
|
} // end of Reset
|
|
|
|
/***********************************************************************/
|
|
/* Get the tiny value pointed by Binp. */
|
|
/***********************************************************************/
|
|
char BINVAL::GetTinyValue(void)
|
|
{
|
|
return *(char*)Binp;
|
|
} // end of GetTinyValue
|
|
|
|
/***********************************************************************/
|
|
/* Get the unsigned tiny value pointed by Binp. */
|
|
/***********************************************************************/
|
|
uchar BINVAL::GetUTinyValue(void)
|
|
{
|
|
return *(uchar*)Binp;
|
|
} // end of GetUTinyValue
|
|
|
|
/***********************************************************************/
|
|
/* Get the short value pointed by Binp. */
|
|
/***********************************************************************/
|
|
short BINVAL::GetShortValue(void)
|
|
{
|
|
if (Len >= 2)
|
|
return *(short*)Binp;
|
|
else
|
|
return (short)GetTinyValue();
|
|
|
|
} // end of GetShortValue
|
|
|
|
/***********************************************************************/
|
|
/* Get the unsigned short value pointed by Binp. */
|
|
/***********************************************************************/
|
|
ushort BINVAL::GetUShortValue(void)
|
|
{
|
|
return (ushort)GetShortValue();
|
|
} // end of GetUshortValue
|
|
|
|
/***********************************************************************/
|
|
/* Get the integer value pointed by Binp. */
|
|
/***********************************************************************/
|
|
int BINVAL::GetIntValue(void)
|
|
{
|
|
if (Len >= 4)
|
|
return *(int*)Binp;
|
|
else
|
|
return (int)GetShortValue();
|
|
|
|
} // end of GetIntValue
|
|
|
|
/***********************************************************************/
|
|
/* Get the unsigned integer value pointed by Binp. */
|
|
/***********************************************************************/
|
|
uint BINVAL::GetUIntValue(void)
|
|
{
|
|
return (uint)GetIntValue();
|
|
} // end of GetUintValue
|
|
|
|
/***********************************************************************/
|
|
/* Get the big integer value pointed by Binp. */
|
|
/***********************************************************************/
|
|
longlong BINVAL::GetBigintValue(void)
|
|
{
|
|
if (Len >= 8)
|
|
return *(longlong*)Binp;
|
|
else
|
|
return (longlong)GetIntValue();
|
|
|
|
} // end of GetBigintValue
|
|
|
|
/***********************************************************************/
|
|
/* Get the unsigned big integer value pointed by Binp. */
|
|
/***********************************************************************/
|
|
ulonglong BINVAL::GetUBigintValue(void)
|
|
{
|
|
return (ulonglong)GetBigintValue();
|
|
} // end of GetUBigintValue
|
|
|
|
/***********************************************************************/
|
|
/* Get the double value pointed by Binp. */
|
|
/***********************************************************************/
|
|
double BINVAL::GetFloatValue(void)
|
|
{
|
|
if (Len >= 8)
|
|
return *(double*)Binp;
|
|
else if (Len >= 4)
|
|
return (double)(*(float*)Binp);
|
|
else
|
|
return 0.0;
|
|
|
|
} // end of GetFloatValue
|
|
|
|
/***********************************************************************/
|
|
/* BINVAL SetValue: copy the value of another Value object. */
|
|
/***********************************************************************/
|
|
bool BINVAL::SetValue_pval(PVAL valp, bool chktype)
|
|
{
|
|
if (chktype && (valp->GetType() != Type || valp->GetSize() > Clen))
|
|
return true;
|
|
|
|
bool rc = false;
|
|
|
|
if (!(Null = valp->IsNull() && Nullable)) {
|
|
if ((rc = (Len = valp->GetSize()) > Clen))
|
|
Len = Clen;
|
|
|
|
memcpy(Binp, valp->GetTo_Val(), Len);
|
|
} else
|
|
Reset();
|
|
|
|
return rc;
|
|
} // end of SetValue_pval
|
|
|
|
/***********************************************************************/
|
|
/* BINVAL SetValue: fill value with chars extracted from a line. */
|
|
/***********************************************************************/
|
|
bool BINVAL::SetValue_char(char *p, int n)
|
|
{
|
|
bool rc;
|
|
|
|
if (p) {
|
|
rc = n > Clen;
|
|
Len = MY_MIN(n, Clen);
|
|
memcpy(Binp, p, Len);
|
|
Null = false;
|
|
} else {
|
|
rc = false;
|
|
Reset();
|
|
Null = Nullable;
|
|
} // endif p
|
|
|
|
return rc;
|
|
} // end of SetValue_char
|
|
|
|
/***********************************************************************/
|
|
/* BINVAL SetValue: fill value with another string. */
|
|
/***********************************************************************/
|
|
void BINVAL::SetValue_psz(PSZ s)
|
|
{
|
|
if (s) {
|
|
Len = MY_MIN(Clen, (signed)strlen(s));
|
|
memcpy(Binp, s, Len);
|
|
Null = false;
|
|
} else {
|
|
Reset();
|
|
Null = Nullable;
|
|
} // endif s
|
|
|
|
} // end of SetValue_psz
|
|
|
|
/***********************************************************************/
|
|
/* BINVAL SetValue: fill value with bytes extracted from a block. */
|
|
/***********************************************************************/
|
|
void BINVAL::SetValue_pvblk(PVBLK blk, int n)
|
|
{
|
|
// STRBLK's can return a NULL pointer
|
|
void *vp = blk->GetValPtrEx(n);
|
|
|
|
if (!vp || blk->IsNull(n)) {
|
|
Reset();
|
|
Null = Nullable;
|
|
} else if (vp != Binp) {
|
|
if (blk->GetType() == TYPE_STRING)
|
|
Len = strlen((char*)vp);
|
|
else
|
|
Len = blk->GetVlen();
|
|
|
|
Len = MY_MIN(Clen, Len);
|
|
memcpy(Binp, vp, Len);
|
|
Null = false;
|
|
} // endif vp
|
|
|
|
} // end of SetValue_pvblk
|
|
|
|
/***********************************************************************/
|
|
/* BINVAL SetValue: get the binary representation of an integer. */
|
|
/***********************************************************************/
|
|
void BINVAL::SetValue(int n)
|
|
{
|
|
if (Clen >= 4) {
|
|
*((int*)Binp) = n;
|
|
Len = 4;
|
|
} else
|
|
SetValue((short)n);
|
|
|
|
} // end of SetValue
|
|
|
|
/***********************************************************************/
|
|
/* BINVAL SetValue: get the binary representation of an uint. */
|
|
/***********************************************************************/
|
|
void BINVAL::SetValue(uint n)
|
|
{
|
|
if (Clen >= 4) {
|
|
*((uint*)Binp) = n;
|
|
Len = 4;
|
|
} else
|
|
SetValue((ushort)n);
|
|
|
|
} // end of SetValue
|
|
|
|
/***********************************************************************/
|
|
/* BINVAL SetValue: get the binary representation of a short int. */
|
|
/***********************************************************************/
|
|
void BINVAL::SetValue(short i)
|
|
{
|
|
if (Clen >= 2) {
|
|
*((int*)Binp) = i;
|
|
Len = 2;
|
|
} else
|
|
SetValue((char)i);
|
|
|
|
} // end of SetValue
|
|
|
|
/***********************************************************************/
|
|
/* BINVAL SetValue: get the binary representation of a ushort int. */
|
|
/***********************************************************************/
|
|
void BINVAL::SetValue(ushort i)
|
|
{
|
|
if (Clen >= 2) {
|
|
*((uint*)Binp) = i;
|
|
Len = 2;
|
|
} else
|
|
SetValue((uchar)i);
|
|
|
|
} // end of SetValue
|
|
|
|
/***********************************************************************/
|
|
/* BINVAL SetValue: get the binary representation of a big integer. */
|
|
/***********************************************************************/
|
|
void BINVAL::SetValue(longlong n)
|
|
{
|
|
if (Clen >= 8) {
|
|
*((longlong*)Binp) = n;
|
|
Len = 8;
|
|
} else
|
|
SetValue((int)n);
|
|
|
|
} // end of SetValue
|
|
|
|
/***********************************************************************/
|
|
/* BINVAL SetValue: get the binary representation of a big integer. */
|
|
/***********************************************************************/
|
|
void BINVAL::SetValue(ulonglong n)
|
|
{
|
|
if (Clen >= 8) {
|
|
*((ulonglong*)Binp) = n;
|
|
Len = 8;
|
|
} else
|
|
SetValue((uint)n);
|
|
} // end of SetValue
|
|
|
|
/***********************************************************************/
|
|
/* BINVAL SetValue: get the binary representation of a double. */
|
|
/***********************************************************************/
|
|
void BINVAL::SetValue(double n)
|
|
{
|
|
if (Clen >= 8) {
|
|
*((double*)Binp) = n;
|
|
Len = 8;
|
|
} else if (Clen >= 4) {
|
|
*((float*)Binp) = (float)n;
|
|
Len = 4;
|
|
} else
|
|
Len = 0;
|
|
|
|
} // end of SetValue
|
|
|
|
/***********************************************************************/
|
|
/* BINVAL SetValue: get the character binary of a tiny int. */
|
|
/***********************************************************************/
|
|
void BINVAL::SetValue(char c)
|
|
{
|
|
*((char*)Binp) = c;
|
|
Len = 1;
|
|
} // end of SetValue
|
|
|
|
/***********************************************************************/
|
|
/* BINVAL SetValue: get the binary representation of a tiny int. */
|
|
/***********************************************************************/
|
|
void BINVAL::SetValue(uchar c)
|
|
{
|
|
*((uchar*)Binp) = c;
|
|
Len = 1;
|
|
} // end of SetValue
|
|
|
|
/***********************************************************************/
|
|
/* BINVAL SetBinValue: fill string with bytes extracted from a line. */
|
|
/***********************************************************************/
|
|
void BINVAL::SetBinValue(void *p)
|
|
{
|
|
memcpy(Binp, p, Clen);
|
|
} // 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 BINVAL::GetBinValue(void *buf, int buflen, bool go)
|
|
{
|
|
if (Len > buflen)
|
|
return true;
|
|
else if (go) {
|
|
memset(buf, 0, buflen);
|
|
memcpy(buf, Binp, Len);
|
|
} // endif go
|
|
|
|
return false;
|
|
} // end of GetBinValue
|
|
|
|
/***********************************************************************/
|
|
/* BINVAL ShowValue: get string representation of a binary value. */
|
|
/***********************************************************************/
|
|
char *BINVAL::ShowValue(char *buf, int len)
|
|
{
|
|
int n = MY_MIN(Len, len / 2);
|
|
|
|
sprintf(buf, GetXfmt(), n, Binp);
|
|
return buf;
|
|
} // end of ShowValue
|
|
|
|
/***********************************************************************/
|
|
/* BINVAL GetCharString: get string representation of a binary value. */
|
|
/***********************************************************************/
|
|
char *BINVAL::GetCharString(char *p)
|
|
{
|
|
if (!Chrp)
|
|
Chrp = (char*)PlugSubAlloc(Global, NULL, Clen * 2 + 1);
|
|
|
|
sprintf(Chrp, GetXfmt(), Len, Binp);
|
|
return Chrp;
|
|
} // end of GetCharString
|
|
|
|
/***********************************************************************/
|
|
/* BINVAL compare value with another Value. */
|
|
/***********************************************************************/
|
|
bool BINVAL::IsEqual(PVAL vp, bool chktype)
|
|
{
|
|
if (this == vp)
|
|
return true;
|
|
else if (chktype && Type != vp->GetType())
|
|
return false;
|
|
else if (Null || vp->IsNull())
|
|
return false;
|
|
else if (Len != vp->GetSize())
|
|
return false;
|
|
|
|
char *v1 = (char*)Binp;
|
|
char *v2 = (char*)vp->GetTo_Val();
|
|
|
|
for (int i = 0; i < Len; i++)
|
|
if (v1[i] != v2[i])
|
|
return false;
|
|
|
|
return true;
|
|
} // end of IsEqual
|
|
|
|
/***********************************************************************/
|
|
/* 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 BINVAL::FormatValue(PVAL vp, char *fmt)
|
|
{
|
|
char *buf = (char*)vp->GetTo_Val(); // Should be big enough
|
|
int n = sprintf(buf, fmt, Len, Binp);
|
|
|
|
return (n > vp->GetValLen());
|
|
} // end of FormatValue
|
|
|
|
/***********************************************************************/
|
|
/* BINVAL SetFormat function (used to set SELECT output format). */
|
|
/***********************************************************************/
|
|
bool BINVAL::SetConstFormat(PGLOBAL g, FORMAT& fmt)
|
|
{
|
|
fmt.Type[0] = 'B';
|
|
fmt.Length = Clen;
|
|
fmt.Prec = 0;
|
|
return false;
|
|
} // end of SetConstFormat
|
|
|
|
/* -------------------------- Class DTVAL ---------------------------- */
|
|
|
|
/***********************************************************************/
|
|
/* DTVAL public constructor for new void values. */
|
|
/***********************************************************************/
|
|
DTVAL::DTVAL(PGLOBAL g, int n, int prec, PSZ fmt)
|
|
: TYPVAL<int>((int)0, TYPE_DATE)
|
|
{
|
|
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 int. */
|
|
/***********************************************************************/
|
|
DTVAL::DTVAL(PGLOBAL g, int n) : TYPVAL<int>(n, TYPE_DATE)
|
|
{
|
|
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;
|
|
memset(&dtm, 0, sizeof(dtm));
|
|
dtm.tm_mday=2;
|
|
dtm.tm_mon=0;
|
|
dtm.tm_year=70;
|
|
|
|
Shift = (int)mktime(&dtm) - 86400;
|
|
|
|
if (trace)
|
|
htrc("DTVAL Shift=%d\n", Shift);
|
|
|
|
} // end of SetTimeShift
|
|
|
|
// Added by Alexander Barkov
|
|
static void TIME_to_localtime(struct tm *tm, const MYSQL_TIME *ltime)
|
|
{
|
|
bzero(tm, sizeof(*tm));
|
|
tm->tm_year= ltime->year - 1900;
|
|
tm->tm_mon= ltime->month - 1;
|
|
tm->tm_mday= ltime->day;
|
|
tm->tm_hour= ltime->hour;
|
|
tm->tm_min= ltime->minute;
|
|
tm->tm_sec= ltime->second;
|
|
}
|
|
|
|
// Added by Alexander Barkov
|
|
static struct tm *gmtime_mysql(const time_t *timep, struct tm *tm)
|
|
{
|
|
MYSQL_TIME ltime;
|
|
thd_gmt_sec_to_TIME(current_thd, <ime, (my_time_t) *timep);
|
|
TIME_to_localtime(tm, <ime);
|
|
return tm;
|
|
}
|
|
|
|
/***********************************************************************/
|
|
/* 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(struct tm *tm_buffer)
|
|
{
|
|
struct tm *datm;
|
|
time_t t = (time_t)Tval;
|
|
|
|
if (Tval < 0) {
|
|
int n;
|
|
|
|
for (n = 0; t < 0; n += 4)
|
|
t += FOURYEARS;
|
|
|
|
datm = gmtime_mysql(&t, tm_buffer);
|
|
|
|
if (datm)
|
|
datm->tm_year -= n;
|
|
|
|
} else
|
|
datm = gmtime_mysql(&t, tm_buffer);
|
|
|
|
return datm;
|
|
} // end of GetGmTime
|
|
|
|
// Added by Alexander Barkov
|
|
static time_t mktime_mysql(struct tm *ptm)
|
|
{
|
|
MYSQL_TIME ltime;
|
|
localtime_to_TIME(<ime, ptm);
|
|
ltime.time_type= MYSQL_TIMESTAMP_DATETIME;
|
|
uint error_code;
|
|
time_t t= TIME_to_timestamp(current_thd, <ime, &error_code);
|
|
return error_code ? (time_t) -1 : t;
|
|
}
|
|
|
|
/***********************************************************************/
|
|
/* 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_mysql(ptm);
|
|
|
|
if (trace > 1)
|
|
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_mysql(ptm);
|
|
} // endfor t
|
|
|
|
if (t == -1)
|
|
return true;
|
|
|
|
if ((t -= (n * FOURYEARS)) > 2000000000)
|
|
return true;
|
|
|
|
}
|
|
Tval= (int) t;
|
|
|
|
if (trace > 1)
|
|
htrc("MakeTime Ival=%d\n", Tval);
|
|
|
|
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;
|
|
bzero(&datm, sizeof(datm));
|
|
datm.tm_mday=1;
|
|
datm.tm_mon=0;
|
|
datm.tm_year=70;
|
|
|
|
if (trace > 1)
|
|
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 > 1)
|
|
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
|
|
Tval = 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 (!(Null = valp->IsNull() && Nullable)) {
|
|
if (Pdtp && !valp->IsTypeNum()) {
|
|
int ndv;
|
|
int dval[6];
|
|
|
|
ndv = ExtractDate(valp->GetCharValue(), Pdtp, DefYear, dval);
|
|
MakeDate(NULL, dval, ndv);
|
|
} else
|
|
Tval = valp->GetIntValue();
|
|
|
|
} else
|
|
Reset();
|
|
|
|
return false;
|
|
} // end of SetValue
|
|
|
|
/***********************************************************************/
|
|
/* SetValue: convert chars extracted from a line to date value. */
|
|
/***********************************************************************/
|
|
bool DTVAL::SetValue_char(char *p, int n)
|
|
{
|
|
bool rc;
|
|
|
|
if (Pdtp) {
|
|
char *p2;
|
|
int ndv;
|
|
int dval[6];
|
|
|
|
// Trim trailing blanks
|
|
for (p2 = p + n -1; p < p2 && *p2 == ' '; p2--) ;
|
|
|
|
if ((rc = (n = p2 - p + 1) > Len))
|
|
n = Len;
|
|
|
|
memcpy(Sdate, p, n);
|
|
Sdate[n] = '\0';
|
|
|
|
ndv = ExtractDate(Sdate, Pdtp, DefYear, dval);
|
|
MakeDate(NULL, dval, ndv);
|
|
|
|
if (trace > 1)
|
|
htrc(" setting date: '%s' -> %d\n", Sdate, Tval);
|
|
|
|
Null = false;
|
|
} else
|
|
rc = TYPVAL<int>::SetValue_char(p, n);
|
|
|
|
return rc;
|
|
} // 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 > 1)
|
|
htrc(" setting date: '%s' -> %d\n", Sdate, Tval);
|
|
|
|
Null = false;
|
|
} else
|
|
TYPVAL<int>::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
|
|
Tval = 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 tm, *ptm= GetGmTime(&tm);
|
|
|
|
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", Tval);
|
|
|
|
Null = false;
|
|
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 tm, *ptm = GetGmTime(&tm);
|
|
|
|
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 TYPVAL<int>::ShowValue(buf, len);
|
|
|
|
} // end of ShowValue
|
|
|
|
#if 0 // Not used by CONNECT
|
|
/***********************************************************************/
|
|
/* Returns a member of the struct tm representation of the date. */
|
|
/***********************************************************************/
|
|
bool DTVAL::GetTmMember(OPVAL op, int& mval)
|
|
{
|
|
bool rc = false;
|
|
struct tm tm, *ptm = GetGmTime(&tm);
|
|
|
|
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 tm, *ptm = GetGmTime(&tm);
|
|
|
|
// 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
|
|
#endif // 0
|
|
|
|
/***********************************************************************/
|
|
/* 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 tm, *ptm = GetGmTime(&tm);
|
|
|
|
if (trace > 1)
|
|
htrc("FormatValue: ptm=%p len=%d\n", ptm, vp->GetValLen());
|
|
|
|
if (ptm) {
|
|
size_t n = strftime(buf, vp->GetValLen(), fmt, ptm);
|
|
|
|
if (trace > 1)
|
|
htrc("strftime: n=%d buf=%s\n", n, (n) ? buf : "???");
|
|
|
|
return (n == 0);
|
|
} else
|
|
return true;
|
|
|
|
} // end of FormatValue
|
|
|
|
/* -------------------------- End of Value --------------------------- */
|