Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
P
Postgres FD Implementation
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Analytics
Analytics
CI / CD
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Abuhujair Javed
Postgres FD Implementation
Commits
2e6f9756
Commit
2e6f9756
authored
Mar 20, 2003
by
Michael Meskes
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Started adding date and timestamp.
parent
26a6378e
Changes
22
Show whitespace changes
Inline
Side-by-side
Showing
22 changed files
with
3674 additions
and
50 deletions
+3674
-50
src/interfaces/ecpg/ChangeLog
src/interfaces/ecpg/ChangeLog
+4
-0
src/interfaces/ecpg/ecpglib/data.c
src/interfaces/ecpg/ecpglib/data.c
+49
-1
src/interfaces/ecpg/ecpglib/execute.c
src/interfaces/ecpg/ecpglib/execute.c
+87
-3
src/interfaces/ecpg/ecpglib/typename.c
src/interfaces/ecpg/ecpglib/typename.c
+5
-1
src/interfaces/ecpg/include/decimal.h
src/interfaces/ecpg/include/decimal.h
+10
-0
src/interfaces/ecpg/include/ecpgtype.h
src/interfaces/ecpg/include/ecpgtype.h
+3
-1
src/interfaces/ecpg/include/pgtypes_date.h
src/interfaces/ecpg/include/pgtypes_date.h
+12
-0
src/interfaces/ecpg/include/pgtypes_error.h
src/interfaces/ecpg/include/pgtypes_error.h
+3
-1
src/interfaces/ecpg/include/pgtypes_timestamp.h
src/interfaces/ecpg/include/pgtypes_timestamp.h
+16
-0
src/interfaces/ecpg/pgtypeslib/Makefile
src/interfaces/ecpg/pgtypeslib/Makefile
+2
-2
src/interfaces/ecpg/pgtypeslib/common.c
src/interfaces/ecpg/pgtypeslib/common.c
+29
-0
src/interfaces/ecpg/pgtypeslib/datetime.c
src/interfaces/ecpg/pgtypeslib/datetime.c
+105
-0
src/interfaces/ecpg/pgtypeslib/dt.h
src/interfaces/ecpg/pgtypeslib/dt.h
+303
-0
src/interfaces/ecpg/pgtypeslib/dt_common.c
src/interfaces/ecpg/pgtypeslib/dt_common.c
+2558
-0
src/interfaces/ecpg/pgtypeslib/extern.h
src/interfaces/ecpg/pgtypeslib/extern.h
+4
-0
src/interfaces/ecpg/pgtypeslib/numeric.c
src/interfaces/ecpg/pgtypeslib/numeric.c
+1
-16
src/interfaces/ecpg/pgtypeslib/timestamp.c
src/interfaces/ecpg/pgtypeslib/timestamp.c
+356
-0
src/interfaces/ecpg/preproc/preproc.y
src/interfaces/ecpg/preproc/preproc.y
+44
-23
src/interfaces/ecpg/preproc/type.c
src/interfaces/ecpg/preproc/type.c
+22
-0
src/interfaces/ecpg/test/Makefile
src/interfaces/ecpg/test/Makefile
+2
-2
src/interfaces/ecpg/test/dt_test.pgc
src/interfaces/ecpg/test/dt_test.pgc
+51
-0
src/interfaces/ecpg/test/num_test.pgc
src/interfaces/ecpg/test/num_test.pgc
+8
-0
No files found.
src/interfaces/ecpg/ChangeLog
View file @
2e6f9756
...
...
@@ -1360,6 +1360,10 @@ Sun Mar 16 11:28:01 CET 2003
- Started with a pgtypes library.
- Renamed lib directory to ecpglib.
- Added numerical functions to library and preprocessor.
Don Mar 20 16:53:40 CET 2003
- Added date/timestamp to library and preprocessor.
- Set ecpg version to 2.12.0.
- Set ecpg library to 3.4.2.
- Set pgtypes library to 1.0.0
...
...
src/interfaces/ecpg/ecpglib/data.c
View file @
2e6f9756
/* $Header: /cvsroot/pgsql/src/interfaces/ecpg/ecpglib/data.c,v 1.
1 2003/03/16 10:42:53
meskes Exp $ */
/* $Header: /cvsroot/pgsql/src/interfaces/ecpg/ecpglib/data.c,v 1.
2 2003/03/20 15:56:50
meskes Exp $ */
#include "postgres_fe.h"
...
...
@@ -11,6 +11,8 @@
#include "extern.h"
#include "sqlca.h"
#include "pgtypes_numeric.h"
#include "pgtypes_date.h"
#include "pgtypes_timestamp.h"
bool
ECPGget_data
(
const
PGresult
*
results
,
int
act_tuple
,
int
act_field
,
int
lineno
,
...
...
@@ -99,6 +101,8 @@ ECPGget_data(const PGresult *results, int act_tuple, int act_field, int lineno,
double
dres
;
char
*
scan_length
;
NumericVar
*
nres
;
Date
ddres
;
Timestamp
tres
;
case
ECPGt_short
:
case
ECPGt_int
:
...
...
@@ -398,6 +402,50 @@ ECPGget_data(const PGresult *results, int act_tuple, int act_field, int lineno,
PGTYPESnumeric_copy
(
nres
,
(
NumericVar
*
)(
var
+
offset
*
act_tuple
));
break
;
case
ECPGt_date
:
if
(
pval
)
{
if
(
isarray
&&
*
pval
==
'"'
)
ddres
=
PGTYPESdate_atod
(
pval
+
1
,
&
scan_length
);
else
ddres
=
PGTYPESdate_atod
(
pval
,
&
scan_length
);
if
(
isarray
&&
*
scan_length
==
'"'
)
scan_length
++
;
if
((
isarray
&&
*
scan_length
!=
','
&&
*
scan_length
!=
'}'
)
||
(
!
isarray
&&
*
scan_length
!=
'\0'
))
/* Garbage left */
{
ECPGraise
(
lineno
,
ECPG_FLOAT_FORMAT
,
pval
);
return
(
false
);
}
*
((
Date
*
)(
var
+
offset
*
act_tuple
))
=
ddres
;
}
break
;
case
ECPGt_timestamp
:
if
(
pval
)
{
if
(
isarray
&&
*
pval
==
'"'
)
tres
=
PGTYPEStimestamp_atot
(
pval
+
1
,
&
scan_length
);
else
tres
=
PGTYPEStimestamp_atot
(
pval
,
&
scan_length
);
if
(
isarray
&&
*
scan_length
==
'"'
)
scan_length
++
;
if
((
isarray
&&
*
scan_length
!=
','
&&
*
scan_length
!=
'}'
)
||
(
!
isarray
&&
*
scan_length
!=
'\0'
))
/* Garbage left */
{
ECPGraise
(
lineno
,
ECPG_FLOAT_FORMAT
,
pval
);
return
(
false
);
}
*
((
Timestamp
*
)(
var
+
offset
*
act_tuple
))
=
tres
;
}
break
;
default:
ECPGraise
(
lineno
,
ECPG_UNSUPPORTED
,
ECPGtype_name
(
type
));
return
(
false
);
...
...
src/interfaces/ecpg/ecpglib/execute.c
View file @
2e6f9756
/* $Header: /cvsroot/pgsql/src/interfaces/ecpg/ecpglib/execute.c,v 1.
3 2003/03/19 16:05:41 petere
Exp $ */
/* $Header: /cvsroot/pgsql/src/interfaces/ecpg/ecpglib/execute.c,v 1.
4 2003/03/20 15:56:50 meskes
Exp $ */
/*
* The aim is to get a simpler inteface to the database routines.
...
...
@@ -27,6 +27,8 @@
#include "sqlca.h"
#include "sql3types.h"
#include "pgtypes_numeric.h"
#include "pgtypes_date.h"
#include "pgtypes_timestamp.h"
/* variables visible to the programs */
struct
sqlca
sqlca
=
...
...
@@ -59,8 +61,7 @@ struct sqlca sqlca =
/* This function returns a newly malloced string that has the \
in the argument quoted with \ and the ' quoted with ' as SQL92 says.
*/
static
char
*
static
char
*
quote_postgres
(
char
*
arg
,
int
lineno
)
{
char
*
res
=
(
char
*
)
ECPGalloc
(
2
*
strlen
(
arg
)
+
3
,
lineno
);
...
...
@@ -876,6 +877,89 @@ ECPGstore_input(const struct statement * stmt, const struct variable * var,
free
(
str
);
}
break
;
case
ECPGt_date
:
{
char
*
str
=
NULL
;
int
slen
;
if
(
var
->
arrsize
>
1
)
{
for
(
element
=
0
;
element
<
var
->
arrsize
;
element
++
)
{
str
=
PGTYPESdate_dtoa
(
*
(
Date
*
)((
var
+
var
->
offset
*
element
)
->
value
));
slen
=
strlen
(
str
);
if
(
!
(
mallocedval
=
ECPGrealloc
(
mallocedval
,
strlen
(
mallocedval
)
+
slen
+
5
,
stmt
->
lineno
)))
return
false
;
if
(
!
element
)
strcpy
(
mallocedval
,
"'{"
);
strncpy
(
mallocedval
+
strlen
(
mallocedval
),
str
,
slen
+
1
);
strcpy
(
mallocedval
+
strlen
(
mallocedval
),
","
);
}
strcpy
(
mallocedval
+
strlen
(
mallocedval
)
-
1
,
"}'"
);
}
else
{
str
=
PGTYPESdate_dtoa
(
*
(
Date
*
)(
var
->
value
));
slen
=
strlen
(
str
);
if
(
!
(
mallocedval
=
ECPGalloc
(
slen
+
1
,
stmt
->
lineno
)))
return
false
;
strncpy
(
mallocedval
,
str
,
slen
);
mallocedval
[
slen
]
=
'\0'
;
}
*
tobeinserted_p
=
mallocedval
;
*
malloced_p
=
true
;
free
(
str
);
}
break
;
case
ECPGt_timestamp
:
{
char
*
str
=
NULL
;
int
slen
;
if
(
var
->
arrsize
>
1
)
{
for
(
element
=
0
;
element
<
var
->
arrsize
;
element
++
)
{
str
=
PGTYPEStimestamp_ttoa
(
*
(
Timestamp
*
)((
var
+
var
->
offset
*
element
)
->
value
));
slen
=
strlen
(
str
);
if
(
!
(
mallocedval
=
ECPGrealloc
(
mallocedval
,
strlen
(
mallocedval
)
+
slen
+
5
,
stmt
->
lineno
)))
return
false
;
if
(
!
element
)
strcpy
(
mallocedval
,
"'{"
);
strncpy
(
mallocedval
+
strlen
(
mallocedval
),
str
,
slen
+
1
);
strcpy
(
mallocedval
+
strlen
(
mallocedval
),
","
);
}
strcpy
(
mallocedval
+
strlen
(
mallocedval
)
-
1
,
"}'"
);
}
else
{
str
=
PGTYPEStimestamp_ttoa
(
*
(
Timestamp
*
)(
var
->
value
));
slen
=
strlen
(
str
);
if
(
!
(
mallocedval
=
ECPGalloc
(
slen
+
1
,
stmt
->
lineno
)))
return
false
;
strncpy
(
mallocedval
,
str
,
slen
);
mallocedval
[
slen
]
=
'\0'
;
}
*
tobeinserted_p
=
mallocedval
;
*
malloced_p
=
true
;
free
(
str
);
}
break
;
default:
/* Not implemented yet */
ECPGraise
(
stmt
->
lineno
,
ECPG_UNSUPPORTED
,
(
char
*
)
ECPGtype_name
(
var
->
type
));
...
...
src/interfaces/ecpg/ecpglib/typename.c
View file @
2e6f9756
/* $Header: /cvsroot/pgsql/src/interfaces/ecpg/ecpglib/typename.c,v 1.
1 2003/03/16 10:42:53
meskes Exp $ */
/* $Header: /cvsroot/pgsql/src/interfaces/ecpg/ecpglib/typename.c,v 1.
2 2003/03/20 15:56:50
meskes Exp $ */
#include "postgres_fe.h"
...
...
@@ -49,6 +49,10 @@ ECPGtype_name(enum ECPGttype typ)
return
"char"
;
case
ECPGt_numeric
:
return
"numeric"
;
case
ECPGt_date
:
return
"date"
;
case
ECPGt_timestamp
:
return
"timestamp"
;
default:
abort
();
}
...
...
src/interfaces/ecpg/include/decimal.h
View file @
2e6f9756
...
...
@@ -2,4 +2,14 @@
#ifndef dec_t
#define dec_t NumericVar
#define CSHORTTYPE 0
#define CMONEYTYPE 0
#define CCHARTYPE 0
#define CDECIMALTYPE 0
#define CINTTYPE 0
#define CDATETYPE 0
#define CDOUBLETYPE 0
#define CLONGTYPE 0
#endif
/* dec_t */
src/interfaces/ecpg/include/ecpgtype.h
View file @
2e6f9756
...
...
@@ -52,7 +52,9 @@ enum ECPGttype
ECPGt_NO_INDICATOR
,
/* no indicator */
ECPGt_long_long
,
ECPGt_unsigned_long_long
,
ECPGt_descriptor
,
/* sql descriptor, no C variable */
ECPGt_numeric
ECPGt_numeric
,
ECPGt_date
,
ECPGt_timestamp
};
/* descriptor items */
...
...
src/interfaces/ecpg/include/pgtypes_date.h
0 → 100644
View file @
2e6f9756
#ifndef PGTYPES_DATETIME
#define PGTYPES_DATETIME
#define Date long
extern
Date
PGTYPESdate_atod
(
char
*
,
char
**
);
extern
char
*
PGTYPESdate_dtoa
(
Date
);
extern
int
PGTYPESdate_julmdy
(
Date
,
int
*
);
extern
int
PGTYPESdate_mdyjul
(
int
*
,
Date
*
);
extern
int
PGTYPESdate_day
(
Date
);
#endif
/* PGTYPES_DATETIME */
src/interfaces/ecpg/include/pgtypes_error.h
View file @
2e6f9756
...
...
@@ -2,5 +2,7 @@
#define PGTYPES_BAD_NUMERIC 202
#define PGTYPES_DIVIDE_ZERO 203
#define PGTYPES_BAD_DATE 300
#define PGTYPES_BAD_DATE 210
#define PGTYPES_BAD_TIMESTAMP 220
src/interfaces/ecpg/include/pgtypes_timestamp.h
0 → 100644
View file @
2e6f9756
#ifndef PGTYPES_TIMESTAMP
#define PGTYPES_TIMESTAMP
#ifdef HAVE_INT64_TIMESTAMP
typedef
int64
Timestamp
;
typedef
int64
TimestampTz
;
#else
typedef
double
Timestamp
;
typedef
double
TimestampTz
;
#endif
extern
Timestamp
PGTYPEStimestamp_atot
(
char
*
,
char
**
);
extern
char
*
PGTYPEStimestamp_ttoa
(
Timestamp
);
#endif
/* PGTYPES_TIMESTAMP */
src/interfaces/ecpg/pgtypeslib/Makefile
View file @
2e6f9756
...
...
@@ -4,7 +4,7 @@
#
# Copyright (c) 1994, Regents of the University of California
#
# $Header: /cvsroot/pgsql/src/interfaces/ecpg/pgtypeslib/Makefile,v 1.
1 2003/03/16 10:42:54
meskes Exp $
# $Header: /cvsroot/pgsql/src/interfaces/ecpg/pgtypeslib/Makefile,v 1.
2 2003/03/20 15:56:50
meskes Exp $
#
#-------------------------------------------------------------------------
...
...
@@ -18,7 +18,7 @@ SO_MINOR_VERSION= 0.0
override CPPFLAGS
:
= -g -I$(top_srcdir)/src/interfaces/ecpg/include -I$(top_srcdir)/src/include/utils $(CPPFLAGS)
OBJS
=
numeric.o
OBJS
=
numeric.o
datetime.o common.o dt_common.o timestamp.o
all
:
all-lib
...
...
src/interfaces/ecpg/pgtypeslib/common.c
0 → 100644
View file @
2e6f9756
#include <errno.h>
#include "extern.h"
char
*
pgtypes_alloc
(
long
size
)
{
char
*
new
=
(
char
*
)
calloc
(
1L
,
size
);
if
(
!
new
)
{
errno
=
ENOMEM
;
return
NULL
;
}
memset
(
new
,
'\0'
,
size
);
return
(
new
);
}
char
*
pgtypes_strdup
(
char
*
str
)
{
char
*
new
=
(
char
*
)
strdup
(
str
);
if
(
!
new
)
errno
=
ENOMEM
;
return
(
new
);
}
src/interfaces/ecpg/pgtypeslib/datetime.c
0 → 100644
View file @
2e6f9756
#include <ctype.h>
#include <errno.h>
#include <time.h>
#include <float.h>
#include <stdlib.h>
#include <stdio.h>
#include "dt.h"
#include "extern.h"
#include "pgtypes_error.h"
#include "pgtypes_date.h"
Date
PGTYPESdate_atod
(
char
*
str
,
char
**
endptr
)
{
Date
dDate
;
fsec_t
fsec
;
struct
tm
tt
,
*
tm
=
&
tt
;
int
tzp
;
int
dtype
;
int
nf
;
char
*
field
[
MAXDATEFIELDS
];
int
ftype
[
MAXDATEFIELDS
];
char
lowstr
[
MAXDATELEN
+
1
];
char
*
realptr
;
char
**
ptr
=
(
endptr
!=
NULL
)
?
endptr
:
&
realptr
;
bool
EuroDates
=
FALSE
;
if
(
strlen
(
str
)
>=
sizeof
(
lowstr
))
{
errno
=
PGTYPES_BAD_DATE
;
return
-
1
;
}
if
((
ParseDateTime
(
str
,
lowstr
,
field
,
ftype
,
MAXDATEFIELDS
,
&
nf
,
ptr
)
!=
0
)
||
(
DecodeDateTime
(
field
,
ftype
,
nf
,
&
dtype
,
tm
,
&
fsec
,
&
tzp
,
EuroDates
)
!=
0
))
{
errno
=
PGTYPES_BAD_DATE
;
return
-
1
;
}
switch
(
dtype
)
{
case
DTK_DATE
:
break
;
case
DTK_EPOCH
:
GetEpochTime
(
tm
);
break
;
default:
errno
=
PGTYPES_BAD_DATE
;
return
-
1
;
}
dDate
=
(
date2j
(
tm
->
tm_year
,
tm
->
tm_mon
,
tm
->
tm_mday
)
-
date2j
(
2000
,
1
,
1
));
return
dDate
;
}
char
*
PGTYPESdate_dtoa
(
Date
dDate
)
{
struct
tm
tt
,
*
tm
=
&
tt
;
char
buf
[
MAXDATELEN
+
1
];
int
DateStyle
=
0
;
bool
EuroDates
=
FALSE
;
j2date
((
dDate
+
date2j
(
2000
,
1
,
1
)),
&
(
tm
->
tm_year
),
&
(
tm
->
tm_mon
),
&
(
tm
->
tm_mday
));
EncodeDateOnly
(
tm
,
DateStyle
,
buf
,
EuroDates
);
return
pgtypes_strdup
(
buf
);
}
int
PGTYPESdate_julmdy
(
Date
jd
,
int
*
mdy
)
{
printf
(
"day: %d
\n
"
,
mdy
[
0
]);
printf
(
"month: %d
\n
"
,
mdy
[
1
]);
printf
(
"year: %d
\n
"
,
mdy
[
2
]);
j2date
((
int
)
jd
,
mdy
+
2
,
mdy
+
1
,
mdy
+
0
);
return
0
;
}
int
PGTYPESdate_mdyjul
(
int
*
mdy
,
Date
*
jdate
)
{
/* month is mdy[0] */
/* day is mdy[1] */
/* year is mdy[2] */
printf
(
"day: %d
\n
"
,
mdy
[
1
]);
printf
(
"month: %d
\n
"
,
mdy
[
0
]);
printf
(
"year: %d
\n
"
,
mdy
[
2
]);
*
jdate
=
(
Date
)
date2j
(
mdy
[
2
],
mdy
[
0
],
mdy
[
1
]);
return
0
;
}
int
PGTYPESdate_day
(
Date
dDate
)
{
return
j2day
(
dDate
);
}
src/interfaces/ecpg/pgtypeslib/dt.h
0 → 100644
View file @
2e6f9756
#ifndef DT_H
#define DT_H
#define MAXTZLEN 10
#ifdef HAVE_INT64_TIMESTAMP
typedef
int32
fsec_t
;
#else
typedef
double
fsec_t
;
#define TIME_PREC_INV 1000000.0
#define JROUND(j) (rint(((double) (j))*TIME_PREC_INV)/TIME_PREC_INV)
#endif
#ifndef bool
#define bool char
#endif
/* ndef bool */
#ifndef FALSE
#define FALSE 0
#endif
/* FALSE */
#ifndef TRUE
#define TRUE 1
#endif
/* TRUE */
#define USE_POSTGRES_DATES 0
#define USE_ISO_DATES 1
#define USE_SQL_DATES 2
#define USE_GERMAN_DATES 3
#define DAGO "ago"
#define EPOCH "epoch"
#define INVALID "invalid"
#define EARLY "-infinity"
#define LATE "infinity"
#define NOW "now"
#define TODAY "today"
#define TOMORROW "tomorrow"
#define YESTERDAY "yesterday"
#define ZULU "zulu"
#define DMICROSEC "usecond"
#define DMILLISEC "msecond"
#define DSECOND "second"
#define DMINUTE "minute"
#define DHOUR "hour"
#define DDAY "day"
#define DWEEK "week"
#define DMONTH "month"
#define DQUARTER "quarter"
#define DYEAR "year"
#define DDECADE "decade"
#define DCENTURY "century"
#define DMILLENNIUM "millennium"
#define DA_D "ad"
#define DB_C "bc"
#define DTIMEZONE "timezone"
#define DCURRENT "current"
/*
* Fundamental time field definitions for parsing.
*
* Meridian: am, pm, or 24-hour style.
* Millennium: ad, bc
*/
#define AM 0
#define PM 1
#define HR24 2
#define AD 0
#define BC 1
/*
* Fields for time decoding.
*
* Can't have more of these than there are bits in an unsigned int
* since these are turned into bit masks during parsing and decoding.
*
* Furthermore, the values for YEAR, MONTH, DAY, HOUR, MINUTE, SECOND
* must be in the range 0..14 so that the associated bitmasks can fit
* into the left half of an INTERVAL's typmod value.
*/
#define RESERV 0
#define MONTH 1
#define YEAR 2
#define DAY 3
#define JULIAN 4
#define TZ 5
#define DTZ 6
#define DTZMOD 7
#define IGNORE_DTF 8
#define AMPM 9
#define HOUR 10
#define MINUTE 11
#define SECOND 12
#define DOY 13
#define DOW 14
#define UNITS 15
#define ADBC 16
/* these are only for relative dates */
#define AGO 17
#define ABS_BEFORE 18
#define ABS_AFTER 19
/* generic fields to help with parsing */
#define ISODATE 20
#define ISOTIME 21
/* reserved for unrecognized string values */
#define UNKNOWN_FIELD 31
/*
* Token field definitions for time parsing and decoding.
* These need to fit into the datetkn table type.
* At the moment, that means keep them within [-127,127].
* These are also used for bit masks in DecodeDateDelta()
* so actually restrict them to within [0,31] for now.
* - thomas 97/06/19
* Not all of these fields are used for masks in DecodeDateDelta
* so allow some larger than 31. - thomas 1997-11-17
*/
#define DTK_NUMBER 0
#define DTK_STRING 1
#define DTK_DATE 2
#define DTK_TIME 3
#define DTK_TZ 4
#define DTK_AGO 5
#define DTK_SPECIAL 6
#define DTK_INVALID 7
#define DTK_CURRENT 8
#define DTK_EARLY 9
#define DTK_LATE 10
#define DTK_EPOCH 11
#define DTK_NOW 12
#define DTK_YESTERDAY 13
#define DTK_TODAY 14
#define DTK_TOMORROW 15
#define DTK_ZULU 16
#define DTK_DELTA 17
#define DTK_SECOND 18
#define DTK_MINUTE 19
#define DTK_HOUR 20
#define DTK_DAY 21
#define DTK_WEEK 22
#define DTK_MONTH 23
#define DTK_QUARTER 24
#define DTK_YEAR 25
#define DTK_DECADE 26
#define DTK_CENTURY 27
#define DTK_MILLENNIUM 28
#define DTK_MILLISEC 29
#define DTK_MICROSEC 30
#define DTK_JULIAN 31
#define DTK_DOW 32
#define DTK_DOY 33
#define DTK_TZ_HOUR 34
#define DTK_TZ_MINUTE 35
/*
* Bit mask definitions for time parsing.
*/
#define DTK_M(t) (0x01 << (t))
#define DTK_DATE_M (DTK_M(YEAR) | DTK_M(MONTH) | DTK_M(DAY))
#define DTK_TIME_M (DTK_M(HOUR) | DTK_M(MINUTE) | DTK_M(SECOND))
#define MAXDATELEN 51
/* maximum possible length of an input
* date string (not counting tr. null) */
#define MAXDATEFIELDS 25
/* maximum possible number of fields in a
* date string */
#define TOKMAXLEN 10
/* only this many chars are stored in
* datetktbl */
/* keep this struct small; it gets used a lot */
typedef
struct
{
#if defined(_AIX)
char
*
token
;
#else
char
token
[
TOKMAXLEN
];
#endif
/* _AIX */
char
type
;
char
value
;
/* this may be unsigned, alas */
}
datetkn
;
/* TMODULO()
* Macro to replace modf(), which is broken on some platforms.
* t = input and remainder
* q = integer part
* u = divisor
*/
#ifdef HAVE_INT64_TIMESTAMP
#define TMODULO(t,q,u) \
do { \
q = (t / u); \
if (q != 0) t -= (q * u); \
} while(0)
#else
#define TMODULO(t,q,u) \
do { \
q = ((t < 0)? ceil(t / u): floor(t / u)); \
if (q != 0) t -= rint(q * u); \
} while(0)
#endif
/* Global variable holding time zone information. */
#if defined(__CYGWIN__) || defined(N_PLAT_NLM)
#define TIMEZONE_GLOBAL _timezone
#else
#define TIMEZONE_GLOBAL timezone
#endif
/*
* Date/time validation
* Include check for leap year.
*/
extern
int
day_tab
[
2
][
13
];
#define isleap(y) (((y) % 4) == 0 && (((y) % 100) != 0 || ((y) % 400) == 0))
/* Julian date support for date2j() and j2date()
* Set the minimum year to one greater than the year of the first valid day
* to avoid having to check year and day both. - tgl 97/05/08
*/
#define JULIAN_MINYEAR (-4713)
#define JULIAN_MINMONTH (11)
#define JULIAN_MINDAY (24)
#define IS_VALID_JULIAN(y,m,d) (((y) > JULIAN_MINYEAR) \
|| (((y) == JULIAN_MINYEAR) && (((m) > JULIAN_MINMONTH) \
|| (((m) == JULIAN_MINMONTH) && ((d) >= JULIAN_MINDAY)))))
#define UTIME_MINYEAR (1901)
#define UTIME_MINMONTH (12)
#define UTIME_MINDAY (14)
#define UTIME_MAXYEAR (2038)
#define UTIME_MAXMONTH (01)
#define UTIME_MAXDAY (18)
#define IS_VALID_UTIME(y,m,d) ((((y) > UTIME_MINYEAR) \
|| (((y) == UTIME_MINYEAR) && (((m) > UTIME_MINMONTH) \
|| (((m) == UTIME_MINMONTH) && ((d) >= UTIME_MINDAY))))) \
&& (((y) < UTIME_MAXYEAR) \
|| (((y) == UTIME_MAXYEAR) && (((m) < UTIME_MAXMONTH) \
|| (((m) == UTIME_MAXMONTH) && ((d) <= UTIME_MAXDAY))))))
#ifdef HUGE_VAL
#define DT_NOBEGIN (-HUGE_VAL)
#define DT_NOEND (HUGE_VAL)
#else
#define DT_NOBEGIN (-DBL_MAX)
#define DT_NOEND (DBL_MAX)
#endif
#define TIMESTAMP_NOBEGIN(j) do {j = DT_NOBEGIN;} while (0)
#define TIMESTAMP_NOEND(j) do {j = DT_NOEND;} while (0)
#define TIMESTAMP_IS_NOBEGIN(j) ((j) == DT_NOBEGIN)
#define TIMESTAMP_IS_NOEND(j) ((j) == DT_NOEND)
#define TIMESTAMP_NOT_FINITE(j) (TIMESTAMP_IS_NOBEGIN(j) || TIMESTAMP_IS_NOEND(j))
extern
int
DecodeTimeOnly
(
char
**
field
,
int
*
ftype
,
int
nf
,
int
*
dtype
,
struct
tm
*
tm
,
fsec_t
*
fsec
,
int
*
tzp
);
extern
int
DecodeInterval
(
char
**
field
,
int
*
ftype
,
int
nf
,
int
*
dtype
,
struct
tm
*
tm
,
fsec_t
*
fsec
);
extern
int
EncodeTimeOnly
(
struct
tm
*
tm
,
fsec_t
fsec
,
int
*
tzp
,
int
style
,
char
*
str
);
extern
int
EncodeDateTime
(
struct
tm
*
tm
,
fsec_t
fsec
,
int
*
tzp
,
char
**
tzn
,
int
style
,
char
*
str
,
bool
);
extern
int
EncodeInterval
(
struct
tm
*
tm
,
fsec_t
fsec
,
int
style
,
char
*
str
);
extern
int
DecodeUnits
(
int
field
,
char
*
lowtoken
,
int
*
val
);
extern
bool
ClearDateCache
(
bool
,
bool
,
bool
);
extern
int
j2day
(
int
jd
);
extern
bool
CheckDateTokenTables
(
void
);
extern
int
EncodeDateOnly
(
struct
tm
*
,
int
,
char
*
,
bool
);
extern
void
GetEpochTime
(
struct
tm
*
);
extern
int
ParseDateTime
(
char
*
,
char
*
,
char
**
,
int
*
,
int
,
int
*
,
char
**
);
extern
int
DecodeDateTime
(
char
**
,
int
*
,
int
,
int
*
,
struct
tm
*
,
fsec_t
*
,
int
*
,
bool
);
extern
void
j2date
(
int
,
int
*
,
int
*
,
int
*
);
extern
int
date2j
(
int
,
int
,
int
);
extern
double
rint
(
double
x
);
#endif
/* DT_H */
src/interfaces/ecpg/pgtypeslib/dt_common.c
0 → 100644
View file @
2e6f9756
#include <ctype.h>
#include <errno.h>
#include <time.h>
#include <float.h>
#include <stdlib.h>
#include <stdio.h>
#include "dt.h"
#include "extern.h"
static
int
day_tab
[
2
][
13
]
=
{
{
31
,
28
,
31
,
30
,
31
,
30
,
31
,
31
,
30
,
31
,
30
,
31
,
0
},
{
31
,
29
,
31
,
30
,
31
,
30
,
31
,
31
,
30
,
31
,
30
,
31
,
0
}};
typedef
long
AbsoluteTime
;
#define ABS_SIGNBIT ((char) 0200)
#define POS(n) (n)
#define NEG(n) ((n)|ABS_SIGNBIT)
#define FROMVAL(tp) (-SIGNEDCHAR((tp)->value) * 15)
/* uncompress */
#define VALMASK ((char) 0177)
#define SIGNEDCHAR(c) ((c)&ABS_SIGNBIT? -((c)&VALMASK): (c))
static
datetkn
datetktbl
[]
=
{
/* text, token, lexval */
{
EARLY
,
RESERV
,
DTK_EARLY
},
/* "-infinity" reserved for "early time" */
{
"abstime"
,
IGNORE_DTF
,
0
},
/* for pre-v6.1 "Invalid Abstime" */
{
"acsst"
,
DTZ
,
POS
(
42
)},
/* Cent. Australia */
{
"acst"
,
DTZ
,
NEG
(
16
)},
/* Atlantic/Porto Acre */
{
"act"
,
TZ
,
NEG
(
20
)},
/* Atlantic/Porto Acre */
{
DA_D
,
ADBC
,
AD
},
/* "ad" for years >= 0 */
{
"adt"
,
DTZ
,
NEG
(
12
)},
/* Atlantic Daylight Time */
{
"aesst"
,
DTZ
,
POS
(
44
)},
/* E. Australia */
{
"aest"
,
TZ
,
POS
(
40
)},
/* Australia Eastern Std Time */
{
"aft"
,
TZ
,
POS
(
18
)},
/* Kabul */
{
"ahst"
,
TZ
,
NEG
(
40
)},
/* Alaska-Hawaii Std Time */
{
"akdt"
,
DTZ
,
NEG
(
32
)},
/* Alaska Daylight Time */
{
"akst"
,
DTZ
,
NEG
(
36
)},
/* Alaska Standard Time */
{
"allballs"
,
RESERV
,
DTK_ZULU
},
/* 00:00:00 */
{
"almst"
,
TZ
,
POS
(
28
)},
/* Almaty Savings Time */
{
"almt"
,
TZ
,
POS
(
24
)},
/* Almaty Time */
{
"am"
,
AMPM
,
AM
},
{
"amst"
,
DTZ
,
POS
(
20
)},
/* Armenia Summer Time (Yerevan) */
#if 0
{"amst", DTZ, NEG(12)}, /* Porto Velho */
#endif
{
"amt"
,
TZ
,
POS
(
16
)},
/* Armenia Time (Yerevan) */
{
"anast"
,
DTZ
,
POS
(
52
)},
/* Anadyr Summer Time (Russia) */
{
"anat"
,
TZ
,
POS
(
48
)},
/* Anadyr Time (Russia) */
{
"apr"
,
MONTH
,
4
},
{
"april"
,
MONTH
,
4
},
#if 0
aqtst
aqtt
arst
#endif
{
"art"
,
TZ
,
NEG
(
12
)},
/* Argentina Time */
#if 0
ashst
ast /* Atlantic Standard Time, Arabia Standard
* Time, Acre Standard Time */
#endif
{
"ast"
,
TZ
,
NEG
(
16
)},
/* Atlantic Std Time (Canada) */
{
"at"
,
IGNORE_DTF
,
0
},
/* "at" (throwaway) */
{
"aug"
,
MONTH
,
8
},
{
"august"
,
MONTH
,
8
},
{
"awsst"
,
DTZ
,
POS
(
36
)},
/* W. Australia */
{
"awst"
,
TZ
,
POS
(
32
)},
/* W. Australia */
{
"awt"
,
DTZ
,
NEG
(
12
)},
{
"azost"
,
DTZ
,
POS
(
0
)},
/* Azores Summer Time */
{
"azot"
,
TZ
,
NEG
(
4
)},
/* Azores Time */
{
"azst"
,
DTZ
,
POS
(
20
)},
/* Azerbaijan Summer Time */
{
"azt"
,
TZ
,
POS
(
16
)},
/* Azerbaijan Time */
{
DB_C
,
ADBC
,
BC
},
/* "bc" for years < 0 */
{
"bdst"
,
TZ
,
POS
(
8
)},
/* British Double Summer Time */
{
"bdt"
,
TZ
,
POS
(
24
)},
/* Dacca */
{
"bnt"
,
TZ
,
POS
(
32
)},
/* Brunei Darussalam Time */
{
"bort"
,
TZ
,
POS
(
32
)},
/* Borneo Time (Indonesia) */
#if 0
bortst
bost
#endif
{
"bot"
,
TZ
,
NEG
(
16
)},
/* Bolivia Time */
{
"bra"
,
TZ
,
NEG
(
12
)},
/* Brazil Time */
#if 0
brst
brt
#endif
{
"bst"
,
DTZ
,
POS
(
4
)},
/* British Summer Time */
#if 0
{"bst", TZ, NEG(12)}, /* Brazil Standard Time */
{"bst", DTZ, NEG(44)}, /* Bering Summer Time */
#endif
{
"bt"
,
TZ
,
POS
(
12
)},
/* Baghdad Time */
{
"btt"
,
TZ
,
POS
(
24
)},
/* Bhutan Time */
{
"cadt"
,
DTZ
,
POS
(
42
)},
/* Central Australian DST */
{
"cast"
,
TZ
,
POS
(
38
)},
/* Central Australian ST */
{
"cat"
,
TZ
,
NEG
(
40
)},
/* Central Alaska Time */
{
"cct"
,
TZ
,
POS
(
32
)},
/* China Coast Time */
#if 0
{"cct", TZ, POS(26)}, /* Indian Cocos (Island) Time */
#endif
{
"cdt"
,
DTZ
,
NEG
(
20
)},
/* Central Daylight Time */
{
"cest"
,
DTZ
,
POS
(
8
)},
/* Central European Dayl.Time */
{
"cet"
,
TZ
,
POS
(
4
)},
/* Central European Time */
{
"cetdst"
,
DTZ
,
POS
(
8
)},
/* Central European Dayl.Time */
{
"chadt"
,
DTZ
,
POS
(
55
)},
/* Chatham Island Daylight Time (13:45) */
{
"chast"
,
TZ
,
POS
(
51
)},
/* Chatham Island Time (12:45) */
#if 0
ckhst
#endif
{
"ckt"
,
TZ
,
POS
(
48
)},
/* Cook Islands Time */
{
"clst"
,
DTZ
,
NEG
(
12
)},
/* Chile Summer Time */
{
"clt"
,
TZ
,
NEG
(
16
)},
/* Chile Time */
#if 0
cost
#endif
{
"cot"
,
TZ
,
NEG
(
20
)},
/* Columbia Time */
{
"cst"
,
TZ
,
NEG
(
24
)},
/* Central Standard Time */
{
DCURRENT
,
RESERV
,
DTK_CURRENT
},
/* "current" is always now */
#if 0
cvst
#endif
{
"cvt"
,
TZ
,
POS
(
28
)},
/* Christmas Island Time (Indian Ocean) */
{
"cxt"
,
TZ
,
POS
(
28
)},
/* Christmas Island Time (Indian Ocean) */
{
"d"
,
UNITS
,
DTK_DAY
},
/* "day of month" for ISO input */
{
"davt"
,
TZ
,
POS
(
28
)},
/* Davis Time (Antarctica) */
{
"ddut"
,
TZ
,
POS
(
40
)},
/* Dumont-d'Urville Time (Antarctica) */
{
"dec"
,
MONTH
,
12
},
{
"december"
,
MONTH
,
12
},
{
"dnt"
,
TZ
,
POS
(
4
)},
/* Dansk Normal Tid */
{
"dow"
,
RESERV
,
DTK_DOW
},
/* day of week */
{
"doy"
,
RESERV
,
DTK_DOY
},
/* day of year */
{
"dst"
,
DTZMOD
,
6
},
#if 0
{"dusst", DTZ, POS(24)}, /* Dushanbe Summer Time */
#endif
{
"easst"
,
DTZ
,
NEG
(
20
)},
/* Easter Island Summer Time */
{
"east"
,
TZ
,
NEG
(
24
)},
/* Easter Island Time */
{
"eat"
,
TZ
,
POS
(
12
)},
/* East Africa Time */
#if 0
{"east", DTZ, POS(16)}, /* Indian Antananarivo Savings Time */
{"eat", TZ, POS(12)}, /* Indian Antananarivo Time */
{"ect", TZ, NEG(16)}, /* Eastern Caribbean Time */
{"ect", TZ, NEG(20)}, /* Ecuador Time */
#endif
{
"edt"
,
DTZ
,
NEG
(
16
)},
/* Eastern Daylight Time */
{
"eest"
,
DTZ
,
POS
(
12
)},
/* Eastern Europe Summer Time */
{
"eet"
,
TZ
,
POS
(
8
)},
/* East. Europe, USSR Zone 1 */
{
"eetdst"
,
DTZ
,
POS
(
12
)},
/* Eastern Europe Daylight Time */
{
"egst"
,
DTZ
,
POS
(
0
)},
/* East Greenland Summer Time */
{
"egt"
,
TZ
,
NEG
(
4
)},
/* East Greenland Time */
#if 0
ehdt
#endif
{
EPOCH
,
RESERV
,
DTK_EPOCH
},
/* "epoch" reserved for system epoch time */
{
"est"
,
TZ
,
NEG
(
20
)},
/* Eastern Standard Time */
{
"feb"
,
MONTH
,
2
},
{
"february"
,
MONTH
,
2
},
{
"fjst"
,
DTZ
,
NEG
(
52
)},
/* Fiji Summer Time (13 hour offset!) */
{
"fjt"
,
TZ
,
NEG
(
48
)},
/* Fiji Time */
{
"fkst"
,
DTZ
,
NEG
(
12
)},
/* Falkland Islands Summer Time */
{
"fkt"
,
TZ
,
NEG
(
8
)},
/* Falkland Islands Time */
#if 0
fnst
fnt
#endif
{
"fri"
,
DOW
,
5
},
{
"friday"
,
DOW
,
5
},
{
"fst"
,
TZ
,
POS
(
4
)},
/* French Summer Time */
{
"fwt"
,
DTZ
,
POS
(
8
)},
/* French Winter Time */
{
"galt"
,
TZ
,
NEG
(
24
)},
/* Galapagos Time */
{
"gamt"
,
TZ
,
NEG
(
36
)},
/* Gambier Time */
{
"gest"
,
DTZ
,
POS
(
20
)},
/* Georgia Summer Time */
{
"get"
,
TZ
,
POS
(
16
)},
/* Georgia Time */
{
"gft"
,
TZ
,
NEG
(
12
)},
/* French Guiana Time */
#if 0
ghst
#endif
{
"gilt"
,
TZ
,
POS
(
48
)},
/* Gilbert Islands Time */
{
"gmt"
,
TZ
,
POS
(
0
)},
/* Greenwish Mean Time */
{
"gst"
,
TZ
,
POS
(
40
)},
/* Guam Std Time, USSR Zone 9 */
{
"gyt"
,
TZ
,
NEG
(
16
)},
/* Guyana Time */
{
"h"
,
UNITS
,
DTK_HOUR
},
/* "hour" */
#if 0
hadt
hast
#endif
{
"hdt"
,
DTZ
,
NEG
(
36
)},
/* Hawaii/Alaska Daylight Time */
#if 0
hkst
#endif
{
"hkt"
,
TZ
,
POS
(
32
)},
/* Hong Kong Time */
#if 0
{"hmt", TZ, POS(12)}, /* Hellas ? ? */
hovst
hovt
#endif
{
"hst"
,
TZ
,
NEG
(
40
)},
/* Hawaii Std Time */
#if 0
hwt
#endif
{
"ict"
,
TZ
,
POS
(
28
)},
/* Indochina Time */
{
"idle"
,
TZ
,
POS
(
48
)},
/* Intl. Date Line, East */
{
"idlw"
,
TZ
,
NEG
(
48
)},
/* Intl. Date Line, West */
#if 0
idt /* Israeli, Iran, Indian Daylight Time */
#endif
{
LATE
,
RESERV
,
DTK_LATE
},
/* "infinity" reserved for "late time" */
{
INVALID
,
RESERV
,
DTK_INVALID
},
/* "invalid" reserved for bad time */
{
"iot"
,
TZ
,
POS
(
20
)},
/* Indian Chagos Time */
{
"irkst"
,
DTZ
,
POS
(
36
)},
/* Irkutsk Summer Time */
{
"irkt"
,
TZ
,
POS
(
32
)},
/* Irkutsk Time */
{
"irt"
,
TZ
,
POS
(
14
)},
/* Iran Time */
#if 0
isst
#endif
{
"ist"
,
TZ
,
POS
(
8
)},
/* Israel */
{
"it"
,
TZ
,
POS
(
14
)},
/* Iran Time */
{
"j"
,
UNITS
,
DTK_JULIAN
},
{
"jan"
,
MONTH
,
1
},
{
"january"
,
MONTH
,
1
},
{
"javt"
,
TZ
,
POS
(
28
)},
/* Java Time (07:00? see JT) */
{
"jayt"
,
TZ
,
POS
(
36
)},
/* Jayapura Time (Indonesia) */
{
"jd"
,
UNITS
,
DTK_JULIAN
},
{
"jst"
,
TZ
,
POS
(
36
)},
/* Japan Std Time,USSR Zone 8 */
{
"jt"
,
TZ
,
POS
(
30
)},
/* Java Time (07:30? see JAVT) */
{
"jul"
,
MONTH
,
7
},
{
"julian"
,
UNITS
,
DTK_JULIAN
},
{
"july"
,
MONTH
,
7
},
{
"jun"
,
MONTH
,
6
},
{
"june"
,
MONTH
,
6
},
{
"kdt"
,
DTZ
,
POS
(
40
)},
/* Korea Daylight Time */
{
"kgst"
,
DTZ
,
POS
(
24
)},
/* Kyrgyzstan Summer Time */
{
"kgt"
,
TZ
,
POS
(
20
)},
/* Kyrgyzstan Time */
{
"kost"
,
TZ
,
POS
(
48
)},
/* Kosrae Time */
{
"krast"
,
DTZ
,
POS
(
28
)},
/* Krasnoyarsk Summer Time */
{
"krat"
,
TZ
,
POS
(
32
)},
/* Krasnoyarsk Standard Time */
{
"kst"
,
TZ
,
POS
(
36
)},
/* Korea Standard Time */
{
"lhdt"
,
DTZ
,
POS
(
44
)},
/* Lord Howe Daylight Time, Australia */
{
"lhst"
,
TZ
,
POS
(
42
)},
/* Lord Howe Standard Time, Australia */
{
"ligt"
,
TZ
,
POS
(
40
)},
/* From Melbourne, Australia */
{
"lint"
,
TZ
,
POS
(
56
)},
/* Line Islands Time (Kiribati; +14
* hours!) */
{
"lkt"
,
TZ
,
POS
(
24
)},
/* Lanka Time */
{
"m"
,
UNITS
,
DTK_MONTH
},
/* "month" for ISO input */
{
"magst"
,
DTZ
,
POS
(
48
)},
/* Magadan Summer Time */
{
"magt"
,
TZ
,
POS
(
44
)},
/* Magadan Time */
{
"mar"
,
MONTH
,
3
},
{
"march"
,
MONTH
,
3
},
{
"mart"
,
TZ
,
NEG
(
38
)},
/* Marquesas Time */
{
"mawt"
,
TZ
,
POS
(
24
)},
/* Mawson, Antarctica */
{
"may"
,
MONTH
,
5
},
{
"mdt"
,
DTZ
,
NEG
(
24
)},
/* Mountain Daylight Time */
{
"mest"
,
DTZ
,
POS
(
8
)},
/* Middle Europe Summer Time */
{
"met"
,
TZ
,
POS
(
4
)},
/* Middle Europe Time */
{
"metdst"
,
DTZ
,
POS
(
8
)},
/* Middle Europe Daylight Time */
{
"mewt"
,
TZ
,
POS
(
4
)},
/* Middle Europe Winter Time */
{
"mez"
,
TZ
,
POS
(
4
)},
/* Middle Europe Zone */
{
"mht"
,
TZ
,
POS
(
48
)},
/* Kwajalein */
{
"mm"
,
UNITS
,
DTK_MINUTE
},
/* "minute" for ISO input */
{
"mmt"
,
TZ
,
POS
(
26
)},
/* Myannar Time */
{
"mon"
,
DOW
,
1
},
{
"monday"
,
DOW
,
1
},
#if 0
most
#endif
{
"mpt"
,
TZ
,
POS
(
40
)},
/* North Mariana Islands Time */
{
"msd"
,
DTZ
,
POS
(
16
)},
/* Moscow Summer Time */
{
"msk"
,
TZ
,
POS
(
12
)},
/* Moscow Time */
{
"mst"
,
TZ
,
NEG
(
28
)},
/* Mountain Standard Time */
{
"mt"
,
TZ
,
POS
(
34
)},
/* Moluccas Time */
{
"mut"
,
TZ
,
POS
(
16
)},
/* Mauritius Island Time */
{
"mvt"
,
TZ
,
POS
(
20
)},
/* Maldives Island Time */
{
"myt"
,
TZ
,
POS
(
32
)},
/* Malaysia Time */
#if 0
ncst
#endif
{
"nct"
,
TZ
,
POS
(
44
)},
/* New Caledonia Time */
{
"ndt"
,
DTZ
,
NEG
(
10
)},
/* Nfld. Daylight Time */
{
"nft"
,
TZ
,
NEG
(
14
)},
/* Newfoundland Standard Time */
{
"nor"
,
TZ
,
POS
(
4
)},
/* Norway Standard Time */
{
"nov"
,
MONTH
,
11
},
{
"november"
,
MONTH
,
11
},
{
"novst"
,
DTZ
,
POS
(
28
)},
/* Novosibirsk Summer Time */
{
"novt"
,
TZ
,
POS
(
24
)},
/* Novosibirsk Standard Time */
{
NOW
,
RESERV
,
DTK_NOW
},
/* current transaction time */
{
"npt"
,
TZ
,
POS
(
23
)},
/* Nepal Standard Time (GMT-5:45) */
{
"nst"
,
TZ
,
NEG
(
14
)},
/* Nfld. Standard Time */
{
"nt"
,
TZ
,
NEG
(
44
)},
/* Nome Time */
{
"nut"
,
TZ
,
NEG
(
44
)},
/* Niue Time */
{
"nzdt"
,
DTZ
,
POS
(
52
)},
/* New Zealand Daylight Time */
{
"nzst"
,
TZ
,
POS
(
48
)},
/* New Zealand Standard Time */
{
"nzt"
,
TZ
,
POS
(
48
)},
/* New Zealand Time */
{
"oct"
,
MONTH
,
10
},
{
"october"
,
MONTH
,
10
},
{
"omsst"
,
DTZ
,
POS
(
28
)},
/* Omsk Summer Time */
{
"omst"
,
TZ
,
POS
(
24
)},
/* Omsk Time */
{
"on"
,
IGNORE_DTF
,
0
},
/* "on" (throwaway) */
{
"pdt"
,
DTZ
,
NEG
(
28
)},
/* Pacific Daylight Time */
#if 0
pest
#endif
{
"pet"
,
TZ
,
NEG
(
20
)},
/* Peru Time */
{
"petst"
,
DTZ
,
POS
(
52
)},
/* Petropavlovsk-Kamchatski Summer Time */
{
"pett"
,
TZ
,
POS
(
48
)},
/* Petropavlovsk-Kamchatski Time */
{
"pgt"
,
TZ
,
POS
(
40
)},
/* Papua New Guinea Time */
{
"phot"
,
TZ
,
POS
(
52
)},
/* Phoenix Islands (Kiribati) Time */
#if 0
phst
#endif
{
"pht"
,
TZ
,
POS
(
32
)},
/* Phillipine Time */
{
"pkt"
,
TZ
,
POS
(
20
)},
/* Pakistan Time */
{
"pm"
,
AMPM
,
PM
},
{
"pmdt"
,
DTZ
,
NEG
(
8
)},
/* Pierre & Miquelon Daylight Time */
#if 0
pmst
#endif
{
"pont"
,
TZ
,
POS
(
44
)},
/* Ponape Time (Micronesia) */
{
"pst"
,
TZ
,
NEG
(
32
)},
/* Pacific Standard Time */
{
"pwt"
,
TZ
,
POS
(
36
)},
/* Palau Time */
{
"pyst"
,
DTZ
,
NEG
(
12
)},
/* Paraguay Summer Time */
{
"pyt"
,
TZ
,
NEG
(
16
)},
/* Paraguay Time */
{
"ret"
,
DTZ
,
POS
(
16
)},
/* Reunion Island Time */
{
"s"
,
UNITS
,
DTK_SECOND
},
/* "seconds" for ISO input */
{
"sadt"
,
DTZ
,
POS
(
42
)},
/* S. Australian Dayl. Time */
#if 0
samst
samt
#endif
{
"sast"
,
TZ
,
POS
(
38
)},
/* South Australian Std Time */
{
"sat"
,
DOW
,
6
},
{
"saturday"
,
DOW
,
6
},
#if 0
sbt
#endif
{
"sct"
,
DTZ
,
POS
(
16
)},
/* Mahe Island Time */
{
"sep"
,
MONTH
,
9
},
{
"sept"
,
MONTH
,
9
},
{
"september"
,
MONTH
,
9
},
{
"set"
,
TZ
,
NEG
(
4
)},
/* Seychelles Time ?? */
#if 0
sgt
#endif
{
"sst"
,
DTZ
,
POS
(
8
)},
/* Swedish Summer Time */
{
"sun"
,
DOW
,
0
},
{
"sunday"
,
DOW
,
0
},
{
"swt"
,
TZ
,
POS
(
4
)},
/* Swedish Winter Time */
#if 0
syot
#endif
{
"t"
,
ISOTIME
,
DTK_TIME
},
/* Filler for ISO time fields */
{
"tft"
,
TZ
,
POS
(
20
)},
/* Kerguelen Time */
{
"that"
,
TZ
,
NEG
(
40
)},
/* Tahiti Time */
{
"thu"
,
DOW
,
4
},
{
"thur"
,
DOW
,
4
},
{
"thurs"
,
DOW
,
4
},
{
"thursday"
,
DOW
,
4
},
{
"tjt"
,
TZ
,
POS
(
20
)},
/* Tajikistan Time */
{
"tkt"
,
TZ
,
NEG
(
40
)},
/* Tokelau Time */
{
"tmt"
,
TZ
,
POS
(
20
)},
/* Turkmenistan Time */
{
TODAY
,
RESERV
,
DTK_TODAY
},
/* midnight */
{
TOMORROW
,
RESERV
,
DTK_TOMORROW
},
/* tomorrow midnight */
#if 0
tost
#endif
{
"tot"
,
TZ
,
POS
(
52
)},
/* Tonga Time */
#if 0
tpt
#endif
{
"truk"
,
TZ
,
POS
(
40
)},
/* Truk Time */
{
"tue"
,
DOW
,
2
},
{
"tues"
,
DOW
,
2
},
{
"tuesday"
,
DOW
,
2
},
{
"tvt"
,
TZ
,
POS
(
48
)},
/* Tuvalu Time */
#if 0
uct
#endif
{
"ulast"
,
DTZ
,
POS
(
36
)},
/* Ulan Bator Summer Time */
{
"ulat"
,
TZ
,
POS
(
32
)},
/* Ulan Bator Time */
{
"undefined"
,
RESERV
,
DTK_INVALID
},
/* pre-v6.1 invalid time */
{
"ut"
,
TZ
,
POS
(
0
)},
{
"utc"
,
TZ
,
POS
(
0
)},
{
"uyst"
,
DTZ
,
NEG
(
8
)},
/* Uruguay Summer Time */
{
"uyt"
,
TZ
,
NEG
(
12
)},
/* Uruguay Time */
{
"uzst"
,
DTZ
,
POS
(
24
)},
/* Uzbekistan Summer Time */
{
"uzt"
,
TZ
,
POS
(
20
)},
/* Uzbekistan Time */
{
"vet"
,
TZ
,
NEG
(
16
)},
/* Venezuela Time */
{
"vlast"
,
DTZ
,
POS
(
44
)},
/* Vladivostok Summer Time */
{
"vlat"
,
TZ
,
POS
(
40
)},
/* Vladivostok Time */
#if 0
vust
#endif
{
"vut"
,
TZ
,
POS
(
44
)},
/* Vanuata Time */
{
"wadt"
,
DTZ
,
POS
(
32
)},
/* West Australian DST */
{
"wakt"
,
TZ
,
POS
(
48
)},
/* Wake Time */
#if 0
warst
#endif
{
"wast"
,
TZ
,
POS
(
28
)},
/* West Australian Std Time */
{
"wat"
,
TZ
,
NEG
(
4
)},
/* West Africa Time */
{
"wdt"
,
DTZ
,
POS
(
36
)},
/* West Australian DST */
{
"wed"
,
DOW
,
3
},
{
"wednesday"
,
DOW
,
3
},
{
"weds"
,
DOW
,
3
},
{
"west"
,
DTZ
,
POS
(
4
)},
/* Western Europe Summer Time */
{
"wet"
,
TZ
,
POS
(
0
)},
/* Western Europe */
{
"wetdst"
,
DTZ
,
POS
(
4
)},
/* Western Europe Daylight Savings Time */
{
"wft"
,
TZ
,
POS
(
48
)},
/* Wallis and Futuna Time */
{
"wgst"
,
DTZ
,
NEG
(
8
)},
/* West Greenland Summer Time */
{
"wgt"
,
TZ
,
NEG
(
12
)},
/* West Greenland Time */
{
"wst"
,
TZ
,
POS
(
32
)},
/* West Australian Standard Time */
{
"y"
,
UNITS
,
DTK_YEAR
},
/* "year" for ISO input */
{
"yakst"
,
DTZ
,
POS
(
40
)},
/* Yakutsk Summer Time */
{
"yakt"
,
TZ
,
POS
(
36
)},
/* Yakutsk Time */
{
"yapt"
,
TZ
,
POS
(
40
)},
/* Yap Time (Micronesia) */
{
"ydt"
,
DTZ
,
NEG
(
32
)},
/* Yukon Daylight Time */
{
"yekst"
,
DTZ
,
POS
(
24
)},
/* Yekaterinburg Summer Time */
{
"yekt"
,
TZ
,
POS
(
20
)},
/* Yekaterinburg Time */
{
YESTERDAY
,
RESERV
,
DTK_YESTERDAY
},
/* yesterday midnight */
{
"yst"
,
TZ
,
NEG
(
36
)},
/* Yukon Standard Time */
{
"z"
,
TZ
,
POS
(
0
)},
/* time zone tag per ISO-8601 */
{
"zp4"
,
TZ
,
NEG
(
16
)},
/* UTC +4 hours. */
{
"zp5"
,
TZ
,
NEG
(
20
)},
/* UTC +5 hours. */
{
"zp6"
,
TZ
,
NEG
(
24
)},
/* UTC +6 hours. */
{
ZULU
,
TZ
,
POS
(
0
)},
/* UTC */
};
static
unsigned
int
szdatetktbl
=
sizeof
datetktbl
/
sizeof
datetktbl
[
0
];
static
datetkn
*
datecache
[
MAXDATEFIELDS
]
=
{
NULL
};
char
*
months
[]
=
{
"Jan"
,
"Feb"
,
"Mar"
,
"Apr"
,
"May"
,
"Jun"
,
"Jul"
,
"Aug"
,
"Sep"
,
"Oct"
,
"Nov"
,
"Dec"
,
NULL
};
char
*
days
[]
=
{
"Sunday"
,
"Monday"
,
"Tuesday"
,
"Wednesday"
,
"Thursday"
,
"Friday"
,
"Saturday"
,
NULL
};
#ifndef HAVE_RINT
/* @(#)s_rint.c 5.1 93/09/24 */
/*
* ====================================================
* Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
*
* Developed at SunPro, a Sun Microsystems, Inc. business.
* Permission to use, copy, modify, and distribute this
* software is freely granted, provided that this notice
* is preserved.
* ====================================================
*/
/*
* rint(x)
* Return x rounded to integral value according to the prevailing
* rounding mode.
* Method:
* Using floating addition.
* Exception:
* Inexact flag raised if x not equal to rint(x).
*/
static
const
double
one
=
1
.
0
,
TWO52
[
2
]
=
{
4.50359962737049600000e+15
,
/* 0x43300000, 0x00000000 */
-
4.50359962737049600000e+15
,
/* 0xC3300000, 0x00000000 */
};
double
rint
(
double
x
)
{
int
i0
,
n0
,
j0
,
sx
;
unsigned
i
,
i1
;
double
w
,
t
;
n0
=
(
*
((
int
*
)
&
one
)
>>
29
)
^
1
;
i0
=
*
(
n0
+
(
int
*
)
&
x
);
sx
=
(
i0
>>
31
)
&
1
;
i1
=
*
(
1
-
n0
+
(
int
*
)
&
x
);
j0
=
((
i0
>>
20
)
&
0x7ff
)
-
0x3ff
;
if
(
j0
<
20
)
{
if
(
j0
<
0
)
{
if
(((
i0
&
0x7fffffff
)
|
i1
)
==
0
)
return
x
;
i1
|=
(
i0
&
0x0fffff
);
i0
&=
0xfffe0000
;
i0
|=
((
i1
|
-
i1
)
>>
12
)
&
0x80000
;
*
(
n0
+
(
int
*
)
&
x
)
=
i0
;
w
=
TWO52
[
sx
]
+
x
;
t
=
w
-
TWO52
[
sx
];
i0
=
*
(
n0
+
(
int
*
)
&
t
);
*
(
n0
+
(
int
*
)
&
t
)
=
(
i0
&
0x7fffffff
)
|
(
sx
<<
31
);
return
t
;
}
else
{
i
=
(
0x000fffff
)
>>
j0
;
if
(((
i0
&
i
)
|
i1
)
==
0
)
return
x
;
/* x is integral */
i
>>=
1
;
if
(((
i0
&
i
)
|
i1
)
!=
0
)
{
if
(
j0
==
19
)
i1
=
0x40000000
;
else
i0
=
(
i0
&
(
~
i
))
|
((
0x20000
)
>>
j0
);
}
}
}
else
if
(
j0
>
51
)
{
if
(
j0
==
0x400
)
return
x
+
x
;
/* inf or NaN */
else
return
x
;
/* x is integral */
}
else
{
i
=
((
unsigned
)
(
0xffffffff
))
>>
(
j0
-
20
);
if
((
i1
&
i
)
==
0
)
return
x
;
/* x is integral */
i
>>=
1
;
if
((
i1
&
i
)
!=
0
)
i1
=
(
i1
&
(
~
i
))
|
((
0x40000000
)
>>
(
j0
-
20
));
}
*
(
n0
+
(
int
*
)
&
x
)
=
i0
;
*
(
1
-
n0
+
(
int
*
)
&
x
)
=
i1
;
w
=
TWO52
[
sx
]
+
x
;
return
w
-
TWO52
[
sx
];
}
#endif
/* !HAVE_RINT */
static
datetkn
*
datebsearch
(
char
*
key
,
datetkn
*
base
,
unsigned
int
nel
)
{
datetkn
*
last
=
base
+
nel
-
1
,
*
position
;
int
result
;
while
(
last
>=
base
)
{
position
=
base
+
((
last
-
base
)
>>
1
);
result
=
key
[
0
]
-
position
->
token
[
0
];
if
(
result
==
0
)
{
result
=
strncmp
(
key
,
position
->
token
,
TOKMAXLEN
);
if
(
result
==
0
)
return
position
;
}
if
(
result
<
0
)
last
=
position
-
1
;
else
base
=
position
+
1
;
}
return
NULL
;
}
/*
* Calendar time to Julian date conversions.
* Julian date is commonly used in astronomical applications,
* since it is numerically accurate and computationally simple.
* The algorithms here will accurately convert between Julian day
* and calendar date for all non-negative Julian days
* (i.e. from Nov 24, -4713 on).
*
* These routines will be used by other date/time packages
* - thomas 97/02/25
*
* Rewritten to eliminate overflow problems. This now allows the
* routines to work correctly for all Julian day counts from
* 0 to 2147483647 (Nov 24, -4713 to Jun 3, 5874898) assuming
* a 32-bit integer. Longer types should also work to the limits
* of their precision.
*/
int
date2j
(
int
y
,
int
m
,
int
d
)
{
int
julian
;
int
century
;
if
(
m
>
2
)
{
m
+=
1
;
y
+=
4800
;
}
else
{
m
+=
13
;
y
+=
4799
;
}
century
=
y
/
100
;
julian
=
y
*
365
-
32167
;
julian
+=
y
/
4
-
century
+
century
/
4
;
julian
+=
7834
*
m
/
256
+
d
;
return
julian
;
}
/* date2j() */
void
j2date
(
int
jd
,
int
*
year
,
int
*
month
,
int
*
day
)
{
unsigned
int
julian
;
unsigned
int
quad
;
unsigned
int
extra
;
int
y
;
julian
=
jd
;
julian
+=
32044
;
quad
=
julian
/
146097
;
extra
=
(
julian
-
quad
*
146097
)
*
4
+
3
;
julian
+=
60
+
quad
*
3
+
extra
/
146097
;
quad
=
julian
/
1461
;
julian
-=
quad
*
1461
;
y
=
julian
*
4
/
1461
;
julian
=
((
y
!=
0
)
?
((
julian
+
305
)
%
365
)
:
((
julian
+
306
)
%
366
))
+
123
;
y
+=
quad
*
4
;
*
year
=
y
-
4800
;
quad
=
julian
*
2141
/
65536
;
*
day
=
julian
-
7834
*
quad
/
256
;
*
month
=
(
quad
+
10
)
%
12
+
1
;
return
;
}
/* j2date() */
int
j2day
(
int
date
)
{
unsigned
int
day
;
day
=
date
;
day
+=
1
;
day
%=
7
;
return
(
int
)
day
;
}
/*j2day() */
/* DecodeSpecial()
* Decode text string using lookup table.
* Implement a cache lookup since it is likely that dates
* will be related in format.
*/
static
int
DecodeSpecial
(
int
field
,
char
*
lowtoken
,
int
*
val
)
{
int
type
;
datetkn
*
tp
;
if
((
datecache
[
field
]
!=
NULL
)
&&
(
strncmp
(
lowtoken
,
datecache
[
field
]
->
token
,
TOKMAXLEN
)
==
0
))
tp
=
datecache
[
field
];
else
{
tp
=
NULL
;
if
(
!
tp
)
tp
=
datebsearch
(
lowtoken
,
datetktbl
,
szdatetktbl
);
}
datecache
[
field
]
=
tp
;
if
(
tp
==
NULL
)
{
type
=
UNKNOWN_FIELD
;
*
val
=
0
;
}
else
{
type
=
tp
->
type
;
switch
(
type
)
{
case
TZ
:
case
DTZ
:
case
DTZMOD
:
*
val
=
FROMVAL
(
tp
);
break
;
default:
*
val
=
tp
->
value
;
break
;
}
}
return
type
;
}
/* DecodeSpecial() */
/* EncodeDateOnly()
* Encode date as local time.
*/
int
EncodeDateOnly
(
struct
tm
*
tm
,
int
style
,
char
*
str
,
bool
EuroDates
)
{
if
((
tm
->
tm_mon
<
1
)
||
(
tm
->
tm_mon
>
12
))
return
-
1
;
switch
(
style
)
{
case
USE_ISO_DATES
:
/* compatible with ISO date formats */
if
(
tm
->
tm_year
>
0
)
sprintf
(
str
,
"%04d-%02d-%02d"
,
tm
->
tm_year
,
tm
->
tm_mon
,
tm
->
tm_mday
);
else
sprintf
(
str
,
"%04d-%02d-%02d %s"
,
-
(
tm
->
tm_year
-
1
),
tm
->
tm_mon
,
tm
->
tm_mday
,
"BC"
);
break
;
case
USE_SQL_DATES
:
/* compatible with Oracle/Ingres date formats */
if
(
EuroDates
)
sprintf
(
str
,
"%02d/%02d"
,
tm
->
tm_mday
,
tm
->
tm_mon
);
else
sprintf
(
str
,
"%02d/%02d"
,
tm
->
tm_mon
,
tm
->
tm_mday
);
if
(
tm
->
tm_year
>
0
)
sprintf
((
str
+
5
),
"/%04d"
,
tm
->
tm_year
);
else
sprintf
((
str
+
5
),
"/%04d %s"
,
-
(
tm
->
tm_year
-
1
),
"BC"
);
break
;
case
USE_GERMAN_DATES
:
/* German-style date format */
sprintf
(
str
,
"%02d.%02d"
,
tm
->
tm_mday
,
tm
->
tm_mon
);
if
(
tm
->
tm_year
>
0
)
sprintf
((
str
+
5
),
".%04d"
,
tm
->
tm_year
);
else
sprintf
((
str
+
5
),
".%04d %s"
,
-
(
tm
->
tm_year
-
1
),
"BC"
);
break
;
case
USE_POSTGRES_DATES
:
default:
/* traditional date-only style for Postgres */
if
(
EuroDates
)
sprintf
(
str
,
"%02d-%02d"
,
tm
->
tm_mday
,
tm
->
tm_mon
);
else
sprintf
(
str
,
"%02d-%02d"
,
tm
->
tm_mon
,
tm
->
tm_mday
);
if
(
tm
->
tm_year
>
0
)
sprintf
((
str
+
5
),
"-%04d"
,
tm
->
tm_year
);
else
sprintf
((
str
+
5
),
"-%04d %s"
,
-
(
tm
->
tm_year
-
1
),
"BC"
);
break
;
}
return
TRUE
;
}
/* EncodeDateOnly() */
static
void
TrimTrailingZeros
(
char
*
str
)
{
int
len
=
strlen
(
str
);
/* chop off trailing zeros... but leave at least 2 fractional digits */
while
((
*
(
str
+
len
-
1
)
==
'0'
)
&&
(
*
(
str
+
len
-
3
)
!=
'.'
))
{
len
--
;
*
(
str
+
len
)
=
'\0'
;
}
}
/* EncodeDateTime()
* Encode date and time interpreted as local time.
* Support several date styles:
* Postgres - day mon hh:mm:ss yyyy tz
* SQL - mm/dd/yyyy hh:mm:ss.ss tz
* ISO - yyyy-mm-dd hh:mm:ss+/-tz
* German - dd.mm.yyyy hh:mm:ss tz
* Variants (affects order of month and day for Postgres and SQL styles):
* US - mm/dd/yyyy
* European - dd/mm/yyyy
*/
int
EncodeDateTime
(
struct
tm
*
tm
,
fsec_t
fsec
,
int
*
tzp
,
char
**
tzn
,
int
style
,
char
*
str
,
bool
EuroDates
)
{
int
day
,
hour
,
min
;
switch
(
style
)
{
case
USE_ISO_DATES
:
/* Compatible with ISO-8601 date formats */
sprintf
(
str
,
"%04d-%02d-%02d %02d:%02d"
,
((
tm
->
tm_year
>
0
)
?
tm
->
tm_year
:
-
(
tm
->
tm_year
-
1
)),
tm
->
tm_mon
,
tm
->
tm_mday
,
tm
->
tm_hour
,
tm
->
tm_min
);
/*
* Print fractional seconds if any. The field widths here should
* be at least equal to MAX_TIMESTAMP_PRECISION.
*
* In float mode, don't print fractional seconds before 1 AD,
* since it's unlikely there's any precision left ...
*/
#ifdef HAVE_INT64_TIMESTAMP
if
(
fsec
!=
0
)
{
sprintf
((
str
+
strlen
(
str
)),
":%02d.%06d"
,
tm
->
tm_sec
,
fsec
);
#else
if
((
fsec
!=
0
)
&&
(
tm
->
tm_year
>
0
))
{
sprintf
((
str
+
strlen
(
str
)),
":%09.6f"
,
tm
->
tm_sec
+
fsec
);
#endif
TrimTrailingZeros
(
str
);
}
else
sprintf
((
str
+
strlen
(
str
)),
":%02d"
,
tm
->
tm_sec
);
if
(
tm
->
tm_year
<=
0
)
sprintf
((
str
+
strlen
(
str
)),
" BC"
);
/*
* tzp == NULL indicates that we don't want *any* time zone
* info in the output string. *tzn != NULL indicates that we
* have alpha time zone info available. tm_isdst != -1
* indicates that we have a valid time zone translation.
*/
if
((
tzp
!=
NULL
)
&&
(
tm
->
tm_isdst
>=
0
))
{
hour
=
-
(
*
tzp
/
3600
);
min
=
((
abs
(
*
tzp
)
/
60
)
%
60
);
sprintf
((
str
+
strlen
(
str
)),
((
min
!=
0
)
?
"%+03d:%02d"
:
"%+03d"
),
hour
,
min
);
}
break
;
case
USE_SQL_DATES
:
/* Compatible with Oracle/Ingres date formats */
if
(
EuroDates
)
sprintf
(
str
,
"%02d/%02d"
,
tm
->
tm_mday
,
tm
->
tm_mon
);
else
sprintf
(
str
,
"%02d/%02d"
,
tm
->
tm_mon
,
tm
->
tm_mday
);
sprintf
((
str
+
5
),
"/%04d %02d:%02d"
,
((
tm
->
tm_year
>
0
)
?
tm
->
tm_year
:
-
(
tm
->
tm_year
-
1
)),
tm
->
tm_hour
,
tm
->
tm_min
);
/*
* Print fractional seconds if any. The field widths here should
* be at least equal to MAX_TIMESTAMP_PRECISION.
*
* In float mode, don't print fractional seconds before 1 AD,
* since it's unlikely there's any precision left ...
*/
#ifdef HAVE_INT64_TIMESTAMP
if
(
fsec
!=
0
)
{
sprintf
((
str
+
strlen
(
str
)),
":%02d.%06d"
,
tm
->
tm_sec
,
fsec
);
#else
if
((
fsec
!=
0
)
&&
(
tm
->
tm_year
>
0
))
{
sprintf
((
str
+
strlen
(
str
)),
":%09.6f"
,
tm
->
tm_sec
+
fsec
);
#endif
TrimTrailingZeros
(
str
);
}
else
sprintf
((
str
+
strlen
(
str
)),
":%02d"
,
tm
->
tm_sec
);
if
(
tm
->
tm_year
<=
0
)
sprintf
((
str
+
strlen
(
str
)),
" BC"
);
if
((
tzp
!=
NULL
)
&&
(
tm
->
tm_isdst
>=
0
))
{
if
(
*
tzn
!=
NULL
)
sprintf
((
str
+
strlen
(
str
)),
" %.*s"
,
MAXTZLEN
,
*
tzn
);
else
{
hour
=
-
(
*
tzp
/
3600
);
min
=
((
abs
(
*
tzp
)
/
60
)
%
60
);
sprintf
((
str
+
strlen
(
str
)),
((
min
!=
0
)
?
"%+03d:%02d"
:
"%+03d"
),
hour
,
min
);
}
}
break
;
case
USE_GERMAN_DATES
:
/* German variant on European style */
sprintf
(
str
,
"%02d.%02d"
,
tm
->
tm_mday
,
tm
->
tm_mon
);
sprintf
((
str
+
5
),
".%04d %02d:%02d"
,
((
tm
->
tm_year
>
0
)
?
tm
->
tm_year
:
-
(
tm
->
tm_year
-
1
)),
tm
->
tm_hour
,
tm
->
tm_min
);
/*
* Print fractional seconds if any. The field widths here should
* be at least equal to MAX_TIMESTAMP_PRECISION.
*
* In float mode, don't print fractional seconds before 1 AD,
* since it's unlikely there's any precision left ...
*/
#ifdef HAVE_INT64_TIMESTAMP
if
(
fsec
!=
0
)
{
sprintf
((
str
+
strlen
(
str
)),
":%02d.%06d"
,
tm
->
tm_sec
,
fsec
);
#else
if
((
fsec
!=
0
)
&&
(
tm
->
tm_year
>
0
))
{
sprintf
((
str
+
strlen
(
str
)),
":%09.6f"
,
tm
->
tm_sec
+
fsec
);
#endif
TrimTrailingZeros
(
str
);
}
else
sprintf
((
str
+
strlen
(
str
)),
":%02d"
,
tm
->
tm_sec
);
if
(
tm
->
tm_year
<=
0
)
sprintf
((
str
+
strlen
(
str
)),
" BC"
);
if
((
tzp
!=
NULL
)
&&
(
tm
->
tm_isdst
>=
0
))
{
if
(
*
tzn
!=
NULL
)
sprintf
((
str
+
strlen
(
str
)),
" %.*s"
,
MAXTZLEN
,
*
tzn
);
else
{
hour
=
-
(
*
tzp
/
3600
);
min
=
((
abs
(
*
tzp
)
/
60
)
%
60
);
sprintf
((
str
+
strlen
(
str
)),
((
min
!=
0
)
?
"%+03d:%02d"
:
"%+03d"
),
hour
,
min
);
}
}
break
;
case
USE_POSTGRES_DATES
:
default:
/* Backward-compatible with traditional Postgres abstime dates */
day
=
date2j
(
tm
->
tm_year
,
tm
->
tm_mon
,
tm
->
tm_mday
);
tm
->
tm_wday
=
j2day
(
day
);
strncpy
(
str
,
days
[
tm
->
tm_wday
],
3
);
strcpy
((
str
+
3
),
" "
);
if
(
EuroDates
)
sprintf
((
str
+
4
),
"%02d %3s"
,
tm
->
tm_mday
,
months
[
tm
->
tm_mon
-
1
]);
else
sprintf
((
str
+
4
),
"%3s %02d"
,
months
[
tm
->
tm_mon
-
1
],
tm
->
tm_mday
);
sprintf
((
str
+
10
),
" %02d:%02d"
,
tm
->
tm_hour
,
tm
->
tm_min
);
/*
* Print fractional seconds if any. The field widths here should
* be at least equal to MAX_TIMESTAMP_PRECISION.
*
* In float mode, don't print fractional seconds before 1 AD,
* since it's unlikely there's any precision left ...
*/
#ifdef HAVE_INT64_TIMESTAMP
if
(
fsec
!=
0
)
{
sprintf
((
str
+
strlen
(
str
)),
":%02d.%06d"
,
tm
->
tm_sec
,
fsec
);
#else
if
((
fsec
!=
0
)
&&
(
tm
->
tm_year
>
0
))
{
sprintf
((
str
+
strlen
(
str
)),
":%09.6f"
,
tm
->
tm_sec
+
fsec
);
#endif
TrimTrailingZeros
(
str
);
}
else
sprintf
((
str
+
strlen
(
str
)),
":%02d"
,
tm
->
tm_sec
);
sprintf
((
str
+
strlen
(
str
)),
" %04d"
,
((
tm
->
tm_year
>
0
)
?
tm
->
tm_year
:
-
(
tm
->
tm_year
-
1
)));
if
(
tm
->
tm_year
<=
0
)
sprintf
((
str
+
strlen
(
str
)),
" BC"
);
if
((
tzp
!=
NULL
)
&&
(
tm
->
tm_isdst
>=
0
))
{
if
(
*
tzn
!=
NULL
)
sprintf
((
str
+
strlen
(
str
)),
" %.*s"
,
MAXTZLEN
,
*
tzn
);
else
{
/*
* We have a time zone, but no string version. Use the
* numeric form, but be sure to include a leading
* space to avoid formatting something which would be
* rejected by the date/time parser later. - thomas
* 2001-10-19
*/
hour
=
-
(
*
tzp
/
3600
);
min
=
((
abs
(
*
tzp
)
/
60
)
%
60
);
sprintf
((
str
+
strlen
(
str
)),
((
min
!=
0
)
?
" %+03d:%02d"
:
" %+03d"
),
hour
,
min
);
}
}
break
;
}
return
TRUE
;
}
/* EncodeDateTime() */
void
GetEpochTime
(
struct
tm
*
tm
)
{
struct
tm
*
t0
;
time_t
epoch
=
0
;
t0
=
gmtime
(
&
epoch
);
tm
->
tm_year
=
t0
->
tm_year
;
tm
->
tm_mon
=
t0
->
tm_mon
;
tm
->
tm_mday
=
t0
->
tm_mday
;
tm
->
tm_hour
=
t0
->
tm_hour
;
tm
->
tm_min
=
t0
->
tm_min
;
tm
->
tm_sec
=
t0
->
tm_sec
;
if
(
tm
->
tm_year
<
1900
)
tm
->
tm_year
+=
1900
;
tm
->
tm_mon
++
;
return
;
}
/* GetEpochTime() */
static
void
abstime2tm
(
AbsoluteTime
_time
,
int
*
tzp
,
struct
tm
*
tm
,
char
**
tzn
)
{
time_t
time
=
(
time_t
)
_time
;
struct
tm
*
tx
;
if
(
tzp
!=
NULL
)
tx
=
localtime
((
time_t
*
)
&
time
);
else
tx
=
gmtime
((
time_t
*
)
&
time
);
tm
->
tm_year
=
tx
->
tm_year
+
1900
;
tm
->
tm_mon
=
tx
->
tm_mon
+
1
;
tm
->
tm_mday
=
tx
->
tm_mday
;
tm
->
tm_hour
=
tx
->
tm_hour
;
tm
->
tm_min
=
tx
->
tm_min
;
tm
->
tm_sec
=
tx
->
tm_sec
;
tm
->
tm_isdst
=
tx
->
tm_isdst
;
#if defined(HAVE_TM_ZONE)
tm
->
tm_gmtoff
=
tx
->
tm_gmtoff
;
tm
->
tm_zone
=
tx
->
tm_zone
;
if
(
tzp
!=
NULL
)
{
/*
* We have a brute force time zone per SQL99? Then use it without
* change since we have already rotated to the time zone.
*/
*
tzp
=
-
tm
->
tm_gmtoff
;
/* tm_gmtoff is Sun/DEC-ism */
/*
* XXX FreeBSD man pages indicate that this should work - tgl
* 97/04/23
*/
if
(
tzn
!=
NULL
)
{
/*
* Copy no more than MAXTZLEN bytes of timezone to tzn, in
* case it contains an error message, which doesn't fit in
* the buffer
*/
StrNCpy
(
*
tzn
,
tm
->
tm_zone
,
MAXTZLEN
+
1
);
if
(
strlen
(
tm
->
tm_zone
)
>
MAXTZLEN
)
elog
(
WARNING
,
"Invalid timezone
\'
%s
\'
"
,
tm
->
tm_zone
);
}
}
else
tm
->
tm_isdst
=
-
1
;
#elif defined(HAVE_INT_TIMEZONE)
if
(
tzp
!=
NULL
)
{
*
tzp
=
((
tm
->
tm_isdst
>
0
)
?
(
TIMEZONE_GLOBAL
-
3600
)
:
TIMEZONE_GLOBAL
);
if
(
tzn
!=
NULL
)
{
/*
* Copy no more than MAXTZLEN bytes of timezone to tzn, in
* case it contains an error message, which doesn't fit in
* the buffer
*/
StrNCpy
(
*
tzn
,
tzname
[
tm
->
tm_isdst
],
MAXTZLEN
+
1
);
if
(
strlen
(
tzname
[
tm
->
tm_isdst
])
>
MAXTZLEN
)
elog
(
WARNING
,
"Invalid timezone
\'
%s
\'
"
,
tzname
[
tm
->
tm_isdst
]);
}
}
else
tm
->
tm_isdst
=
-
1
;
#else
/* not (HAVE_TM_ZONE || HAVE_INT_TIMEZONE) */
if
(
tzp
!=
NULL
)
{
/* default to UTC */
*
tzp
=
0
;
if
(
tzn
!=
NULL
)
*
tzn
=
NULL
;
}
else
tm
->
tm_isdst
=
-
1
;
#endif
}
static
void
GetCurrentDateTime
(
struct
tm
*
tm
)
{
int
tz
;
abstime2tm
(
time
(
NULL
),
&
tz
,
tm
,
NULL
);
}
/* DetermineLocalTimeZone()
*
* Given a struct tm in which tm_year, tm_mon, tm_mday, tm_hour, tm_min, and
* tm_sec fields are set, attempt to determine the applicable local zone
* (ie, regular or daylight-savings time) at that time. Set the struct tm's
* tm_isdst field accordingly, and return the actual timezone offset.
*
* This subroutine exists to centralize uses of mktime() and defend against
* mktime() bugs/restrictions on various platforms. This should be
* the *only* call of mktime() in the backend.
*/
static
int
DetermineLocalTimeZone
(
struct
tm
*
tm
)
{
int
tz
;
if
(
IS_VALID_UTIME
(
tm
->
tm_year
,
tm
->
tm_mon
,
tm
->
tm_mday
))
{
#if defined(HAVE_TM_ZONE) || defined(HAVE_INT_TIMEZONE)
/*
* Some buggy mktime() implementations may change the
* year/month/day when given a time right at a DST boundary. To
* prevent corruption of the caller's data, give mktime() a
* copy...
*/
struct
tm
tt
,
*
tmp
=
&
tt
;
*
tmp
=
*
tm
;
/* change to Unix conventions for year/month */
tmp
->
tm_year
-=
1900
;
tmp
->
tm_mon
-=
1
;
/* indicate timezone unknown */
tmp
->
tm_isdst
=
-
1
;
if
(
mktime
(
tmp
)
!=
((
time_t
)
-
1
)
&&
tmp
->
tm_isdst
>=
0
)
{
/* mktime() succeeded, trust its result */
tm
->
tm_isdst
=
tmp
->
tm_isdst
;
#if defined(HAVE_TM_ZONE)
/* tm_gmtoff is Sun/DEC-ism */
tz
=
-
(
tmp
->
tm_gmtoff
);
#elif defined(HAVE_INT_TIMEZONE)
tz
=
((
tmp
->
tm_isdst
>
0
)
?
(
TIMEZONE_GLOBAL
-
3600
)
:
TIMEZONE_GLOBAL
);
#endif
/* HAVE_INT_TIMEZONE */
}
else
{
/*
* We have a buggy (not to say deliberately brain damaged)
* mktime(). Work around it by using localtime() instead.
*
* First, generate the time_t value corresponding to the given
* y/m/d/h/m/s taken as GMT time. This will not overflow (at
* least not for time_t taken as signed) because of the range
* check we did above.
*/
long
day
,
mysec
,
locsec
,
delta1
,
delta2
;
time_t
mytime
;
day
=
(
date2j
(
tm
->
tm_year
,
tm
->
tm_mon
,
tm
->
tm_mday
)
-
date2j
(
1970
,
1
,
1
));
mysec
=
tm
->
tm_sec
+
(
tm
->
tm_min
+
(
day
*
24
+
tm
->
tm_hour
)
*
60
)
*
60
;
mytime
=
(
time_t
)
mysec
;
/*
* Use localtime to convert that time_t to broken-down time,
* and reassemble to get a representation of local time.
*/
tmp
=
localtime
(
&
mytime
);
day
=
(
date2j
(
tmp
->
tm_year
+
1900
,
tmp
->
tm_mon
+
1
,
tmp
->
tm_mday
)
-
date2j
(
1970
,
1
,
1
));
locsec
=
tmp
->
tm_sec
+
(
tmp
->
tm_min
+
(
day
*
24
+
tmp
->
tm_hour
)
*
60
)
*
60
;
/*
* The local time offset corresponding to that GMT time is now
* computable as mysec - locsec.
*/
delta1
=
mysec
-
locsec
;
/*
* However, if that GMT time and the local time we are
* actually interested in are on opposite sides of a
* daylight-savings-time transition, then this is not the time
* offset we want. So, adjust the time_t to be what we think
* the GMT time corresponding to our target local time is, and
* repeat the localtime() call and delta calculation. We may
* have to do it twice before we have a trustworthy delta.
*
* Note: think not to put a loop here, since if we've been given
* an "impossible" local time (in the gap during a
* spring-forward transition) we'd never get out of the loop.
* Twice is enough to give the behavior we want, which is that
* "impossible" times are taken as standard time, while at a
* fall-back boundary ambiguous times are also taken as
* standard.
*/
mysec
+=
delta1
;
mytime
=
(
time_t
)
mysec
;
tmp
=
localtime
(
&
mytime
);
day
=
(
date2j
(
tmp
->
tm_year
+
1900
,
tmp
->
tm_mon
+
1
,
tmp
->
tm_mday
)
-
date2j
(
1970
,
1
,
1
));
locsec
=
tmp
->
tm_sec
+
(
tmp
->
tm_min
+
(
day
*
24
+
tmp
->
tm_hour
)
*
60
)
*
60
;
delta2
=
mysec
-
locsec
;
if
(
delta2
!=
delta1
)
{
mysec
+=
(
delta2
-
delta1
);
mytime
=
(
time_t
)
mysec
;
tmp
=
localtime
(
&
mytime
);
day
=
(
date2j
(
tmp
->
tm_year
+
1900
,
tmp
->
tm_mon
+
1
,
tmp
->
tm_mday
)
-
date2j
(
1970
,
1
,
1
));
locsec
=
tmp
->
tm_sec
+
(
tmp
->
tm_min
+
(
day
*
24
+
tmp
->
tm_hour
)
*
60
)
*
60
;
delta2
=
mysec
-
locsec
;
}
tm
->
tm_isdst
=
tmp
->
tm_isdst
;
tz
=
(
int
)
delta2
;
}
#else
/* not (HAVE_TM_ZONE || HAVE_INT_TIMEZONE) */
/* Assume UTC if no system timezone info available */
tm
->
tm_isdst
=
0
;
tz
=
0
;
#endif
}
else
{
/* Given date is out of range, so assume UTC */
tm
->
tm_isdst
=
0
;
tz
=
0
;
}
return
tz
;
}
static
void
dt2time
(
double
jd
,
int
*
hour
,
int
*
min
,
int
*
sec
,
fsec_t
*
fsec
)
{
#ifdef HAVE_INT64_TIMESTAMP
int64
time
;
#else
double
time
;
#endif
time
=
jd
;
#ifdef HAVE_INT64_TIMESTAMP
*
hour
=
(
time
/
INT64CONST
(
3600000000
));
time
-=
((
*
hour
)
*
INT64CONST
(
3600000000
));
*
min
=
(
time
/
INT64CONST
(
60000000
));
time
-=
((
*
min
)
*
INT64CONST
(
60000000
));
*
sec
=
(
time
/
INT64CONST
(
1000000
));
*
fsec
=
(
time
-
(
*
sec
*
INT64CONST
(
1000000
)));
#else
*
hour
=
(
time
/
3600
);
time
-=
((
*
hour
)
*
3600
);
*
min
=
(
time
/
60
);
time
-=
((
*
min
)
*
60
);
*
sec
=
time
;
*
fsec
=
JROUND
(
time
-
*
sec
);
#endif
return
;
}
/* dt2time() */
/* DecodeNumberField()
* Interpret numeric string as a concatenated date or time field.
* Use the context of previously decoded fields to help with
* the interpretation.
*/
static
int
DecodeNumberField
(
int
len
,
char
*
str
,
int
fmask
,
int
*
tmask
,
struct
tm
*
tm
,
fsec_t
*
fsec
,
int
*
is2digits
,
bool
EuroDates
)
{
char
*
cp
;
/*
* Have a decimal point? Then this is a date or something with a
* seconds field...
*/
if
((
cp
=
strchr
(
str
,
'.'
))
!=
NULL
)
{
#ifdef HAVE_INT64_TIMESTAMP
char
fstr
[
MAXDATELEN
+
1
];
/*
* OK, we have at most six digits to care about. Let's construct a
* string and then do the conversion to an integer.
*/
strcpy
(
fstr
,
(
cp
+
1
));
strcpy
((
fstr
+
strlen
(
fstr
)),
"000000"
);
*
(
fstr
+
6
)
=
'\0'
;
*
fsec
=
strtol
(
fstr
,
NULL
,
10
);
#else
*
fsec
=
strtod
(
cp
,
NULL
);
#endif
*
cp
=
'\0'
;
len
=
strlen
(
str
);
}
/* No decimal point and no complete date yet? */
else
if
((
fmask
&
DTK_DATE_M
)
!=
DTK_DATE_M
)
{
/* yyyymmdd? */
if
(
len
==
8
)
{
*
tmask
=
DTK_DATE_M
;
tm
->
tm_mday
=
atoi
(
str
+
6
);
*
(
str
+
6
)
=
'\0'
;
tm
->
tm_mon
=
atoi
(
str
+
4
);
*
(
str
+
4
)
=
'\0'
;
tm
->
tm_year
=
atoi
(
str
+
0
);
return
DTK_DATE
;
}
/* yymmdd? */
else
if
(
len
==
6
)
{
*
tmask
=
DTK_DATE_M
;
tm
->
tm_mday
=
atoi
(
str
+
4
);
*
(
str
+
4
)
=
'\0'
;
tm
->
tm_mon
=
atoi
(
str
+
2
);
*
(
str
+
2
)
=
'\0'
;
tm
->
tm_year
=
atoi
(
str
+
0
);
*
is2digits
=
TRUE
;
return
DTK_DATE
;
}
/* yyddd? */
else
if
(
len
==
5
)
{
*
tmask
=
DTK_DATE_M
;
tm
->
tm_mday
=
atoi
(
str
+
2
);
*
(
str
+
2
)
=
'\0'
;
tm
->
tm_mon
=
1
;
tm
->
tm_year
=
atoi
(
str
+
0
);
*
is2digits
=
TRUE
;
return
DTK_DATE
;
}
}
/* not all time fields are specified? */
if
((
fmask
&
DTK_TIME_M
)
!=
DTK_TIME_M
)
{
/* hhmmss */
if
(
len
==
6
)
{
*
tmask
=
DTK_TIME_M
;
tm
->
tm_sec
=
atoi
(
str
+
4
);
*
(
str
+
4
)
=
'\0'
;
tm
->
tm_min
=
atoi
(
str
+
2
);
*
(
str
+
2
)
=
'\0'
;
tm
->
tm_hour
=
atoi
(
str
+
0
);
return
DTK_TIME
;
}
/* hhmm? */
else
if
(
len
==
4
)
{
*
tmask
=
DTK_TIME_M
;
tm
->
tm_sec
=
0
;
tm
->
tm_min
=
atoi
(
str
+
2
);
*
(
str
+
2
)
=
'\0'
;
tm
->
tm_hour
=
atoi
(
str
+
0
);
return
DTK_TIME
;
}
}
return
-
1
;
}
/* DecodeNumberField() */
/* DecodeNumber()
* Interpret plain numeric field as a date value in context.
*/
static
int
DecodeNumber
(
int
flen
,
char
*
str
,
int
fmask
,
int
*
tmask
,
struct
tm
*
tm
,
fsec_t
*
fsec
,
int
*
is2digits
,
bool
EuroDates
)
{
int
val
;
char
*
cp
;
*
tmask
=
0
;
val
=
strtol
(
str
,
&
cp
,
10
);
if
(
cp
==
str
)
return
-
1
;
if
(
*
cp
==
'.'
)
{
/*
* More than two digits? Then could be a date or a run-together
* time: 2001.360 20011225 040506.789
*/
if
((
cp
-
str
)
>
2
)
return
DecodeNumberField
(
flen
,
str
,
(
fmask
|
DTK_DATE_M
),
tmask
,
tm
,
fsec
,
is2digits
,
EuroDates
);
*
fsec
=
strtod
(
cp
,
&
cp
);
if
(
*
cp
!=
'\0'
)
return
-
1
;
}
else
if
(
*
cp
!=
'\0'
)
return
-
1
;
/* Special case day of year? */
if
((
flen
==
3
)
&&
(
fmask
&
DTK_M
(
YEAR
))
&&
((
val
>=
1
)
&&
(
val
<=
366
)))
{
*
tmask
=
(
DTK_M
(
DOY
)
|
DTK_M
(
MONTH
)
|
DTK_M
(
DAY
));
tm
->
tm_yday
=
val
;
j2date
((
date2j
(
tm
->
tm_year
,
1
,
1
)
+
tm
->
tm_yday
-
1
),
&
tm
->
tm_year
,
&
tm
->
tm_mon
,
&
tm
->
tm_mday
);
}
/***
* Enough digits to be unequivocal year? Used to test for 4 digits or
* more, but we now test first for a three-digit doy so anything
* bigger than two digits had better be an explicit year.
* - thomas 1999-01-09
* Back to requiring a 4 digit year. We accept a two digit
* year farther down. - thomas 2000-03-28
***/
else
if
(
flen
>=
4
)
{
*
tmask
=
DTK_M
(
YEAR
);
/* already have a year? then see if we can substitute... */
if
((
fmask
&
DTK_M
(
YEAR
))
&&
(
!
(
fmask
&
DTK_M
(
DAY
)))
&&
((
tm
->
tm_year
>=
1
)
&&
(
tm
->
tm_year
<=
31
)))
{
tm
->
tm_mday
=
tm
->
tm_year
;
*
tmask
=
DTK_M
(
DAY
);
}
tm
->
tm_year
=
val
;
}
/* already have year? then could be month */
else
if
((
fmask
&
DTK_M
(
YEAR
))
&&
(
!
(
fmask
&
DTK_M
(
MONTH
)))
&&
((
val
>=
1
)
&&
(
val
<=
12
)))
{
*
tmask
=
DTK_M
(
MONTH
);
tm
->
tm_mon
=
val
;
}
/* no year and EuroDates enabled? then could be day */
else
if
((
EuroDates
||
(
fmask
&
DTK_M
(
MONTH
)))
&&
(
!
(
fmask
&
DTK_M
(
YEAR
))
&&
!
(
fmask
&
DTK_M
(
DAY
)))
&&
((
val
>=
1
)
&&
(
val
<=
31
)))
{
*
tmask
=
DTK_M
(
DAY
);
tm
->
tm_mday
=
val
;
}
else
if
((
!
(
fmask
&
DTK_M
(
MONTH
)))
&&
((
val
>=
1
)
&&
(
val
<=
12
)))
{
*
tmask
=
DTK_M
(
MONTH
);
tm
->
tm_mon
=
val
;
}
else
if
((
!
(
fmask
&
DTK_M
(
DAY
)))
&&
((
val
>=
1
)
&&
(
val
<=
31
)))
{
*
tmask
=
DTK_M
(
DAY
);
tm
->
tm_mday
=
val
;
}
/*
* Check for 2 or 4 or more digits, but currently we reach here only
* if two digits. - thomas 2000-03-28
*/
else
if
(
!
(
fmask
&
DTK_M
(
YEAR
))
&&
((
flen
>=
4
)
||
(
flen
==
2
)))
{
*
tmask
=
DTK_M
(
YEAR
);
tm
->
tm_year
=
val
;
/* adjust ONLY if exactly two digits... */
*
is2digits
=
(
flen
==
2
);
}
else
return
-
1
;
return
0
;
}
/* DecodeNumber() */
/* DecodeDate()
* Decode date string which includes delimiters.
* Insist on a complete set of fields.
*/
static
int
DecodeDate
(
char
*
str
,
int
fmask
,
int
*
tmask
,
struct
tm
*
tm
,
bool
EuroDates
)
{
fsec_t
fsec
;
int
nf
=
0
;
int
i
,
len
;
int
bc
=
FALSE
;
int
is2digits
=
FALSE
;
int
type
,
val
,
dmask
=
0
;
char
*
field
[
MAXDATEFIELDS
];
/* parse this string... */
while
((
*
str
!=
'\0'
)
&&
(
nf
<
MAXDATEFIELDS
))
{
/* skip field separators */
while
(
!
isalnum
((
unsigned
char
)
*
str
))
str
++
;
field
[
nf
]
=
str
;
if
(
isdigit
((
unsigned
char
)
*
str
))
{
while
(
isdigit
((
unsigned
char
)
*
str
))
str
++
;
}
else
if
(
isalpha
((
unsigned
char
)
*
str
))
{
while
(
isalpha
((
unsigned
char
)
*
str
))
str
++
;
}
/* Just get rid of any non-digit, non-alpha characters... */
if
(
*
str
!=
'\0'
)
*
str
++
=
'\0'
;
nf
++
;
}
#if 0
/* don't allow too many fields */
if (nf > 3)
return -1;
#endif
*
tmask
=
0
;
/* look first for text fields, since that will be unambiguous month */
for
(
i
=
0
;
i
<
nf
;
i
++
)
{
if
(
isalpha
((
unsigned
char
)
*
field
[
i
]))
{
type
=
DecodeSpecial
(
i
,
field
[
i
],
&
val
);
if
(
type
==
IGNORE_DTF
)
continue
;
dmask
=
DTK_M
(
type
);
switch
(
type
)
{
case
MONTH
:
tm
->
tm_mon
=
val
;
break
;
case
ADBC
:
bc
=
(
val
==
BC
);
break
;
default:
return
-
1
;
}
if
(
fmask
&
dmask
)
return
-
1
;
fmask
|=
dmask
;
*
tmask
|=
dmask
;
/* mark this field as being completed */
field
[
i
]
=
NULL
;
}
}
/* now pick up remaining numeric fields */
for
(
i
=
0
;
i
<
nf
;
i
++
)
{
if
(
field
[
i
]
==
NULL
)
continue
;
if
((
len
=
strlen
(
field
[
i
]))
<=
0
)
return
-
1
;
if
(
DecodeNumber
(
len
,
field
[
i
],
fmask
,
&
dmask
,
tm
,
&
fsec
,
&
is2digits
,
EuroDates
)
!=
0
)
return
-
1
;
if
(
fmask
&
dmask
)
return
-
1
;
fmask
|=
dmask
;
*
tmask
|=
dmask
;
}
if
((
fmask
&
~
(
DTK_M
(
DOY
)
|
DTK_M
(
TZ
)))
!=
DTK_DATE_M
)
return
-
1
;
/* there is no year zero in AD/BC notation; i.e. "1 BC" == year 0 */
if
(
bc
)
{
if
(
tm
->
tm_year
>
0
)
tm
->
tm_year
=
-
(
tm
->
tm_year
-
1
);
else
return
-
1
;
}
else
if
(
is2digits
)
{
if
(
tm
->
tm_year
<
70
)
tm
->
tm_year
+=
2000
;
else
if
(
tm
->
tm_year
<
100
)
tm
->
tm_year
+=
1900
;
}
return
0
;
}
/* DecodeDate() */
/* DecodeTime()
* Decode time string which includes delimiters.
* Only check the lower limit on hours, since this same code
* can be used to represent time spans.
*/
static
int
DecodeTime
(
char
*
str
,
int
fmask
,
int
*
tmask
,
struct
tm
*
tm
,
fsec_t
*
fsec
)
{
char
*
cp
;
*
tmask
=
DTK_TIME_M
;
tm
->
tm_hour
=
strtol
(
str
,
&
cp
,
10
);
if
(
*
cp
!=
':'
)
return
-
1
;
str
=
cp
+
1
;
tm
->
tm_min
=
strtol
(
str
,
&
cp
,
10
);
if
(
*
cp
==
'\0'
)
{
tm
->
tm_sec
=
0
;
*
fsec
=
0
;
}
else
if
(
*
cp
!=
':'
)
return
-
1
;
else
{
str
=
cp
+
1
;
tm
->
tm_sec
=
strtol
(
str
,
&
cp
,
10
);
if
(
*
cp
==
'\0'
)
*
fsec
=
0
;
else
if
(
*
cp
==
'.'
)
{
#ifdef HAVE_INT64_TIMESTAMP
char
fstr
[
MAXDATELEN
+
1
];
/*
* OK, we have at most six digits to work with. Let's
* construct a string and then do the conversion to an
* integer.
*/
strncpy
(
fstr
,
(
cp
+
1
),
7
);
strcpy
((
fstr
+
strlen
(
fstr
)),
"000000"
);
*
(
fstr
+
6
)
=
'\0'
;
*
fsec
=
strtol
(
fstr
,
&
cp
,
10
);
#else
str
=
cp
;
*
fsec
=
strtod
(
str
,
&
cp
);
#endif
if
(
*
cp
!=
'\0'
)
return
-
1
;
}
else
return
-
1
;
}
/* do a sanity check */
#ifdef HAVE_INT64_TIMESTAMP
if
((
tm
->
tm_hour
<
0
)
||
(
tm
->
tm_min
<
0
)
||
(
tm
->
tm_min
>
59
)
||
(
tm
->
tm_sec
<
0
)
||
(
tm
->
tm_sec
>
59
)
||
(
*
fsec
>=
INT64CONST
(
1000000
)))
return
-
1
;
#else
if
((
tm
->
tm_hour
<
0
)
||
(
tm
->
tm_min
<
0
)
||
(
tm
->
tm_min
>
59
)
||
(
tm
->
tm_sec
<
0
)
||
(
tm
->
tm_sec
>
59
)
||
(
*
fsec
>=
1
))
return
-
1
;
#endif
return
0
;
}
/* DecodeTime() */
/* DecodeTimezone()
* Interpret string as a numeric timezone.
*
* Note: we allow timezone offsets up to 13:59. There are places that
* use +1300 summer time.
*/
static
int
DecodeTimezone
(
char
*
str
,
int
*
tzp
)
{
int
tz
;
int
hr
,
min
;
char
*
cp
;
int
len
;
/* assume leading character is "+" or "-" */
hr
=
strtol
((
str
+
1
),
&
cp
,
10
);
/* explicit delimiter? */
if
(
*
cp
==
':'
)
min
=
strtol
((
cp
+
1
),
&
cp
,
10
);
/* otherwise, might have run things together... */
else
if
((
*
cp
==
'\0'
)
&&
((
len
=
strlen
(
str
))
>
3
))
{
min
=
strtol
((
str
+
len
-
2
),
&
cp
,
10
);
if
((
min
<
0
)
||
(
min
>=
60
))
return
-
1
;
*
(
str
+
len
-
2
)
=
'\0'
;
hr
=
strtol
((
str
+
1
),
&
cp
,
10
);
if
((
hr
<
0
)
||
(
hr
>
13
))
return
-
1
;
}
else
min
=
0
;
tz
=
(
hr
*
60
+
min
)
*
60
;
if
(
*
str
==
'-'
)
tz
=
-
tz
;
*
tzp
=
-
tz
;
return
*
cp
!=
'\0'
;
}
/* DecodeTimezone() */
/* DecodePosixTimezone()
* Interpret string as a POSIX-compatible timezone:
* PST-hh:mm
* PST+h
* - thomas 2000-03-15
*/
static
int
DecodePosixTimezone
(
char
*
str
,
int
*
tzp
)
{
int
val
,
tz
;
int
type
;
char
*
cp
;
char
delim
;
cp
=
str
;
while
((
*
cp
!=
'\0'
)
&&
isalpha
((
unsigned
char
)
*
cp
))
cp
++
;
if
(
DecodeTimezone
(
cp
,
&
tz
)
!=
0
)
return
-
1
;
delim
=
*
cp
;
*
cp
=
'\0'
;
type
=
DecodeSpecial
(
MAXDATEFIELDS
-
1
,
str
,
&
val
);
*
cp
=
delim
;
switch
(
type
)
{
case
DTZ
:
case
TZ
:
*
tzp
=
(
val
*
60
)
-
tz
;
break
;
default:
return
-
1
;
}
return
0
;
}
/* DecodePosixTimezone() */
/* ParseDateTime()
* Break string into tokens based on a date/time context.
* Several field types are assigned:
* DTK_NUMBER - digits and (possibly) a decimal point
* DTK_DATE - digits and two delimiters, or digits and text
* DTK_TIME - digits, colon delimiters, and possibly a decimal point
* DTK_STRING - text (no digits)
* DTK_SPECIAL - leading "+" or "-" followed by text
* DTK_TZ - leading "+" or "-" followed by digits
* Note that some field types can hold unexpected items:
* DTK_NUMBER can hold date fields (yy.ddd)
* DTK_STRING can hold months (January) and time zones (PST)
* DTK_DATE can hold Posix time zones (GMT-8)
*/
int
ParseDateTime
(
char
*
timestr
,
char
*
lowstr
,
char
**
field
,
int
*
ftype
,
int
maxfields
,
int
*
numfields
,
char
**
endstr
)
{
int
nf
=
0
;
char
*
lp
=
lowstr
;
*
endstr
=
timestr
;
/* outer loop through fields */
while
(
*
(
*
endstr
)
!=
'\0'
)
{
field
[
nf
]
=
lp
;
/* leading digit? then date or time */
if
(
isdigit
((
unsigned
char
)
*
(
*
endstr
)))
{
*
lp
++
=
*
(
*
endstr
)
++
;
while
(
isdigit
((
unsigned
char
)
*
(
*
endstr
)))
*
lp
++
=
*
(
*
endstr
)
++
;
/* time field? */
if
(
*
(
*
endstr
)
==
':'
)
{
ftype
[
nf
]
=
DTK_TIME
;
*
lp
++
=
*
(
*
endstr
)
++
;
while
(
isdigit
((
unsigned
char
)
*
(
*
endstr
))
||
(
*
(
*
endstr
)
==
':'
)
||
(
*
(
*
endstr
)
==
'.'
))
*
lp
++
=
*
(
*
endstr
)
++
;
}
/* date field? allow embedded text month */
else
if
((
*
(
*
endstr
)
==
'-'
)
||
(
*
(
*
endstr
)
==
'/'
)
||
(
*
(
*
endstr
)
==
'.'
))
{
/* save delimiting character to use later */
char
*
dp
=
(
*
endstr
);
*
lp
++
=
*
(
*
endstr
)
++
;
/* second field is all digits? then no embedded text month */
if
(
isdigit
((
unsigned
char
)
*
(
*
endstr
)))
{
ftype
[
nf
]
=
((
*
dp
==
'.'
)
?
DTK_NUMBER
:
DTK_DATE
);
while
(
isdigit
((
unsigned
char
)
*
(
*
endstr
)))
*
lp
++
=
*
(
*
endstr
)
++
;
/*
* insist that the delimiters match to get a
* three-field date.
*/
if
(
*
(
*
endstr
)
==
*
dp
)
{
ftype
[
nf
]
=
DTK_DATE
;
*
lp
++
=
*
(
*
endstr
)
++
;
while
(
isdigit
((
unsigned
char
)
*
(
*
endstr
))
||
(
*
(
*
endstr
)
==
*
dp
))
*
lp
++
=
*
(
*
endstr
)
++
;
}
}
else
{
ftype
[
nf
]
=
DTK_DATE
;
while
(
isalnum
((
unsigned
char
)
*
(
*
endstr
))
||
(
*
(
*
endstr
)
==
*
dp
))
*
lp
++
=
tolower
((
unsigned
char
)
*
(
*
endstr
)
++
);
}
}
/*
* otherwise, number only and will determine year, month, day,
* or concatenated fields later...
*/
else
ftype
[
nf
]
=
DTK_NUMBER
;
}
/* Leading decimal point? Then fractional seconds... */
else
if
(
*
(
*
endstr
)
==
'.'
)
{
*
lp
++
=
*
(
*
endstr
)
++
;
while
(
isdigit
((
unsigned
char
)
*
(
*
endstr
)))
*
lp
++
=
*
(
*
endstr
)
++
;
ftype
[
nf
]
=
DTK_NUMBER
;
}
/*
* text? then date string, month, day of week, special, or
* timezone
*/
else
if
(
isalpha
((
unsigned
char
)
*
(
*
endstr
)))
{
ftype
[
nf
]
=
DTK_STRING
;
*
lp
++
=
tolower
((
unsigned
char
)
*
(
*
endstr
)
++
);
while
(
isalpha
((
unsigned
char
)
*
(
*
endstr
)))
*
lp
++
=
tolower
((
unsigned
char
)
*
(
*
endstr
)
++
);
/*
* Full date string with leading text month? Could also be a
* POSIX time zone...
*/
if
((
*
(
*
endstr
)
==
'-'
)
||
(
*
(
*
endstr
)
==
'/'
)
||
(
*
(
*
endstr
)
==
'.'
))
{
char
*
dp
=
(
*
endstr
);
ftype
[
nf
]
=
DTK_DATE
;
*
lp
++
=
*
(
*
endstr
)
++
;
while
(
isdigit
((
unsigned
char
)
*
(
*
endstr
))
||
(
*
(
*
endstr
)
==
*
dp
))
*
lp
++
=
*
(
*
endstr
)
++
;
}
}
/* skip leading spaces */
else
if
(
isspace
((
unsigned
char
)
*
(
*
endstr
)))
{
(
*
endstr
)
++
;
continue
;
}
/* sign? then special or numeric timezone */
else
if
((
*
(
*
endstr
)
==
'+'
)
||
(
*
(
*
endstr
)
==
'-'
))
{
*
lp
++
=
*
(
*
endstr
)
++
;
/* soak up leading whitespace */
while
(
isspace
((
unsigned
char
)
*
(
*
endstr
)))
(
*
endstr
)
++
;
/* numeric timezone? */
if
(
isdigit
((
unsigned
char
)
*
(
*
endstr
)))
{
ftype
[
nf
]
=
DTK_TZ
;
*
lp
++
=
*
(
*
endstr
)
++
;
while
(
isdigit
((
unsigned
char
)
*
(
*
endstr
))
||
(
*
(
*
endstr
)
==
':'
)
||
(
*
(
*
endstr
)
==
'.'
))
*
lp
++
=
*
(
*
endstr
)
++
;
}
/* special? */
else
if
(
isalpha
((
unsigned
char
)
*
(
*
endstr
)))
{
ftype
[
nf
]
=
DTK_SPECIAL
;
*
lp
++
=
tolower
((
unsigned
char
)
*
(
*
endstr
)
++
);
while
(
isalpha
((
unsigned
char
)
*
(
*
endstr
)))
*
lp
++
=
tolower
((
unsigned
char
)
*
(
*
endstr
)
++
);
}
/* otherwise something wrong... */
else
return
-
1
;
}
/* ignore punctuation but use as delimiter */
else
if
(
ispunct
((
unsigned
char
)
*
(
*
endstr
)))
{
(
*
endstr
)
++
;
continue
;
}
/* otherwise, something is not right... */
else
return
-
1
;
/* force in a delimiter after each field */
*
lp
++
=
'\0'
;
nf
++
;
if
(
nf
>
MAXDATEFIELDS
)
return
-
1
;
}
*
numfields
=
nf
;
return
0
;
}
/* ParseDateTime() */
/* DecodeDateTime()
* Interpret previously parsed fields for general date and time.
* Return 0 if full date, 1 if only time, and -1 if problems.
* External format(s):
* "<weekday> <month>-<day>-<year> <hour>:<minute>:<second>"
* "Fri Feb-7-1997 15:23:27"
* "Feb-7-1997 15:23:27"
* "2-7-1997 15:23:27"
* "1997-2-7 15:23:27"
* "1997.038 15:23:27" (day of year 1-366)
* Also supports input in compact time:
* "970207 152327"
* "97038 152327"
* "20011225T040506.789-07"
*
* Use the system-provided functions to get the current time zone
* if not specified in the input string.
* If the date is outside the time_t system-supported time range,
* then assume UTC time zone. - thomas 1997-05-27
*/
int
DecodeDateTime
(
char
**
field
,
int
*
ftype
,
int
nf
,
int
*
dtype
,
struct
tm
*
tm
,
fsec_t
*
fsec
,
int
*
tzp
,
bool
EuroDates
)
{
int
fmask
=
0
,
tmask
,
type
;
int
ptype
=
0
;
/* "prefix type" for ISO y2001m02d04
* format */
int
i
;
int
val
;
int
mer
=
HR24
;
int
haveTextMonth
=
FALSE
;
int
is2digits
=
FALSE
;
int
bc
=
FALSE
;
/***
* We'll insist on at least all of the date fields, but initialize the
* remaining fields in case they are not set later...
***/
*
dtype
=
DTK_DATE
;
tm
->
tm_hour
=
0
;
tm
->
tm_min
=
0
;
tm
->
tm_sec
=
0
;
*
fsec
=
0
;
/* don't know daylight savings time status apriori */
tm
->
tm_isdst
=
-
1
;
if
(
tzp
!=
NULL
)
*
tzp
=
0
;
for
(
i
=
0
;
i
<
nf
;
i
++
)
{
switch
(
ftype
[
i
])
{
case
DTK_DATE
:
/***
* Integral julian day with attached time zone?
* All other forms with JD will be separated into
* distinct fields, so we handle just this case here.
***/
if
(
ptype
==
DTK_JULIAN
)
{
char
*
cp
;
int
val
;
if
(
tzp
==
NULL
)
return
-
1
;
val
=
strtol
(
field
[
i
],
&
cp
,
10
);
if
(
*
cp
!=
'-'
)
return
-
1
;
j2date
(
val
,
&
tm
->
tm_year
,
&
tm
->
tm_mon
,
&
tm
->
tm_mday
);
/* Get the time zone from the end of the string */
if
(
DecodeTimezone
(
cp
,
tzp
)
!=
0
)
return
-
1
;
tmask
=
DTK_DATE_M
|
DTK_TIME_M
|
DTK_M
(
TZ
);
ptype
=
0
;
break
;
}
/***
* Already have a date? Then this might be a POSIX time
* zone with an embedded dash (e.g. "PST-3" == "EST") or
* a run-together time with trailing time zone (e.g. hhmmss-zz).
* - thomas 2001-12-25
***/
else
if
(((
fmask
&
DTK_DATE_M
)
==
DTK_DATE_M
)
||
(
ptype
!=
0
))
{
/* No time zone accepted? Then quit... */
if
(
tzp
==
NULL
)
return
-
1
;
if
(
isdigit
((
unsigned
char
)
*
field
[
i
])
||
ptype
!=
0
)
{
char
*
cp
;
if
(
ptype
!=
0
)
{
/* Sanity check; should not fail this test */
if
(
ptype
!=
DTK_TIME
)
return
-
1
;
ptype
=
0
;
}
/*
* Starts with a digit but we already have a time
* field? Then we are in trouble with a date and
* time already...
*/
if
((
fmask
&
DTK_TIME_M
)
==
DTK_TIME_M
)
return
-
1
;
if
((
cp
=
strchr
(
field
[
i
],
'-'
))
==
NULL
)
return
-
1
;
/* Get the time zone from the end of the string */
if
(
DecodeTimezone
(
cp
,
tzp
)
!=
0
)
return
-
1
;
*
cp
=
'\0'
;
/*
* Then read the rest of the field as a
* concatenated time
*/
if
((
ftype
[
i
]
=
DecodeNumberField
(
strlen
(
field
[
i
]),
field
[
i
],
fmask
,
&
tmask
,
tm
,
fsec
,
&
is2digits
,
EuroDates
))
<
0
)
return
-
1
;
/*
* modify tmask after returning from
* DecodeNumberField()
*/
tmask
|=
DTK_M
(
TZ
);
}
else
{
if
(
DecodePosixTimezone
(
field
[
i
],
tzp
)
!=
0
)
return
-
1
;
ftype
[
i
]
=
DTK_TZ
;
tmask
=
DTK_M
(
TZ
);
}
}
else
if
(
DecodeDate
(
field
[
i
],
fmask
,
&
tmask
,
tm
,
EuroDates
)
!=
0
)
return
-
1
;
break
;
case
DTK_TIME
:
if
(
DecodeTime
(
field
[
i
],
fmask
,
&
tmask
,
tm
,
fsec
)
!=
0
)
return
-
1
;
/*
* Check upper limit on hours; other limits checked in
* DecodeTime()
*/
if
(
tm
->
tm_hour
>
23
)
return
-
1
;
break
;
case
DTK_TZ
:
{
int
tz
;
if
(
tzp
==
NULL
)
return
-
1
;
if
(
DecodeTimezone
(
field
[
i
],
&
tz
)
!=
0
)
return
-
1
;
/*
* Already have a time zone? Then maybe this is the
* second field of a POSIX time: EST+3 (equivalent to
* PST)
*/
if
((
i
>
0
)
&&
((
fmask
&
DTK_M
(
TZ
))
!=
0
)
&&
(
ftype
[
i
-
1
]
==
DTK_TZ
)
&&
(
isalpha
((
unsigned
char
)
*
field
[
i
-
1
])))
{
*
tzp
-=
tz
;
tmask
=
0
;
}
else
{
*
tzp
=
tz
;
tmask
=
DTK_M
(
TZ
);
}
}
break
;
case
DTK_NUMBER
:
/*
* Was this an "ISO date" with embedded field labels? An
* example is "y2001m02d04" - thomas 2001-02-04
*/
if
(
ptype
!=
0
)
{
char
*
cp
;
int
val
;
val
=
strtol
(
field
[
i
],
&
cp
,
10
);
/*
* only a few kinds are allowed to have an embedded
* decimal
*/
if
(
*
cp
==
'.'
)
switch
(
ptype
)
{
case
DTK_JULIAN
:
case
DTK_TIME
:
case
DTK_SECOND
:
break
;
default:
return
1
;
break
;
}
else
if
(
*
cp
!=
'\0'
)
return
-
1
;
switch
(
ptype
)
{
case
DTK_YEAR
:
tm
->
tm_year
=
val
;
tmask
=
DTK_M
(
YEAR
);
break
;
case
DTK_MONTH
:
/*
* already have a month and hour? then assume
* minutes
*/
if
(((
fmask
&
DTK_M
(
MONTH
))
!=
0
)
&&
((
fmask
&
DTK_M
(
HOUR
))
!=
0
))
{
tm
->
tm_min
=
val
;
tmask
=
DTK_M
(
MINUTE
);
}
else
{
tm
->
tm_mon
=
val
;
tmask
=
DTK_M
(
MONTH
);
}
break
;
case
DTK_DAY
:
tm
->
tm_mday
=
val
;
tmask
=
DTK_M
(
DAY
);
break
;
case
DTK_HOUR
:
tm
->
tm_hour
=
val
;
tmask
=
DTK_M
(
HOUR
);
break
;
case
DTK_MINUTE
:
tm
->
tm_min
=
val
;
tmask
=
DTK_M
(
MINUTE
);
break
;
case
DTK_SECOND
:
tm
->
tm_sec
=
val
;
tmask
=
DTK_M
(
SECOND
);
if
(
*
cp
==
'.'
)
{
double
frac
;
frac
=
strtod
(
cp
,
&
cp
);
if
(
*
cp
!=
'\0'
)
return
-
1
;
#ifdef HAVE_INT64_TIMESTAMP
*
fsec
=
frac
*
1000000
;
#else
*
fsec
=
frac
;
#endif
}
break
;
case
DTK_TZ
:
tmask
=
DTK_M
(
TZ
);
if
(
DecodeTimezone
(
field
[
i
],
tzp
)
!=
0
)
return
-
1
;
break
;
case
DTK_JULIAN
:
/***
* previous field was a label for "julian date"?
***/
tmask
=
DTK_DATE_M
;
j2date
(
val
,
&
tm
->
tm_year
,
&
tm
->
tm_mon
,
&
tm
->
tm_mday
);
/* fractional Julian Day? */
if
(
*
cp
==
'.'
)
{
double
time
;
time
=
strtod
(
cp
,
&
cp
);
if
(
*
cp
!=
'\0'
)
return
-
1
;
tmask
|=
DTK_TIME_M
;
#ifdef HAVE_INT64_TIMESTAMP
dt2time
((
time
*
86400000000
),
&
tm
->
tm_hour
,
&
tm
->
tm_min
,
&
tm
->
tm_sec
,
fsec
);
#else
dt2time
((
time
*
86400
),
&
tm
->
tm_hour
,
&
tm
->
tm_min
,
&
tm
->
tm_sec
,
fsec
);
#endif
}
break
;
case
DTK_TIME
:
/* previous field was "t" for ISO time */
if
((
ftype
[
i
]
=
DecodeNumberField
(
strlen
(
field
[
i
]),
field
[
i
],
(
fmask
|
DTK_DATE_M
),
&
tmask
,
tm
,
fsec
,
&
is2digits
,
EuroDates
))
<
0
)
return
-
1
;
if
(
tmask
!=
DTK_TIME_M
)
return
-
1
;
break
;
default:
return
-
1
;
break
;
}
ptype
=
0
;
*
dtype
=
DTK_DATE
;
}
else
{
char
*
cp
;
int
flen
;
flen
=
strlen
(
field
[
i
]);
cp
=
strchr
(
field
[
i
],
'.'
);
/* Embedded decimal and no date yet? */
if
((
cp
!=
NULL
)
&&
!
(
fmask
&
DTK_DATE_M
))
{
if
(
DecodeDate
(
field
[
i
],
fmask
,
&
tmask
,
tm
,
EuroDates
)
!=
0
)
return
-
1
;
}
/* embedded decimal and several digits before? */
else
if
((
cp
!=
NULL
)
&&
((
flen
-
strlen
(
cp
))
>
2
))
{
/*
* Interpret as a concatenated date or time Set
* the type field to allow decoding other fields
* later. Example: 20011223 or 040506
*/
if
((
ftype
[
i
]
=
DecodeNumberField
(
flen
,
field
[
i
],
fmask
,
&
tmask
,
tm
,
fsec
,
&
is2digits
,
EuroDates
))
<
0
)
return
-
1
;
}
else
if
(
flen
>
4
)
{
if
((
ftype
[
i
]
=
DecodeNumberField
(
flen
,
field
[
i
],
fmask
,
&
tmask
,
tm
,
fsec
,
&
is2digits
,
EuroDates
))
<
0
)
return
-
1
;
}
/* otherwise it is a single date/time field... */
else
if
(
DecodeNumber
(
flen
,
field
[
i
],
fmask
,
&
tmask
,
tm
,
fsec
,
&
is2digits
,
EuroDates
)
!=
0
)
return
-
1
;
}
break
;
case
DTK_STRING
:
case
DTK_SPECIAL
:
type
=
DecodeSpecial
(
i
,
field
[
i
],
&
val
);
if
(
type
==
IGNORE_DTF
)
continue
;
tmask
=
DTK_M
(
type
);
switch
(
type
)
{
case
RESERV
:
switch
(
val
)
{
case
DTK_NOW
:
tmask
=
(
DTK_DATE_M
|
DTK_TIME_M
|
DTK_M
(
TZ
));
*
dtype
=
DTK_DATE
;
GetCurrentDateTime
(
tm
);
break
;
case
DTK_YESTERDAY
:
tmask
=
DTK_DATE_M
;
*
dtype
=
DTK_DATE
;
GetCurrentDateTime
(
tm
);
j2date
((
date2j
(
tm
->
tm_year
,
tm
->
tm_mon
,
tm
->
tm_mday
)
-
1
),
&
tm
->
tm_year
,
&
tm
->
tm_mon
,
&
tm
->
tm_mday
);
tm
->
tm_hour
=
0
;
tm
->
tm_min
=
0
;
tm
->
tm_sec
=
0
;
break
;
case
DTK_TODAY
:
tmask
=
DTK_DATE_M
;
*
dtype
=
DTK_DATE
;
GetCurrentDateTime
(
tm
);
tm
->
tm_hour
=
0
;
tm
->
tm_min
=
0
;
tm
->
tm_sec
=
0
;
break
;
case
DTK_TOMORROW
:
tmask
=
DTK_DATE_M
;
*
dtype
=
DTK_DATE
;
GetCurrentDateTime
(
tm
);
j2date
((
date2j
(
tm
->
tm_year
,
tm
->
tm_mon
,
tm
->
tm_mday
)
+
1
),
&
tm
->
tm_year
,
&
tm
->
tm_mon
,
&
tm
->
tm_mday
);
tm
->
tm_hour
=
0
;
tm
->
tm_min
=
0
;
tm
->
tm_sec
=
0
;
break
;
case
DTK_ZULU
:
tmask
=
(
DTK_TIME_M
|
DTK_M
(
TZ
));
*
dtype
=
DTK_DATE
;
tm
->
tm_hour
=
0
;
tm
->
tm_min
=
0
;
tm
->
tm_sec
=
0
;
if
(
tzp
!=
NULL
)
*
tzp
=
0
;
break
;
default:
*
dtype
=
val
;
}
break
;
case
MONTH
:
/*
* already have a (numeric) month? then see if we
* can substitute...
*/
if
((
fmask
&
DTK_M
(
MONTH
))
&&
(
!
haveTextMonth
)
&&
(
!
(
fmask
&
DTK_M
(
DAY
)))
&&
((
tm
->
tm_mon
>=
1
)
&&
(
tm
->
tm_mon
<=
31
)))
{
tm
->
tm_mday
=
tm
->
tm_mon
;
tmask
=
DTK_M
(
DAY
);
}
haveTextMonth
=
TRUE
;
tm
->
tm_mon
=
val
;
break
;
case
DTZMOD
:
/*
* daylight savings time modifier (solves "MET
* DST" syntax)
*/
tmask
|=
DTK_M
(
DTZ
);
tm
->
tm_isdst
=
1
;
if
(
tzp
==
NULL
)
return
-
1
;
*
tzp
+=
val
*
60
;
break
;
case
DTZ
:
/*
* set mask for TZ here _or_ check for DTZ later
* when getting default timezone
*/
tmask
|=
DTK_M
(
TZ
);
tm
->
tm_isdst
=
1
;
if
(
tzp
==
NULL
)
return
-
1
;
*
tzp
=
val
*
60
;
ftype
[
i
]
=
DTK_TZ
;
break
;
case
TZ
:
tm
->
tm_isdst
=
0
;
if
(
tzp
==
NULL
)
return
-
1
;
*
tzp
=
val
*
60
;
ftype
[
i
]
=
DTK_TZ
;
break
;
case
IGNORE_DTF
:
break
;
case
AMPM
:
mer
=
val
;
break
;
case
ADBC
:
bc
=
(
val
==
BC
);
break
;
case
DOW
:
tm
->
tm_wday
=
val
;
break
;
case
UNITS
:
tmask
=
0
;
ptype
=
val
;
break
;
case
ISOTIME
:
/*
* This is a filler field "t" indicating that the
* next field is time. Try to verify that this is
* sensible.
*/
tmask
=
0
;
/* No preceeding date? Then quit... */
if
((
fmask
&
DTK_DATE_M
)
!=
DTK_DATE_M
)
return
-
1
;
/***
* We will need one of the following fields:
* DTK_NUMBER should be hhmmss.fff
* DTK_TIME should be hh:mm:ss.fff
* DTK_DATE should be hhmmss-zz
***/
if
((
i
>=
(
nf
-
1
))
||
((
ftype
[
i
+
1
]
!=
DTK_NUMBER
)
&&
(
ftype
[
i
+
1
]
!=
DTK_TIME
)
&&
(
ftype
[
i
+
1
]
!=
DTK_DATE
)))
return
-
1
;
ptype
=
val
;
break
;
default:
return
-
1
;
}
break
;
default:
return
-
1
;
}
if
(
tmask
&
fmask
)
return
-
1
;
fmask
|=
tmask
;
}
/* there is no year zero in AD/BC notation; i.e. "1 BC" == year 0 */
if
(
bc
)
{
if
(
tm
->
tm_year
>
0
)
tm
->
tm_year
=
-
(
tm
->
tm_year
-
1
);
else
return
-
1
;
}
else
if
(
is2digits
)
{
if
(
tm
->
tm_year
<
70
)
tm
->
tm_year
+=
2000
;
else
if
(
tm
->
tm_year
<
100
)
tm
->
tm_year
+=
1900
;
}
if
((
mer
!=
HR24
)
&&
(
tm
->
tm_hour
>
12
))
return
-
1
;
if
((
mer
==
AM
)
&&
(
tm
->
tm_hour
==
12
))
tm
->
tm_hour
=
0
;
else
if
((
mer
==
PM
)
&&
(
tm
->
tm_hour
!=
12
))
tm
->
tm_hour
+=
12
;
/* do additional checking for full date specs... */
if
(
*
dtype
==
DTK_DATE
)
{
if
((
fmask
&
DTK_DATE_M
)
!=
DTK_DATE_M
)
return
((
fmask
&
DTK_TIME_M
)
==
DTK_TIME_M
)
?
1
:
-
1
;
/*
* check for valid day of month, now that we know for sure the
* month and year...
*/
if
((
tm
->
tm_mday
<
1
)
||
(
tm
->
tm_mday
>
day_tab
[
isleap
(
tm
->
tm_year
)][
tm
->
tm_mon
-
1
]))
return
-
1
;
/* timezone not specified? then find local timezone if possible */
if
(((
fmask
&
DTK_DATE_M
)
==
DTK_DATE_M
)
&&
(
tzp
!=
NULL
)
&&
(
!
(
fmask
&
DTK_M
(
TZ
))))
{
/*
* daylight savings time modifier but no standard timezone?
* then error
*/
if
(
fmask
&
DTK_M
(
DTZMOD
))
return
-
1
;
*
tzp
=
DetermineLocalTimeZone
(
tm
);
}
}
return
0
;
}
/* DecodeDateTime() */
src/interfaces/ecpg/pgtypeslib/extern.h
0 → 100644
View file @
2e6f9756
#include <string.h>
extern
char
*
pgtypes_alloc
(
long
);
extern
char
*
pgtypes_strdup
(
char
*
);
src/interfaces/ecpg/pgtypeslib/numeric.c
View file @
2e6f9756
...
...
@@ -5,9 +5,9 @@
#include <math.h>
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include "c.h"
#include "extern.h"
#include "numeric.h"
#include "pgtypes_error.h"
...
...
@@ -25,21 +25,6 @@
#include "pgtypes_numeric.h"
static
char
*
pgtypes_alloc
(
long
size
)
{
char
*
new
=
(
char
*
)
calloc
(
1L
,
size
);
if
(
!
new
)
{
errno
=
ENOMEM
;
return
NULL
;
}
memset
(
new
,
'\0'
,
size
);
return
(
new
);
}
#if 0
/* ----------
* apply_typmod() -
...
...
src/interfaces/ecpg/pgtypeslib/timestamp.c
0 → 100644
View file @
2e6f9756
#include <math.h>
#include <time.h>
#include <string.h>
#include <errno.h>
#include <float.h>
#include <stdio.h>
#ifdef __FAST_MATH__
#error -ffast-math is known to break this code
#endif
#include "dt.h"
#include "extern.h"
#include "pgtypes_error.h"
#include "pgtypes_timestamp.h"
#ifdef HAVE_INT64_TIMESTAMP
static
int64
time2t
(
const
int
hour
,
const
int
min
,
const
int
sec
,
const
fsec_t
fsec
)
{
return
((((((
hour
*
60
)
+
min
)
*
60
)
+
sec
)
*
INT64CONST
(
1000000
))
+
fsec
);
}
/* time2t() */
#else
static
double
time2t
(
const
int
hour
,
const
int
min
,
const
int
sec
,
const
fsec_t
fsec
)
{
return
((((
hour
*
60
)
+
min
)
*
60
)
+
sec
+
fsec
);
}
/* time2t() */
#endif
static
Timestamp
dt2local
(
Timestamp
dt
,
int
tz
)
{
#ifdef HAVE_INT64_TIMESTAMP
dt
-=
(
tz
*
INT64CONST
(
1000000
));
#else
dt
-=
tz
;
dt
=
JROUND
(
dt
);
#endif
return
dt
;
}
/* dt2local() */
/* tm2timestamp()
* Convert a tm structure to a timestamp data type.
* Note that year is _not_ 1900-based, but is an explicit full value.
* Also, month is one-based, _not_ zero-based.
*/
static
int
tm2timestamp
(
struct
tm
*
tm
,
fsec_t
fsec
,
int
*
tzp
,
Timestamp
*
result
)
{
#ifdef HAVE_INT64_TIMESTAMP
int
date
;
int64
time
;
#else
double
date
,
time
;
#endif
/* Julian day routines are not correct for negative Julian days */
if
(
!
IS_VALID_JULIAN
(
tm
->
tm_year
,
tm
->
tm_mon
,
tm
->
tm_mday
))
return
-
1
;
date
=
date2j
(
tm
->
tm_year
,
tm
->
tm_mon
,
tm
->
tm_mday
)
-
date2j
(
2000
,
1
,
1
);
time
=
time2t
(
tm
->
tm_hour
,
tm
->
tm_min
,
tm
->
tm_sec
,
fsec
);
#ifdef HAVE_INT64_TIMESTAMP
*
result
=
((
date
*
INT64CONST
(
86400000000
))
+
time
);
if
((
*
result
<
0
&&
date
>=
0
)
||
(
*
result
>=
0
&&
date
<
0
))
elog
(
ERROR
,
"TIMESTAMP out of range '%04d-%02d-%02d'"
,
tm
->
tm_year
,
tm
->
tm_mon
,
tm
->
tm_mday
);
#else
*
result
=
((
date
*
86400
)
+
time
);
#endif
if
(
tzp
!=
NULL
)
*
result
=
dt2local
(
*
result
,
-
(
*
tzp
));
return
0
;
}
/* tm2timestamp() */
static
Timestamp
SetEpochTimestamp
(
void
)
{
Timestamp
dt
;
struct
tm
tt
,
*
tm
=
&
tt
;
GetEpochTime
(
tm
);
tm2timestamp
(
tm
,
0
,
NULL
,
&
dt
);
return
dt
;
}
/* SetEpochTimestamp() */
static
void
dt2time
(
Timestamp
jd
,
int
*
hour
,
int
*
min
,
int
*
sec
,
fsec_t
*
fsec
)
{
#ifdef HAVE_INT64_TIMESTAMP
int64
time
;
#else
double
time
;
#endif
time
=
jd
;
#ifdef HAVE_INT64_TIMESTAMP
*
hour
=
(
time
/
INT64CONST
(
3600000000
));
time
-=
((
*
hour
)
*
INT64CONST
(
3600000000
));
*
min
=
(
time
/
INT64CONST
(
60000000
));
time
-=
((
*
min
)
*
INT64CONST
(
60000000
));
*
sec
=
(
time
/
INT64CONST
(
1000000
));
*
fsec
=
(
time
-
(
*
sec
*
INT64CONST
(
1000000
)));
*
sec
=
(
time
/
INT64CONST
(
1000000
));
*
fsec
=
(
time
-
(
*
sec
*
INT64CONST
(
1000000
)));
#else
*
hour
=
(
time
/
3600
);
time
-=
((
*
hour
)
*
3600
);
*
min
=
(
time
/
60
);
time
-=
((
*
min
)
*
60
);
*
sec
=
time
;
*
fsec
=
JROUND
(
time
-
*
sec
);
#endif
return
;
}
/* dt2time() */
/* timestamp2tm()
* Convert timestamp data type to POSIX time structure.
* Note that year is _not_ 1900-based, but is an explicit full value.
* Also, month is one-based, _not_ zero-based.
* Returns:
* 0 on success
* -1 on out of range
*
* For dates within the system-supported time_t range, convert to the
* local time zone. If out of this range, leave as GMT. - tgl 97/05/27
*/
static
int
timestamp2tm
(
Timestamp
dt
,
int
*
tzp
,
struct
tm
*
tm
,
fsec_t
*
fsec
,
char
**
tzn
)
{
#ifdef HAVE_INT64_TIMESTAMP
int
date
,
date0
;
int64
time
;
#else
double
date
,
date0
;
double
time
;
#endif
time_t
utime
;
#if defined(HAVE_TM_ZONE) || defined(HAVE_INT_TIMEZONE)
struct
tm
*
tx
;
#endif
date0
=
date2j
(
2000
,
1
,
1
);
time
=
dt
;
#ifdef HAVE_INT64_TIMESTAMP
TMODULO
(
time
,
date
,
INT64CONST
(
86400000000
));
if
(
time
<
INT64CONST
(
0
))
{
time
+=
INT64CONST
(
86400000000
);
date
-=
1
;
}
#else
TMODULO
(
time
,
date
,
86400e0
);
if
(
time
<
0
)
{
time
+=
86400
;
date
-=
1
;
}
#endif
/* Julian day routine does not work for negative Julian days */
if
(
date
<
-
date0
)
return
-
1
;
/* add offset to go from J2000 back to standard Julian date */
date
+=
date0
;
j2date
((
int
)
date
,
&
tm
->
tm_year
,
&
tm
->
tm_mon
,
&
tm
->
tm_mday
);
dt2time
(
time
,
&
tm
->
tm_hour
,
&
tm
->
tm_min
,
&
tm
->
tm_sec
,
fsec
);
if
(
tzp
!=
NULL
)
{
/*
* Does this fall within the capabilities of the localtime()
* interface? Then use this to rotate to the local time zone.
*/
if
(
IS_VALID_UTIME
(
tm
->
tm_year
,
tm
->
tm_mon
,
tm
->
tm_mday
))
{
#ifdef HAVE_INT64_TIMESTAMP
utime
=
((
dt
/
INT64CONST
(
1000000
))
+
((
date0
-
date2j
(
1970
,
1
,
1
))
*
INT64CONST
(
86400
)));
#else
utime
=
(
dt
+
((
date0
-
date2j
(
1970
,
1
,
1
))
*
86400
));
#endif
#if defined(HAVE_TM_ZONE) || defined(HAVE_INT_TIMEZONE)
tx
=
localtime
(
&
utime
);
tm
->
tm_year
=
tx
->
tm_year
+
1900
;
tm
->
tm_mon
=
tx
->
tm_mon
+
1
;
tm
->
tm_mday
=
tx
->
tm_mday
;
tm
->
tm_hour
=
tx
->
tm_hour
;
tm
->
tm_min
=
tx
->
tm_min
;
tm
->
tm_isdst
=
tx
->
tm_isdst
;
#if defined(HAVE_TM_ZONE)
tm
->
tm_gmtoff
=
tx
->
tm_gmtoff
;
tm
->
tm_zone
=
tx
->
tm_zone
;
*
tzp
=
-
(
tm
->
tm_gmtoff
);
/* tm_gmtoff is Sun/DEC-ism */
if
(
tzn
!=
NULL
)
*
tzn
=
(
char
*
)
tm
->
tm_zone
;
#elif defined(HAVE_INT_TIMEZONE)
*
tzp
=
((
tm
->
tm_isdst
>
0
)
?
(
TIMEZONE_GLOBAL
-
3600
)
:
TIMEZONE_GLOBAL
);
if
(
tzn
!=
NULL
)
*
tzn
=
tzname
[(
tm
->
tm_isdst
>
0
)];
#endif
#else
/* not (HAVE_TM_ZONE || HAVE_INT_TIMEZONE) */
*
tzp
=
0
;
/* Mark this as *no* time zone available */
tm
->
tm_isdst
=
-
1
;
if
(
tzn
!=
NULL
)
*
tzn
=
NULL
;
#endif
dt
=
dt2local
(
dt
,
*
tzp
);
}
else
{
*
tzp
=
0
;
/* Mark this as *no* time zone available */
tm
->
tm_isdst
=
-
1
;
if
(
tzn
!=
NULL
)
*
tzn
=
NULL
;
}
}
else
{
tm
->
tm_isdst
=
-
1
;
if
(
tzn
!=
NULL
)
*
tzn
=
NULL
;
}
return
0
;
}
/* timestamp2tm() */
/* EncodeSpecialTimestamp()
* * Convert reserved timestamp data type to string.
* */
static
int
EncodeSpecialTimestamp
(
Timestamp
dt
,
char
*
str
)
{
if
(
TIMESTAMP_IS_NOBEGIN
(
dt
))
strcpy
(
str
,
EARLY
);
else
if
(
TIMESTAMP_IS_NOEND
(
dt
))
strcpy
(
str
,
LATE
);
else
return
FALSE
;
return
TRUE
;
}
/* EncodeSpecialTimestamp() */
Timestamp
PGTYPEStimestamp_atot
(
char
*
str
,
char
**
endptr
)
{
Timestamp
result
;
#ifdef HAVE_INT64_TIMESTAMP
int64
noresult
=
0
;
#else
double
noresult
=
0
.
0
;
#endif
fsec_t
fsec
;
struct
tm
tt
,
*
tm
=
&
tt
;
int
tz
;
int
dtype
;
int
nf
;
char
*
field
[
MAXDATEFIELDS
];
int
ftype
[
MAXDATEFIELDS
];
char
lowstr
[
MAXDATELEN
+
MAXDATEFIELDS
];
char
*
realptr
;
char
**
ptr
=
(
endptr
!=
NULL
)
?
endptr
:
&
realptr
;
errno
=
0
;
if
(
strlen
(
str
)
>=
sizeof
(
lowstr
))
{
errno
=
PGTYPES_BAD_TIMESTAMP
;
return
(
noresult
);
}
if
((
ParseDateTime
(
str
,
lowstr
,
field
,
ftype
,
MAXDATEFIELDS
,
&
nf
,
ptr
)
!=
0
)
||
(
DecodeDateTime
(
field
,
ftype
,
nf
,
&
dtype
,
tm
,
&
fsec
,
&
tz
,
0
)
!=
0
))
{
errno
=
PGTYPES_BAD_TIMESTAMP
;
return
(
noresult
);
}
switch
(
dtype
)
{
case
DTK_DATE
:
if
(
tm2timestamp
(
tm
,
fsec
,
NULL
,
&
result
)
!=
0
)
{
errno
=
PGTYPES_BAD_TIMESTAMP
;
return
(
noresult
);;
}
break
;
case
DTK_EPOCH
:
result
=
SetEpochTimestamp
();
break
;
case
DTK_LATE
:
TIMESTAMP_NOEND
(
result
);
break
;
case
DTK_EARLY
:
TIMESTAMP_NOBEGIN
(
result
);
break
;
case
DTK_INVALID
:
errno
=
PGTYPES_BAD_TIMESTAMP
;
return
(
noresult
);
default:
errno
=
PGTYPES_BAD_TIMESTAMP
;
return
(
noresult
);
}
/* AdjustTimestampForTypmod(&result, typmod); */
return
result
;
}
char
*
PGTYPEStimestamp_ttoa
(
Timestamp
tstamp
)
{
struct
tm
tt
,
*
tm
=
&
tt
;
char
buf
[
MAXDATELEN
+
1
];
char
*
tzn
=
NULL
;
fsec_t
fsec
;
int
DateStyle
=
0
;
if
(
TIMESTAMP_NOT_FINITE
(
tstamp
))
EncodeSpecialTimestamp
(
tstamp
,
buf
);
else
if
(
timestamp2tm
(
tstamp
,
NULL
,
tm
,
&
fsec
,
NULL
)
==
0
)
EncodeDateTime
(
tm
,
fsec
,
NULL
,
&
tzn
,
DateStyle
,
buf
,
0
);
else
{
errno
=
PGTYPES_BAD_TIMESTAMP
;
return
NULL
;
}
return
pgtypes_strdup
(
buf
);
}
src/interfaces/ecpg/preproc/preproc.y
View file @
2e6f9756
/* $Header: /cvsroot/pgsql/src/interfaces/ecpg/preproc/Attic/preproc.y,v 1.21
2 2003/03/16 10:42:54
meskes Exp $ */
/* $Header: /cvsroot/pgsql/src/interfaces/ecpg/preproc/Attic/preproc.y,v 1.21
3 2003/03/20 15:56:50
meskes Exp $ */
/* Copyright comment */
%{
...
...
@@ -4223,6 +4223,22 @@ single_vt_type: common_type
$$.type_index = -1;
$$.type_sizeof = NULL;
}
else if (strcmp($1, "date") == 0)
{
$$.type_enum = ECPGt_date;
$$.type_str = make_str("Date");
$$.type_dimension = -1;
$$.type_index = -1;
$$.type_sizeof = NULL;
}
else if (strcmp($1, "timestamp") == 0)
{
$$.type_enum = ECPGt_timestamp;
$$.type_str = make_str("Timestamp");
$$.type_dimension = -1;
$$.type_index = -1;
$$.type_sizeof = NULL;
}
else
{
/* this is for typedef'ed types */
...
...
@@ -4236,17 +4252,6 @@ single_vt_type: common_type
struct_member_list[struct_level] = ECPGstruct_member_dup(this->struct_member_list);
}
}
| ECPGColLabelCommon '(' precision opt_scale ')'
{
if (strcmp($1, "numeric") != 0 && strcmp($1, "decimal") != 0)
mmerror(PARSE_ERROR, ET_ERROR, "Only numeric/decimal have precision/scale argument");
$$.type_enum = ECPGt_numeric;
$$.type_str = EMPTY;
$$.type_dimension = -1;
$$.type_index = -1;
$$.type_sizeof = NULL;
}
;
/*
...
...
@@ -4415,6 +4420,17 @@ common_type: simple_type
$$.type_index = -1;
$$.type_sizeof = NULL;
}
| ECPGColLabelCommon '(' precision opt_scale ')'
{
if (strcmp($1, "numeric") != 0 && strcmp($1, "decimal") != 0)
mmerror(PARSE_ERROR, ET_ERROR, "Only numeric/decimal have precision/scale argument");
$$.type_enum = ECPGt_numeric;
$$.type_str = EMPTY;
$$.type_dimension = -1;
$$.type_index = -1;
$$.type_sizeof = NULL;
}
;
var_type: common_type
...
...
@@ -4464,6 +4480,22 @@ var_type: common_type
$$.type_index = -1;
$$.type_sizeof = NULL;
}
else if (strcmp($1, "date") == 0)
{
$$.type_enum = ECPGt_date;
$$.type_str = make_str("Date");
$$.type_dimension = -1;
$$.type_index = -1;
$$.type_sizeof = NULL;
}
else if (strcmp($1, "timestamp") == 0)
{
$$.type_enum = ECPGt_timestamp;
$$.type_str = make_str("Timestamp");
$$.type_dimension = -1;
$$.type_index = -1;
$$.type_sizeof = NULL;
}
else
{
/* this is for typedef'ed types */
...
...
@@ -4477,17 +4509,6 @@ var_type: common_type
struct_member_list[struct_level] = ECPGstruct_member_dup(this->struct_member_list);
}
}
| ECPGColLabelCommon '(' precision opt_scale ')'
{
if (strcmp($1, "numeric") != 0 && strcmp($1, "decimal") != 0)
mmerror(PARSE_ERROR, ET_ERROR, "Only numeric/decimal have precision/scale argument");
$$.type_enum = ECPGt_numeric;
$$.type_str = EMPTY;
$$.type_dimension = -1;
$$.type_index = -1;
$$.type_sizeof = NULL;
}
;
enum_type: SQL_ENUM opt_symbol enum_definition
...
...
src/interfaces/ecpg/preproc/type.c
View file @
2e6f9756
...
...
@@ -175,6 +175,12 @@ get_type(enum ECPGttype type)
case
ECPGt_descriptor
:
return
(
"ECPGt_descriptor"
);
break
;
case
ECPGt_date
:
return
(
"ECPGt_date"
);
break
;
case
ECPGt_timestamp
:
return
(
"ECPGt_timestamp"
);
break
;
default:
sprintf
(
errortext
,
"illegal variable type %d
\n
"
,
type
);
yyerror
(
errortext
);
...
...
@@ -330,6 +336,22 @@ ECPGdump_a_simple(FILE *o, const char *name, enum ECPGttype type,
sprintf
(
variable
,
"&(%s%s)"
,
prefix
?
prefix
:
""
,
name
);
sprintf
(
offset
,
"sizeof(struct NumericVar)"
);
break
;
case
ECPGt_date
:
/*
* we have to use a pointer and translate the variable type
*/
sprintf
(
variable
,
"&(%s%s)"
,
prefix
?
prefix
:
""
,
name
);
sprintf
(
offset
,
"sizeof(Date)"
);
break
;
case
ECPGt_timestamp
:
/*
* we have to use a pointer and translate the variable type
*/
sprintf
(
variable
,
"&(%s%s)"
,
prefix
?
prefix
:
""
,
name
);
sprintf
(
offset
,
"sizeof(Date)"
);
break
;
default:
/*
...
...
src/interfaces/ecpg/test/Makefile
View file @
2e6f9756
# $Header: /cvsroot/pgsql/src/interfaces/ecpg/test/Makefile,v 1.3
4 2003/03/16 10:42:54
meskes Exp $
# $Header: /cvsroot/pgsql/src/interfaces/ecpg/test/Makefile,v 1.3
5 2003/03/20 15:56:50
meskes Exp $
subdir
=
src/interfaces/ecpg/test
top_builddir
=
../../../..
...
...
@@ -8,7 +8,7 @@ override CPPFLAGS := -I$(srcdir)/../include $(CPPFLAGS) -g
ECPG
=
../preproc/ecpg
-I
$(srcdir)
/../include
TESTS
=
test1 test2 test3 test4 perftest dyntest dyntest2 test_notice test_code100 test_init testdynalloc num_test
TESTS
=
test1 test2 test3 test4 perftest dyntest dyntest2 test_notice test_code100 test_init testdynalloc num_test
dt_test
all
:
$(TESTS)
...
...
src/interfaces/ecpg/test/dt_test.pgc
0 → 100644
View file @
2e6f9756
#include <stdio.h>
#include <pgtypes_date.h>
#include <pgtypes_timestamp.h>
int
main()
{
exec sql begin declare section;
date date1;
timestamp ts1;
char *text;
exec sql end declare section;
#if 0
Date date2;
short int mdy[3] = { 4, 19, 1998 };
#endif
FILE *dbgs;
if ((dbgs = fopen("log", "w")) != NULL)
ECPGdebug(1, dbgs);
exec sql whenever sqlerror do sqlprint();
exec sql connect to mm;
exec sql create table date_test (d date, ts timestamp);
exec sql insert into date_test(d, ts) values ('Mon Jan 17 1966', '2000-7-12 17:34:29');
exec sql select * into :date1, :ts1 from date_test;
text = PGTYPESdate_dtoa(date1);
printf ("Date: %s\n", text);
ts1 = PGTYPEStimestamp_atot("2000-7-12 17:34:29", NULL);
text = PGTYPEStimestamp_ttoa(ts1);
printf ("timestamp: %s\n", text);
#if 0
PGTYPESdate_mdyjul(mdy, &date2);
printf("m: %d, d: %d, y: %d\n", mdy[0], mdy[1], mdy[2]);
/* reset */
mdy[0] = mdy[1] = mdy[2] = 0;
PGTYPESdate_julmdy(date2, mdy);
printf("m: %d, d: %d, y: %d\n", mdy[0], mdy[1], mdy[2]);
#endif
exec sql rollback;
exec sql disconnect;
if (dbgs != NULL)
fclose(dbgs);
return (0);
}
src/interfaces/ecpg/test/num_test.pgc
View file @
2e6f9756
...
...
@@ -8,6 +8,7 @@ main()
NumericVar *value1, *value2, *res;
exec sql begin declare section;
decimal(14,7) des = {0, 0, 0, 0, 0, NULL, NULL} ;
numeric num;
exec sql end declare section;
double d;
FILE *dbgs;
...
...
@@ -52,6 +53,13 @@ main()
text = PGTYPESnumeric_ntoa(res);
PGTYPESnumeric_ntod(res, &d);
printf("div = %s %e\n", text, d);
exec sql rollback;
exec sql disconnect;
if (dbgs != NULL)
fclose(dbgs);
return (0);
}
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment