00001
00002
00003
00004
00005
00006
00007
00008
00009
00010 #include "csv.h"
00011 #include "csv_local.h"
00012 #include "csv_extern.h"
00013
00014 static int DbRecord_field(DbRecord *, u_int, void *, datatype);
00015 static int DbRecord_search_field(DbField *, char *, OPERATOR);
00016 static int DbRecord_search_recno(char *, OPERATOR);
00017
00018
00019
00020
00021
00022 void
00023 DbRecord_print(DbRecord *recordp, FILE *fp)
00024 {
00025 DbField *f;
00026 void *faddr;
00027
00028 if (fp == NULL)
00029 fp = stdout;
00030
00031 fprintf(fp, "Record: %lu:\n", (u_long)recordp->recno);
00032 for (f = fieldlist; f->name != NULL; ++f) {
00033 faddr = (u_int8_t *)recordp + f->offset;
00034 fprintf(fp, "\t%s: ", f->name);
00035 switch (f->type) {
00036 case NOTSET:
00037
00038 abort();
00039 break;
00040 case DOUBLE:
00041 fprintf(fp, "%f\n", *(double *)faddr);
00042 break;
00043 case STRING:
00044 fprintf(fp, "%s\n", *(char **)faddr);
00045 break;
00046 case ULONG:
00047 fprintf(fp, "%lu\n", *(u_long *)faddr);
00048 break;
00049 }
00050 }
00051 }
00052
00053
00054
00055
00056
00057 int
00058 DbRecord_read(u_long recno_ulong, DbRecord *recordp)
00059 {
00060 DBT key, data;
00061 u_int32_t recno;
00062 int ret;
00063
00064
00065
00066
00067
00068
00069 recno = recno_ulong;
00070
00071
00072
00073
00074
00075
00076
00077
00078
00079
00080
00081
00082 memset(&key, 0, sizeof(key));
00083 memset(&data, 0, sizeof(data));
00084 key.data = &recno;
00085 key.size = sizeof(recno);
00086 data.flags = DB_DBT_MALLOC;
00087 if ((ret = db->get(db, NULL, &key, &data, 0)) != 0)
00088 return (ret);
00089
00090 if ((ret = DbRecord_init(&key, &data, recordp)) != 0)
00091 return (ret);
00092
00093 return (0);
00094 }
00095
00096
00097
00098
00099
00100 int
00101 DbRecord_discard(DbRecord *recordp)
00102 {
00103
00104 free(recordp->raw);
00105 recordp->raw = NULL;
00106
00107 return (0);
00108 }
00109
00110
00111
00112
00113
00114 int
00115 DbRecord_init(const DBT *key, const DBT *data, DbRecord *recordp)
00116 {
00117 DbField *f;
00118 u_int32_t skip;
00119 void *faddr;
00120
00121
00122 *recordp = DbRecord_base;
00123
00124
00125 memcpy(&recordp->recno, key->data, sizeof(u_int32_t));
00126 memcpy(&recordp->version,
00127 (u_int32_t *)data->data + 1, sizeof(u_int32_t));
00128
00129
00130 recordp->raw = data->data;
00131 recordp->offset = (u_int32_t *)data->data + 1;
00132 skip = (recordp->field_count + 2) * sizeof(u_int32_t);
00133 recordp->record = (u_int8_t *)data->data + skip;
00134 recordp->record_len = data->size - skip;
00135
00136 for (f = fieldlist; f->name != NULL; ++f) {
00137 faddr = (u_int8_t *)recordp + f->offset;
00138 if (DbRecord_field(
00139 recordp, f->fieldno, faddr, f->type) != 0)
00140 return (1);
00141 }
00142 return (0);
00143 }
00144
00145
00146
00147
00148
00149 static int
00150 DbRecord_field(
00151 DbRecord *recordp, u_int field, void *addr, datatype type)
00152 {
00153 size_t len;
00154 char number_buf[20];
00155
00156
00157
00158
00159
00160 --field;
00161
00162 switch (type) {
00163 case NOTSET:
00164
00165 abort();
00166 break;
00167 case STRING:
00168 *((u_char **)addr) = recordp->record + recordp->offset[field];
00169 recordp->record[recordp->offset[field] +
00170 OFFSET_LEN(recordp->offset, field)] = '\0';
00171 break;
00172 case DOUBLE:
00173 case ULONG:
00174
00175 len = OFFSET_LEN(recordp->offset, field);
00176 if (len > sizeof(number_buf) - 1) {
00177 dbenv->errx(dbenv,
00178 "record %lu field %lu: numeric field is %lu bytes and too large to copy",
00179 recordp->recno, field, (u_long)len);
00180 return (1);
00181 }
00182 memcpy(number_buf,
00183 recordp->record + recordp->offset[field], len);
00184 number_buf[len] = '\0';
00185
00186 if (type == DOUBLE) {
00187 if (len == 0)
00188 *(double *)addr = 0;
00189 else if (strtod_err(number_buf, (double *)addr) != 0)
00190 goto fmt_err;
00191 } else
00192 if (len == 0)
00193 *(u_long *)addr = 0;
00194 else if (strtoul_err(number_buf, (u_long *)addr) != 0) {
00195 fmt_err: dbenv->errx(dbenv,
00196 "record %lu: numeric field %u error: %s",
00197 recordp->recno, field, number_buf);
00198 return (1);
00199 }
00200 break;
00201 }
00202 return (0);
00203 }
00204
00205
00206
00207
00208
00209 int
00210 DbRecord_search_field_name(char *field, char *value, OPERATOR op)
00211 {
00212 DbField *f;
00213
00214 for (f = fieldlist; f->name != NULL; ++f)
00215 if (strcasecmp(field, f->name) == 0)
00216 return (DbRecord_search_field(f, value, op));
00217
00218
00219 if (strcasecmp(field, "id") == 0)
00220 return (DbRecord_search_recno(value, op));
00221
00222 dbenv->errx(dbenv, "unknown field name: %s", field);
00223 return (1);
00224 }
00225
00226
00227
00228
00229
00230 int
00231 DbRecord_search_field_number(u_int32_t fieldno, char *value, OPERATOR op)
00232 {
00233 DbField *f;
00234
00235 for (f = fieldlist; f->name != NULL; ++f)
00236 if (fieldno == f->fieldno)
00237 return (DbRecord_search_field(f, value, op));
00238
00239 dbenv->errx(dbenv, "field number %lu not configured", (u_long)fieldno);
00240 return (1);
00241 }
00242
00243
00244
00245
00246
00247 static int
00248 DbRecord_search_recno(char *value, OPERATOR op)
00249 {
00250 DBC *dbc;
00251 DbRecord record;
00252 DBT key, data;
00253 u_int32_t recno;
00254 u_long recno_ulong;
00255 int ret;
00256
00257
00258
00259
00260
00261
00262 if (strtoul_err(value, &recno_ulong) != 0)
00263 return (1);
00264
00265 memset(&key, 0, sizeof(key));
00266 memset(&data, 0, sizeof(data));
00267 key.data = &recno;
00268 key.size = sizeof(recno);
00269
00270 if ((ret = db->cursor(db, NULL, &dbc, 0)) != 0)
00271 return (ret);
00272
00273
00274
00275
00276
00277
00278
00279
00280
00281
00282
00283
00284
00285 if (op == LT || op == LTEQ || op == NEQ || op == WC || op == NWC)
00286 recno = 1;
00287 else if (op == WC || op == NWC) {
00288 dbenv->errx(dbenv,
00289 "wildcard operator only supported for string fields");
00290 return (1);
00291 } else {
00292 recno = recno_ulong;
00293 if (op == GT)
00294 ++recno;
00295 }
00296 if ((ret = dbc->c_get(dbc, &key, &data, DB_SET)) != 0)
00297 goto err;
00298
00299 for (;;) {
00300 if ((ret = DbRecord_init(&key, &data, &record)) != 0)
00301 break;
00302 if (field_cmp_ulong(&record.recno, &recno_ulong, op))
00303 DbRecord_print(&record, NULL);
00304 else
00305 if (op == LT || op == LTEQ || op == EQ)
00306 break;
00307 if ((ret = dbc->c_get(dbc, &key, &data, DB_NEXT)) != 0)
00308 break;
00309 }
00310
00311 err: return (ret == DB_NOTFOUND ? 0 : ret);
00312 }
00313
00314
00315
00316
00317
00318 static int
00319 DbRecord_search_field(DbField *f, char *value, OPERATOR op)
00320 {
00321 #ifdef HAVE_WILDCARD_SUPPORT
00322 regex_t preq;
00323 #endif
00324 DBC *dbc;
00325 DbRecord record;
00326 DBT key, data, pkey;
00327 double value_double;
00328 u_long value_ulong;
00329 u_int32_t cursor_flags;
00330 int ret, t_ret;
00331 int (*cmp)(void *, void *, OPERATOR);
00332 void *faddr, *valuep;
00333
00334 dbc = NULL;
00335 memset(&key, 0, sizeof(key));
00336 memset(&pkey, 0, sizeof(pkey));
00337 memset(&data, 0, sizeof(data));
00338
00339
00340
00341
00342
00343 if (op == WC || op == NWC) {
00344 #ifdef HAVE_WILDCARD_SUPPORT
00345 if (f->type != STRING) {
00346 dbenv->errx(dbenv,
00347 "wildcard operator only supported for string fields");
00348 return (1);
00349 }
00350 if (regcomp(&preq, value, 0) != 0) {
00351 dbenv->errx(dbenv, "regcomp of pattern failed");
00352 return (1);
00353 }
00354 valuep = &preq;
00355 cmp = field_cmp_re;
00356 #else
00357 dbenv->errx(dbenv,
00358 "wildcard operators not supported in this build");
00359 return (1);
00360 #endif
00361 } else
00362 switch (f->type) {
00363 case DOUBLE:
00364 if (strtod_err(value, &value_double) != 0)
00365 return (1);
00366 cmp = field_cmp_double;
00367 valuep = &value_double;
00368 key.size = sizeof(double);
00369 break;
00370 case STRING:
00371 valuep = value;
00372 cmp = field_cmp_string;
00373 key.size = strlen(value);
00374 break;
00375 case ULONG:
00376 if (strtoul_err(value, &value_ulong) != 0)
00377 return (1);
00378 cmp = field_cmp_ulong;
00379 valuep = &value_ulong;
00380 key.size = sizeof(u_long);
00381 break;
00382 default:
00383 case NOTSET:
00384 abort();
00385
00386 }
00387
00388
00389
00390
00391
00392
00393
00394
00395
00396
00397
00398
00399
00400
00401
00402
00403
00404
00405
00406
00407
00408
00409
00410
00411 if (f->secondary == NULL || op == NEQ || op == WC || op == NWC) {
00412 if ((ret = db->cursor(db, NULL, &dbc, 0)) != 0)
00413 goto err;
00414 while ((ret = dbc->c_get(dbc, &key, &data, DB_NEXT)) == 0) {
00415 if ((ret = DbRecord_init(&key, &data, &record)) != 0)
00416 break;
00417 faddr = (u_int8_t *)&record + f->offset;
00418 if (cmp(faddr, valuep, op))
00419 DbRecord_print(&record, NULL);
00420 else
00421 if (op == EQ || op == LT || op == LTEQ)
00422 break;
00423 }
00424 } else {
00425 if ((ret =
00426 f->secondary->cursor(f->secondary, NULL, &dbc, 0)) != 0)
00427 goto err;
00428 key.data = valuep;
00429 cursor_flags = op == LT || op == LTEQ ? DB_FIRST : DB_SET_RANGE;
00430 if ((ret =
00431 dbc->c_pget(dbc, &key, &pkey, &data, cursor_flags)) != 0)
00432 goto done;
00433 if (op == GT) {
00434 while ((ret = dbc->c_pget(
00435 dbc, &key, &pkey, &data, DB_NEXT)) == 0) {
00436 if ((ret =
00437 DbRecord_init(&pkey, &data, &record)) != 0)
00438 break;
00439 faddr = (u_int8_t *)&record + f->offset;
00440 if (cmp(faddr, valuep, op) != 0)
00441 break;
00442 }
00443 if (ret != 0)
00444 goto done;
00445 }
00446 do {
00447 if ((ret = DbRecord_init(&pkey, &data, &record)) != 0)
00448 break;
00449 faddr = (u_int8_t *)&record + f->offset;
00450 if (cmp(faddr, valuep, op))
00451 DbRecord_print(&record, NULL);
00452 else
00453 if (op == EQ || op == LT || op == LTEQ)
00454 break;
00455 } while ((ret =
00456 dbc->c_pget(dbc, &key, &pkey, &data, DB_NEXT)) == 0);
00457 }
00458
00459 done: if (ret == DB_NOTFOUND)
00460 ret = 0;
00461
00462 err: if (dbc != NULL && (t_ret = dbc->c_close(dbc)) != 0 && ret == 0)
00463 ret = t_ret;
00464
00465 #ifdef HAVE_WILDCARD_SUPPORT
00466 if (op == WC || op == NWC)
00467 regfree(&preq);
00468 #endif
00469
00470 return (ret);
00471 }