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
7c5a561f
Commit
7c5a561f
authored
Nov 26, 2008
by
Michael Meskes
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Applied patch by Ron Mayer <rm_pg@cheapcomplexdevices.com> to merge the new
interval style into ecpg.
parent
cbb3e1cd
Changes
6
Hide whitespace changes
Inline
Side-by-side
Showing
6 changed files
with
791 additions
and
376 deletions
+791
-376
src/interfaces/ecpg/ChangeLog
src/interfaces/ecpg/ChangeLog
+2
-0
src/interfaces/ecpg/pgtypeslib/dt.h
src/interfaces/ecpg/pgtypeslib/dt.h
+35
-13
src/interfaces/ecpg/pgtypeslib/interval.c
src/interfaces/ecpg/pgtypeslib/interval.c
+721
-343
src/interfaces/ecpg/test/expected/pgtypeslib-dt_test.c
src/interfaces/ecpg/test/expected/pgtypeslib-dt_test.c
+14
-8
src/interfaces/ecpg/test/expected/pgtypeslib-dt_test.stderr
src/interfaces/ecpg/test/expected/pgtypeslib-dt_test.stderr
+18
-12
src/interfaces/ecpg/test/pgtypeslib/dt_test.pgc
src/interfaces/ecpg/test/pgtypeslib/dt_test.pgc
+1
-0
No files found.
src/interfaces/ecpg/ChangeLog
View file @
7c5a561f
...
...
@@ -2394,6 +2394,8 @@ Sat, 25 Oct 2008 16:34:28 +0200
Wed, 26 Nov 2008 14:09:08 +0100
- When creating a varchar struct name braces must be discarded.
- Applied patch by Ron Mayer <rm_pg@cheapcomplexdevices.com> to merge
the new interval style into ecpg.
- Set pgtypes library version to 3.1.
- Set compat library version to 3.1.
- Set ecpg library version to 6.2.
...
...
src/interfaces/ecpg/pgtypeslib/dt.h
View file @
7c5a561f
/* $PostgreSQL: pgsql/src/interfaces/ecpg/pgtypeslib/dt.h,v 1.
39 2007/11/15 21:14:45 momjian
Exp $ */
/* $PostgreSQL: pgsql/src/interfaces/ecpg/pgtypeslib/dt.h,v 1.
40 2008/11/26 16:31:02 meskes
Exp $ */
#ifndef DT_H
#define DT_H
...
...
@@ -25,6 +25,22 @@ typedef double fsec_t;
#define USE_SQL_DATES 2
#define USE_GERMAN_DATES 3
#define INTSTYLE_POSTGRES 0
#define INTSTYLE_POSTGRES_VERBOSE 1
#define INTSTYLE_SQL_STANDARD 2
#define INTSTYLE_ISO_8601 3
#define INTERVAL_FULL_RANGE (0x7FFF)
#define INTERVAL_MASK(b) (1 << (b))
#define MAX_INTERVAL_PRECISION 6
#define DTERR_BAD_FORMAT (-1)
#define DTERR_FIELD_OVERFLOW (-2)
#define DTERR_MD_FIELD_OVERFLOW (-3)
/* triggers hint about DateStyle */
#define DTERR_INTERVAL_OVERFLOW (-4)
#define DTERR_TZDISP_OVERFLOW (-5)
#define DAGO "ago"
#define EPOCH "epoch"
#define INVALID "invalid"
...
...
@@ -77,6 +93,9 @@ typedef double fsec_t;
* 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.
*
* Copy&pasted these values from src/include/utils/datetime.h
* 2008-11-20, changing a number of their values.
*/
#define RESERV 0
...
...
@@ -92,20 +111,23 @@ typedef double fsec_t;
#define HOUR 10
#define MINUTE 11
#define SECOND 12
#define DOY 13
#define DOW 14
#define UNITS 15
#define ADBC 16
#define MILLISECOND 13
#define MICROSECOND 14
#define DOY 15
#define DOW 16
#define UNITS 17
#define ADBC 18
/* these are only for relative dates */
#define AGO 1
7
#define ABS_BEFORE
18
#define ABS_AFTER
19
#define AGO 1
9
#define ABS_BEFORE
20
#define ABS_AFTER
21
/* generic fields to help with parsing */
#define ISODATE 2
0
#define ISOTIME 2
1
#define ISODATE 2
2
#define ISOTIME 2
3
/* 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.
...
...
@@ -164,13 +186,13 @@ typedef double fsec_t;
/*
* Bit mask definitions for time parsing.
*/
/* Copy&pasted these values from src/include/utils/datetime.h */
#define DTK_M(t) (0x01 << (t))
#define DTK_ALL_SECS_M (DTK_M(SECOND) | DTK_M(MILLISECOND) | DTK_M(MICROSECOND))
#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
#define MAXDATELEN
63
/* maximum possible length of an input date
* string (not counting tr. null) */
#define MAXDATEFIELDS 25
/* maximum possible number of fields in a date
* string */
...
...
src/interfaces/ecpg/pgtypeslib/interval.c
View file @
7c5a561f
/* $PostgreSQL: pgsql/src/interfaces/ecpg/pgtypeslib/interval.c,v 1.3
7 2007/08/22 08:20:58
meskes Exp $ */
/* $PostgreSQL: pgsql/src/interfaces/ecpg/pgtypeslib/interval.c,v 1.3
8 2008/11/26 16:31:02
meskes Exp $ */
#include "postgres_fe.h"
#include <time.h>
...
...
@@ -13,39 +13,347 @@
#include "pgtypes_error.h"
#include "pgtypes_interval.h"
/* DecodeInterval()
* Interpret previously parsed fields for general time interval.
* Return 0 if decoded and -1 if problems.
/* copy&pasted from .../src/backend/utils/adt/datetime.c */
static
int
strtoi
(
const
char
*
nptr
,
char
**
endptr
,
int
base
)
{
long
val
;
val
=
strtol
(
nptr
,
endptr
,
base
);
#ifdef HAVE_LONG_INT_64
if
(
val
!=
(
long
)
((
int32
)
val
))
errno
=
ERANGE
;
#endif
return
(
int
)
val
;
}
/* copy&pasted from .../src/backend/utils/adt/datetime.c
* and changesd struct pg_tm to struct tm
*/
static
void
AdjustFractSeconds
(
double
frac
,
struct
/*pg_*/
tm
*
tm
,
fsec_t
*
fsec
,
int
scale
)
{
int
sec
;
if
(
frac
==
0
)
return
;
frac
*=
scale
;
sec
=
(
int
)
frac
;
tm
->
tm_sec
+=
sec
;
frac
-=
sec
;
#ifdef HAVE_INT64_TIMESTAMP
*
fsec
+=
rint
(
frac
*
1000000
);
#else
*
fsec
+=
frac
;
#endif
}
/* copy&pasted from .../src/backend/utils/adt/datetime.c
* and changesd struct pg_tm to struct tm
*/
static
void
AdjustFractDays
(
double
frac
,
struct
/*pg_*/
tm
*
tm
,
fsec_t
*
fsec
,
int
scale
)
{
int
extra_days
;
if
(
frac
==
0
)
return
;
frac
*=
scale
;
extra_days
=
(
int
)
frac
;
tm
->
tm_mday
+=
extra_days
;
frac
-=
extra_days
;
AdjustFractSeconds
(
frac
,
tm
,
fsec
,
SECS_PER_DAY
);
}
/* copy&pasted from .../src/backend/utils/adt/datetime.c */
static
int
ParseISO8601Number
(
char
*
str
,
char
**
endptr
,
int
*
ipart
,
double
*
fpart
)
{
double
val
;
if
(
!
(
isdigit
((
unsigned
char
)
*
str
)
||
*
str
==
'-'
||
*
str
==
'.'
))
return
DTERR_BAD_FORMAT
;
errno
=
0
;
val
=
strtod
(
str
,
endptr
);
/* did we not see anything that looks like a double? */
if
(
*
endptr
==
str
||
errno
!=
0
)
return
DTERR_BAD_FORMAT
;
/* watch out for overflow */
if
(
val
<
INT_MIN
||
val
>
INT_MAX
)
return
DTERR_FIELD_OVERFLOW
;
/* be very sure we truncate towards zero (cf dtrunc()) */
if
(
val
>=
0
)
*
ipart
=
(
int
)
floor
(
val
);
else
*
ipart
=
(
int
)
-
floor
(
-
val
);
*
fpart
=
val
-
*
ipart
;
return
0
;
}
/* copy&pasted from .../src/backend/utils/adt/datetime.c */
static
int
ISO8601IntegerWidth
(
char
*
fieldstart
)
{
/* We might have had a leading '-' */
if
(
*
fieldstart
==
'-'
)
fieldstart
++
;
return
strspn
(
fieldstart
,
"0123456789"
);
}
/* copy&pasted from .../src/backend/utils/adt/datetime.c
* and changesd struct pg_tm to struct tm
*/
static
inline
void
ClearPgTm
(
struct
/*pg_*/
tm
*
tm
,
fsec_t
*
fsec
)
{
tm
->
tm_year
=
0
;
tm
->
tm_mon
=
0
;
tm
->
tm_mday
=
0
;
tm
->
tm_hour
=
0
;
tm
->
tm_min
=
0
;
tm
->
tm_sec
=
0
;
*
fsec
=
0
;
}
/* copy&pasted from .../src/backend/utils/adt/datetime.c
*
* * changesd struct pg_tm to struct tm
*
* * Made the function static
*/
static
int
DecodeISO8601Interval
(
char
*
str
,
int
*
dtype
,
struct
/*pg_*/
tm
*
tm
,
fsec_t
*
fsec
)
{
bool
datepart
=
true
;
bool
havefield
=
false
;
*
dtype
=
DTK_DELTA
;
ClearPgTm
(
tm
,
fsec
);
if
(
strlen
(
str
)
<
2
||
str
[
0
]
!=
'P'
)
return
DTERR_BAD_FORMAT
;
str
++
;
while
(
*
str
)
{
char
*
fieldstart
;
int
val
;
double
fval
;
char
unit
;
int
dterr
;
if
(
*
str
==
'T'
)
/* T indicates the beginning of the time part */
{
datepart
=
false
;
havefield
=
false
;
str
++
;
continue
;
}
fieldstart
=
str
;
dterr
=
ParseISO8601Number
(
str
,
&
str
,
&
val
,
&
fval
);
if
(
dterr
)
return
dterr
;
/*
* Note: we could step off the end of the string here. Code below
* *must* exit the loop if unit == '\0'.
*/
unit
=
*
str
++
;
if
(
datepart
)
{
switch
(
unit
)
/* before T: Y M W D */
{
case
'Y'
:
tm
->
tm_year
+=
val
;
tm
->
tm_mon
+=
(
fval
*
12
);
break
;
case
'M'
:
tm
->
tm_mon
+=
val
;
AdjustFractDays
(
fval
,
tm
,
fsec
,
DAYS_PER_MONTH
);
break
;
case
'W'
:
tm
->
tm_mday
+=
val
*
7
;
AdjustFractDays
(
fval
,
tm
,
fsec
,
7
);
break
;
case
'D'
:
tm
->
tm_mday
+=
val
;
AdjustFractSeconds
(
fval
,
tm
,
fsec
,
SECS_PER_DAY
);
break
;
case
'T'
:
/* ISO 8601 4.4.3.3 Alternative Format / Basic */
case
'\0'
:
if
(
ISO8601IntegerWidth
(
fieldstart
)
==
8
&&
!
havefield
)
{
tm
->
tm_year
+=
val
/
10000
;
tm
->
tm_mon
+=
(
val
/
100
)
%
100
;
tm
->
tm_mday
+=
val
%
100
;
AdjustFractSeconds
(
fval
,
tm
,
fsec
,
SECS_PER_DAY
);
if
(
unit
==
'\0'
)
return
0
;
datepart
=
false
;
havefield
=
false
;
continue
;
}
/* Else fall through to extended alternative format */
case
'-'
:
/* ISO 8601 4.4.3.3 Alternative Format, Extended */
if
(
havefield
)
return
DTERR_BAD_FORMAT
;
tm
->
tm_year
+=
val
;
tm
->
tm_mon
+=
(
fval
*
12
);
if
(
unit
==
'\0'
)
return
0
;
if
(
unit
==
'T'
)
{
datepart
=
false
;
havefield
=
false
;
continue
;
}
dterr
=
ParseISO8601Number
(
str
,
&
str
,
&
val
,
&
fval
);
if
(
dterr
)
return
dterr
;
tm
->
tm_mon
+=
val
;
AdjustFractDays
(
fval
,
tm
,
fsec
,
DAYS_PER_MONTH
);
if
(
*
str
==
'\0'
)
return
0
;
if
(
*
str
==
'T'
)
{
datepart
=
false
;
havefield
=
false
;
continue
;
}
if
(
*
str
!=
'-'
)
return
DTERR_BAD_FORMAT
;
str
++
;
dterr
=
ParseISO8601Number
(
str
,
&
str
,
&
val
,
&
fval
);
if
(
dterr
)
return
dterr
;
tm
->
tm_mday
+=
val
;
AdjustFractSeconds
(
fval
,
tm
,
fsec
,
SECS_PER_DAY
);
if
(
*
str
==
'\0'
)
return
0
;
if
(
*
str
==
'T'
)
{
datepart
=
false
;
havefield
=
false
;
continue
;
}
return
DTERR_BAD_FORMAT
;
default:
/* not a valid date unit suffix */
return
DTERR_BAD_FORMAT
;
}
}
else
{
switch
(
unit
)
/* after T: H M S */
{
case
'H'
:
tm
->
tm_hour
+=
val
;
AdjustFractSeconds
(
fval
,
tm
,
fsec
,
SECS_PER_HOUR
);
break
;
case
'M'
:
tm
->
tm_min
+=
val
;
AdjustFractSeconds
(
fval
,
tm
,
fsec
,
SECS_PER_MINUTE
);
break
;
case
'S'
:
tm
->
tm_sec
+=
val
;
AdjustFractSeconds
(
fval
,
tm
,
fsec
,
1
);
break
;
case
'\0'
:
/* ISO 8601 4.4.3.3 Alternative Format */
if
(
ISO8601IntegerWidth
(
fieldstart
)
==
6
&&
!
havefield
)
{
tm
->
tm_hour
+=
val
/
10000
;
tm
->
tm_min
+=
(
val
/
100
)
%
100
;
tm
->
tm_sec
+=
val
%
100
;
AdjustFractSeconds
(
fval
,
tm
,
fsec
,
1
);
return
0
;
}
/* Else fall through to extended alternative format */
case
':'
:
/* ISO 8601 4.4.3.3 Alternative Format, Extended */
if
(
havefield
)
return
DTERR_BAD_FORMAT
;
tm
->
tm_hour
+=
val
;
AdjustFractSeconds
(
fval
,
tm
,
fsec
,
SECS_PER_HOUR
);
if
(
unit
==
'\0'
)
return
0
;
dterr
=
ParseISO8601Number
(
str
,
&
str
,
&
val
,
&
fval
);
if
(
dterr
)
return
dterr
;
tm
->
tm_min
+=
val
;
AdjustFractSeconds
(
fval
,
tm
,
fsec
,
SECS_PER_MINUTE
);
if
(
*
str
==
'\0'
)
return
0
;
if
(
*
str
!=
':'
)
return
DTERR_BAD_FORMAT
;
str
++
;
dterr
=
ParseISO8601Number
(
str
,
&
str
,
&
val
,
&
fval
);
if
(
dterr
)
return
dterr
;
tm
->
tm_sec
+=
val
;
AdjustFractSeconds
(
fval
,
tm
,
fsec
,
1
);
if
(
*
str
==
'\0'
)
return
0
;
return
DTERR_BAD_FORMAT
;
default:
/* not a valid time unit suffix */
return
DTERR_BAD_FORMAT
;
}
}
havefield
=
true
;
}
return
0
;
}
/* copy&pasted from .../src/backend/utils/adt/datetime.c
* with 3 exceptions
*
* * changesd struct pg_tm to struct tm
*
* * ECPG code called this without a 'range' parameter
* removed 'int range' from the argument list and
* places where DecodeTime is called; and added
* int range = INTERVAL_FULL_RANGE;
*
* Allow "date" field DTK_DATE since this could be just
* an unsigned floating point number. - thomas 1997-11-16
* * ECPG semes not to have a global IntervalStyle
* so added
* int IntervalStyle = INTSTYLE_POSTGRES;
*
* Allow ISO-style time span, with implicit units on number of days
* preceding an hh:mm:ss field. - thomas 1998-04-30
* * Assert wasn't available so removed it.
*/
int
DecodeInterval
(
char
**
field
,
int
*
ftype
,
int
nf
,
int
*
dtype
,
struct
tm
*
tm
,
fsec_t
*
fsec
)
DecodeInterval
(
char
**
field
,
int
*
ftype
,
int
nf
,
/*int range,*/
int
*
dtype
,
struct
/*pg_*/
tm
*
tm
,
fsec_t
*
fsec
)
{
int
is_before
=
FALSE
;
int
IntervalStyle
=
INTSTYLE_POSTGRES_VERBOSE
;
int
range
=
INTERVAL_FULL_RANGE
;
bool
is_before
=
FALSE
;
char
*
cp
;
int
fmask
=
0
,
tmask
,
type
;
int
i
;
int
dterr
;
int
val
;
double
fval
;
*
dtype
=
DTK_DELTA
;
type
=
IGNORE_DTF
;
tm
->
tm_year
=
0
;
tm
->
tm_mon
=
0
;
tm
->
tm_mday
=
0
;
tm
->
tm_hour
=
0
;
tm
->
tm_min
=
0
;
tm
->
tm_sec
=
0
;
*
fsec
=
0
;
ClearPgTm
(
tm
,
fsec
);
/* read through list backwards to pick up units before values */
for
(
i
=
nf
-
1
;
i
>=
0
;
i
--
)
...
...
@@ -53,8 +361,10 @@ DecodeInterval(char **field, int *ftype, int nf, int *dtype, struct tm * tm, fse
switch
(
ftype
[
i
])
{
case
DTK_TIME
:
if
(
DecodeTime
(
field
[
i
],
fmask
,
&
tmask
,
tm
,
fsec
)
!=
0
)
return
-
1
;
dterr
=
DecodeTime
(
field
[
i
],
fmask
,
/* range, */
&
tmask
,
tm
,
fsec
);
if
(
dterr
)
return
dterr
;
type
=
DTK_DAY
;
break
;
...
...
@@ -62,18 +372,19 @@ DecodeInterval(char **field, int *ftype, int nf, int *dtype, struct tm * tm, fse
/*
* Timezone is a token with a leading sign character and
* otherwise the same as a non-signed time field
* at least one digit; there could be ':', '.', '-'
* embedded in it as well.
*/
/* Assert(*field[i] == '-' || *field[i] == '+'); */
/*
*
A single signed number ends up here, but will be rejected
*
by DecodeTime(). So, work this out to drop through to
*
DTK_NUMBER, which *can* tolerate thi
s.
*
Try for hh:mm or hh:mm:ss. If not, fall through to
*
DTK_NUMBER case, which can handle signed float numbers
*
and signed year-month value
s.
*/
cp
=
field
[
i
]
+
1
;
while
(
*
cp
!=
'\0'
&&
*
cp
!=
':'
&&
*
cp
!=
'.'
)
cp
++
;
if
(
*
cp
==
':'
&&
DecodeTime
((
field
[
i
]
+
1
),
fmask
,
&
tmask
,
tm
,
fsec
)
==
0
)
if
(
strchr
(
field
[
i
]
+
1
,
':'
)
!=
NULL
&&
DecodeTime
(
field
[
i
]
+
1
,
fmask
,
/* INTERVAL_FULL_RANGE, */
&
tmask
,
tm
,
fsec
)
==
0
)
{
if
(
*
field
[
i
]
==
'-'
)
{
...
...
@@ -93,47 +404,81 @@ DecodeInterval(char **field, int *ftype, int nf, int *dtype, struct tm * tm, fse
tmask
=
DTK_M
(
TZ
);
break
;
}
else
if
(
type
==
IGNORE_DTF
)
/* FALL THROUGH */
case
DTK_DATE
:
case
DTK_NUMBER
:
if
(
type
==
IGNORE_DTF
)
{
if
(
*
cp
==
'.'
)
/* use typmod to decide what rightmost field is */
switch
(
range
)
{
/*
* Got a decimal point? Then assume some sort of
* seconds specification
*/
type
=
DTK_SECOND
;
}
else
if
(
*
cp
==
'\0'
)
{
/*
* Only a signed integer? Then must assume a
* timezone-like usage
*/
type
=
DTK_HOUR
;
case
INTERVAL_MASK
(
YEAR
):
type
=
DTK_YEAR
;
break
;
case
INTERVAL_MASK
(
MONTH
):
case
INTERVAL_MASK
(
YEAR
)
|
INTERVAL_MASK
(
MONTH
):
type
=
DTK_MONTH
;
break
;
case
INTERVAL_MASK
(
DAY
):
type
=
DTK_DAY
;
break
;
case
INTERVAL_MASK
(
HOUR
):
case
INTERVAL_MASK
(
DAY
)
|
INTERVAL_MASK
(
HOUR
):
case
INTERVAL_MASK
(
DAY
)
|
INTERVAL_MASK
(
HOUR
)
|
INTERVAL_MASK
(
MINUTE
):
case
INTERVAL_MASK
(
DAY
)
|
INTERVAL_MASK
(
HOUR
)
|
INTERVAL_MASK
(
MINUTE
)
|
INTERVAL_MASK
(
SECOND
):
type
=
DTK_HOUR
;
break
;
case
INTERVAL_MASK
(
MINUTE
):
case
INTERVAL_MASK
(
HOUR
)
|
INTERVAL_MASK
(
MINUTE
):
type
=
DTK_MINUTE
;
break
;
case
INTERVAL_MASK
(
SECOND
):
case
INTERVAL_MASK
(
HOUR
)
|
INTERVAL_MASK
(
MINUTE
)
|
INTERVAL_MASK
(
SECOND
):
case
INTERVAL_MASK
(
MINUTE
)
|
INTERVAL_MASK
(
SECOND
):
type
=
DTK_SECOND
;
break
;
default:
type
=
DTK_SECOND
;
break
;
}
}
/* DROP THROUGH */
case
DTK_DATE
:
case
DTK_NUMBER
:
val
=
strtol
(
field
[
i
],
&
cp
,
10
);
errno
=
0
;
val
=
strtoi
(
field
[
i
],
&
cp
,
10
);
if
(
errno
==
ERANGE
)
return
DTERR_FIELD_OVERFLOW
;
if
(
type
==
IGNORE_DTF
)
type
=
DTK_SECOND
;
if
(
*
cp
==
'-'
)
{
/* SQL "years-months" syntax */
int
val2
;
if
(
*
cp
==
'.'
)
val2
=
strtoi
(
cp
+
1
,
&
cp
,
10
);
if
(
errno
==
ERANGE
||
val2
<
0
||
val2
>=
MONTHS_PER_YEAR
)
return
DTERR_FIELD_OVERFLOW
;
if
(
*
cp
!=
'\0'
)
return
DTERR_BAD_FORMAT
;
type
=
DTK_MONTH
;
if
(
*
field
[
i
]
==
'-'
)
val2
=
-
val2
;
val
=
val
*
MONTHS_PER_YEAR
+
val2
;
fval
=
0
;
}
else
if
(
*
cp
==
'.'
)
{
errno
=
0
;
fval
=
strtod
(
cp
,
&
cp
);
if
(
*
cp
!=
'\0'
)
return
-
1
;
if
(
*
cp
!=
'\0'
||
errno
!=
0
)
return
DTERR_BAD_FORMAT
;
if
(
val
<
0
)
if
(
*
field
[
i
]
==
'-'
)
fval
=
-
fval
;
}
else
if
(
*
cp
==
'\0'
)
fval
=
0
;
else
return
-
1
;
return
DTERR_BAD_FORMAT
;
tmask
=
0
;
/* DTK_M(type); */
...
...
@@ -141,135 +486,68 @@ DecodeInterval(char **field, int *ftype, int nf, int *dtype, struct tm * tm, fse
{
case
DTK_MICROSEC
:
#ifdef HAVE_INT64_TIMESTAMP
*
fsec
+=
val
+
fval
;
*
fsec
+=
rint
(
val
+
fval
)
;
#else
*
fsec
+=
(
val
+
fval
)
*
1e-6
;
#endif
tmask
=
DTK_M
(
MICROSECOND
);
break
;
case
DTK_MILLISEC
:
#ifdef HAVE_INT64_TIMESTAMP
*
fsec
+=
(
val
+
fval
)
*
1000
;
*
fsec
+=
rint
((
val
+
fval
)
*
1000
)
;
#else
*
fsec
+=
(
val
+
fval
)
*
1e-3
;
#endif
tmask
=
DTK_M
(
MILLISECOND
);
break
;
case
DTK_SECOND
:
tm
->
tm_sec
+=
val
;
#ifdef HAVE_INT64_TIMESTAMP
*
fsec
+=
fval
*
1000000
;
*
fsec
+=
rint
(
fval
*
1000000
)
;
#else
*
fsec
+=
fval
;
#endif
tmask
=
DTK_M
(
SECOND
);
/*
* If any subseconds were specified, consider this
* microsecond and millisecond input as well.
*/
if
(
fval
==
0
)
tmask
=
DTK_M
(
SECOND
);
else
tmask
=
DTK_ALL_SECS_M
;
break
;
case
DTK_MINUTE
:
tm
->
tm_min
+=
val
;
if
(
fval
!=
0
)
{
int
sec
;
fval
*=
SECS_PER_MINUTE
;
sec
=
fval
;
tm
->
tm_sec
+=
sec
;
#ifdef HAVE_INT64_TIMESTAMP
*
fsec
+=
((
fval
-
sec
)
*
1000000
);
#else
*
fsec
+=
fval
-
sec
;
#endif
}
AdjustFractSeconds
(
fval
,
tm
,
fsec
,
SECS_PER_MINUTE
);
tmask
=
DTK_M
(
MINUTE
);
break
;
case
DTK_HOUR
:
tm
->
tm_hour
+=
val
;
if
(
fval
!=
0
)
{
int
sec
;
fval
*=
SECS_PER_HOUR
;
sec
=
fval
;
tm
->
tm_sec
+=
sec
;
#ifdef HAVE_INT64_TIMESTAMP
*
fsec
+=
(
fval
-
sec
)
*
1000000
;
#else
*
fsec
+=
fval
-
sec
;
#endif
}
AdjustFractSeconds
(
fval
,
tm
,
fsec
,
SECS_PER_HOUR
);
tmask
=
DTK_M
(
HOUR
);
type
=
DTK_DAY
;
break
;
case
DTK_DAY
:
tm
->
tm_mday
+=
val
;
if
(
fval
!=
0
)
{
int
sec
;
fval
*=
SECS_PER_DAY
;
sec
=
fval
;
tm
->
tm_sec
+=
sec
;
#ifdef HAVE_INT64_TIMESTAMP
*
fsec
+=
(
fval
-
sec
)
*
1000000
;
#else
*
fsec
+=
fval
-
sec
;
#endif
}
AdjustFractSeconds
(
fval
,
tm
,
fsec
,
SECS_PER_DAY
);
tmask
=
(
fmask
&
DTK_M
(
DAY
))
?
0
:
DTK_M
(
DAY
);
break
;
case
DTK_WEEK
:
tm
->
tm_mday
+=
val
*
7
;
if
(
fval
!=
0
)
{
int
extra_days
;
fval
*=
7
;
extra_days
=
(
int32
)
fval
;
tm
->
tm_mday
+=
extra_days
;
fval
-=
extra_days
;
if
(
fval
!=
0
)
{
int
sec
;
fval
*=
SECS_PER_DAY
;
sec
=
fval
;
tm
->
tm_sec
+=
sec
;
#ifdef HAVE_INT64_TIMESTAMP
*
fsec
+=
(
fval
-
sec
)
*
1000000
;
#else
*
fsec
+=
fval
-
sec
;
#endif
}
}
AdjustFractDays
(
fval
,
tm
,
fsec
,
7
);
tmask
=
(
fmask
&
DTK_M
(
DAY
))
?
0
:
DTK_M
(
DAY
);
break
;
case
DTK_MONTH
:
tm
->
tm_mon
+=
val
;
if
(
fval
!=
0
)
{
int
day
;
fval
*=
DAYS_PER_MONTH
;
day
=
fval
;
tm
->
tm_mday
+=
day
;
fval
-=
day
;
if
(
fval
!=
0
)
{
int
sec
;
fval
*=
SECS_PER_DAY
;
sec
=
fval
;
tm
->
tm_sec
+=
sec
;
#ifdef HAVE_INT64_TIMESTAMP
*
fsec
+=
(
fval
-
sec
)
*
1000000
;
#else
*
fsec
+=
fval
-
sec
;
#endif
}
}
AdjustFractDays
(
fval
,
tm
,
fsec
,
DAYS_PER_MONTH
);
tmask
=
DTK_M
(
MONTH
);
break
;
...
...
@@ -302,7 +580,7 @@ DecodeInterval(char **field, int *ftype, int nf, int *dtype, struct tm * tm, fse
break
;
default:
return
-
1
;
return
DTERR_BAD_FORMAT
;
}
break
;
...
...
@@ -330,19 +608,24 @@ DecodeInterval(char **field, int *ftype, int nf, int *dtype, struct tm * tm, fse
break
;
default:
return
-
1
;
return
DTERR_BAD_FORMAT
;
}
break
;
default:
return
-
1
;
return
DTERR_BAD_FORMAT
;
}
if
(
tmask
&
fmask
)
return
-
1
;
return
DTERR_BAD_FORMAT
;
fmask
|=
tmask
;
}
/* ensure that at least one time field has been found */
if
(
fmask
==
0
)
return
DTERR_BAD_FORMAT
;
/* ensure fractional seconds are fractional */
if
(
*
fsec
!=
0
)
{
int
sec
;
...
...
@@ -356,250 +639,344 @@ DecodeInterval(char **field, int *ftype, int nf, int *dtype, struct tm * tm, fse
tm
->
tm_sec
+=
sec
;
}
/*----------
* The SQL standard defines the interval literal
* '-1 1:00:00'
* to mean "negative 1 days and negative 1 hours", while Postgres
* traditionally treats this as meaning "negative 1 days and positive
* 1 hours". In SQL_STANDARD intervalstyle, we apply the leading sign
* to all fields if there are no other explicit signs.
*
* We leave the signs alone if there are additional explicit signs.
* This protects us against misinterpreting postgres-style dump output,
* since the postgres-style output code has always put an explicit sign on
* all fields following a negative field. But note that SQL-spec output
* is ambiguous and can be misinterpreted on load! (So it's best practice
* to dump in postgres style, not SQL style.)
*----------
*/
if
(
IntervalStyle
==
INTSTYLE_SQL_STANDARD
&&
*
field
[
0
]
==
'-'
)
{
/* Check for additional explicit signs */
bool
more_signs
=
false
;
for
(
i
=
1
;
i
<
nf
;
i
++
)
{
if
(
*
field
[
i
]
==
'-'
||
*
field
[
i
]
==
'+'
)
{
more_signs
=
true
;
break
;
}
}
if
(
!
more_signs
)
{
/*
* Rather than re-determining which field was field[0], just
* force 'em all negative.
*/
if
(
*
fsec
>
0
)
*
fsec
=
-
(
*
fsec
);
if
(
tm
->
tm_sec
>
0
)
tm
->
tm_sec
=
-
tm
->
tm_sec
;
if
(
tm
->
tm_min
>
0
)
tm
->
tm_min
=
-
tm
->
tm_min
;
if
(
tm
->
tm_hour
>
0
)
tm
->
tm_hour
=
-
tm
->
tm_hour
;
if
(
tm
->
tm_mday
>
0
)
tm
->
tm_mday
=
-
tm
->
tm_mday
;
if
(
tm
->
tm_mon
>
0
)
tm
->
tm_mon
=
-
tm
->
tm_mon
;
if
(
tm
->
tm_year
>
0
)
tm
->
tm_year
=
-
tm
->
tm_year
;
}
}
/* finally, AGO negates everything */
if
(
is_before
)
{
*
fsec
=
-
(
*
fsec
);
tm
->
tm_sec
=
-
(
tm
->
tm_sec
)
;
tm
->
tm_min
=
-
(
tm
->
tm_min
)
;
tm
->
tm_hour
=
-
(
tm
->
tm_hour
)
;
tm
->
tm_mday
=
-
(
tm
->
tm_mday
)
;
tm
->
tm_mon
=
-
(
tm
->
tm_mon
)
;
tm
->
tm_year
=
-
(
tm
->
tm_year
)
;
tm
->
tm_sec
=
-
tm
->
tm_sec
;
tm
->
tm_min
=
-
tm
->
tm_min
;
tm
->
tm_hour
=
-
tm
->
tm_hour
;
tm
->
tm_mday
=
-
tm
->
tm_mday
;
tm
->
tm_mon
=
-
tm
->
tm_mon
;
tm
->
tm_year
=
-
tm
->
tm_year
;
}
/* ensure that at least one time field has been found */
return
(
fmask
!=
0
)
?
0
:
-
1
;
}
/* DecodeInterval() */
return
0
;
}
/* EncodeInterval()
* Interpret time structure as a delta time and convert to string.
*
* Support "traditional Postgres" and ISO-8601 styles.
* Actually, afaik ISO does not address time interval formatting,
* but this looks similar to the spec for absolute date/time.
* - thomas 1998-04-30
/* copy&pasted from .../src/backend/utils/adt/datetime.c */
static
char
*
AddVerboseIntPart
(
char
*
cp
,
int
value
,
const
char
*
units
,
bool
*
is_zero
,
bool
*
is_before
)
{
if
(
value
==
0
)
return
cp
;
/* first nonzero value sets is_before */
if
(
*
is_zero
)
{
*
is_before
=
(
value
<
0
);
value
=
abs
(
value
);
}
else
if
(
*
is_before
)
value
=
-
value
;
sprintf
(
cp
,
" %d %s%s"
,
value
,
units
,
(
value
==
1
)
?
""
:
"s"
);
*
is_zero
=
FALSE
;
return
cp
+
strlen
(
cp
);
}
/* copy&pasted from .../src/backend/utils/adt/datetime.c */
static
char
*
AddPostgresIntPart
(
char
*
cp
,
int
value
,
const
char
*
units
,
bool
*
is_zero
,
bool
*
is_before
)
{
if
(
value
==
0
)
return
cp
;
sprintf
(
cp
,
"%s%s%d %s%s"
,
(
!*
is_zero
)
?
" "
:
""
,
(
*
is_before
&&
value
>
0
)
?
"+"
:
""
,
value
,
units
,
(
value
!=
1
)
?
"s"
:
""
);
/*
* Each nonzero field sets is_before for (only) the next one. This is
* a tad bizarre but it's how it worked before...
*/
*
is_before
=
(
value
<
0
);
*
is_zero
=
FALSE
;
return
cp
+
strlen
(
cp
);
}
/* copy&pasted from .../src/backend/utils/adt/datetime.c */
static
char
*
AddISO8601IntPart
(
char
*
cp
,
int
value
,
char
units
)
{
if
(
value
==
0
)
return
cp
;
sprintf
(
cp
,
"%d%c"
,
value
,
units
);
return
cp
+
strlen
(
cp
);
}
/* copy&pasted from .../src/backend/utils/adt/datetime.c */
static
void
AppendSeconds
(
char
*
cp
,
int
sec
,
fsec_t
fsec
,
int
precision
,
bool
fillzeros
)
{
if
(
fsec
==
0
)
{
if
(
fillzeros
)
sprintf
(
cp
,
"%02d"
,
abs
(
sec
));
else
sprintf
(
cp
,
"%d"
,
abs
(
sec
));
}
else
{
#ifdef HAVE_INT64_TIMESTAMP
if
(
fillzeros
)
sprintf
(
cp
,
"%02d.%0*d"
,
abs
(
sec
),
precision
,
(
int
)
Abs
(
fsec
));
else
sprintf
(
cp
,
"%d.%0*d"
,
abs
(
sec
),
precision
,
(
int
)
Abs
(
fsec
));
#else
if
(
fillzeros
)
sprintf
(
cp
,
"%0*.*f"
,
precision
+
3
,
precision
,
fabs
(
sec
+
fsec
));
else
sprintf
(
cp
,
"%.*f"
,
precision
,
fabs
(
sec
+
fsec
));
#endif
TrimTrailingZeros
(
cp
);
}
}
/* copy&pasted from .../src/backend/utils/adt/datetime.c
*
* Change pg_tm to tm
*/
int
EncodeInterval
(
struct
tm
*
tm
,
fsec_t
fsec
,
int
style
,
char
*
str
)
EncodeInterval
(
struct
/*pg_*/
tm
*
tm
,
fsec_t
fsec
,
int
style
,
char
*
str
)
{
int
is_before
=
FALSE
;
int
is_nonzero
=
FALSE
;
char
*
cp
=
str
;
int
year
=
tm
->
tm_year
;
int
mon
=
tm
->
tm_mon
;
int
mday
=
tm
->
tm_mday
;
int
hour
=
tm
->
tm_hour
;
int
min
=
tm
->
tm_min
;
int
sec
=
tm
->
tm_sec
;
bool
is_before
=
FALSE
;
bool
is_zero
=
TRUE
;
/*
* The sign of year and month are guaranteed to match, since they are
* stored internally as "month". But we'll need to check for is_before and
* is_nonzero when determining the signs of hour/minute/seconds fields.
* is_zero when determining the signs of day and hour/minute/seconds
* fields.
*/
switch
(
style
)
{
/* compatible with ISO date formats */
case
USE_ISO_DATES
:
if
(
tm
->
tm_year
!=
0
)
{
sprintf
(
cp
,
"%d year%s"
,
tm
->
tm_year
,
(
tm
->
tm_year
!=
1
)
?
"s"
:
""
);
cp
+=
strlen
(
cp
);
is_before
=
(
tm
->
tm_year
<
0
);
is_nonzero
=
TRUE
;
}
if
(
tm
->
tm_mon
!=
0
)
{
sprintf
(
cp
,
"%s%s%d mon%s"
,
is_nonzero
?
" "
:
""
,
(
is_before
&&
tm
->
tm_mon
>
0
)
?
"+"
:
""
,
tm
->
tm_mon
,
(
tm
->
tm_mon
!=
1
)
?
"s"
:
""
);
cp
+=
strlen
(
cp
);
is_before
=
(
tm
->
tm_mon
<
0
);
is_nonzero
=
TRUE
;
}
if
(
tm
->
tm_mday
!=
0
)
{
sprintf
(
cp
,
"%s%s%d day%s"
,
is_nonzero
?
" "
:
""
,
(
is_before
&&
tm
->
tm_mday
>
0
)
?
"+"
:
""
,
tm
->
tm_mday
,
(
tm
->
tm_mday
!=
1
)
?
"s"
:
""
);
cp
+=
strlen
(
cp
);
is_before
=
(
tm
->
tm_mday
<
0
);
is_nonzero
=
TRUE
;
}
if
(
!
is_nonzero
||
tm
->
tm_hour
!=
0
||
tm
->
tm_min
!=
0
||
tm
->
tm_sec
!=
0
||
fsec
!=
0
)
/* SQL Standard interval format */
case
INTSTYLE_SQL_STANDARD
:
{
int
minus
=
tm
->
tm_hour
<
0
||
tm
->
tm_min
<
0
||
tm
->
tm_sec
<
0
||
fsec
<
0
;
bool
has_negative
=
year
<
0
||
mon
<
0
||
mday
<
0
||
hour
<
0
||
min
<
0
||
sec
<
0
||
fsec
<
0
;
bool
has_positive
=
year
>
0
||
mon
>
0
||
mday
>
0
||
hour
>
0
||
min
>
0
||
sec
>
0
||
fsec
>
0
;
bool
has_year_month
=
year
!=
0
||
mon
!=
0
;
bool
has_day_time
=
mday
!=
0
||
hour
!=
0
||
min
!=
0
||
sec
!=
0
||
fsec
!=
0
;
bool
has_day
=
mday
!=
0
;
bool
sql_standard_value
=
!
(
has_negative
&&
has_positive
)
&&
!
(
has_year_month
&&
has_day_time
);
sprintf
(
cp
,
"%s%s%02d:%02d"
,
(
is_nonzero
?
" "
:
""
),
(
minus
?
"-"
:
(
is_before
?
"+"
:
""
)),
abs
(
tm
->
tm_hour
),
abs
(
tm
->
tm_min
));
cp
+=
strlen
(
cp
);
/* Mark as "non-zero" since the fields are now filled in */
is_nonzero
=
TRUE
;
/*
* SQL Standard wants only 1 "<sign>" preceding the whole
* interval ... but can't do that if mixed signs.
*/
if
(
has_negative
&&
sql_standard_value
)
{
*
cp
++
=
'-'
;
year
=
-
year
;
mon
=
-
mon
;
mday
=
-
mday
;
hour
=
-
hour
;
min
=
-
min
;
sec
=
-
sec
;
fsec
=
-
fsec
;
}
/* fractional seconds? */
if
(
fsec
!=
0
)
if
(
!
has_negative
&&
!
has_positive
)
{
#ifdef HAVE_INT64_TIMESTAMP
sprintf
(
cp
,
":%02d"
,
abs
(
tm
->
tm_sec
));
sprintf
(
cp
,
"0"
);
}
else
if
(
!
sql_standard_value
)
{
/*
* For non sql-standard interval values,
* force outputting the signs to avoid
* ambiguities with intervals with mixed
* sign components.
*/
char
year_sign
=
(
year
<
0
||
mon
<
0
)
?
'-'
:
'+'
;
char
day_sign
=
(
mday
<
0
)
?
'-'
:
'+'
;
char
sec_sign
=
(
hour
<
0
||
min
<
0
||
sec
<
0
||
fsec
<
0
)
?
'-'
:
'+'
;
sprintf
(
cp
,
"%c%d-%d %c%d %c%d:%02d:"
,
year_sign
,
abs
(
year
),
abs
(
mon
),
day_sign
,
abs
(
mday
),
sec_sign
,
abs
(
hour
),
abs
(
min
));
cp
+=
strlen
(
cp
);
sprintf
(
cp
,
".%06d"
,
Abs
(
fsec
));
#else
fsec
+=
tm
->
tm_sec
;
sprintf
(
cp
,
":%012.9f"
,
fabs
(
fsec
));
#endif
TrimTrailingZeros
(
cp
);
AppendSeconds
(
cp
,
sec
,
fsec
,
MAX_INTERVAL_PRECISION
,
true
);
}
else
if
(
has_year_month
)
{
sprintf
(
cp
,
"%d-%d"
,
year
,
mon
);
}
else
if
(
has_day
)
{
sprintf
(
cp
,
"%d %d:%02d:"
,
mday
,
hour
,
min
);
cp
+=
strlen
(
cp
);
is_nonzero
=
TRUE
;
AppendSeconds
(
cp
,
sec
,
fsec
,
MAX_INTERVAL_PRECISION
,
true
)
;
}
/* otherwise, integer seconds only? */
else
if
(
tm
->
tm_sec
!=
0
)
else
{
sprintf
(
cp
,
"
:%02d"
,
abs
(
tm
->
tm_sec
)
);
sprintf
(
cp
,
"
%d:%02d:"
,
hour
,
min
);
cp
+=
strlen
(
cp
);
is_nonzero
=
TRUE
;
AppendSeconds
(
cp
,
sec
,
fsec
,
MAX_INTERVAL_PRECISION
,
true
)
;
}
}
break
;
case
USE_POSTGRES_DATES
:
default:
strcpy
(
cp
,
"@ "
);
cp
+=
strlen
(
cp
);
if
(
tm
->
tm_year
!=
0
)
/* ISO 8601 "time-intervals by duration only" */
case
INTSTYLE_ISO_8601
:
/* special-case zero to avoid printing nothing */
if
(
year
==
0
&&
mon
==
0
&&
mday
==
0
&&
hour
==
0
&&
min
==
0
&&
sec
==
0
&&
fsec
==
0
)
{
int
year
=
tm
->
tm_year
;
if
(
tm
->
tm_year
<
0
)
year
=
-
year
;
sprintf
(
cp
,
"%d year%s"
,
year
,
(
year
!=
1
)
?
"s"
:
""
);
cp
+=
strlen
(
cp
);
is_before
=
(
tm
->
tm_year
<
0
);
is_nonzero
=
TRUE
;
}
if
(
tm
->
tm_mon
!=
0
)
{
int
mon
=
tm
->
tm_mon
;
if
(
is_before
||
(
!
is_nonzero
&&
tm
->
tm_mon
<
0
))
mon
=
-
mon
;
sprintf
(
cp
,
"%s%d mon%s"
,
is_nonzero
?
" "
:
""
,
mon
,
(
mon
!=
1
)
?
"s"
:
""
);
cp
+=
strlen
(
cp
);
if
(
!
is_nonzero
)
is_before
=
(
tm
->
tm_mon
<
0
);
is_nonzero
=
TRUE
;
}
if
(
tm
->
tm_mday
!=
0
)
{
int
day
=
tm
->
tm_mday
;
if
(
is_before
||
(
!
is_nonzero
&&
tm
->
tm_mday
<
0
))
day
=
-
day
;
sprintf
(
cp
,
"%s%d day%s"
,
is_nonzero
?
" "
:
""
,
day
,
(
day
!=
1
)
?
"s"
:
""
);
cp
+=
strlen
(
cp
);
if
(
!
is_nonzero
)
is_before
=
(
tm
->
tm_mday
<
0
);
is_nonzero
=
TRUE
;
sprintf
(
cp
,
"PT0S"
);
break
;
}
if
(
tm
->
tm_hour
!=
0
)
*
cp
++
=
'P'
;
cp
=
AddISO8601IntPart
(
cp
,
year
,
'Y'
);
cp
=
AddISO8601IntPart
(
cp
,
mon
,
'M'
);
cp
=
AddISO8601IntPart
(
cp
,
mday
,
'D'
);
if
(
hour
!=
0
||
min
!=
0
||
sec
!=
0
||
fsec
!=
0
)
*
cp
++
=
'T'
;
cp
=
AddISO8601IntPart
(
cp
,
hour
,
'H'
);
cp
=
AddISO8601IntPart
(
cp
,
min
,
'M'
);
if
(
sec
!=
0
||
fsec
!=
0
)
{
int
hour
=
tm
->
tm_hour
;
if
(
is_before
||
(
!
is_nonzero
&&
tm
->
tm_hour
<
0
))
hour
=
-
hour
;
sprintf
(
cp
,
"%s%d hour%s"
,
is_nonzero
?
" "
:
""
,
hour
,
(
hour
!=
1
)
?
"s"
:
""
);
if
(
sec
<
0
||
fsec
<
0
)
*
cp
++
=
'-'
;
AppendSeconds
(
cp
,
sec
,
fsec
,
MAX_INTERVAL_PRECISION
,
false
);
cp
+=
strlen
(
cp
);
if
(
!
is_nonzero
)
is_before
=
(
tm
->
tm_hour
<
0
);
is_nonzero
=
TRUE
;
*
cp
++
=
'S'
;
*
cp
++
=
'\0'
;
}
break
;
if
(
tm
->
tm_min
!=
0
)
/* Compatible with postgresql < 8.4 when DateStyle = 'iso' */
case
INTSTYLE_POSTGRES
:
cp
=
AddPostgresIntPart
(
cp
,
year
,
"year"
,
&
is_zero
,
&
is_before
);
cp
=
AddPostgresIntPart
(
cp
,
mon
,
"mon"
,
&
is_zero
,
&
is_before
);
cp
=
AddPostgresIntPart
(
cp
,
mday
,
"day"
,
&
is_zero
,
&
is_before
);
if
(
is_zero
||
hour
!=
0
||
min
!=
0
||
sec
!=
0
||
fsec
!=
0
)
{
int
min
=
tm
->
tm_min
;
bool
minus
=
(
hour
<
0
||
min
<
0
||
sec
<
0
||
fsec
<
0
)
;
if
(
is_before
||
(
!
is_nonzero
&&
tm
->
tm_min
<
0
))
min
=
-
min
;
sprintf
(
cp
,
"%s%d min%s"
,
is_nonzero
?
" "
:
""
,
min
,
(
min
!=
1
)
?
"s"
:
""
);
sprintf
(
cp
,
"%s%s%02d:%02d:"
,
is_zero
?
""
:
" "
,
(
minus
?
"-"
:
(
is_before
?
"+"
:
""
)),
abs
(
hour
),
abs
(
min
));
cp
+=
strlen
(
cp
);
if
(
!
is_nonzero
)
is_before
=
(
tm
->
tm_min
<
0
);
is_nonzero
=
TRUE
;
AppendSeconds
(
cp
,
sec
,
fsec
,
MAX_INTERVAL_PRECISION
,
true
);
}
break
;
/* fractional seconds? */
if
(
fsec
!=
0
)
{
#ifdef HAVE_INT64_TIMESTAMP
if
(
is_before
||
(
!
is_nonzero
&&
tm
->
tm_sec
<
0
))
tm
->
tm_sec
=
-
tm
->
tm_sec
;
sprintf
(
cp
,
"%s%d.%02d secs"
,
is_nonzero
?
" "
:
""
,
tm
->
tm_sec
,
((
int
)
fsec
)
/
10000
);
cp
+=
strlen
(
cp
);
if
(
!
is_nonzero
)
is_before
=
(
fsec
<
0
);
#else
fsec_t
sec
;
fsec
+=
tm
->
tm_sec
;
sec
=
fsec
;
if
(
is_before
||
(
!
is_nonzero
&&
fsec
<
0
))
sec
=
-
sec
;
sprintf
(
cp
,
"%s%.2f secs"
,
is_nonzero
?
" "
:
""
,
sec
);
cp
+=
strlen
(
cp
);
if
(
!
is_nonzero
)
is_before
=
(
fsec
<
0
);
#endif
is_nonzero
=
TRUE
;
/* otherwise, integer seconds only? */
}
else
if
(
tm
->
tm_sec
!=
0
)
/* Compatible with postgresql < 8.4 when DateStyle != 'iso' */
case
INTSTYLE_POSTGRES_VERBOSE
:
default:
strcpy
(
cp
,
"@"
);
cp
++
;
cp
=
AddVerboseIntPart
(
cp
,
year
,
"year"
,
&
is_zero
,
&
is_before
);
cp
=
AddVerboseIntPart
(
cp
,
mon
,
"mon"
,
&
is_zero
,
&
is_before
);
cp
=
AddVerboseIntPart
(
cp
,
mday
,
"day"
,
&
is_zero
,
&
is_before
);
cp
=
AddVerboseIntPart
(
cp
,
hour
,
"hour"
,
&
is_zero
,
&
is_before
);
cp
=
AddVerboseIntPart
(
cp
,
min
,
"min"
,
&
is_zero
,
&
is_before
);
if
(
sec
!=
0
||
fsec
!=
0
)
{
int
sec
=
tm
->
tm_sec
;
if
(
is_before
||
(
!
is_nonzero
&&
tm
->
tm_sec
<
0
))
sec
=
-
sec
;
sprintf
(
cp
,
"%s%d sec%s"
,
is_nonzero
?
" "
:
""
,
sec
,
(
sec
!=
1
)
?
"s"
:
""
);
*
cp
++
=
' '
;
if
(
sec
<
0
||
(
sec
==
0
&&
fsec
<
0
))
{
if
(
is_zero
)
is_before
=
TRUE
;
else
if
(
!
is_before
)
*
cp
++
=
'-'
;
}
else
if
(
is_before
)
*
cp
++
=
'-'
;
AppendSeconds
(
cp
,
sec
,
fsec
,
MAX_INTERVAL_PRECISION
,
false
);
cp
+=
strlen
(
cp
);
if
(
!
is_nonzero
)
is_before
=
(
tm
->
tm_sec
<
0
);
is_
nonzero
=
TRU
E
;
sprintf
(
cp
,
" sec%s"
,
(
abs
(
sec
)
!=
1
||
fsec
!=
0
)
?
"s"
:
""
);
is_
zero
=
FALS
E
;
}
/* identically zero? then put in a unitless zero... */
if
(
is_zero
)
strcat
(
cp
,
" 0"
);
if
(
is_before
)
strcat
(
cp
,
" ago"
);
break
;
}
/* identically zero? then put in a unitless zero... */
if
(
!
is_nonzero
)
{
strcat
(
cp
,
"0"
);
cp
+=
strlen
(
cp
);
}
if
(
is_before
&&
(
style
!=
USE_ISO_DATES
))
{
strcat
(
cp
,
" ago"
);
cp
+=
strlen
(
cp
);
}
return
0
;
}
/* EncodeInterval() */
/* interval2tm()
* Convert a interval data type to a tm structure.
*/
...
...
@@ -719,7 +1096,8 @@ PGTYPESinterval_from_asc(char *str, char **endptr)
}
if
(
ParseDateTime
(
str
,
lowstr
,
field
,
ftype
,
MAXDATEFIELDS
,
&
nf
,
ptr
)
!=
0
||
DecodeInterval
(
field
,
ftype
,
nf
,
&
dtype
,
tm
,
&
fsec
)
!=
0
)
(
DecodeInterval
(
field
,
ftype
,
nf
,
&
dtype
,
tm
,
&
fsec
)
!=
0
&&
DecodeISO8601Interval
(
str
,
&
dtype
,
tm
,
&
fsec
)
!=
0
))
{
errno
=
PGTYPES_INTVL_BAD_INTERVAL
;
return
NULL
;
...
...
@@ -754,7 +1132,7 @@ PGTYPESinterval_to_asc(interval * span)
*
tm
=
&
tt
;
fsec_t
fsec
;
char
buf
[
MAXDATELEN
+
1
];
int
DateStyle
=
0
;
int
IntervalStyle
=
INTSTYLE_POSTGRES_VERBOSE
;
if
(
interval2tm
(
*
span
,
tm
,
&
fsec
)
!=
0
)
{
...
...
@@ -762,7 +1140,7 @@ PGTYPESinterval_to_asc(interval * span)
return
NULL
;
}
if
(
EncodeInterval
(
tm
,
fsec
,
Date
Style
,
buf
)
!=
0
)
if
(
EncodeInterval
(
tm
,
fsec
,
Interval
Style
,
buf
)
!=
0
)
{
errno
=
PGTYPES_INTVL_BAD_INTERVAL
;
return
NULL
;
...
...
src/interfaces/ecpg/test/expected/pgtypeslib-dt_test.c
View file @
7c5a561f
...
...
@@ -77,6 +77,12 @@ if (sqlca.sqlcode < 0) sqlprint ( );}
if
(
sqlca
.
sqlcode
<
0
)
sqlprint
(
);}
#line 30 "dt_test.pgc"
{
ECPGdo
(
__LINE__
,
0
,
1
,
NULL
,
0
,
ECPGst_normal
,
"set intervalstyle to postgres_verbose"
,
ECPGt_EOIT
,
ECPGt_EORT
);
#line 31 "dt_test.pgc"
if
(
sqlca
.
sqlcode
<
0
)
sqlprint
(
);}
#line 31 "dt_test.pgc"
date1
=
PGTYPESdate_from_asc
(
d1
,
NULL
);
ts1
=
PGTYPEStimestamp_from_asc
(
t1
,
NULL
);
...
...
@@ -86,10 +92,10 @@ if (sqlca.sqlcode < 0) sqlprint ( );}
ECPGt_NO_INDICATOR
,
NULL
,
0L
,
0L
,
0L
,
ECPGt_timestamp
,
&
(
ts1
),(
long
)
1
,(
long
)
1
,
sizeof
(
timestamp
),
ECPGt_NO_INDICATOR
,
NULL
,
0L
,
0L
,
0L
,
ECPGt_EOIT
,
ECPGt_EORT
);
#line 3
5
"dt_test.pgc"
#line 3
6
"dt_test.pgc"
if
(
sqlca
.
sqlcode
<
0
)
sqlprint
(
);}
#line 3
5
"dt_test.pgc"
#line 3
6
"dt_test.pgc"
{
ECPGdo
(
__LINE__
,
0
,
1
,
NULL
,
0
,
ECPGst_normal
,
"select * from date_test where d = $1 "
,
...
...
@@ -99,10 +105,10 @@ if (sqlca.sqlcode < 0) sqlprint ( );}
ECPGt_NO_INDICATOR
,
NULL
,
0L
,
0L
,
0L
,
ECPGt_timestamp
,
&
(
ts1
),(
long
)
1
,(
long
)
1
,
sizeof
(
timestamp
),
ECPGt_NO_INDICATOR
,
NULL
,
0L
,
0L
,
0L
,
ECPGt_EORT
);
#line 3
7
"dt_test.pgc"
#line 3
8
"dt_test.pgc"
if
(
sqlca
.
sqlcode
<
0
)
sqlprint
(
);}
#line 3
7
"dt_test.pgc"
#line 3
8
"dt_test.pgc"
text
=
PGTYPESdate_to_asc
(
date1
);
...
...
@@ -417,16 +423,16 @@ if (sqlca.sqlcode < 0) sqlprint ( );}
free
(
text
);
{
ECPGtrans
(
__LINE__
,
NULL
,
"rollback "
);
#line 35
0
"dt_test.pgc"
#line 35
1
"dt_test.pgc"
if
(
sqlca
.
sqlcode
<
0
)
sqlprint
(
);}
#line 35
0
"dt_test.pgc"
#line 35
1
"dt_test.pgc"
{
ECPGdisconnect
(
__LINE__
,
"CURRENT"
);
#line 35
1
"dt_test.pgc"
#line 35
2
"dt_test.pgc"
if
(
sqlca
.
sqlcode
<
0
)
sqlprint
(
);}
#line 35
1
"dt_test.pgc"
#line 35
2
"dt_test.pgc"
return
(
0
);
...
...
src/interfaces/ecpg/test/expected/pgtypeslib-dt_test.stderr
View file @
7c5a561f
...
...
@@ -14,29 +14,35 @@
[NO_PID]: sqlca: code: 0, state: 00000
[NO_PID]: ecpg_execute on line 30: OK: SET
[NO_PID]: sqlca: code: 0, state: 00000
[NO_PID]: ecpg_execute on line 3
5: query: insert into date_test ( d , ts ) values ( $1 , $2 ) ; with 2
parameter(s) on connection regress1
[NO_PID]: ecpg_execute on line 3
1: query: set intervalstyle to postgres_verbose; with 0
parameter(s) on connection regress1
[NO_PID]: sqlca: code: 0, state: 00000
[NO_PID]: ecpg_execute on line 3
5: using PQexecParams
[NO_PID]: ecpg_execute on line 3
1: using PQexec
[NO_PID]: sqlca: code: 0, state: 00000
[NO_PID]:
free_params on line 35: parameter 1 = 1966-01-17
[NO_PID]:
ecpg_execute on line 31: OK: SET
[NO_PID]: sqlca: code: 0, state: 00000
[NO_PID]:
free_params on line 35: parameter 2 = 2000-07-12 17:34:29
[NO_PID]:
ecpg_execute on line 36: query: insert into date_test ( d , ts ) values ( $1 , $2 ) ; with 2 parameter(s) on connection regress1
[NO_PID]: sqlca: code: 0, state: 00000
[NO_PID]: ecpg_execute on line 3
5: OK: INSERT 0 1
[NO_PID]: ecpg_execute on line 3
6: using PQexecParams
[NO_PID]: sqlca: code: 0, state: 00000
[NO_PID]:
ecpg_execute on line 37: query: select * from date_test where d = $1 ; with 1 parameter(s) on connection regress1
[NO_PID]:
free_params on line 36: parameter 1 = 1966-01-17
[NO_PID]: sqlca: code: 0, state: 00000
[NO_PID]:
ecpg_execute on line 37: using PQexecParams
[NO_PID]:
free_params on line 36: parameter 2 = 2000-07-12 17:34:29
[NO_PID]: sqlca: code: 0, state: 00000
[NO_PID]:
free_params on line 37: parameter 1 = 1966-01-17
[NO_PID]:
ecpg_execute on line 36: OK: INSERT 0 1
[NO_PID]: sqlca: code: 0, state: 00000
[NO_PID]: ecpg_execute on line 3
7: correctly got 1 tuples with 2 fields
[NO_PID]: ecpg_execute on line 3
8: query: select * from date_test where d = $1 ; with 1 parameter(s) on connection regress1
[NO_PID]: sqlca: code: 0, state: 00000
[NO_PID]: ecpg_
get_data on line 37: RESULT: 1966-01-17 offset: -1; array: ye
s
[NO_PID]: ecpg_
execute on line 38: using PQexecParam
s
[NO_PID]: sqlca: code: 0, state: 00000
[NO_PID]:
ecpg_get_data on line 37: RESULT: 2000-07-12 17:34:29 offset: -1; array: yes
[NO_PID]:
free_params on line 38: parameter 1 = 1966-01-17
[NO_PID]: sqlca: code: 0, state: 00000
[NO_PID]: ECPGtrans on line 350: action "rollback "; connection "regress1"
[NO_PID]: ecpg_execute on line 38: correctly got 1 tuples with 2 fields
[NO_PID]: sqlca: code: 0, state: 00000
[NO_PID]: ecpg_get_data on line 38: RESULT: 1966-01-17 offset: -1; array: yes
[NO_PID]: sqlca: code: 0, state: 00000
[NO_PID]: ecpg_get_data on line 38: RESULT: 2000-07-12 17:34:29 offset: -1; array: yes
[NO_PID]: sqlca: code: 0, state: 00000
[NO_PID]: ECPGtrans on line 351: action "rollback "; connection "regress1"
[NO_PID]: sqlca: code: 0, state: 00000
[NO_PID]: ecpg_finish: connection regress1 closed
[NO_PID]: sqlca: code: 0, state: 00000
src/interfaces/ecpg/test/pgtypeslib/dt_test.pgc
View file @
7c5a561f
...
...
@@ -28,6 +28,7 @@ main(void)
exec sql connect to REGRESSDB1;
exec sql create table date_test (d date, ts timestamp);
exec sql set datestyle to iso;
exec sql set intervalstyle to postgres_verbose;
date1 = PGTYPESdate_from_asc(d1, NULL);
ts1 = PGTYPEStimestamp_from_asc(t1, NULL);
...
...
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