table: fixed bug when field length > 128.
[libastrodb.git] / src / table_insert.c
blob0b73b78210a8afb05ff0e9385b2869c4d7896946
1 /*
2 * This library is free software; you can redistribute it and/or
3 * modify it under the terms of the GNU Lesser General Public
4 * License as published by the Free Software Foundation; either
5 * version 2 of the License, or (at your option) any later version.
7 * This library is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
10 * Lesser General Public License for more details.
12 * You should have received a copy of the GNU General Public License
13 * along with this program; if not, write to the Free Software
14 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
16 * Copyright (C) 2008 Liam Girdwood
19 #define _GNU_SOURCE /* for strtof and NAN */
21 #include <stdlib.h>
22 #include <stdio.h>
23 #include <errno.h>
24 #include <string.h>
25 #include <unistd.h>
26 #include <math.h>
27 #include <ctype.h>
29 #include <libastrodb/db.h>
30 #include <libastrodb/astro.h>
31 #include <libastrodb/table.h>
32 #include <libastrodb/adbstdio.h>
34 #define FILE_NAME_SIZE 256
35 #define FLOAT_SIZE '6' /* CDS F size and below for a float else double */
36 #define IMPORT_LINE_SIZE 1024
39 * libastrodb interface version
41 #define ADB_IDX_VERSION 2
43 /*! \fn static int insert_posn_mag (void* d, void* object)
44 * \brief Insert object into dataset based upon position and mag
46 static int insert_posn_mag(void *d, void *object)
48 int ra, dec, mag, offset;
49 struct astrodb_table *table = (struct astrodb_table *) d;
50 struct astrodb_object_deep *dobject = object;
52 if (dobject->posn.ra < table->db->ra_min ||
53 dobject->posn.ra > table->db->ra_max)
54 return 0;
55 if (dobject->posn.dec < table->db->dec_min ||
56 dobject->posn.dec > table->db->dec_max)
57 return 0;
58 if (dobject->Vmag > table->db->mag_faint ||
59 dobject->Vmag < table->db->mag_bright)
60 return 0;
62 ra = floor((dobject->posn.ra - table->db->ra_min) /
63 table->ra_stride_size);
64 dec = floor((dobject->posn.dec - table->db->dec_min) /
65 table->dec_stride_size);
66 mag = floor((dobject->Vmag - table->db->mag_bright) /
67 table->mag_stride_size);
69 offset = table_calc_deep_offset(table, ra, dec, mag);
71 if (offset < 0) {
72 astrodb_error("failed to calculate offset for RA %3.2f"
73 " DEC %3.2f mag %3.2f\n", ra, dec, mag);
74 return 0;
77 *(table->objects + offset) =
78 astrodb_slist_prepend(*(table->objects + offset), object);
79 (table->status + offset)->flags = ADB_SMEM;
80 (table->status + offset)->size++;
81 return 1;
84 /*! \fn static int insert_posn_type (void* d, void* object)
85 * \brief Insert object into dataset based upon position and type
87 static int insert_posn_type(void *d, void *object)
89 int ra, dec, type, offset;
90 struct astrodb_table *table = (struct astrodb_table *) d;
91 struct astrodb_object_deep *dobject = object;
93 if (dobject->posn.ra < table->db->ra_min ||
94 dobject->posn.ra > table->db->ra_max)
95 return 0;
96 if (dobject->posn.dec < table->db->dec_min ||
97 dobject->posn.dec > table->db->dec_max)
98 return 0;
99 if (dobject->Vmag > table->db->mag_faint ||
100 dobject->Vmag < table->db->mag_bright)
101 return 0;
103 ra = floor((dobject->posn.ra - table->db->ra_min) /
104 table->ra_stride_size);
105 dec = floor((dobject->posn.dec - table->db->dec_min) /
106 table->dec_stride_size);
107 type = dobject->aobject.oclass;
109 offset = table_calc_deep_offset(table, ra, dec, type);
110 if (offset < 0) {
111 astrodb_error("failed to calculate offset for RA %3.2f"
112 " DEC %3.2f type %3.2f\n", ra, dec, type);
113 return 0;
116 *(table->objects + offset) =
117 astrodb_slist_prepend(*(table->objects + offset), object);
118 (table->status + offset)->flags = ADB_SMEM;
119 (table->status + offset)->size++;
120 return 1;
123 /*! \fn static int insert_hash_id (void* d, void* object)
124 * \brief Insert object into dataset based upon position and mag
126 static int insert_hash_id(void *d, void *object)
128 struct astrodb_table *table = (struct astrodb_table *) d;
129 int offset = table_calc_hash(((struct astrodb_object *) object)->id,
130 OBJECT_ID_SIZE, table->no_tiles);
132 *(table->objects + offset) =
133 astrodb_slist_prepend(*(table->objects + offset), object);
134 (table->status + offset)->flags = ADB_SMEM;
135 (table->status + offset)->size++;
136 return 1;
139 /*! \fn static inline int insert_hash_id_hobject(astrodb_table *table, void *object, int hid)
140 * \brief Insert object into dataset based upon position and mag
142 static inline int insert_hash_id_hobject(struct astrodb_table *table,
143 void *object, int hid)
145 int offset;
147 offset = table_calc_hash((char *) object + table->hmaps[hid].offset,
148 OBJECT_ID_SIZE, table->no_tiles);
150 *(table->hmaps[hid].hobjects + offset) =
151 astrodb_slist_prepend(*(table->hmaps[hid].hobjects + offset), object);
152 return 1;
155 /*! \fn static int insert_posn_mag_hash (void* d, void* object)
156 * \brief Insert object into dataset based upon position and mag
158 static int insert_posn_mag_hash(void *d, void *object)
160 int ra, dec, mag, offset;
161 struct astrodb_table *table = (struct astrodb_table *) d;
162 struct astrodb_object_deep *dobject = object;
163 int i;
165 if (dobject->posn.ra < table->db->ra_min ||
166 dobject->posn.ra > table->db->ra_max)
167 return 0;
168 if (dobject->posn.dec < table->db->dec_min ||
169 dobject->posn.dec > table->db->dec_max)
170 return 0;
171 if (dobject->Vmag > table->db->mag_faint ||
172 dobject->Vmag < table->db->mag_bright)
173 return 0;
175 ra = floor((dobject->posn.ra - table->db->ra_min) /
176 table->ra_stride_size);
177 dec = floor((dobject->posn.dec - table->db->dec_min) /
178 table->dec_stride_size);
179 mag = floor((dobject->Vmag - table->db->mag_bright) /
180 table->mag_stride_size);
182 offset = table_calc_deep_offset(table, ra, dec, mag);
183 if (offset < 0) {
184 astrodb_error("failed to calculate deep offset for RA %3.2f"
185 " DEC %3.2f mag %3.2f\n", ra, dec, mag);
186 return 0;
189 *(table->objects + offset) =
190 astrodb_slist_prepend(*(table->objects + offset), object);
191 (table->status + offset)->flags = ADB_SMEM;
192 (table->status + offset)->size++;
194 for (i = 0; i < table->num_hmaps; i++)
195 insert_hash_id_hobject(table, object, i);
197 return 1;
200 /*! \fn static int insert_posn_type_hash (void* d, void* object)
201 * \brief Insert object into dataset based upon position and type
203 static int insert_posn_type_hash(void *d, void *object)
205 int ra, dec, type, offset, i;
206 struct astrodb_table *table = (struct astrodb_table *) d;
207 struct astrodb_object_deep *dobject = object;
209 if (dobject->posn.ra < table->db->ra_min ||
210 dobject->posn.ra > table->db->ra_max)
211 return 0;
212 if (dobject->posn.dec < table->db->dec_min ||
213 dobject->posn.dec > table->db->dec_max)
214 return 0;
215 if (dobject->Vmag > table->db->mag_faint ||
216 dobject->Vmag < table->db->mag_bright)
217 return 0;
219 ra = floor((dobject->posn.ra - table->db->ra_min) /
220 table->ra_stride_size);
221 dec = floor((dobject->posn.dec - table->db->dec_min) /
222 table->dec_stride_size);
223 type = dobject->aobject.oclass;
224 offset = table_calc_deep_offset(table, ra, dec, type);
225 if (offset < 0) {
226 astrodb_error("failed to calculate deep offset for RA %3.2f"
227 " DEC %3.2f type %3.2f\n", ra, dec, type);
228 return 0;
231 *(table->objects + offset) =
232 astrodb_slist_prepend(*(table->objects + offset), object);
233 (table->status + offset)->flags = ADB_SMEM;
234 (table->status + offset)->size++;
236 for (i = 0; i < table->num_hmaps; i++)
237 insert_hash_id_hobject(table, object, i);
239 return 1;
242 struct _insert {
243 void *func;
244 int id;
248 * Table containing dataset insertion funcs and ID's
250 struct _insert table_insert[] = {
251 {insert_posn_mag, INSERT_POSN_MAG},
252 {insert_posn_type, INSERT_POSN_TYPE},
253 {insert_hash_id, INSERT_HASH_ID},
254 {insert_posn_mag_hash, INSERT_POSN_MAG_HASH},
255 {insert_posn_type_hash, INSERT_POSN_TYPE_HASH},
258 void table_set_insert(struct astrodb_table *table, int id)
260 int i;
262 for (i = 0; i < astrodb_size(table_insert); i++) {
263 if (id == table_insert[i].id) {
264 table->object_insert = table_insert[i].func;
265 return;
268 table->object_insert = NULL;
271 /* table type insert's */
272 static int int_insert(void *dest, void *src)
274 char *ptr;
276 *(int *) dest = strtol(src, &ptr, 10);
277 if (src == ptr)
278 return -1;
279 return 0;
281 static int float_insert(void *dest, void *src)
283 char *ptr;
285 *(float *) dest = strtof(src, &ptr);
286 if (src == ptr) {
287 *(float*) dest = FP_NAN;
288 return -1;
290 return 0;
292 static int double_insert(void *dest, void *src)
294 char *ptr;
296 *(double *) dest = strtod(src, &ptr);
297 if (src == ptr) {
298 *(double*) dest = FP_NAN;
299 return -1;
301 return 0;
303 static int str_insert(void *dest, void *src)
305 strcpy(dest, src);
306 return 0;
309 static int double_dms_mins(void *dest, void *src)
311 char *ptr;
313 *(double *) dest += strtod(src, &ptr) / 60.0;
314 if (src == ptr)
315 return -1;
316 return 0;
318 static int double_dms_secs(void *dest, void *src)
320 char *ptr;
322 *(double *) dest += strtod(src, &ptr) / 3600.0;
323 if (src == ptr)
324 return -1;
325 return 0;
327 static int sign_insert(void *dest, void *src)
329 if (*(char*)src == '-')
330 *(double *) dest *= -1.0;
331 return 0;
333 static int double_hms_hrs(void *dest, void *src)
335 char *ptr;
337 *(double *) dest = strtod(src, &ptr) * 15.0;
338 if (src == ptr)
339 return -1;
340 return 0;
342 static int double_hms_mins(void *dest, void *src)
344 char *ptr;
346 *(double *) dest += strtod(src, &ptr) * 15.0 / 60.0;
347 if (src == ptr)
348 return -1;
349 return 0;
351 static int double_hms_secs(void *dest, void *src)
353 char *ptr;
355 *(double *) dest += strtod(src, &ptr) * 15.0 / 3600.0;
356 if (src == ptr)
357 return -1;
358 return 0;
361 static int float_alt_insert(void *dest, void *src, void *src2)
363 char *ptr;
365 *(float *) dest = strtof(src, &ptr);
367 /* is primary source invalid then try alternate source */
368 if (src == ptr) {
369 *(float *) dest = strtof(src2, &ptr);
370 if (src2 == ptr) {
371 *(float*) dest = FP_NAN;
372 return -1;
375 return 0;
378 static int double_alt_insert(void *dest, void *src, void *src2)
380 char *ptr;
382 *(double *) dest = strtod(src, &ptr);
384 /* is primary source invalid then try alternate source */
385 if (src == ptr) {
386 *(double *) dest = strtod(src2, &ptr);
387 if (src2 == ptr) {
388 *(double *) dest = FP_NAN;
389 return -1;
392 return 0;
395 /*! \fn astrodb_ctype table_get_ctype(char *type)
396 * \brief Get C type from ASCII type
398 astrodb_ctype table_get_ctype(char *type)
400 if (*type == 'I')
401 return CT_INT;
402 if (*type == 'A')
403 return CT_STRING;
404 if (*type == 'F') {
405 if (*(type + 1) > FLOAT_SIZE)
406 return CT_DOUBLE;
407 else
408 return CT_FLOAT;
410 return CT_NULL;
413 /*! \fn int table_get_csize(char *type)
414 * \brief Get C size from ASCII size
416 int table_get_csize(char *type)
418 if (*type == 'I')
419 return sizeof(int);
420 if (*type == 'A')
421 return strtol(type + 1, NULL, 10);
422 if (*type == 'F') {
423 if (*(type + 1) > FLOAT_SIZE)
424 return sizeof(double);
425 else
426 return sizeof(float);
428 return 0;
431 /*! \fn void *table_get_custom_insert(char *type)
432 * Get dataset type insert
434 void *table_get_custom_insert(char *type)
436 if (*type == 'I')
437 return (void *) int_insert;
438 if (*type == 'A')
439 return (void *) str_insert;
440 if (*type == 'F') {
441 if (*(type + 1) > FLOAT_SIZE)
442 return (void *) double_insert;
443 else
444 return (void *) float_insert;
446 return NULL;
449 /*! \fn void *table_get_key_insert(astrodb_ctype type)
450 * Get dataset type insert
452 void *table_get_key_insert(astrodb_ctype type)
454 switch (type) {
455 case CT_DOUBLE_DMS_DEGS:
456 case CT_DOUBLE:
457 return double_insert;
458 case CT_INT:
459 return int_insert;
460 case CT_STRING:
461 return str_insert;
462 case CT_FLOAT:
463 return float_insert;
464 case CT_DOUBLE_DMS_MINS:
465 return double_dms_mins;
466 case CT_DOUBLE_DMS_SECS:
467 return double_dms_secs;
468 case CT_SIGN:
469 return sign_insert;
470 case CT_DOUBLE_MPC:
471 case CT_NULL:
472 return NULL;
473 case CT_DOUBLE_HMS_HRS:
474 return double_hms_hrs;
475 case CT_DOUBLE_HMS_MINS:
476 return double_hms_mins;
477 case CT_DOUBLE_HMS_SECS:
478 return double_hms_secs;
480 astrodb_error("Invalid column insert %d\n", type);
481 return NULL;
484 /*! \fn void *table_get_alt_key_insert(astrodb_ctype type)
485 * Get dataset type insert
487 void *table_get_alt_key_insert(astrodb_ctype type)
489 switch (type) {
490 case CT_DOUBLE:
491 return double_alt_insert;
492 case CT_FLOAT:
493 return float_alt_insert;
494 case CT_INT:
495 case CT_STRING:
496 case CT_DOUBLE_DMS_DEGS:
497 case CT_DOUBLE_DMS_MINS:
498 case CT_DOUBLE_DMS_SECS:
499 case CT_SIGN:
500 case CT_DOUBLE_MPC:
501 case CT_NULL:
502 case CT_DOUBLE_HMS_HRS:
503 case CT_DOUBLE_HMS_MINS:
504 case CT_DOUBLE_HMS_SECS:
505 astrodb_error("Invalid alt column insert %d\n", type);
506 return NULL;
508 return NULL;
511 /*! \fn void table_get_object_insert(astrodb_table * table)
512 * \brief Get object insert func for table
513 * \todo index on position ans type/class
515 void table_get_object_insert(struct astrodb_table *table)
517 if (table_is_field(table, "RA") &&
518 table_is_field(table, "DEC") &&
519 table_is_field(table, "Vmag")) {
521 if (table->num_hmaps) {
522 astrodb_info("Table Sectioned on Position, Magnitude and"
523 "ID (Hash)\n");
524 table_set_insert(table, INSERT_POSN_MAG_HASH);
525 } else {
526 astrodb_info("Table Sectioned on Position, Magnitude\n");
527 table_set_insert(table, INSERT_POSN_MAG);
529 return;
532 if (table_is_field(table, "RAh") &&
533 table_is_field(table, "DEd") &&
534 table_is_field(table, "Vmag")) {
536 if (table->num_hmaps) {
537 astrodb_info("Table Sectioned on Position, Magnitude and"
538 "ID (Hash)\n");
539 table_set_insert(table, INSERT_POSN_MAG_HASH);
540 } else {
541 astrodb_info("Table Sectioned on Position, Magnitude\n");
542 table_set_insert(table, INSERT_POSN_MAG);
544 return;
547 astrodb_info("Indexing on ID\n");
548 table_set_insert(table, INSERT_HASH_ID);
551 static void get_import_buffer_size(struct astrodb_table *table)
553 int i;
555 table->buffer_size = 0;
557 for (i = 0; i < table->object_fields; i++) {
558 if (table->idx[i].l_size > table->buffer_size)
559 table->buffer_size = table->idx[i].l_size;
563 static int import_data(struct astrodb_table *table, FILE *f)
565 int i, j, count = 0, short_records = 0, insert, warn;
566 char *line;
567 char buf[IMPORT_LINE_SIZE];
568 void *object;
569 size_t size;
570 ssize_t rsize;
572 line = malloc(IMPORT_LINE_SIZE);
573 if (line == NULL)
574 return -ENOMEM;
576 astrodb_info("Starting import with object size %d bytes\n",
577 table->object_size);
579 size = table->record_size + 10;
580 for (j = 0; j < table->table_size; j++) {
581 warn = 0;
582 object = malloc(table->object_size);
583 if (object == NULL) {
584 free(line);
585 return -ENOMEM;
587 bzero(object, table->object_size);
588 bzero(line, IMPORT_LINE_SIZE);
590 /* try and read a little extra padding */
591 rsize = getline(&line, &size, f);
593 if (rsize < table->record_size)
594 short_records++;
596 /* create row by inserting column (field) data */
597 for (i = 0; i < table->object_fields; i++) {
598 bzero(buf, table->buffer_size);
599 strncpy(buf, line + table->idx[i].l_offset,
600 table->idx[i].l_size);
601 insert = table->idx[i].
602 insert(object + table->idx[i].s_offset, buf);
603 if (insert < 0) {
604 astrodb_warn(" blank field %s\n",
605 table->idx[i].symbol);
606 warn = 1;
610 if (warn) {
611 astrodb_warn("At line %d :-\n", count);
612 astrodb_warn("line %s\n\n", line);
615 /* insert row into table */
616 count += table->object_insert(table, object);
618 astrodb_info("Got %d short records\n", short_records);
619 astrodb_info("Imported %d records\n", count);
620 free(line);
621 return count;
624 static int import_data_alt(struct astrodb_table *table, FILE *f)
626 int i, j, k, count = 0, short_records = 0, warn, insert;
627 char *line;
628 char buf[IMPORT_LINE_SIZE], buf2[IMPORT_LINE_SIZE];
629 void *object;
630 size_t size;
631 ssize_t rsize;
633 line = malloc(IMPORT_LINE_SIZE);
634 if (line == NULL)
635 return -ENOMEM;
637 astrodb_info("Starting import with object size %d bytes\n",
638 table->object_size);
639 astrodb_info("Importing %d alt fields\n", table->alt_fields);
641 size = table->record_size + 10;
642 for (j = 0; j < table->table_size; j++) {
643 object = calloc(1, table->object_size);
644 if (object == NULL) {
645 free(line);
646 return -ENOMEM;
648 warn = 0;
649 bzero(object, table->object_size);
650 bzero(line, IMPORT_LINE_SIZE);
652 /* try and read a little extra padding */
653 rsize = getline(&line, &size, f);
655 if (rsize < table->record_size)
656 short_records++;
658 /* create row by inserting colunm (field) data */
659 for (i = 0; i < table->object_fields; i++) {
660 bzero(buf, table->buffer_size);
661 strncpy(buf, line + table->idx[i].l_offset,
662 table->idx[i].l_size);
663 insert = table->idx[i].insert(
664 object + table->idx[i].s_offset, buf);
665 if (insert < 0) {
666 astrodb_warn(" blank field %s\n",
667 table->idx[i].symbol);
668 warn = 1;
672 /* complete row by inserting alt column (field) data */
673 for (k = 0; k < table->alt_fields; k++) {
674 bzero(buf, table->buffer_size);
675 bzero(buf2, table->buffer_size);
676 strncpy(buf, line + table->alt_idx[k].pri.l_offset,
677 table->alt_idx[k].pri.l_size);
678 strncpy(buf2, line + table->alt_idx[k].sec.l_offset,
679 table->alt_idx[k].sec.l_size);
680 insert = table->alt_idx[k].insert(object +
681 table->alt_idx[k].pri.s_offset,
682 buf, buf2);
683 if (insert < 0) {
684 astrodb_warn(" blank fields %s %s\n",
685 table->alt_idx[k].pri.symbol,
686 table->alt_idx[k].sec.symbol);
687 warn = 1;
691 if (warn) {
692 astrodb_warn("At line %d :-\n", count);
693 astrodb_warn("line %s\n\n", line);
696 /* insert row into table */
697 count += table->object_insert(table, object);
699 astrodb_info("Got %d short records\n", short_records);
700 astrodb_info("Imported %d records\n", count);
701 free(line);
702 return count;
705 /*! \fn int table_import(astrodb_table * table, char *file, astrodb_progress progress)
706 * \brief Import an ASCII dataset into table tile array
708 int table_import(struct astrodb_table *table, char *file)
710 FILE *f = NULL;
712 if (!table->object_insert) {
713 astrodb_error("Invalid object insert\n");
714 return -EINVAL;
717 f = fopen(file, "r");
718 if (f == NULL) {
719 astrodb_error("failed to open file %s\n", file);
720 return -EIO;
723 table_order_index(table);
725 get_import_buffer_size(table);
727 if (table->alt_fields)
728 import_data_alt(table, f);
729 else
730 import_data(table, f);
732 fclose(f);
733 return 0;