Initial import.
[libastrodb.git] / src / table_insert.c
blob9d3ccc0d05e7e7c1a04d310696608eef7b9f3bf6
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 = ((int) dobject->posn.ra - table->db->ra_min) /
63 table->ra_stride_size;
64 dec = ((int) dobject->posn.dec - table->db->dec_min) /
65 table->dec_stride_size;
66 mag = ((int) dobject->Vmag - table->db->mag_bright) /
67 table->mag_stride_size;
69 if ((offset = table_calc_deep_offset(table, ra, dec, mag)) < 0)
70 return 0;
72 *(table->objects + offset) =
73 astrodb_slist_prepend(*(table->objects + offset), object);
74 (table->status + offset)->flags = ADB_SMEM;
75 (table->status + offset)->size++;
76 return 1;
79 /*! \fn static int insert_posn_type (void* d, void* object)
80 * \brief Insert object into dataset based upon position and type
82 static int insert_posn_type(void *d, void *object)
84 int ra, dec, type, offset;
85 struct astrodb_table *table = (struct astrodb_table *) d;
86 struct astrodb_object_deep *dobject = object;
88 if (dobject->posn.ra < table->db->ra_min ||
89 dobject->posn.ra > table->db->ra_max)
90 return 0;
91 if (dobject->posn.dec < table->db->dec_min ||
92 dobject->posn.dec > table->db->dec_max)
93 return 0;
94 if (dobject->Vmag > table->db->mag_faint ||
95 dobject->Vmag < table->db->mag_bright)
96 return 0;
98 ra = ((int) dobject->posn.ra - table->db->ra_min) /
99 table->ra_stride_size;
100 dec = ((int) dobject->posn.dec - table->db->dec_min) /
101 table->dec_stride_size;
102 type = (int) dobject->aobject.oclass;
104 if ((offset = table_calc_deep_offset(table, ra, dec, type)) < 0)
105 return 0;
107 *(table->objects + offset) =
108 astrodb_slist_prepend(*(table->objects + offset), object);
109 (table->status + offset)->flags = ADB_SMEM;
110 (table->status + offset)->size++;
111 return 1;
114 /*! \fn static int insert_hash_id (void* d, void* object)
115 * \brief Insert object into dataset based upon position and mag
117 static int insert_hash_id(void *d, void *object)
119 struct astrodb_table *table = (struct astrodb_table *) d;
120 int offset = table_calc_hash(((struct astrodb_object *) object)->id,
121 OBJECT_ID_SIZE, table->no_tiles);
123 *(table->objects + offset) =
124 astrodb_slist_prepend(*(table->objects + offset), object);
125 (table->status + offset)->flags = ADB_SMEM;
126 (table->status + offset)->size++;
127 return 1;
130 /*! \fn static inline int insert_hash_id_hobject(astrodb_table *table, void *object, int hid)
131 * \brief Insert object into dataset based upon position and mag
133 static inline int insert_hash_id_hobject(struct astrodb_table *table,
134 void *object, int hid)
136 int offset;
138 offset = table_calc_hash((char *) object + table->hmaps[hid].offset,
139 OBJECT_ID_SIZE, table->no_tiles);
141 *(table->hmaps[hid].hobjects + offset) =
142 astrodb_slist_prepend(*(table->hmaps[hid].hobjects + offset), object);
143 return 1;
146 /*! \fn static int insert_posn_mag_hash (void* d, void* object)
147 * \brief Insert object into dataset based upon position and mag
149 static int insert_posn_mag_hash(void *d, void *object)
151 int ra, dec, mag, offset;
152 struct astrodb_table *table = (struct astrodb_table *) d;
153 struct astrodb_object_deep *dobject = object;
154 int i;
156 if (dobject->posn.ra < table->db->ra_min ||
157 dobject->posn.ra > table->db->ra_max)
158 return 0;
159 if (dobject->posn.dec < table->db->dec_min ||
160 dobject->posn.dec > table->db->dec_max)
161 return 0;
162 if (dobject->Vmag > table->db->mag_faint ||
163 dobject->Vmag < table->db->mag_bright)
164 return 0;
166 ra = ((int) dobject->posn.ra - table->db->ra_min) /
167 table->ra_stride_size;
168 dec = ((int) dobject->posn.dec - table->db->dec_min) /
169 table->dec_stride_size;
170 mag = ((int) dobject->Vmag - table->db->mag_bright) /
171 table->mag_stride_size;
173 offset = table_calc_deep_offset(table, ra, dec, mag);
174 if (offset < 0) {
175 astrodb_error("failed to calculate deep offset for RA %3.2f"
176 " DEC %3.2f mag %3.2f\n", ra, dec, mag);
177 return 0;
180 *(table->objects + offset) =
181 astrodb_slist_prepend(*(table->objects + offset), object);
182 (table->status + offset)->flags = ADB_SMEM;
183 (table->status + offset)->size++;
185 for (i = 0; i < table->num_hmaps; i++)
186 insert_hash_id_hobject(table, object, i);
188 return 1;
191 /*! \fn static int insert_posn_type_hash (void* d, void* object)
192 * \brief Insert object into dataset based upon position and type
194 static int insert_posn_type_hash(void *d, void *object)
196 int ra, dec, type, offset, i;
197 struct astrodb_table *table = (struct astrodb_table *) d;
198 struct astrodb_object_deep *dobject = object;
200 if (dobject->posn.ra < table->db->ra_min ||
201 dobject->posn.ra > table->db->ra_max)
202 return 0;
203 if (dobject->posn.dec < table->db->dec_min ||
204 dobject->posn.dec > table->db->dec_max)
205 return 0;
206 if (dobject->Vmag > table->db->mag_faint ||
207 dobject->Vmag < table->db->mag_bright)
208 return 0;
210 ra = ((int) dobject->posn.ra - table->db->ra_min) /
211 table->ra_stride_size;
212 dec = ((int) dobject->posn.dec - table->db->dec_min) /
213 table->dec_stride_size;
214 type = (int) dobject->aobject.oclass;
215 if ((offset = table_calc_deep_offset(table, ra, dec, type)) < 0)
216 return 0;
218 *(table->objects + offset) =
219 astrodb_slist_prepend(*(table->objects + offset), object);
220 (table->status + offset)->flags = ADB_SMEM;
221 (table->status + offset)->size++;
223 for (i = 0; i < table->num_hmaps; i++)
224 insert_hash_id_hobject(table, object, i);
226 return 1;
229 struct _insert {
230 void *func;
231 int id;
235 * Table containing dataset insertion funcs and ID's
237 struct _insert table_insert[] = {
238 {insert_posn_mag, INSERT_POSN_MAG},
239 {insert_posn_type, INSERT_POSN_TYPE},
240 {insert_hash_id, INSERT_HASH_ID},
241 {insert_posn_mag_hash, INSERT_POSN_MAG_HASH},
242 {insert_posn_type_hash, INSERT_POSN_TYPE_HASH},
245 void table_set_insert(struct astrodb_table *table, int id)
247 int i;
249 for (i = 0; i < astrodb_size(table_insert); i++) {
250 if (id == table_insert[i].id) {
251 table->object_insert = table_insert[i].func;
252 return;
255 table->object_insert = NULL;
258 /* table type insert's */
259 static int int_insert(void *dest, void *src)
261 char *ptr;
263 *(int *) dest = strtol(src, &ptr, 10);
264 if (src == ptr)
265 return -1;
266 return 0;
268 static int float_insert(void *dest, void *src)
270 char *ptr;
272 *(float *) dest = strtof(src, &ptr);
273 if (src == ptr) {
274 *(float*) dest = FP_NAN;
275 return -1;
277 return 0;
279 static int double_insert(void *dest, void *src)
281 char *ptr;
283 *(double *) dest = strtod(src, &ptr);
284 if (src == ptr) {
285 *(double*) dest = FP_NAN;
286 return -1;
288 return 0;
290 static int str_insert(void *dest, void *src)
292 strcpy(dest, src);
293 return 0;
296 static int double_dms_mins(void *dest, void *src)
298 char *ptr;
300 *(double *) dest += strtod(src, &ptr) / 60.0;
301 if (src == ptr)
302 return -1;
303 return 0;
305 static int double_dms_secs(void *dest, void *src)
307 char *ptr;
309 *(double *) dest += strtod(src, &ptr) / 3600.0;
310 if (src == ptr)
311 return -1;
312 return 0;
314 static int sign_insert(void *dest, void *src)
316 if (*(char*)src == '-')
317 *(double *) dest *= -1.0;
318 return 0;
320 static int double_hms_hrs(void *dest, void *src)
322 char *ptr;
324 *(double *) dest = strtod(src, &ptr) * 15.0;
325 if (src == ptr)
326 return -1;
327 return 0;
329 static int double_hms_mins(void *dest, void *src)
331 char *ptr;
333 *(double *) dest += strtod(src, &ptr) * 15.0 / 60.0;
334 if (src == ptr)
335 return -1;
336 return 0;
338 static int double_hms_secs(void *dest, void *src)
340 char *ptr;
342 *(double *) dest += strtod(src, &ptr) * 15.0 / 3600.0;
343 if (src == ptr)
344 return -1;
345 return 0;
348 static int float_alt_insert(void *dest, void *src, void *src2)
350 char *ptr;
352 *(float *) dest = strtof(src, &ptr);
354 /* is primary source invalid then try alternate source */
355 if (src == ptr) {
356 *(float *) dest = strtof(src2, &ptr);
357 if (src2 == ptr) {
358 *(float*) dest = FP_NAN;
359 return -1;
362 return 0;
365 static int double_alt_insert(void *dest, void *src, void *src2)
367 char *ptr;
369 *(double *) dest = strtod(src, &ptr);
371 /* is primary source invalid then try alternate source */
372 if (src == ptr) {
373 *(double *) dest = strtod(src2, &ptr);
374 if (src2 == ptr) {
375 *(double *) dest = FP_NAN;
376 return -1;
379 return 0;
382 /*! \fn astrodb_ctype table_get_ctype(char *type)
383 * \brief Get C type from ASCII type
385 astrodb_ctype table_get_ctype(char *type)
387 if (*type == 'I')
388 return CT_INT;
389 if (*type == 'A')
390 return CT_STRING;
391 if (*type == 'F') {
392 if (*(type + 1) > FLOAT_SIZE)
393 return CT_DOUBLE;
394 else
395 return CT_FLOAT;
397 return CT_NULL;
400 /*! \fn int table_get_csize(char *type)
401 * \brief Get C size from ASCII size
403 int table_get_csize(char *type)
405 if (*type == 'I')
406 return sizeof(int);
407 if (*type == 'A')
408 return strtol(type + 1, NULL, 10);
409 if (*type == 'F') {
410 if (*(type + 1) > FLOAT_SIZE)
411 return sizeof(double);
412 else
413 return sizeof(float);
415 return 0;
418 /*! \fn void *table_get_custom_insert(char *type)
419 * Get dataset type insert
421 void *table_get_custom_insert(char *type)
423 if (*type == 'I')
424 return (void *) int_insert;
425 if (*type == 'A')
426 return (void *) str_insert;
427 if (*type == 'F') {
428 if (*(type + 1) > FLOAT_SIZE)
429 return (void *) double_insert;
430 else
431 return (void *) float_insert;
433 return NULL;
436 /*! \fn void *table_get_key_insert(astrodb_ctype type)
437 * Get dataset type insert
439 void *table_get_key_insert(astrodb_ctype type)
441 switch (type) {
442 case CT_DOUBLE_DMS_DEGS:
443 case CT_DOUBLE:
444 return double_insert;
445 case CT_INT:
446 return int_insert;
447 case CT_STRING:
448 return str_insert;
449 case CT_FLOAT:
450 return float_insert;
451 case CT_DOUBLE_DMS_MINS:
452 return double_dms_mins;
453 case CT_DOUBLE_DMS_SECS:
454 return double_dms_secs;
455 case CT_SIGN:
456 return sign_insert;
457 case CT_DOUBLE_MPC:
458 case CT_NULL:
459 return NULL;
460 case CT_DOUBLE_HMS_HRS:
461 return double_hms_hrs;
462 case CT_DOUBLE_HMS_MINS:
463 return double_hms_mins;
464 case CT_DOUBLE_HMS_SECS:
465 return double_hms_secs;
467 astrodb_error("Invalid column insert %d\n", type);
468 return NULL;
471 /*! \fn void *table_get_alt_key_insert(astrodb_ctype type)
472 * Get dataset type insert
474 void *table_get_alt_key_insert(astrodb_ctype type)
476 switch (type) {
477 case CT_DOUBLE:
478 return double_alt_insert;
479 case CT_FLOAT:
480 return float_alt_insert;
481 case CT_INT:
482 case CT_STRING:
483 case CT_DOUBLE_DMS_DEGS:
484 case CT_DOUBLE_DMS_MINS:
485 case CT_DOUBLE_DMS_SECS:
486 case CT_SIGN:
487 case CT_DOUBLE_MPC:
488 case CT_NULL:
489 case CT_DOUBLE_HMS_HRS:
490 case CT_DOUBLE_HMS_MINS:
491 case CT_DOUBLE_HMS_SECS:
492 astrodb_error("Invalid alt column insert %d\n", type);
493 return NULL;
495 return NULL;
498 /*! \fn void table_get_object_insert(astrodb_table * table)
499 * \brief Get object insert func for table
500 * \todo index on position ans type/class
502 void table_get_object_insert(struct astrodb_table *table)
504 if (table_is_field(table, "RA") &&
505 table_is_field(table, "DEC") &&
506 table_is_field(table, "Vmag")) {
508 if (table->num_hmaps) {
509 astrodb_info("Table Sectioned on Position, Magnitude and"
510 "ID (Hash)\n");
511 table_set_insert(table, INSERT_POSN_MAG_HASH);
512 } else {
513 astrodb_info("Table Sectioned on Position, Magnitude\n");
514 table_set_insert(table, INSERT_POSN_MAG);
516 return;
519 if (table_is_field(table, "RAh") &&
520 table_is_field(table, "DEd") &&
521 table_is_field(table, "Vmag")) {
523 if (table->num_hmaps) {
524 astrodb_info("Table Sectioned on Position, Magnitude and"
525 "ID (Hash)\n");
526 table_set_insert(table, INSERT_POSN_MAG_HASH);
527 } else {
528 astrodb_info("Table Sectioned on Position, Magnitude\n");
529 table_set_insert(table, INSERT_POSN_MAG);
531 return;
534 astrodb_info("Indexing on ID\n");
535 table_set_insert(table, INSERT_HASH_ID);
538 #define INSERT_BUFFER_SIZE 128
540 static int import_data(struct astrodb_table *table, FILE *f)
542 int i, j, count = 0, short_records = 0, insert, warn;
543 char *line;
544 char buf[INSERT_BUFFER_SIZE];
545 void *object;
546 size_t size;
547 ssize_t rsize;
549 line = malloc(IMPORT_LINE_SIZE);
550 if (line == NULL)
551 return -ENOMEM;
553 astrodb_info("Starting import with object size %d bytes\n",
554 table->object_size);
556 size = table->record_size + 10;
557 for (j = 0; j < table->table_size; j++) {
558 warn = 0;
559 object = malloc(table->object_size);
560 if (object == NULL) {
561 free(line);
562 return -ENOMEM;
564 bzero(object, table->object_size);
565 bzero(line, IMPORT_LINE_SIZE);
567 /* try and read a little extra padding */
568 rsize = getline(&line, &size, f);
570 if (rsize < table->record_size)
571 short_records++;
573 /* create row by inserting column (field) data */
574 for (i = 0; i < table->object_fields; i++) {
575 bzero(buf, INSERT_BUFFER_SIZE);
576 strncpy(buf, line + table->idx[i].l_offset,
577 table->idx[i].l_size);
578 insert = table->idx[i].
579 insert(object + table->idx[i].s_offset, buf);
580 if (insert < 0) {
581 astrodb_warn(" blank field %s\n",
582 table->idx[i].symbol);
583 warn = 1;
587 if (warn) {
588 astrodb_warn("At line %d :-\n", count);
589 astrodb_warn("line %s\n\n", line);
592 /* insert row into table */
593 count += table->object_insert(table, object);
595 astrodb_info("Got %d short records\n", short_records);
596 astrodb_info("Imported %d records\n", count);
597 free(line);
598 return count;
601 static int import_data_alt(struct astrodb_table *table, FILE *f)
603 int i, j, k, count = 0, short_records = 0, warn, insert;
604 char *line;
605 char buf[INSERT_BUFFER_SIZE], buf2[INSERT_BUFFER_SIZE];
606 void *object;
607 size_t size;
608 ssize_t rsize;
610 line = malloc(IMPORT_LINE_SIZE);
611 if (line == NULL)
612 return -ENOMEM;
614 astrodb_info("Starting import with object size %d bytes\n",
615 table->object_size);
616 astrodb_info("Importing %d alt fields\n", table->alt_fields);
618 size = table->record_size + 10;
619 for (j = 0; j < table->table_size; j++) {
620 object = calloc(1, table->object_size);
621 if (object == NULL) {
622 free(line);
623 return -ENOMEM;
625 warn = 0;
626 bzero(object, table->object_size);
627 bzero(line, IMPORT_LINE_SIZE);
629 /* try and read a little extra padding */
630 rsize = getline(&line, &size, f);
632 if (rsize < table->record_size)
633 short_records++;
635 /* create row by inserting colunm (field) data */
636 for (i = 0; i < table->object_fields; i++) {
637 bzero(buf, INSERT_BUFFER_SIZE);
638 strncpy(buf, line + table->idx[i].l_offset,
639 table->idx[i].l_size);
640 insert = table->idx[i].insert(
641 object + table->idx[i].s_offset, buf);
642 if (insert < 0) {
643 astrodb_warn(" blank field %s\n",
644 table->idx[i].symbol);
645 warn = 1;
649 /* complete row by inserting alt column (field) data */
650 for (k = 0; k < table->alt_fields; k++) {
651 bzero(buf, INSERT_BUFFER_SIZE);
652 bzero(buf2, INSERT_BUFFER_SIZE);
653 strncpy(buf, line + table->alt_idx[k].pri.l_offset,
654 table->alt_idx[k].pri.l_size);
655 strncpy(buf2, line + table->alt_idx[k].sec.l_offset,
656 table->alt_idx[k].sec.l_size);
657 insert = table->alt_idx[k].insert(object +
658 table->alt_idx[k].pri.s_offset,
659 buf, buf2);
660 if (insert < 0) {
661 astrodb_warn(" blank fields %s %s\n",
662 table->alt_idx[k].pri.symbol,
663 table->alt_idx[k].sec.symbol);
664 warn = 1;
668 if (warn) {
669 astrodb_warn("At line %d :-\n", count);
670 astrodb_warn("line %s\n\n", line);
673 /* insert row into table */
674 count += table->object_insert(table, object);
676 astrodb_info("Got %d short records\n", short_records);
677 astrodb_info("Imported %d records\n", count);
678 free(line);
679 return count;
682 /*! \fn int table_import(astrodb_table * table, char *file, astrodb_progress progress)
683 * \brief Import an ASCII dataset into table tile array
685 int table_import(struct astrodb_table *table, char *file)
687 FILE *f = NULL;
689 if (!table->object_insert) {
690 astrodb_error("Invalid object insert\n");
691 return -EINVAL;
694 f = fopen(file, "r");
695 if (f == NULL) {
696 astrodb_error("failed to open file %s\n", file);
697 return -EIO;
700 table_order_index(table);
702 if (table->alt_fields)
703 import_data_alt(table, f);
704 else
705 import_data(table, f);
707 fclose(f);
708 return 0;