fixes, pgsql
[libpgclient.git] / src / pgfld.c
blobe9ac3463c9b010fe16f1f029d64a84a49206c9b0
1 #include "libpgcli/pgfld.h"
3 //******************************************************************************
4 // Time functions
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) \
22 do { \
23 (q) = ((t) / (u)); \
24 if ((q) != 0) (t) -= ((q) * (u)); \
25 } while(0)
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) {
39 unsigned int julian;
40 unsigned int quad;
41 unsigned int extra;
42 int y;
43 julian = jd;
44 julian += 32044;
45 quad = julian / 146097;
46 extra = (julian - quad * 146097) * 4 + 3;
47 julian += 60 + quad * 3 + extra / 146097;
48 quad = julian / 1461;
49 julian -= quad * 1461;
50 y = julian * 4 / 1461;
51 julian = ((y != 0) ? ((julian + 305) % 365) : ((julian + 306) % 366)) + 123;
52 y += quad * 4;
53 *year = y - 4800;
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) {
60 int julian;
61 int century;
62 if (m > 2) {
63 m += 1;
64 y += 4800;
65 } else {
66 m += 13;
67 y += 4799;
69 century = y / 100;
70 julian = y * 365 - 32167;
71 julian += y / 4 - century + century / 4;
72 julian += 7834 * m / 256 + d;
74 return julian;
77 static void dt2time(int64_t jd, int *hour, int *min, int *sec) {
78 tm_t time;
79 time = jd;
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) {
88 tm_t date, time = dt;
89 memset(tm, 0, sizeof(struct tm));
90 TMODULO(time, date, USECS_PER_DAY);
91 if (time < INT64CONST(0)) {
92 time += USECS_PER_DAY;
93 date -= 1;
95 date += POSTGRES_EPOCH_JDATE;
96 if (date < 0 || date > (int64_t)INT_MAX)
97 return -1;
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);
100 return 0;
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);
109 return dt;
112 int tm_to_timestamp (struct tm *tm, fsec_t fsec, int *tzp, tm_t *result) {
113 int dDate;
114 int64_t time;
115 if (!IS_VALID_JULIAN(tm->tm_year, tm->tm_mon, tm->tm_mday))
116 return -1;
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)
121 return -1;
122 if ((*result < 0 && dDate > 0) ||
123 (*result > 0 && dDate < -1))
124 return -1;
125 if (tzp != NULL)
126 *result = dt2local(*result, -(*tzp));
127 if (!IS_VALID_TIMESTAMP(*result))
128 return -1;
129 return 0;
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);
136 return tm;
139 struct tm *interval_to_tm(pg_intv_t *span, struct tm *tm) {
140 tm_t time;
141 if (span->month != 0) {
142 tm->tm_year = span->month / MONTHS_PER_YEAR;
143 tm->tm_mon = span->month % MONTHS_PER_YEAR;
144 } else {
145 tm->tm_year = 0;
146 tm->tm_mon = 0;
148 time = span->time;
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;
156 return tm;
159 //******************************************************************************
160 // Double function
161 //******************************************************************************
162 double pg_conv_double (double d) {
163 union {
164 double d;
165 unsigned char bytes [8];
166 } src, dst;
167 src.d = d;
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];
176 return dst.d;
179 float pg_conv_float (float f) {
180 union {
181 float f;
182 unsigned char bytes [4];
183 } src, dst;
184 src.f = f;
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];
189 return dst.f;
192 //******************************************************************************
193 // Numeric functions
194 //******************************************************************************
195 #ifdef HAVE_GMP
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) {
198 int i = 1;
199 mpz_t m;
200 mpz_init_set_ui(m, 1);
201 if (p_digits < digits)
202 mpz_set_ui(x, 0);
203 else
204 mpz_set_ui(x, *p_digits);
205 p_digits++;
206 if (len < weight) {
207 while (i < len) {
208 if (p_digits < digits)
209 mpz_mul_si(m, m, 10000);
210 else
211 mpz_set_ui(m, 10000);
212 mpz_mul(x, x, m);
213 mpz_add_ui(x, x, *p_digits++);
214 i++;
216 while (i < weight) {
217 mpz_mul_si(x, x, 10000);
218 ++i;
220 } else {
221 while (i < weight) {
222 if (p_digits < digits)
223 mpz_mul_si(m, m, 10000);
224 else
225 mpz_set_ui(m, 10000);
226 mpz_mul(x, x, m);
227 mpz_add_ui(x, x, *p_digits++);
228 i++;
231 mpz_clear(m);
234 static void set_digits_d (mpz_t x, int count) {
235 int i = 0;
236 while (i < count) {
237 mpz_mul_si(x, x, 10000);
238 i++;
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);
246 mpq_init(res);
247 if (sign == NUMERIC_POS || sign == NUMERIC_NEG || sign == NUMERIC_NAN) {
248 uint16_t dscale = be16toh(*(uint16_t*)buf); buf += sizeof(uint16_t);
249 if (scale)
250 *scale = dscale;
251 if ((dscale & NUMERIC_DSCALE_MASK) == dscale) {
252 if (0 == len)
253 return;
254 mpq_t x, y;
255 mpq_ptr q = x;
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);
261 ++weight;
262 mpz_init(n);
263 if (weight > 0)
264 set_digits_n(n, p_digits, digits, len, weight);
265 mpz_init(d);
266 mpz_set_si(d, 1);
267 int cnt = len - weight;
268 if (cnt <= 0)
269 mpq_set(res, q);
270 else {
271 p_digits += weight;
272 q = y;
273 n = &q->_mp_num;
274 d = &q->_mp_den;
275 mpz_init(n);
276 mpz_init_set_si(d, 1);
277 set_digits_n(n, p_digits, digits, cnt, cnt);
278 set_digits_d(d, cnt);
279 mpq_add(res, x, y);
280 mpq_clear(y);
282 if (sign == NUMERIC_NEG)
283 mpq_neg(res, res);
284 free(digits);
285 mpq_clear(x);
288 return;
291 str_t *pg_numstr (mpq_ptr x, int base, uint16_t dscale, int float_prec) {
292 char *s;
293 mpf_t f;
294 mp_exp_t exp;
295 if (0 == dscale) {
296 mpz_ptr z = &x->_mp_num;
297 if (!(s = mpz_get_str(NULL, base, z)))
298 return NULL;
299 str_t *res = mkstr(s, strlen(s), 8);
300 free(s);
301 return res;
303 mpf_init2(f, float_prec);
304 mpf_set_q(f, x);
305 if ((s = mpf_get_str(NULL, &exp, base, 0, f))) {
306 str_t *res;
307 ssize_t n;
308 char *e, *p;
309 if (exp > 0) {
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"));
314 } else
315 strepl(&res, res->ptr + exp, 0, CONST_STR_LEN("."));
316 } else {
317 res = mkstr(CONST_STR_LEN("0."), 8);
318 if (exp < 0)
319 strpad(&res, -(exp-2), '0', STR_LEFT);
320 strnadd(&res, s, strlen(s));
321 exp = 1;
323 p = res->ptr + exp;
324 free(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);
328 mpf_clear(f);
329 return res;
331 mpf_clear(f);
332 return NULL;
334 #endif