1 /*Copyright (c) Brian B.
3 This library is free software; you can redistribute it and/or
4 modify it under the terms of the GNU Lesser General Public
5 License as published by the Free Software Foundation; either
6 version 3 of the License, or (at your option) any later version.
7 See the file LICENSE included with this distribution for more
10 #include "libpgcli/pgfld.h"
12 //******************************************************************************
14 //******************************************************************************
15 #define MONTHS_PER_YEAR 12
16 #define POSTGRES_EPOCH_JDATE 2451545
17 #define INT64CONST(x) (x##L)
18 #define SECS_PER_YEAR (36525 * 864)
19 #define SECS_PER_DAY 86400
20 #define SECS_PER_HOUR 3600
21 #define SECS_PER_MINUTE 60
22 #define MINS_PER_HOUR 60
23 #define USECS_PER_DAY INT64CONST(86400000000)
24 #define USECS_PER_HOUR INT64CONST(3600000000)
25 #define USECS_PER_MINUTE INT64CONST(60000000)
26 #define USECS_PER_SEC INT64CONST(1000000)
27 #define MIN_TIMESTAMP INT64CONST(-211813488000000000)
28 #define END_TIMESTAMP INT64CONST(9223371331200000000)
29 #define IS_VALID_TIMESTAMP(t) (MIN_TIMESTAMP <= (t) && (t) < END_TIMESTAMP)
30 #define TMODULO(t,q,u) \
33 if ((q) != 0) (t) -= ((q) * (u)); \
35 #define JULIAN_MINYEAR (-4713)
36 #define JULIAN_MINMONTH (11)
37 #define JULIAN_MINDAY (24)
38 #define JULIAN_MAXYEAR (5874898)
39 #define JULIAN_MAXMONTH (6)
40 #define JULIAN_MAXDAY (3)
41 #define IS_VALID_JULIAN(y,m,d) \
42 (((y) > JULIAN_MINYEAR || \
43 ((y) == JULIAN_MINYEAR && ((m) >= JULIAN_MINMONTH))) && \
44 ((y) < JULIAN_MAXYEAR || \
45 ((y) == JULIAN_MAXYEAR && ((m) < JULIAN_MAXMONTH))))
47 void j2date(int jd
, int *year
, int *month
, int *day
) {
54 quad
= julian
/ 146097;
55 extra
= (julian
- quad
* 146097) * 4 + 3;
56 julian
+= 60 + quad
* 3 + extra
/ 146097;
58 julian
-= quad
* 1461;
59 y
= julian
* 4 / 1461;
60 julian
= ((y
!= 0) ? ((julian
+ 305) % 365) : ((julian
+ 306) % 366)) + 123;
63 quad
= julian
* 2141 / 65536;
64 *day
= julian
- 7834 * quad
/ 256;
65 *month
= (quad
+ 10) % MONTHS_PER_YEAR
+ 1;
68 int date2j(int y
, int m
, int d
) {
79 julian
= y
* 365 - 32167;
80 julian
+= y
/ 4 - century
+ century
/ 4;
81 julian
+= 7834 * m
/ 256 + d
;
86 static void dt2time(int64_t jd
, int *hour
, int *min
, int *sec
) {
89 *hour
= time
/ USECS_PER_HOUR
;
90 time
-= (*hour
) * USECS_PER_HOUR
;
91 *min
= time
/ USECS_PER_MINUTE
;
92 time
-= (*min
) * USECS_PER_MINUTE
;
93 *sec
= time
/ USECS_PER_SEC
;
96 int timestamp_to_tm (tm_t dt
, struct tm
*tm
) {
98 memset(tm
, 0, sizeof(struct tm
));
99 TMODULO(time
, date
, USECS_PER_DAY
);
100 if (time
< INT64CONST(0)) {
101 time
+= USECS_PER_DAY
;
104 date
+= POSTGRES_EPOCH_JDATE
;
105 if (date
< 0 || date
> (int64_t)INT_MAX
)
107 j2date((int)date
, &tm
->tm_year
, &tm
->tm_mon
, &tm
->tm_mday
);
108 dt2time(time
, &tm
->tm_hour
, &tm
->tm_min
, &tm
->tm_sec
);
112 static int64_t time2t(const int hour
, const int min
, const int sec
, const fsec_t fsec
) {
113 return (((((hour
* MINS_PER_HOUR
) + min
) * SECS_PER_MINUTE
) + sec
) * USECS_PER_SEC
) + fsec
;
116 static tm_t
dt2local(tm_t dt
, int tz
) {
117 dt
-= (tz
* USECS_PER_SEC
);
121 int tm_to_timestamp (struct tm
*tm
, fsec_t fsec
, int *tzp
, tm_t
*result
) {
124 if (!IS_VALID_JULIAN(tm
->tm_year
, tm
->tm_mon
, tm
->tm_mday
))
126 dDate
= date2j(tm
->tm_year
, tm
->tm_mon
, tm
->tm_mday
) - date2j(2000, 1, 1);
127 time
= time2t(tm
->tm_hour
, tm
->tm_min
, tm
->tm_sec
, fsec
);
128 *result
= (dDate
* USECS_PER_DAY
) + time
;
129 if ((*result
- time
) / USECS_PER_DAY
!= dDate
)
131 if ((*result
< 0 && dDate
> 0) ||
132 (*result
> 0 && dDate
< -1))
135 *result
= dt2local(*result
, -(*tzp
));
136 if (!IS_VALID_TIMESTAMP(*result
))
142 struct tm
*date_to_tm (date_t dt
, struct tm
*tm
) {
143 memset(tm
, 0, sizeof(struct tm
));
144 j2date(dt
+ POSTGRES_EPOCH_JDATE
, &tm
->tm_year
, &tm
->tm_mon
, &tm
->tm_mday
);
148 date_t
tm_to_date (struct tm
*tm
) {
149 date_t dt
= date2j(tm
->tm_year
, tm
->tm_mon
, tm
->tm_mday
);
150 return dt
- POSTGRES_EPOCH_JDATE
;
153 struct tm
*interval_to_tm(pg_intv_t
*span
, struct tm
*tm
) {
155 if (span
->month
!= 0) {
156 tm
->tm_year
= span
->month
/ MONTHS_PER_YEAR
;
157 tm
->tm_mon
= span
->month
% MONTHS_PER_YEAR
;
163 tm
->tm_mday
= time
/ USECS_PER_DAY
;
164 time
-= tm
->tm_mday
* USECS_PER_DAY
;
165 tm
->tm_hour
= time
/ USECS_PER_HOUR
;
166 time
-= tm
->tm_hour
* USECS_PER_HOUR
;
167 tm
->tm_min
= time
/ USECS_PER_MINUTE
;
168 time
-= tm
->tm_min
* USECS_PER_MINUTE
;
169 tm
->tm_sec
= time
/ USECS_PER_SEC
;
173 //******************************************************************************
175 //******************************************************************************
176 double pg_conv_double (double d
) {
179 unsigned char bytes
[8];
182 dst
.bytes
[0] = src
.bytes
[7];
183 dst
.bytes
[1] = src
.bytes
[6];
184 dst
.bytes
[2] = src
.bytes
[5];
185 dst
.bytes
[3] = src
.bytes
[4];
186 dst
.bytes
[4] = src
.bytes
[3];
187 dst
.bytes
[5] = src
.bytes
[2];
188 dst
.bytes
[6] = src
.bytes
[1];
189 dst
.bytes
[7] = src
.bytes
[0];
193 float pg_conv_float (float f
) {
196 unsigned char bytes
[4];
199 dst
.bytes
[0] = src
.bytes
[3];
200 dst
.bytes
[1] = src
.bytes
[2];
201 dst
.bytes
[2] = src
.bytes
[1];
202 dst
.bytes
[3] = src
.bytes
[0];
206 //******************************************************************************
208 //******************************************************************************
210 #define MAX_DIGITS (sizeof(mp_limb_t) / sizeof(int16_t))
211 static void set_digits_n (mpz_t x
, int16_t *p_digits
, int16_t *digits
, int len
, int weight
) {
214 mpz_init_set_ui(m
, 1);
215 if (p_digits
< digits
)
218 mpz_set_ui(x
, *p_digits
);
222 if (p_digits
< digits
)
223 mpz_mul_si(m
, m
, 10000);
225 mpz_set_ui(m
, 10000);
227 mpz_add_ui(x
, x
, *p_digits
++);
231 mpz_mul_si(x
, x
, 10000);
236 if (p_digits
< digits
)
237 mpz_mul_si(m
, m
, 10000);
239 mpz_set_ui(m
, 10000);
241 mpz_add_ui(x
, x
, *p_digits
++);
248 static void set_digits_d (mpz_t x
, int count
) {
251 mpz_mul_si(x
, x
, 10000);
256 void pg_get_numeric (uint8_t *buf
, mpq_t res
, uint16_t *scale
) {
257 int16_t len
= be16toh(*(int16_t*)buf
); buf
+= sizeof(int16_t);
258 int16_t weight
= be16toh(*(int16_t*)buf
); buf
+= sizeof(int16_t);
259 int16_t sign
= be16toh(*(int16_t*)buf
); buf
+= sizeof(int16_t);
261 if (sign
== NUMERIC_POS
|| sign
== NUMERIC_NEG
|| sign
== NUMERIC_NAN
) {
262 uint16_t dscale
= be16toh(*(uint16_t*)buf
); buf
+= sizeof(uint16_t);
265 if ((dscale
& NUMERIC_DSCALE_MASK
) == dscale
) {
270 mpz_ptr n
= &q
->_mp_num
, d
= &q
->_mp_den
;
271 int16_t *digits
= malloc(len
* sizeof(int16_t)), *p_digits
= digits
;
272 for (int i
= 0; i
< len
; ++i
)
273 digits
[i
] = be16toh(*(int16_t*)buf
);
274 buf
+= sizeof(int16_t);
278 set_digits_n(n
, p_digits
, digits
, len
, weight
);
281 int cnt
= len
- weight
;
290 mpz_init_set_si(d
, 1);
291 set_digits_n(n
, p_digits
, digits
, cnt
, cnt
);
292 set_digits_d(d
, cnt
);
296 if (sign
== NUMERIC_NEG
)
305 str_t
*pg_numstr (mpq_ptr x
, int base
, uint16_t dscale
, int float_prec
) {
310 mpz_ptr z
= &x
->_mp_num
;
311 if (!(s
= mpz_get_str(NULL
, base
, z
)))
313 str_t
*res
= mkstr(s
, strlen(s
), 8);
317 mpf_init2(f
, float_prec
);
319 if ((s
= mpf_get_str(NULL
, &exp
, base
, 0, f
))) {
324 res
= mkstr(s
, strlen(s
), 8);
325 if (exp
> res
->len
) {
326 strpad(&res
, exp
, '0', STR_LEFT
);
327 strnadd(&res
, CONST_STR_LEN(".0"));
329 strepl(&res
, res
->ptr
+ exp
, 0, CONST_STR_LEN("."));
331 res
= mkstr(CONST_STR_LEN("0."), 8);
333 strpad(&res
, -(exp
-2), '0', STR_LEFT
);
334 strnadd(&res
, s
, strlen(s
));
339 e
= res
->ptr
+ res
->len
;
340 if (0 < (n
= dscale
- ((intptr_t)e
- (intptr_t)p
- 1)))
341 strpad(&res
, res
->len
+ n
, '0', STR_LEFT
);