8
0
mirror of https://github.com/FirebirdSQL/firebird.git synced 2025-01-27 20:43:03 +01:00
firebird-mirror/src/qli/mov.cpp

1616 lines
33 KiB
C++
Raw Normal View History

2001-05-23 15:26:42 +02:00
/*
* PROGRAM: QLI Access Method
* MODULE: mov.cpp
2001-05-23 15:26:42 +02:00
* DESCRIPTION: Data mover and converter and comparator, etc.
*
* The contents of this file are subject to the Interbase Public
* License Version 1.0 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy
* of the License at http://www.Inprise.com/IPL.html
*
* Software distributed under the License is distributed on an
* "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either express
* or implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code was created by Inprise Corporation
* and its predecessors. Portions created by Inprise Corporation are
* Copyright (C) Inprise Corporation.
*
* All Rights Reserved.
* Contributor(s): ______________________________________.
*/
#include "firebird.h"
2004-04-29 00:36:29 +02:00
#include <stdio.h>
2001-05-23 15:26:42 +02:00
#include <string.h>
#include "../qli/dtr.h"
#include "../common/classes/timestamp.h"
2001-05-23 15:26:42 +02:00
#include "../jrd/intl.h"
#include "../qli/err_proto.h"
#include "../jrd/gds_proto.h"
#include "../jrd/gdsassert.h"
2001-05-23 15:26:42 +02:00
#include "../qli/mov_proto.h"
2008-01-15 21:15:58 +01:00
#include "../common/utils_proto.h"
2001-05-23 15:26:42 +02:00
using MsgFormat::SafeArg;
static void date_error(const TEXT*, const USHORT);
static double double_from_text(const dsc* desc);
2008-12-09 08:24:32 +01:00
static void sql_date_to_text(const SLONG[1], DSC*);
static void sql_time_to_text(const ULONG[1], DSC*);
static void timestamp_to_text(const SLONG[2], DSC*);
2001-05-23 15:26:42 +02:00
static void mover_error(int, USHORT, USHORT);
2003-10-08 10:42:48 +02:00
static void now_to_date(const tm*, SLONG[2]);
static void numeric_to_text(const dsc*, dsc*);
static void string_to_date(const TEXT*, USHORT, SLONG[2]);
2003-12-22 11:00:59 +01:00
static void string_to_time(const TEXT*, USHORT, SLONG[2]);
static const TEXT* type_name(USHORT);
2001-05-23 15:26:42 +02:00
2001-05-23 15:26:42 +02:00
#define LETTER(c) (c >= 'A' && c <= 'Z')
#define DIGIT(c) (c >= '0' && c <= '9')
2003-12-31 06:36:12 +01:00
const char* const TODAY = "TODAY";
const char* const NOW = "NOW";
const char* const TOMORROW = "TOMORROW";
const char* const YESTERDAY = "YESTERDAY";
2001-05-23 15:26:42 +02:00
2004-05-16 03:42:11 +02:00
const int PRECISION = 10000;
2001-05-23 15:26:42 +02:00
2008-12-05 02:20:14 +01:00
struct dtypes_t
2008-01-15 21:15:58 +01:00
{
2001-05-23 15:26:42 +02:00
USHORT type;
2003-12-31 06:36:12 +01:00
const TEXT* description;
};
2001-05-23 15:26:42 +02:00
2009-01-10 11:51:02 +01:00
static const dtypes_t dtypes_table[] =
{
2003-12-22 11:00:59 +01:00
{ dtype_unknown, "NULL" },
{ dtype_text, "character string" },
{ dtype_cstring, "character string" },
{ dtype_varying, "varying string" },
{ dtype_packed, "packed decimal" },
{ dtype_byte, "byte integer" },
{ dtype_short, "short integer" },
{ dtype_long, "long integer" },
{ dtype_quad, "quadword integer" },
{ dtype_real, "single precision floating" },
{ dtype_double, "double precision floating" },
{ dtype_d_float, "double precision floating" },
{ dtype_timestamp, "date" },
{ dtype_sql_date, "SQL date" },
{ dtype_sql_time, "SQL time" },
{ dtype_blob, "blob" },
{ dtype_int64, "big integer" },
{ 0, 0 }
2001-05-23 15:26:42 +02:00
};
int MOVQ_compare(const dsc* arg1, const dsc* arg2)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* M O V Q _ c o m p a r e
*
**************************************
*
* Functional description
* Compare two descriptors. Return (-1, 0, 1) if a<b, a=b, or a>b.
*
**************************************/
2008-12-05 02:20:14 +01:00
// Handle the simple (matched) ones first
2001-05-23 15:26:42 +02:00
2008-12-09 08:24:32 +01:00
if (arg1->dsc_dtype == arg2->dsc_dtype && arg1->dsc_scale == arg2->dsc_scale)
{
const UCHAR* p1 = arg1->dsc_address;
const UCHAR* p2 = arg2->dsc_address;
2001-05-23 15:26:42 +02:00
2009-01-10 11:51:02 +01:00
switch (arg1->dsc_dtype)
{
2001-05-23 15:26:42 +02:00
case dtype_short:
2009-01-10 11:51:02 +01:00
if (*(SSHORT*) p1 == *(SSHORT*) p2)
2001-05-23 15:26:42 +02:00
return 0;
2009-01-10 11:51:02 +01:00
if (*(SSHORT*) p1 > *(SSHORT*) p2)
2001-05-23 15:26:42 +02:00
return 1;
return -1;
case dtype_long:
case dtype_sql_date:
case dtype_sql_time:
2009-01-10 11:51:02 +01:00
if (*(SLONG*) p1 == *(SLONG*) p2)
2001-05-23 15:26:42 +02:00
return 0;
2009-01-10 11:51:02 +01:00
if (*(SLONG*) p1 > *(SLONG*) p2)
2001-05-23 15:26:42 +02:00
return 1;
return -1;
case dtype_int64:
case dtype_timestamp:
2001-05-23 15:26:42 +02:00
case dtype_quad:
2009-01-10 11:51:02 +01:00
if (((SLONG*) p1)[0] < ((SLONG*) p2)[0])
2001-05-23 15:26:42 +02:00
return -1;
2009-01-10 11:51:02 +01:00
if (((SLONG*) p1)[0] > ((SLONG*) p2)[0])
2001-05-23 15:26:42 +02:00
return 1;
2009-01-10 11:51:02 +01:00
if (((ULONG*) p1)[1] < ((ULONG*) p2)[1])
2001-05-23 15:26:42 +02:00
return -1;
2009-01-10 11:51:02 +01:00
if (((ULONG*) p1)[1] > ((ULONG*) p2)[1])
2001-05-23 15:26:42 +02:00
return 1;
return 0;
case dtype_real:
2009-01-10 11:51:02 +01:00
if (*(float*) p1 == *(float*) p2)
2001-05-23 15:26:42 +02:00
return 0;
2009-01-10 11:51:02 +01:00
if (*(float*) p1 > *(float*) p2)
2001-05-23 15:26:42 +02:00
return 1;
return -1;
case dtype_double:
2009-01-10 11:51:02 +01:00
if (*(double*) p1 == *(double*) p2)
2001-05-23 15:26:42 +02:00
return 0;
2009-01-10 11:51:02 +01:00
if (*(double*) p1 > *(double*) p2)
2001-05-23 15:26:42 +02:00
return 1;
return -1;
case dtype_text:
{
SSHORT length;
2009-01-10 11:51:02 +01:00
if (arg1->dsc_length >= arg2->dsc_length)
{
if (length = arg2->dsc_length)
do {
if (*p1++ != *p2++)
2008-01-15 21:15:58 +01:00
return (p1[-1] > p2[-1]) ? 1 : -1;
} while (--length);
if (length = arg1->dsc_length - arg2->dsc_length)
do {
if (*p1++ != ' ')
2008-01-15 21:15:58 +01:00
return (p1[-1] > ' ') ? 1 : -1;
} while (--length);
return 0;
}
if (length = arg1->dsc_length)
do {
2001-05-23 15:26:42 +02:00
if (*p1++ != *p2++)
2008-01-15 21:15:58 +01:00
return (p1[-1] > p2[-1]) ? 1 : -1;
} while (--length);
length = arg2->dsc_length - arg1->dsc_length;
do {
if (*p2++ != ' ')
2008-01-15 21:15:58 +01:00
return (' ' > p2[-1]) ? 1 : -1;
} while (--length);
return 0;
}
2001-05-23 15:26:42 +02:00
}
}
// Handle mixed string comparisons
2001-05-23 15:26:42 +02:00
2009-01-10 11:51:02 +01:00
if (arg1->dsc_dtype <= dtype_varying && arg2->dsc_dtype <= dtype_varying)
{
const TEXT* p1;
const TEXT* p2;
SSHORT length = MOVQ_get_string(arg1, &p1, 0, 0);
SSHORT length2 = MOVQ_get_string(arg2, &p2, 0, 0);
SSHORT fill = length - length2;
2009-01-10 11:51:02 +01:00
if (length >= length2)
{
2001-05-23 15:26:42 +02:00
if (length2)
do {
2001-05-23 15:26:42 +02:00
if (*p1++ != *p2++)
2008-01-15 21:15:58 +01:00
return (p1[-1] > p2[-1]) ? 1 : -1;
} while (--length2);
2001-05-23 15:26:42 +02:00
if (fill > 0)
do {
2001-05-23 15:26:42 +02:00
if (*p1++ != ' ')
2008-01-15 21:15:58 +01:00
return (p1[-1] > ' ') ? 1 : -1;
} while (--fill);
2001-05-23 15:26:42 +02:00
return 0;
}
2009-01-10 11:51:02 +01:00
if (length)
{
do {
2001-05-23 15:26:42 +02:00
if (*p1++ != *p2++)
2008-01-15 21:15:58 +01:00
return (p1[-1] > p2[-1]) ? 1 : -1;
} while (--length);
}
do {
2001-05-23 15:26:42 +02:00
if (*p2++ != ' ')
2008-01-15 21:15:58 +01:00
return (' ' > p2[-1]) ? 1 : -1;
} while (++fill);
2001-05-23 15:26:42 +02:00
return 0;
}
// Handle hetergeneous compares
2001-05-23 15:26:42 +02:00
if (arg1->dsc_dtype < arg2->dsc_dtype)
return (-MOVQ_compare(arg2, arg1));
dsc desc;
SLONG date[2];
2008-12-05 02:20:14 +01:00
2009-01-10 11:51:02 +01:00
switch (arg1->dsc_dtype)
{
2001-05-23 15:26:42 +02:00
case dtype_timestamp:
desc.dsc_dtype = dtype_timestamp;
desc.dsc_length = sizeof(date);
desc.dsc_scale = 0;
2009-01-14 13:19:43 +01:00
desc.dsc_address = (UCHAR*) date;
2001-05-23 15:26:42 +02:00
desc.dsc_sub_type = 0;
MOVQ_move(arg2, &desc);
return MOVQ_compare(arg1, &desc);
case dtype_sql_time:
desc.dsc_dtype = dtype_sql_time;
desc.dsc_length = sizeof(date[0]);
desc.dsc_scale = 0;
2009-01-14 13:19:43 +01:00
desc.dsc_address = (UCHAR*) date;
2001-05-23 15:26:42 +02:00
desc.dsc_sub_type = 0;
MOVQ_move(arg2, &desc);
return MOVQ_compare(arg1, &desc);
case dtype_sql_date:
desc.dsc_dtype = dtype_sql_date;
desc.dsc_length = sizeof(date[0]);
desc.dsc_scale = 0;
2009-01-14 13:19:43 +01:00
desc.dsc_address = (UCHAR*) date;
2001-05-23 15:26:42 +02:00
desc.dsc_sub_type = 0;
MOVQ_move(arg2, &desc);
return MOVQ_compare(arg1, &desc);
case dtype_short:
case dtype_long:
{
const SSHORT scale = MIN(arg1->dsc_scale, arg2->dsc_scale);
2001-05-23 15:26:42 +02:00
const SLONG temp1 = MOVQ_get_long(arg1, scale);
const SLONG temp2 = MOVQ_get_long(arg2, scale);
2001-05-23 15:26:42 +02:00
if (temp1 == temp2)
return 0;
if (temp1 > temp2)
return 1;
return -1;
}
case dtype_real:
{
const float temp1 = MOVQ_get_double(arg1);
const float temp2 = MOVQ_get_double(arg2);
2001-05-23 15:26:42 +02:00
if (temp1 == temp2)
return 0;
if (temp1 > temp2)
return 1;
return -1;
}
case dtype_double:
{
const double temp1 = MOVQ_get_double(arg1);
const double temp2 = MOVQ_get_double(arg2);
2001-05-23 15:26:42 +02:00
if (temp1 == temp2)
return 0;
if (temp1 > temp2)
return 1;
return -1;
}
case dtype_blob:
IBERROR(48); // Msg 48 Blob conversion is not supported
2001-05-23 15:26:42 +02:00
default:
mover_error(410, arg1->dsc_dtype, arg2->dsc_dtype);
}
2002-06-29 10:49:39 +02:00
return -1;
2001-05-23 15:26:42 +02:00
}
double MOVQ_date_to_double(const dsc* desc)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* M O V Q _ d a t e _ t o _ d o u b l e
*
**************************************
*
* Functional description
* Convert a date to double precision for
* date arithmetic routines.
*
**************************************/
SLONG temp[2], *date;
// If the input descriptor is not in date form, convert it.
2001-05-23 15:26:42 +02:00
if (desc->dsc_dtype == dtype_timestamp)
date = (SLONG *) desc->dsc_address;
2009-01-10 11:51:02 +01:00
else
{
dsc temp_desc;
2001-05-23 15:26:42 +02:00
temp_desc.dsc_dtype = dtype_timestamp;
temp_desc.dsc_length = sizeof(temp);
temp_desc.dsc_scale = 0;
temp_desc.dsc_sub_type = 0;
date = temp;
2009-01-14 13:19:43 +01:00
temp_desc.dsc_address = (UCHAR*) date;
QLI_validate_desc(temp_desc);
2001-05-23 15:26:42 +02:00
MOVQ_move(desc, &temp_desc);
}
return date[0] + (double) date[1] / (24. * 60. * 60. * PRECISION);
}
int MOVQ_decompose(const TEXT* string, USHORT length, SLONG* return_value)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* M O V Q _ d e c o m p o s e
*
**************************************
*
* Functional description
* Decompose a numeric string in mantissa and exponent.
*
**************************************/
SSHORT scale = 0;
SLONG value = 0;
2001-05-23 15:26:42 +02:00
SCHAR temp[128];
bool sign = false;
bool fraction = false;
2001-05-23 15:26:42 +02:00
const TEXT* p = string;
const TEXT* const end = p + length;
2008-12-05 02:20:14 +01:00
for (; p < end; p++)
2008-01-15 21:15:58 +01:00
{
2001-05-23 15:26:42 +02:00
if (*p == ',')
continue;
2008-12-05 02:20:14 +01:00
2008-01-15 21:15:58 +01:00
if (DIGIT(*p)) {
2001-05-23 15:26:42 +02:00
value = value * 10 + *p - '0';
if (fraction)
--scale;
}
else if (*p == '.')
2008-01-15 21:15:58 +01:00
{
2001-05-23 15:26:42 +02:00
if (fraction) {
MOVQ_terminate(string, temp, length, sizeof(temp));
ERRQ_error(411, temp);
2001-05-23 15:26:42 +02:00
}
else
fraction = true;
2008-01-15 21:15:58 +01:00
}
2001-05-23 15:26:42 +02:00
else if (*p == '-' && !value && !sign)
sign = true;
2001-05-23 15:26:42 +02:00
else if (*p == '+' && !value && !sign)
sign = false;
2001-05-23 15:26:42 +02:00
else if (*p == 'e' || *p == 'E')
break;
else if (*p != ' ') {
MOVQ_terminate(string, temp, length, sizeof(temp));
ERRQ_error(411, temp);
2001-05-23 15:26:42 +02:00
}
}
if (sign)
value = -value;
/* If there's still something left, there must be an explicit
exponent */
2009-01-10 11:51:02 +01:00
if (p < end)
{
SSHORT exp = 0;
sign = false;
2008-12-05 02:20:14 +01:00
for (p++; p < end; p++)
2008-01-15 21:15:58 +01:00
{
2001-05-23 15:26:42 +02:00
if (DIGIT(*p))
exp = exp * 10 + *p - '0';
else if (*p == '-' && !exp)
sign = true;
2001-05-23 15:26:42 +02:00
else if (*p == '+' && !exp && !sign)
continue;
else if (*p != ' ') {
MOVQ_terminate(string, temp, length, sizeof(temp));
ERRQ_error(411, temp);
2001-05-23 15:26:42 +02:00
}
}
if (sign)
scale -= exp;
else
scale += exp;
}
*return_value = value;
return scale;
}
void MOVQ_double_to_date( double real, SLONG fixed[2])
{
/**************************************
*
* M O V Q _ d o u b l e _ t o _ d a t e
*
**************************************
*
* Functional description
* Convert a double precision representation of a date
* to a fixed point representation. Double is used for
* date arithmetic.
*
**************************************/
2004-03-14 06:51:54 +01:00
fixed[0] = static_cast<SLONG>(real);
fixed[1] = static_cast<SLONG>((real - fixed[0]) * 24. * 60. * 60. * PRECISION);
2001-05-23 15:26:42 +02:00
}
double MOVQ_get_double(const dsc* desc)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* M O V Q _ g e t _ d o u b l e
*
**************************************
*
* Functional description
* Convert something arbitrary to a
* double_precision representation.
2001-05-23 15:26:42 +02:00
*
**************************************/
double value = 0;
2001-05-23 15:26:42 +02:00
2009-01-10 11:51:02 +01:00
switch (desc->dsc_dtype)
{
2001-05-23 15:26:42 +02:00
case dtype_short:
2009-01-10 11:51:02 +01:00
value = *((SSHORT*) desc->dsc_address);
2001-05-23 15:26:42 +02:00
break;
case dtype_long:
2009-01-10 11:51:02 +01:00
value = *((SLONG*) desc->dsc_address);
2001-05-23 15:26:42 +02:00
break;
case dtype_int64:
2009-01-10 11:51:02 +01:00
value = *((SINT64*) desc->dsc_address);
break;
2001-05-23 15:26:42 +02:00
case dtype_real:
2009-01-10 11:51:02 +01:00
return *((float*) desc->dsc_address);
2001-05-23 15:26:42 +02:00
case dtype_double:
2009-01-10 11:51:02 +01:00
return *((double*) desc->dsc_address);
2001-05-23 15:26:42 +02:00
case dtype_varying:
case dtype_cstring:
case dtype_text:
return double_from_text(desc);
2001-05-23 15:26:42 +02:00
default:
mover_error(410, desc->dsc_dtype, dtype_double);
}
// Last, but not least, adjust for scale
2001-05-23 15:26:42 +02:00
2007-02-23 06:55:37 +01:00
int scale = desc->dsc_scale;
if (scale == 0)
2001-05-23 15:26:42 +02:00
return value;
if (scale > 0)
do {
2001-05-23 15:26:42 +02:00
value *= 10.;
} while (--scale);
2001-05-23 15:26:42 +02:00
else
do {
2001-05-23 15:26:42 +02:00
value /= 10.;
} while (++scale);
2001-05-23 15:26:42 +02:00
return value;
}
SLONG MOVQ_get_long(const dsc* desc, SSHORT scale)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* M O V Q _ g e t _ l o n g
*
**************************************
*
* Functional description
* Convert something arbitrary to a long (32 bit) integer of given
* scale.
*
**************************************/
SLONG value;
double d;
scale -= (SSHORT) desc->dsc_scale;
2009-01-14 13:19:43 +01:00
const TEXT* p = (TEXT*) desc->dsc_address;
2009-01-10 11:51:02 +01:00
switch (desc->dsc_dtype)
{
2001-05-23 15:26:42 +02:00
case dtype_short:
2009-01-10 11:51:02 +01:00
value = *((SSHORT*) p);
2001-05-23 15:26:42 +02:00
break;
case dtype_int64:
2009-01-10 11:51:02 +01:00
value = *((SINT64*) p);
break;
2001-05-23 15:26:42 +02:00
case dtype_long:
2009-01-10 11:51:02 +01:00
value = *((SLONG*) p);
2001-05-23 15:26:42 +02:00
break;
case dtype_real:
2009-01-10 11:51:02 +01:00
d = *((float*) p);
2001-05-23 15:26:42 +02:00
if (scale > 0)
do {
2001-05-23 15:26:42 +02:00
d /= 10.;
} while (--scale);
2001-05-23 15:26:42 +02:00
else if (scale < 0)
do {
2001-05-23 15:26:42 +02:00
d *= 10.;
} while (++scale);
2001-05-23 15:26:42 +02:00
if (d > 0)
d += 0.5;
else
d -= 0.5;
return (SLONG) d;
case dtype_double:
2009-01-10 11:51:02 +01:00
d = *((double*) p);
2001-05-23 15:26:42 +02:00
if (scale > 0)
do {
2001-05-23 15:26:42 +02:00
d /= 10.;
} while (--scale);
2001-05-23 15:26:42 +02:00
else if (scale < 0)
do {
2001-05-23 15:26:42 +02:00
d *= 10.;
} while (++scale);
2001-05-23 15:26:42 +02:00
if (d > 0)
d += 0.5;
else
d -= 0.5;
return (SLONG) d;
case dtype_varying:
case dtype_cstring:
case dtype_text:
{
const SSHORT length = MOVQ_get_string(desc, &p, 0, 0);
scale -= MOVQ_decompose(p, length, &value);
break;
}
2001-05-23 15:26:42 +02:00
default:
mover_error(410, desc->dsc_dtype, dtype_long);
}
// Last, but not least, adjust for scale
2001-05-23 15:26:42 +02:00
if (scale == 0)
return value;
2009-01-10 11:51:02 +01:00
if (scale > 0)
{
2007-02-23 06:55:37 +01:00
if ((desc->dsc_dtype == dtype_short) || (desc->dsc_dtype == dtype_long))
{
int fraction = 0;
2001-05-23 15:26:42 +02:00
do {
if (scale == 1)
fraction = value % 10;
value /= 10;
} while (--scale);
if (fraction > 4)
value++;
}
else
do {
2001-05-23 15:26:42 +02:00
value /= 10;
} while (--scale);
2001-05-23 15:26:42 +02:00
}
else
do {
2001-05-23 15:26:42 +02:00
value *= 10;
} while (++scale);
2001-05-23 15:26:42 +02:00
return value;
}
2009-01-10 11:51:02 +01:00
int MOVQ_get_string(const dsc* desc, const TEXT** address, vary* temp, USHORT length)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* M O V Q _ g e t _ s t r i n g
*
**************************************
*
* Functional description
* Get address and length of string, converting the value to
* string, if necessary. The caller must provide a sufficiently
* large temporary. The address of the resultant string is returned
* by reference. Get_string returns the length of the string.
*
* Note: If the descriptor is known to be a string type, the third
* argument (temp buffer) may be omitted.
*
**************************************/
/* If the value is already a string (fixed or varying), just return
the address and length. */
if (desc->dsc_dtype == dtype_text) {
2009-01-14 13:19:43 +01:00
*address = (TEXT*) desc->dsc_address;
2001-05-23 15:26:42 +02:00
return desc->dsc_length;
}
// Perhaps it a "C" type string?
2001-05-23 15:26:42 +02:00
if (desc->dsc_dtype == dtype_cstring) {
2009-01-14 13:19:43 +01:00
*address = (TEXT*) desc->dsc_address;
2004-03-14 06:51:54 +01:00
return MIN(static_cast<int>(strlen((char*)desc->dsc_address)), desc->dsc_length - 1);
2001-05-23 15:26:42 +02:00
}
// No luck -- convert value to varying string.
2001-05-23 15:26:42 +02:00
if (desc->dsc_dtype == dtype_varying) {
vary* varying = (vary*) desc->dsc_address;
2001-05-23 15:26:42 +02:00
*address = varying->vary_string;
return varying->vary_length;
}
dsc temp_desc;
2001-05-23 15:26:42 +02:00
temp_desc.dsc_length = length;
2009-01-14 13:19:43 +01:00
temp_desc.dsc_address = (UCHAR*) temp;
2001-05-23 15:26:42 +02:00
temp_desc.dsc_scale = 0;
temp_desc.dsc_dtype = dtype_varying;
temp_desc.dsc_sub_type = ttype_ascii;
QLI_validate_desc(temp_desc);
2001-05-23 15:26:42 +02:00
MOVQ_move(desc, &temp_desc);
*address = temp->vary_string;
return temp->vary_length;
}
void MOVQ_move(const dsc* from, dsc* to)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* M O V Q _ m o v e
*
**************************************
*
* Functional description
* Move (and possible convert) something to something else.
*
**************************************/
USHORT length = from->dsc_length;
UCHAR* p = to->dsc_address;
const UCHAR* q = from->dsc_address;
2001-05-23 15:26:42 +02:00
/* If the datatypes and lengths are identical, just move the
stuff byte by byte. Although this may seem slower than
2001-05-23 15:26:42 +02:00
optimal, it would cost more to find the fast move than the
fast move would gain. */
if (DSC_EQUIV(from, to, false))
2001-05-23 15:26:42 +02:00
/*
if (((ALT_DSC*) from)->dsc_combined_type == ((ALT_DSC*) to)->dsc_combined_type)
*/
{
if (length)
2007-02-23 06:55:37 +01:00
memcpy(p, q, length);
2008-12-05 02:20:14 +01:00
2001-05-23 15:26:42 +02:00
return;
}
const TEXT* ptr;
2001-05-23 15:26:42 +02:00
/* Do data type by data type conversions. Not all are supported,
and some will drop out for additional handling. */
2009-01-10 11:51:02 +01:00
switch (to->dsc_dtype)
{
2001-05-23 15:26:42 +02:00
case dtype_timestamp:
2009-01-10 11:51:02 +01:00
switch (from->dsc_dtype)
{
2001-05-23 15:26:42 +02:00
case dtype_varying:
case dtype_cstring:
case dtype_text:
length = MOVQ_get_string(from, &ptr, 0, 0);
2009-01-10 11:51:02 +01:00
string_to_date((TEXT*) ptr, length, (SLONG*) to->dsc_address);
2001-05-23 15:26:42 +02:00
return;
case dtype_sql_date:
2009-01-10 11:51:02 +01:00
((SLONG*) to->dsc_address)[0] = *(SLONG*) from->dsc_address;
((SLONG*) to->dsc_address)[1] = 0;
2001-05-23 15:26:42 +02:00
return;
case dtype_sql_time:
2009-01-10 11:51:02 +01:00
((SLONG*) to->dsc_address)[0] = 0;
((SLONG*) to->dsc_address)[1] = *(SLONG*) from->dsc_address;
2001-05-23 15:26:42 +02:00
return;
}
break;
case dtype_sql_date:
switch (from->dsc_dtype) {
case dtype_varying:
case dtype_cstring:
case dtype_text:
{
SLONG date[2];
length = MOVQ_get_string(from, &ptr, 0, 0);
2009-01-10 11:51:02 +01:00
string_to_date((TEXT*) ptr, length, (SLONG*) date);
((SLONG*) to->dsc_address)[0] = date[0];
2001-05-23 15:26:42 +02:00
}
return;
case dtype_timestamp:
2009-01-10 11:51:02 +01:00
((SLONG*) to->dsc_address)[0] = ((SLONG*) from->dsc_address)[0];
2001-05-23 15:26:42 +02:00
return;
case dtype_sql_time:
// Error situation
2001-05-23 15:26:42 +02:00
break;
}
break;
case dtype_sql_time:
switch (from->dsc_dtype) {
case dtype_varying:
case dtype_cstring:
case dtype_text:
{
SLONG date[2];
length = MOVQ_get_string(from, &ptr, 0, 0);
2004-01-22 07:51:37 +01:00
string_to_time((TEXT*) ptr, length, (SLONG*) date);
2009-01-10 11:51:02 +01:00
((SLONG*) to->dsc_address)[0] = date[1];
2001-05-23 15:26:42 +02:00
}
return;
case dtype_timestamp:
2009-01-10 11:51:02 +01:00
((SLONG*) to->dsc_address)[0] = ((SLONG*) from->dsc_address)[1];
2001-05-23 15:26:42 +02:00
return;
case dtype_sql_date:
// Error situation
2001-05-23 15:26:42 +02:00
break;
}
break;
case dtype_text:
case dtype_cstring:
case dtype_varying:
2008-12-05 02:20:14 +01:00
switch (from->dsc_dtype)
{
2001-05-23 15:26:42 +02:00
case dtype_varying:
case dtype_cstring:
case dtype_text:
{
length = MOVQ_get_string(from, &ptr, 0, 0);
const TEXT* s = ptr;
2008-12-05 02:20:14 +01:00
switch (to->dsc_dtype)
{
case dtype_text:
{
length = MIN(length, to->dsc_length);
SSHORT fill = to->dsc_length - length;
if (length)
2008-01-15 21:15:58 +01:00
memcpy(p, s, length);
if (fill > 0)
2008-01-15 21:15:58 +01:00
memset(p + length, ' ', fill);
return;
}
case dtype_cstring:
length = MIN(length, to->dsc_length - 1);
if (length)
2008-01-15 21:15:58 +01:00
memcpy(p, s, length);
p[length] = 0;
return;
case dtype_varying:
2008-01-15 21:15:58 +01:00
{
length = MIN(length, to->dsc_length - sizeof(SSHORT));
vary* avary = reinterpret_cast<vary*>(p);
avary->vary_length = length;
if (length)
memcpy(avary->vary_string, s, length);
}
return;
}
2001-05-23 15:26:42 +02:00
}
case dtype_int64:
2001-05-23 15:26:42 +02:00
case dtype_short:
case dtype_long:
case dtype_real:
case dtype_double:
numeric_to_text(from, to);
return;
case dtype_sql_date:
2004-01-22 07:51:37 +01:00
sql_date_to_text((SLONG*) from->dsc_address, to);
2001-05-23 15:26:42 +02:00
return;
case dtype_sql_time:
2001-07-12 07:46:06 +02:00
sql_time_to_text((ULONG*) from->dsc_address, to);
2001-05-23 15:26:42 +02:00
return;
case dtype_timestamp:
2004-01-22 07:51:37 +01:00
timestamp_to_text((SLONG*) from->dsc_address, to);
2001-05-23 15:26:42 +02:00
return;
}
break;
case dtype_blob:
if (from->dsc_dtype == dtype_quad) {
2009-01-10 11:51:02 +01:00
((SLONG*) p)[0] = ((SLONG*) q)[0];
((SLONG*) p)[1] = ((SLONG*) q)[1];
2001-05-23 15:26:42 +02:00
return;
}
break;
case dtype_quad:
if (from->dsc_dtype == dtype_blob) {
2009-01-10 11:51:02 +01:00
((SLONG*) p)[0] = ((SLONG*) q)[0];
((SLONG*) p)[1] = ((SLONG*) q)[1];
2001-05-23 15:26:42 +02:00
return;
}
break;
case dtype_short:
{
const SLONG l = MOVQ_get_long(from, to->dsc_scale);
2009-01-10 11:51:02 +01:00
*(SSHORT*) p = l;
if (*(SSHORT*) p != l)
IBERROR(14); // Msg14 integer overflow
return;
}
2001-05-23 15:26:42 +02:00
case dtype_long:
2009-01-10 11:51:02 +01:00
*(SLONG*) p = MOVQ_get_long(from, to->dsc_scale);
2001-05-23 15:26:42 +02:00
return;
case dtype_int64:
2009-01-10 11:51:02 +01:00
*(SINT64*) p = MOVQ_get_long(from, to->dsc_scale);
return;
2001-05-23 15:26:42 +02:00
case dtype_real:
2009-01-10 11:51:02 +01:00
*(float*) p = MOVQ_get_double(from);
2001-05-23 15:26:42 +02:00
return;
case dtype_double:
2009-01-10 11:51:02 +01:00
*(double*) p = MOVQ_get_double(from);
2001-05-23 15:26:42 +02:00
return;
}
if (to->dsc_dtype == dtype_blob || from->dsc_dtype == dtype_blob)
IBERROR(55); // Msg 55 Blob conversion is not supported
2001-05-23 15:26:42 +02:00
mover_error(410, from->dsc_dtype, to->dsc_dtype);
}
2009-01-10 11:51:02 +01:00
void MOVQ_terminate(const SCHAR* from, SCHAR* to, USHORT length, USHORT max_length)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* M O V Q _ t e r m i n a t e
*
**************************************
*
* Functional description
* Null-terminate a possibly non-
* null-terminated string with max
* buffer room.
*
**************************************/
fb_assert(max_length != 0);
2001-05-23 15:26:42 +02:00
if (length) {
length = MIN(length, max_length - 1);
2008-01-15 21:15:58 +01:00
memcpy(to, from, length);
to[length] = '\0';
2001-05-23 15:26:42 +02:00
}
2008-01-15 21:15:58 +01:00
else
fb_utils::copy_terminate(to, from, max_length);
2001-05-23 15:26:42 +02:00
}
static void date_error(const TEXT* string, const USHORT length)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* d a t e _ e r r o r
*
**************************************
*
* Functional description
* A date conversion error occurred. Complain.
*
**************************************/
SCHAR temp[128];
MOVQ_terminate(string, temp, length, sizeof(temp));
ERRQ_error(56, temp);
// Msg 56 Error converting string \"%s\" to date
2001-05-23 15:26:42 +02:00
}
static double double_from_text(const dsc* desc)
{
const TEXT* p;
const SSHORT length = MOVQ_get_string(desc, &p, 0, 0);
2007-02-23 06:55:37 +01:00
int scale = 0;
bool fraction = false, sign = false;
double value = 0;
const TEXT* const end = p + length;
2008-12-05 02:20:14 +01:00
for (; p < end; p++)
2008-01-15 21:15:58 +01:00
{
if (*p == ',')
continue;
2008-12-05 02:20:14 +01:00
2008-01-15 21:15:58 +01:00
if (DIGIT(*p)) {
value = value * 10. + (*p - '0');
if (fraction)
scale++;
}
else if (*p == '.')
2008-01-15 21:15:58 +01:00
{
if (fraction)
IBERROR(52); // Msg 52 conversion error
else
fraction = true;
2008-01-15 21:15:58 +01:00
}
else if (!value && *p == '-')
sign = true;
else if (!value && *p == '+')
continue;
else if (*p == 'e' || *p == 'E')
break;
else if (*p != ' ')
IBERROR(53); // Msg 53 conversion error
}
if (sign)
value = -value;
/* If there's still something left, there must be an explicit
exponent */
2009-01-10 11:51:02 +01:00
if (p < end)
{
sign = false;
2007-02-23 06:55:37 +01:00
int exp = 0;
2009-01-10 11:51:02 +01:00
for (p++; p < end; p++)
{
if (DIGIT(*p))
exp = exp * 10 + *p - '0';
else if (*p == '-' && !exp)
sign = true;
2007-02-23 06:55:37 +01:00
else if (*p == '+' && !exp)
;
else if (*p != ' ')
IBERROR(54); // Msg 54 conversion error
}
if (sign)
scale += exp;
else
scale -= exp;
}
if (scale > 0)
do {
value /= 10.;
} while (--scale);
else if (scale)
do {
value *= 10.;
} while (++scale);
return value;
}
2008-12-09 08:24:32 +01:00
static void sql_date_to_text( const SLONG date[1], DSC* to)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* s q l _ d a t e _ t o _ t e x t
*
**************************************
*
* Functional description
* Convert date to text.
*
**************************************/
2003-09-23 12:13:39 +02:00
tm times;
2001-05-23 15:26:42 +02:00
SLONG date2[2];
2002-06-29 10:49:39 +02:00
date2[0] = date[0];
2001-05-23 15:26:42 +02:00
date2[1] = 0;
2008-12-09 08:24:32 +01:00
isc_decode_date((const ISC_QUAD*) date2, &times);
TEXT temp[35];
2001-05-23 15:26:42 +02:00
sprintf(temp, "%2d-%.3s-%04d", times.tm_mday,
2003-12-31 06:36:12 +01:00
FB_LONG_MONTHS_UPPER[times.tm_mon], times.tm_year + 1900);
2001-05-23 15:26:42 +02:00
const TEXT* p = temp;
while (*p)
++p;
2001-05-23 15:26:42 +02:00
dsc desc;
2001-05-23 15:26:42 +02:00
desc.dsc_length = p - temp;
2009-01-14 13:19:43 +01:00
desc.dsc_address = (UCHAR*) temp;
2001-05-23 15:26:42 +02:00
desc.dsc_dtype = dtype_text;
desc.dsc_scale = 0;
desc.dsc_sub_type = ttype_ascii;
QLI_validate_desc(desc);
2001-05-23 15:26:42 +02:00
MOVQ_move(&desc, to);
}
2008-12-09 08:24:32 +01:00
static void sql_time_to_text( const ULONG date[1], DSC* to)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* s q l _ t i m e _ t o _ t e x t
*
**************************************
*
* Functional description
* Convert sql time to text.
*
**************************************/
2003-09-23 12:13:39 +02:00
tm times;
2001-05-23 15:26:42 +02:00
SLONG date2[2];
date2[0] = 0;
2002-06-29 10:49:39 +02:00
date2[1] = date[0];
2001-05-23 15:26:42 +02:00
2008-12-09 08:24:32 +01:00
isc_decode_date((const ISC_QUAD*) date2, &times);
2001-05-23 15:26:42 +02:00
TEXT temp[35];
sprintf(temp, " %2d:%.2d:%.2d.%.4"SLONGFORMAT, times.tm_hour, times.tm_min,
2001-05-23 15:26:42 +02:00
times.tm_sec, date2[1] % PRECISION);
const TEXT* p = temp;
while (*p)
++p;
2001-05-23 15:26:42 +02:00
dsc desc;
2001-05-23 15:26:42 +02:00
desc.dsc_length = p - temp;
2009-01-14 13:19:43 +01:00
desc.dsc_address = (UCHAR*) temp;
2001-05-23 15:26:42 +02:00
desc.dsc_dtype = dtype_text;
desc.dsc_scale = 0;
desc.dsc_sub_type = ttype_ascii;
QLI_validate_desc(desc);
2001-05-23 15:26:42 +02:00
MOVQ_move(&desc, to);
}
2008-12-09 08:24:32 +01:00
static void timestamp_to_text( const SLONG date[2], DSC* to)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* t i m e s t a m p _ t o _ t e x t
*
**************************************
*
* Functional description
* Convert date to text.
*
**************************************/
2003-09-23 12:13:39 +02:00
tm times;
2008-12-09 08:24:32 +01:00
isc_decode_date((const ISC_QUAD*) date, &times);
2001-05-23 15:26:42 +02:00
TEXT temp[35];
2001-05-23 15:26:42 +02:00
sprintf(temp, "%2d-%.3s-%04d", times.tm_mday,
2003-12-31 06:36:12 +01:00
FB_LONG_MONTHS_UPPER[times.tm_mon], times.tm_year + 1900);
2001-05-23 15:26:42 +02:00
if (times.tm_hour || times.tm_min || times.tm_sec || date[1]) {
TEXT time[15];
sprintf(time, " %2d:%.2d:%.2d.%.4"SLONGFORMAT, times.tm_hour, times.tm_min,
2001-05-23 15:26:42 +02:00
times.tm_sec, date[1] % PRECISION);
strcat(temp, time);
}
const TEXT* p = temp;
while (*p)
++p;
2001-05-23 15:26:42 +02:00
dsc desc;
2001-05-23 15:26:42 +02:00
desc.dsc_length = p - temp;
2009-01-14 13:19:43 +01:00
desc.dsc_address = (UCHAR*) temp;
2001-05-23 15:26:42 +02:00
desc.dsc_dtype = dtype_text;
desc.dsc_scale = 0;
desc.dsc_sub_type = ttype_ascii;
QLI_validate_desc(desc);
2001-05-23 15:26:42 +02:00
MOVQ_move(&desc, to);
}
static void mover_error( int pattern, USHORT in_type, USHORT out_type)
{
/**************************************
*
* m o v e r _ e r r o r
2001-05-23 15:26:42 +02:00
*
**************************************
*
* Functional description
* Return a reasonable error for
* unreasonable conversions and
* comparisons.
*
**************************************/
TEXT in_name[25], out_name[25], msg_unknown[40];
2001-05-23 15:26:42 +02:00
ERRQ_msg_get(504, msg_unknown, sizeof(msg_unknown)); // Msg504 unknown datatype %d
2001-05-23 15:26:42 +02:00
2003-12-22 11:00:59 +01:00
const TEXT* in = type_name(in_type);
if (!in) {
2001-05-23 15:26:42 +02:00
in = in_name;
sprintf(in_name, msg_unknown, in_type);
}
2003-12-22 11:00:59 +01:00
const TEXT* out = type_name(out_type);
if (!out) {
2001-05-23 15:26:42 +02:00
out = out_name;
2003-12-22 11:00:59 +01:00
sprintf(out_name, msg_unknown, out_type);
2001-05-23 15:26:42 +02:00
}
ERRQ_error(pattern, SafeArg() << in << out);
2001-05-23 15:26:42 +02:00
}
2003-10-08 10:42:48 +02:00
static void now_to_date(const tm* time, SLONG date[2])
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* n o w _ t o _ d a t e
*
**************************************
*
* Functional description
* Convert "now" (or best guess) to
* a date attempting to get millisecond
* precision. This unfortunately means
* that we use one routine for VAX, one
* for Apollo, and a third for Unix.
*
**************************************/
isc_encode_date(time, (ISC_QUAD*)date);
2001-05-23 15:26:42 +02:00
}
static void numeric_to_text(const dsc* from, dsc* to)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* n u m e r i c _ t o _ t e x t
*
**************************************
*
* Functional description
* Convert your basic number to nice, formatted text.
*
**************************************/
/* Save (or compute) scale of source. Then convert source to ordinary
longword. */
SSHORT scale = from->dsc_scale;
2001-05-23 15:26:42 +02:00
SSHORT pad = 0, decimal = 0;
2001-05-23 15:26:42 +02:00
if (scale > 0)
pad = scale;
else if (scale < 0)
decimal = 1;
SLONG n;
dsc intermediate;
2001-05-23 15:26:42 +02:00
intermediate.dsc_dtype = dtype_long;
intermediate.dsc_length = sizeof(SLONG);
intermediate.dsc_scale = scale;
intermediate.dsc_sub_type = 0;
2009-01-14 13:19:43 +01:00
intermediate.dsc_address = (UCHAR*) &n;
QLI_validate_desc(intermediate);
2001-05-23 15:26:42 +02:00
MOVQ_move(from, &intermediate);
// Check for negation, then convert the number to a string of digits
2001-05-23 15:26:42 +02:00
SSHORT neg = 0;
2001-05-23 15:26:42 +02:00
if (n < 0) {
neg = 1;
n = -n;
}
TEXT temp[32];
TEXT* p = temp;
2001-05-23 15:26:42 +02:00
do {
*p++ = n % 10 + '0';
n /= 10;
} while (n);
/* Compute the total length off the field formatted. Make sure it
fits. Keep in mind that routine handles both string and varying
string fields. */
SSHORT l = p - temp;
2004-03-14 06:51:54 +01:00
const size_t length = l + neg + decimal + pad;
2001-05-23 15:26:42 +02:00
if ((to->dsc_dtype == dtype_text && length > to->dsc_length) ||
(to->dsc_dtype == dtype_cstring && length >= to->dsc_length) ||
2008-12-09 08:24:32 +01:00
(to->dsc_dtype == dtype_varying && length > to->dsc_length - sizeof(SSHORT)))
{
IBERROR(57); // Msg 57 overflow during conversion
}
2001-05-23 15:26:42 +02:00
// Hopefully a cstring never reached this point.
2004-12-16 04:03:13 +01:00
TEXT* q = (TEXT*) ((to->dsc_dtype == dtype_text) ?
to->dsc_address : to->dsc_address + sizeof(SSHORT));
2001-05-23 15:26:42 +02:00
// If negative, put in minus sign
2001-05-23 15:26:42 +02:00
if (neg)
*q++ = '-';
/* If a decimal point is required, do the formatting. Otherwise just
copy number */
2009-01-10 11:51:02 +01:00
if (scale < 0)
{
2001-05-23 15:26:42 +02:00
if ((l += scale) > 0)
do {
2001-05-23 15:26:42 +02:00
*q++ = *--p;
} while (--l);
2001-05-23 15:26:42 +02:00
*q++ = '.';
do {
2001-05-23 15:26:42 +02:00
*q++ = *--p;
} while (++scale);
2001-05-23 15:26:42 +02:00
}
else
do {
2001-05-23 15:26:42 +02:00
*q++ = *--p;
} while (--l);
2001-05-23 15:26:42 +02:00
// If padding is required, do it now.
2001-05-23 15:26:42 +02:00
if (pad)
do {
2001-05-23 15:26:42 +02:00
*q++ = '0';
} while (--pad);
2001-05-23 15:26:42 +02:00
/* Finish up by padding (if fixed) or computing the actual length
(varying string) */
2009-01-10 11:51:02 +01:00
if (to->dsc_dtype == dtype_text)
{
2001-05-23 15:26:42 +02:00
if (l = to->dsc_length - length)
do {
2001-05-23 15:26:42 +02:00
*q++ = ' ';
} while (--l);
2001-05-23 15:26:42 +02:00
return;
}
if (to->dsc_dtype == dtype_cstring) {
*q = 0;
return;
}
2009-01-14 13:19:43 +01:00
*(SSHORT*) (to->dsc_address) = (UCHAR*) q - to->dsc_address - sizeof(SSHORT);
2001-05-23 15:26:42 +02:00
}
static void string_to_date(const TEXT* string, USHORT length, SLONG date[2])
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* s t r i n g _ t o _ d a t e
*
**************************************
*
* Functional description
* Convert an arbitrary string to a date.
*
**************************************/
if (!length) {
date[0] = date[1] = 0;
return;
}
const TEXT* p = string;
const TEXT* const end = p + length;
2001-05-23 15:26:42 +02:00
USHORT month_position = 0;
2001-05-23 15:26:42 +02:00
2003-10-08 10:42:48 +02:00
const time_t clock = time(0);
tm* today = localtime(&clock);
2001-05-23 15:26:42 +02:00
2007-02-23 06:55:37 +01:00
int i;
USHORT components[7];
2001-05-23 15:26:42 +02:00
for (i = 0; i < 7; i++)
components[i] = 0;
// Parse components
TEXT temp[15];
USHORT n, precision;
bool year = false;
2001-05-23 15:26:42 +02:00
2009-01-10 11:51:02 +01:00
for (i = 0; i < 7; i++)
{
2001-05-23 15:26:42 +02:00
/* Skip leading blanks. If we run out of characters, we're done
with parse. */
while (p < end && *p == ' ')
p++;
if (p == end)
break;
// Handle digit or character strings
2001-05-23 15:26:42 +02:00
TEXT c = UPPER(*p);
2009-01-10 11:51:02 +01:00
if (DIGIT(c))
{
2001-05-23 15:26:42 +02:00
precision = n = 0;
while (p < end && DIGIT(*p)) {
n = n * 10 + *p++ - '0';
precision++;
}
if (i == 2)
year = true;
2001-05-23 15:26:42 +02:00
}
2009-01-10 11:51:02 +01:00
else if (LETTER(c))
{
TEXT* t = temp;
2001-05-23 15:26:42 +02:00
while (p < end && LETTER(c)) {
c = UPPER(*p);
if (!LETTER(c))
break;
*t++ = c;
p++;
}
*t = 0;
2003-12-31 06:36:12 +01:00
const TEXT** month_ptr = FB_LONG_MONTHS_UPPER;
2009-01-10 11:51:02 +01:00
while (true)
{
if (!*month_ptr)
{
2001-05-23 15:26:42 +02:00
while (++p < end)
if (*p != ' ' && *p != '\t' && *p != 0)
date_error(string, length);
if (strcmp(temp, NOW) == 0) {
now_to_date(today, date);
return;
}
today->tm_hour = today->tm_min = today->tm_sec = 0;
isc_encode_date(today, (ISC_QUAD*)date);
2001-05-23 15:26:42 +02:00
if (strcmp(temp, TODAY) == 0)
return;
if (strcmp(temp, TOMORROW) == 0) {
++date[0];
return;
}
if (strcmp(temp, YESTERDAY) == 0) {
--date[0];
return;
}
date_error(string, length);
}
t = temp;
for (const TEXT* m = *month_ptr++; *t && *t == *m; t++, m++);
2001-05-23 15:26:42 +02:00
if (!*t)
break;
}
2003-12-31 06:36:12 +01:00
n = month_ptr - FB_LONG_MONTHS_UPPER;
2001-05-23 15:26:42 +02:00
month_position = i;
}
else {
date_error(string, length);
return;
}
components[i] = n;
while (p < end && *p == ' ')
p++;
if (*p == '/' || *p == '-' || *p == ',' || *p == ':') {
p++;
continue;
}
if (*p == '.') {
if (!month_position && i < 2)
month_position = 1;
p++;
continue;
}
}
// Slide things into day, month, year form
2001-05-23 15:26:42 +02:00
tm times;
2001-05-23 15:26:42 +02:00
if (month_position) {
times.tm_mon = components[1];
times.tm_mday = components[0];
}
else {
times.tm_mon = components[0];
times.tm_mday = components[1];
}
// Handle defaulting of year
2001-05-23 15:26:42 +02:00
if (((times.tm_year = components[2]) == 0) && !year)
times.tm_year = today->tm_year + 1900;
2009-01-10 11:51:02 +01:00
else if (times.tm_year < 100)
{
2001-05-23 15:26:42 +02:00
if (times.tm_year < (today->tm_year - 50) % 100)
times.tm_year += 2000;
else
times.tm_year += 1900;
}
times.tm_year -= 1900;
times.tm_mon -= 1;
times.tm_hour = components[3];
times.tm_min = components[4];
times.tm_sec = components[5];
// convert day/month/year to Julian and validate result
2001-05-23 15:26:42 +02:00
isc_encode_date(&times, (ISC_QUAD*)date);
tm times2;
isc_decode_date((ISC_QUAD*)date, &times2);
2001-05-23 15:26:42 +02:00
if (times.tm_year != times2.tm_year ||
times.tm_mon != times2.tm_mon || times.tm_mday != times2.tm_mday)
2008-12-09 08:24:32 +01:00
{
2001-05-23 15:26:42 +02:00
date_error(string, length);
2008-12-09 08:24:32 +01:00
}
2001-05-23 15:26:42 +02:00
while (precision++ < 4)
components[6] *= 10;
date[1] += components[6];
}
2003-12-22 11:00:59 +01:00
static void string_to_time(const TEXT* string, USHORT length, SLONG date[2])
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* s t r i n g _ t o _ t i m e
*
**************************************
*
* Functional description
2003-12-22 11:00:59 +01:00
* Convert an arbitrary string to a time.
2001-05-23 15:26:42 +02:00
*
**************************************/
if (!length) {
date[0] = date[1] = 0;
return;
}
const TEXT* p = string;
const TEXT* const end = p + length;
2001-05-23 15:26:42 +02:00
2003-10-08 10:42:48 +02:00
const time_t clock = time(0);
const tm* today = localtime(&clock);
2001-05-23 15:26:42 +02:00
2007-02-23 06:55:37 +01:00
int i;
USHORT components[7];
2001-05-23 15:26:42 +02:00
for (i = 0; i < 7; i++)
components[i] = 0;
// Parse components
TEXT temp[15];
USHORT n, precision;
2001-05-23 15:26:42 +02:00
2009-01-10 11:51:02 +01:00
for (i = 3; i < 7; i++)
{
2001-05-23 15:26:42 +02:00
/* Skip leading blanks. If we run out of characters, we're done
with parse. */
while (p < end && *p == ' ')
p++;
if (p == end)
break;
// Handle digit or character strings
2001-05-23 15:26:42 +02:00
TEXT c = UPPER(*p);
2009-01-10 11:51:02 +01:00
if (DIGIT(c))
{
2001-05-23 15:26:42 +02:00
precision = n = 0;
while (p < end && DIGIT(*p)) {
n = n * 10 + *p++ - '0';
precision++;
}
}
2009-01-10 11:51:02 +01:00
else if (LETTER(c))
{
TEXT* t = temp;
2001-05-23 15:26:42 +02:00
while (p < end && LETTER(c)) {
c = UPPER(*p);
if (!LETTER(c))
break;
*t++ = c;
p++;
}
*t = 0;
while (++p < end)
2008-01-15 21:15:58 +01:00
{
2001-05-23 15:26:42 +02:00
if (*p != ' ' && *p != '\t' && *p != 0)
date_error(string, length);
2008-01-15 21:15:58 +01:00
}
2001-05-23 15:26:42 +02:00
if (strcmp(temp, NOW) == 0) {
now_to_date(today, date);
return;
}
date_error(string, length);
}
else {
date_error(string, length);
return;
}
components[i] = n;
while (p < end && *p == ' ')
p++;
if (*p == '/' || *p == '-' || *p == ',' || *p == ':' || *p == '.') {
p++;
continue;
}
}
tm times;
2001-05-23 15:26:42 +02:00
times.tm_hour = components[3];
times.tm_min = components[4];
times.tm_sec = components[5];
// convert day/month/year to Julian and validate result
2001-05-23 15:26:42 +02:00
isc_encode_date(&times, (ISC_QUAD*)date);
2001-05-23 15:26:42 +02:00
while (precision++ < 4)
components[6] *= 10;
date[1] += components[6];
}
2003-12-22 11:00:59 +01:00
static const TEXT* type_name( USHORT dtype)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* t y p e _ n a m e
*
**************************************
*
* Functional description
* Return the name of a data type.
*
**************************************/
2003-12-22 11:00:59 +01:00
for (const dtypes_t* names = dtypes_table; names->description; names++) {
2001-05-23 15:26:42 +02:00
if (names->type == dtype)
return names->description;
2003-12-22 11:00:59 +01:00
}
2001-05-23 15:26:42 +02:00
return NULL;
}