1 #include "libpgcli/pgfld.h"
3 //******************************************************************************
5 //******************************************************************************
6 #define MONTHS_PER_YEAR 12
7 #define POSTGRES_EPOCH_JDATE 2451545
8 #define INT64CONST(x) (x##L)
9 #define SECS_PER_YEAR (36525 * 864)
10 #define SECS_PER_DAY 86400
11 #define SECS_PER_HOUR 3600
12 #define SECS_PER_MINUTE 60
13 #define MINS_PER_HOUR 60
14 #define USECS_PER_DAY INT64CONST(86400000000)
15 #define USECS_PER_HOUR INT64CONST(3600000000)
16 #define USECS_PER_MINUTE INT64CONST(60000000)
17 #define USECS_PER_SEC INT64CONST(1000000)
18 #define MIN_TIMESTAMP INT64CONST(-211813488000000000)
19 #define END_TIMESTAMP INT64CONST(9223371331200000000)
20 #define IS_VALID_TIMESTAMP(t) (MIN_TIMESTAMP <= (t) && (t) < END_TIMESTAMP)
21 #define TMODULO(t,q,u) \
24 if ((q) != 0) (t) -= ((q) * (u)); \
26 #define JULIAN_MINYEAR (-4713)
27 #define JULIAN_MINMONTH (11)
28 #define JULIAN_MINDAY (24)
29 #define JULIAN_MAXYEAR (5874898)
30 #define JULIAN_MAXMONTH (6)
31 #define JULIAN_MAXDAY (3)
32 #define IS_VALID_JULIAN(y,m,d) \
33 (((y) > JULIAN_MINYEAR || \
34 ((y) == JULIAN_MINYEAR && ((m) >= JULIAN_MINMONTH))) && \
35 ((y) < JULIAN_MAXYEAR || \
36 ((y) == JULIAN_MAXYEAR && ((m) < JULIAN_MAXMONTH))))
38 void j2date(int jd
, int *year
, int *month
, int *day
) {
45 quad
= julian
/ 146097;
46 extra
= (julian
- quad
* 146097) * 4 + 3;
47 julian
+= 60 + quad
* 3 + extra
/ 146097;
49 julian
-= quad
* 1461;
50 y
= julian
* 4 / 1461;
51 julian
= ((y
!= 0) ? ((julian
+ 305) % 365) : ((julian
+ 306) % 366)) + 123;
54 quad
= julian
* 2141 / 65536;
55 *day
= julian
- 7834 * quad
/ 256;
56 *month
= (quad
+ 10) % MONTHS_PER_YEAR
+ 1;
59 int date2j(int y
, int m
, int d
) {
70 julian
= y
* 365 - 32167;
71 julian
+= y
/ 4 - century
+ century
/ 4;
72 julian
+= 7834 * m
/ 256 + d
;
77 static void dt2time(int64_t jd
, int *hour
, int *min
, int *sec
) {
80 *hour
= time
/ USECS_PER_HOUR
;
81 time
-= (*hour
) * USECS_PER_HOUR
;
82 *min
= time
/ USECS_PER_MINUTE
;
83 time
-= (*min
) * USECS_PER_MINUTE
;
84 *sec
= time
/ USECS_PER_SEC
;
87 int timestamp_to_tm (tm_t dt
, struct tm
*tm
) {
89 memset(tm
, 0, sizeof(struct tm
));
90 TMODULO(time
, date
, USECS_PER_DAY
);
91 if (time
< INT64CONST(0)) {
92 time
+= USECS_PER_DAY
;
95 date
+= POSTGRES_EPOCH_JDATE
;
96 if (date
< 0 || date
> (int64_t)INT_MAX
)
98 j2date((int)date
, &tm
->tm_year
, &tm
->tm_mon
, &tm
->tm_mday
);
99 dt2time(time
, &tm
->tm_hour
, &tm
->tm_min
, &tm
->tm_sec
);
103 static int64_t time2t(const int hour
, const int min
, const int sec
, const fsec_t fsec
) {
104 return (((((hour
* MINS_PER_HOUR
) + min
) * SECS_PER_MINUTE
) + sec
) * USECS_PER_SEC
) + fsec
;
107 static tm_t
dt2local(tm_t dt
, int tz
) {
108 dt
-= (tz
* USECS_PER_SEC
);
112 int tm_to_timestamp (struct tm
*tm
, fsec_t fsec
, int *tzp
, tm_t
*result
) {
115 if (!IS_VALID_JULIAN(tm
->tm_year
, tm
->tm_mon
, tm
->tm_mday
))
117 dDate
= date2j(tm
->tm_year
, tm
->tm_mon
, tm
->tm_mday
) - date2j(2000, 1, 1);
118 time
= time2t(tm
->tm_hour
, tm
->tm_min
, tm
->tm_sec
, fsec
);
119 *result
= (dDate
* USECS_PER_DAY
) + time
;
120 if ((*result
- time
) / USECS_PER_DAY
!= dDate
)
122 if ((*result
< 0 && dDate
> 0) ||
123 (*result
> 0 && dDate
< -1))
126 *result
= dt2local(*result
, -(*tzp
));
127 if (!IS_VALID_TIMESTAMP(*result
))
133 struct tm
*date_to_tm (date_t dt
, struct tm
*tm
) {
134 memset(tm
, 0, sizeof(struct tm
));
135 j2date(dt
+ POSTGRES_EPOCH_JDATE
, &tm
->tm_year
, &tm
->tm_mon
, &tm
->tm_mday
);
139 struct tm
*interval_to_tm(pg_intv_t
*span
, struct tm
*tm
) {
141 if (span
->month
!= 0) {
142 tm
->tm_year
= span
->month
/ MONTHS_PER_YEAR
;
143 tm
->tm_mon
= span
->month
% MONTHS_PER_YEAR
;
149 tm
->tm_mday
= time
/ USECS_PER_DAY
;
150 time
-= tm
->tm_mday
* USECS_PER_DAY
;
151 tm
->tm_hour
= time
/ USECS_PER_HOUR
;
152 time
-= tm
->tm_hour
* USECS_PER_HOUR
;
153 tm
->tm_min
= time
/ USECS_PER_MINUTE
;
154 time
-= tm
->tm_min
* USECS_PER_MINUTE
;
155 tm
->tm_sec
= time
/ USECS_PER_SEC
;
159 //******************************************************************************
161 //******************************************************************************
162 double pg_conv_double (double d
) {
165 unsigned char bytes
[8];
168 dst
.bytes
[0] = src
.bytes
[7];
169 dst
.bytes
[1] = src
.bytes
[6];
170 dst
.bytes
[2] = src
.bytes
[5];
171 dst
.bytes
[3] = src
.bytes
[4];
172 dst
.bytes
[4] = src
.bytes
[3];
173 dst
.bytes
[5] = src
.bytes
[2];
174 dst
.bytes
[6] = src
.bytes
[1];
175 dst
.bytes
[7] = src
.bytes
[0];
179 float pg_conv_float (float f
) {
182 unsigned char bytes
[4];
185 dst
.bytes
[0] = src
.bytes
[3];
186 dst
.bytes
[1] = src
.bytes
[2];
187 dst
.bytes
[2] = src
.bytes
[1];
188 dst
.bytes
[3] = src
.bytes
[0];
192 //******************************************************************************
194 //******************************************************************************
196 #define MAX_DIGITS (sizeof(mp_limb_t) / sizeof(int16_t))
197 static void set_digits_n (mpz_t x
, int16_t *p_digits
, int16_t *digits
, int len
, int weight
) {
200 mpz_init_set_ui(m
, 1);
201 if (p_digits
< digits
)
204 mpz_set_ui(x
, *p_digits
);
208 if (p_digits
< digits
)
209 mpz_mul_si(m
, m
, 10000);
211 mpz_set_ui(m
, 10000);
213 mpz_add_ui(x
, x
, *p_digits
++);
217 mpz_mul_si(x
, x
, 10000);
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
++);
234 static void set_digits_d (mpz_t x
, int count
) {
237 mpz_mul_si(x
, x
, 10000);
242 void pg_get_numeric (uint8_t *buf
, mpq_t res
, uint16_t *scale
) {
243 int16_t len
= be16toh(*(int16_t*)buf
); buf
+= sizeof(int16_t);
244 int16_t weight
= be16toh(*(int16_t*)buf
); buf
+= sizeof(int16_t);
245 int16_t sign
= be16toh(*(int16_t*)buf
); buf
+= sizeof(int16_t);
247 if (sign
== NUMERIC_POS
|| sign
== NUMERIC_NEG
|| sign
== NUMERIC_NAN
) {
248 uint16_t dscale
= be16toh(*(uint16_t*)buf
); buf
+= sizeof(uint16_t);
251 if ((dscale
& NUMERIC_DSCALE_MASK
) == dscale
) {
256 mpz_ptr n
= &q
->_mp_num
, d
= &q
->_mp_den
;
257 int16_t *digits
= malloc(len
* sizeof(int16_t)), *p_digits
= digits
;
258 for (int i
= 0; i
< len
; ++i
) {
259 digits
[i
] = be16toh(*(int16_t*)buf
); buf
+= sizeof(int16_t);
264 set_digits_n(n
, p_digits
, digits
, len
, weight
);
267 int cnt
= len
- weight
;
276 mpz_init_set_si(d
, 1);
277 set_digits_n(n
, p_digits
, digits
, cnt
, cnt
);
278 set_digits_d(d
, cnt
);
282 if (sign
== NUMERIC_NEG
)
291 str_t
*pg_numstr (mpq_ptr x
, int base
, uint16_t dscale
, int float_prec
) {
296 mpz_ptr z
= &x
->_mp_num
;
297 if (!(s
= mpz_get_str(NULL
, base
, z
)))
299 str_t
*res
= mkstr(s
, strlen(s
), 8);
303 mpf_init2(f
, float_prec
);
305 if ((s
= mpf_get_str(NULL
, &exp
, base
, 0, f
))) {
310 res
= mkstr(s
, strlen(s
), 8);
311 if (exp
> res
->len
) {
312 strpad(&res
, exp
, '0', STR_LEFT
);
313 strnadd(&res
, CONST_STR_LEN(".0"));
315 strepl(&res
, res
->ptr
+ exp
, 0, CONST_STR_LEN("."));
317 res
= mkstr(CONST_STR_LEN("0."), 8);
319 strpad(&res
, -(exp
-2), '0', STR_LEFT
);
320 strnadd(&res
, s
, strlen(s
));
325 e
= res
->ptr
+ res
->len
;
326 if (0 < (n
= dscale
- ((intptr_t)e
- (intptr_t)p
- 1)))
327 strpad(&res
, res
->len
+ n
, '0', STR_LEFT
);