annotate insert.cpp @ 507:e7fd50483311

Free bits of the datum constructed in audioDB::query. We're not quite safe: error calls between allocation of some of these bits and pieces and their use will cause failure... but not freeing things here is definitely wrong.
author mas01cr
date Tue, 13 Jan 2009 21:37:10 +0000
parents 342822c2d49a
children cc2b97d020b1
rev   line source
mas01cr@239 1 #include "audioDB.h"
mas01cr@498 2 extern "C" {
mas01cr@498 3 #include "audioDB_API.h"
mas01cr@498 4 }
mas01cr@498 5 #include "audioDB-internals.h"
mas01cr@239 6
mas01cr@498 7 static bool audiodb_enough_data_space_free(adb_t *adb, off_t size) {
mas01cr@498 8 adb_header_t *header = adb->header;
mas01cr@498 9 if(header->flags & O2_FLAG_LARGE_ADB) {
mas01cr@498 10 return true;
mas01cr@498 11 } else {
mas01cr@498 12 /* FIXME: timesTableOffset isn't necessarily the next biggest
mas01cr@498 13 * offset after dataOffset. Maybe make the offsets into an array
mas01cr@498 14 * that we can iterate over... */
mas01cr@498 15 return (header->timesTableOffset >
mas01cr@498 16 (header->dataOffset + header->length + size));
mas01cr@239 17 }
mas01cr@239 18 }
mas01cr@239 19
mas01cr@498 20 static bool audiodb_enough_per_file_space_free(adb_t *adb) {
mas01cr@498 21 /* FIXME: the comment above about the ordering of the tables applies
mas01cr@498 22 here too. */
mas01cr@498 23 adb_header_t *header = adb->header;
mas01cr@498 24 off_t file_table_length = header->trackTableOffset - header->fileTableOffset;
mas01cr@498 25 off_t track_table_length = header->dataOffset - header->trackTableOffset;
mas01cr@498 26 int fmaxfiles = file_table_length / O2_FILETABLE_ENTRY_SIZE;
mas01cr@498 27 int tmaxfiles = track_table_length / O2_TRACKTABLE_ENTRY_SIZE;
mas01cr@498 28 /* maxfiles is the _minimum_ of the two. Do not be confused... */
mas01cr@498 29 int maxfiles = fmaxfiles > tmaxfiles ? tmaxfiles : fmaxfiles;
mas01cr@498 30 if(header->flags & O2_FLAG_LARGE_ADB) {
mas01cr@498 31 /* by default, these tables are created with the same size as the
mas01cr@498 32 * fileTable (which should be called key_table); relying on that
mas01cr@498 33 * always being the case, though, smacks of optimism, so instead
mas01cr@498 34 * we code defensively... */
mas01cr@498 35 off_t data_table_length = header->timesTableOffset - header->dataOffset;
mas01cr@498 36 off_t times_table_length = header->powerTableOffset - header->timesTableOffset;
mas01cr@498 37 off_t power_table_length = header->dbSize - header->powerTableOffset;
mas01cr@498 38 int dmaxfiles = data_table_length / O2_FILETABLE_ENTRY_SIZE;
mas01cr@498 39 int timaxfiles = times_table_length / O2_FILETABLE_ENTRY_SIZE;
mas01cr@498 40 int pmaxfiles = power_table_length / O2_FILETABLE_ENTRY_SIZE;
mas01cr@498 41 /* ... even though it means a certain amount of tedium. */
mas01cr@498 42 maxfiles = maxfiles > dmaxfiles ? dmaxfiles : maxfiles;
mas01cr@498 43 maxfiles = maxfiles > timaxfiles ? timaxfiles : maxfiles;
mas01cr@498 44 maxfiles = maxfiles > pmaxfiles ? pmaxfiles : maxfiles;
mas01cr@498 45 }
mas01cr@498 46 return (header->numFiles < (unsigned int) maxfiles);
mas01cr@498 47 }
mas01cr@498 48
mas01cr@498 49 /*
mas01cr@498 50 * Hey, look, a comment. Normally I wouldn't bother, as the code
mas01cr@498 51 * should be self-documenting, but a lot of logic is concentrated in
mas01cr@498 52 * this one place, so let's give an overview beforehand. To insert a
mas01cr@498 53 * datum into the database, we:
mas01cr@498 54 *
mas01cr@498 55 * 1. check write permission;
mas01cr@498 56 * 2. check for enough space;
mas01cr@498 57 * 3. check that datum->dim and adb->header->dim agree (or that the
mas01cr@498 58 * header dimension is zero, in which case write datum->dim to
mas01cr@498 59 * adb->header->dim).
mas01cr@498 60 * 4. check for presence of datum->key in adb->keymap;
mas01cr@498 61 * 5. check for consistency between power and O2_FLAG_POWER, and
mas01cr@498 62 * times and O2_FLAG_TIMES;
mas01cr@498 63 * 6. write in data, power, times as appropriate; add to track
mas01cr@498 64 * and key tables too;
mas01cr@498 65 * 7. if O2_FLAG_L2NORM and !O2_FLAG_LARGE_ADB, compute norms and fill
mas01cr@498 66 * in table;
mas01cr@498 67 * 8. update adb->keys, adb->keymap, adb->track_lengths,
mas01cr@498 68 * adb->track_offsets and adb->header;
mas01cr@498 69 * 9. sync adb->header with disk.
mas01cr@498 70 *
mas01cr@498 71 * Step 9 essentially commits the transaction; until we update
mas01cr@498 72 * header->length, nothing will recognize the newly-written data. In
mas01cr@498 73 * principle, if it fails, we should roll back, which we can in fact
mas01cr@498 74 * do on the assumption that nothing in step 8 can ever fail; on the
mas01cr@498 75 * other hand, if it's failed, then it's unlikely that rolling back by
mas01cr@498 76 * syncing the original header back to disk is going to work
mas01cr@498 77 * desperately well. We should perhaps take an operating-system lock
mas01cr@498 78 * around step 9, so that we can't be interrupted part-way through
mas01cr@498 79 * (except of course for SIGKILL, but if we're hit with that we will
mas01cr@498 80 * always lose).
mas01cr@498 81 */
mas01cr@498 82 static int audiodb_insert_datum_internal(adb_t *adb, adb_datum_internal_t *datum) {
mas01cr@498 83
mas01cr@498 84 off_t size, offset, nfiles;
mas01cr@498 85 double *l2norm_buffer = NULL;
mas01cr@498 86
mas01cr@498 87 /* 1. check write permission; */
mas01cr@498 88 if(!(adb->flags & O_RDWR)) {
mas01cr@498 89 return 1;
mas01cr@498 90 }
mas01cr@498 91 /* 2. check for enough space; */
mas01cr@498 92 size = sizeof(double) * datum->nvectors * datum->dim;
mas01cr@498 93 if(!audiodb_enough_data_space_free(adb, size)) {
mas01cr@498 94 return 1;
mas01cr@498 95 }
mas01cr@498 96 if(!audiodb_enough_per_file_space_free(adb)) {
mas01cr@498 97 return 1;
mas01cr@498 98 }
mas01cr@498 99 /* 3. check that datum->dim and adb->header->dim agree (or that the
mas01cr@498 100 * header dimension is zero, in which case write datum->dim to
mas01cr@498 101 * adb->header->dim).
mas01cr@498 102 */
mas01cr@498 103 if(adb->header->dim == 0) {
mas01cr@498 104 adb->header->dim = datum->dim;
mas01cr@498 105 } else if (adb->header->dim != datum->dim) {
mas01cr@498 106 return 1;
mas01cr@498 107 }
mas01cr@498 108 /* 4. check for presence of datum->key in adb->keymap; */
mas01cr@498 109 if(adb->keymap->count(datum->key)) {
mas01cr@498 110 /* not part of an explicit API/ABI, but we need a distinguished
mas01cr@498 111 value in this circumstance to preserve somewhat wonky behaviour
mas01cr@498 112 of audioDB::batchinsert. */
mas01cr@498 113 return 2;
mas01cr@498 114 }
mas01cr@498 115 /* 5. check for consistency between power and O2_FLAG_POWER, and
mas01cr@498 116 * times and O2_FLAG_TIMES;
mas01cr@498 117 */
mas01cr@498 118 if((datum->power && !(adb->header->flags & O2_FLAG_POWER)) ||
mas01cr@498 119 ((adb->header->flags & O2_FLAG_POWER) && !datum->power)) {
mas01cr@498 120 return 1;
mas01cr@498 121 }
mas01cr@498 122 if(datum->times && !(adb->header->flags & O2_FLAG_TIMES)) {
mas01cr@498 123 if(adb->header->numFiles == 0) {
mas01cr@498 124 adb->header->flags |= O2_FLAG_TIMES;
mas01cr@498 125 } else {
mas01cr@498 126 return 1;
mas01cr@239 127 }
mas01cr@498 128 } else if ((adb->header->flags & O2_FLAG_TIMES) && !datum->times) {
mas01cr@498 129 return 1;
mas01cr@498 130 }
mas01cr@498 131 /* 6. write in data, power, times as appropriate; add to track
mas01cr@498 132 * and key tables too;
mas01cr@498 133 */
mas01cr@498 134 offset = adb->header->length;
mas01cr@498 135 nfiles = adb->header->numFiles;
mas01cr@498 136
mas01cr@498 137 /* FIXME: checking for all these lseek()s */
mas01cr@498 138 lseek(adb->fd, adb->header->fileTableOffset + nfiles * O2_FILETABLE_ENTRY_SIZE, SEEK_SET);
mas01cr@498 139 write_or_goto_error(adb->fd, datum->key, strlen(datum->key)+1);
mas01cr@498 140 lseek(adb->fd, adb->header->trackTableOffset + nfiles * O2_TRACKTABLE_ENTRY_SIZE, SEEK_SET);
mas01cr@498 141 write_or_goto_error(adb->fd, &datum->nvectors, O2_TRACKTABLE_ENTRY_SIZE);
mas01cr@498 142 if(adb->header->flags & O2_FLAG_LARGE_ADB) {
mas01cr@498 143 char cwd[PATH_MAX];
mas01cr@498 144 char slash = '/';
mas01cr@498 145
mas01cr@498 146 if(!getcwd(cwd, PATH_MAX)) {
mas01cr@498 147 goto error;
mas01cr@498 148 }
mas01cr@498 149 lseek(adb->fd, adb->header->dataOffset + nfiles * O2_FILETABLE_ENTRY_SIZE, SEEK_SET);
mas01cr@498 150 if(*((char *) datum->data) != '/') {
mas01cr@498 151 write_or_goto_error(adb->fd, cwd, strlen(cwd));
mas01cr@498 152 write_or_goto_error(adb->fd, &slash, 1);
mas01cr@498 153 }
mas01cr@498 154 write_or_goto_error(adb->fd, datum->data, strlen((const char *) datum->data)+1);
mas01cr@498 155 if(datum->power) {
mas01cr@498 156 lseek(adb->fd, adb->header->powerTableOffset + nfiles * O2_FILETABLE_ENTRY_SIZE, SEEK_SET);
mas01cr@498 157 if(*((char *) datum->power) != '/') {
mas01cr@498 158 write_or_goto_error(adb->fd, cwd, strlen(cwd));
mas01cr@498 159 write_or_goto_error(adb->fd, &slash, 1);
mas01cr@498 160 }
mas01cr@498 161 write_or_goto_error(adb->fd, datum->power, strlen((const char *) datum->power)+1);
mas01cr@498 162 }
mas01cr@498 163 if(datum->times) {
mas01cr@498 164 lseek(adb->fd, adb->header->timesTableOffset + nfiles * O2_FILETABLE_ENTRY_SIZE, SEEK_SET);
mas01cr@498 165 if(*((char *) datum->times) != '/') {
mas01cr@498 166 write_or_goto_error(adb->fd, cwd, strlen(cwd));
mas01cr@498 167 write_or_goto_error(adb->fd, &slash, 1);
mas01cr@498 168 }
mas01cr@498 169 write_or_goto_error(adb->fd, datum->times, strlen((const char *) datum->times)+1);
mas01cr@498 170 }
mas01cr@498 171 } else {
mas01cr@498 172 lseek(adb->fd, adb->header->dataOffset + offset, SEEK_SET);
mas01cr@498 173 write_or_goto_error(adb->fd, datum->data, sizeof(double) * datum->nvectors * datum->dim);
mas01cr@498 174 if(datum->power) {
mas01cr@498 175 lseek(adb->fd, adb->header->powerTableOffset + offset / datum->dim, SEEK_SET);
mas01cr@498 176 write_or_goto_error(adb->fd, datum->power, sizeof(double) * datum->nvectors);
mas01cr@498 177 }
mas01cr@498 178 if(datum->times) {
mas01cr@498 179 lseek(adb->fd, adb->header->timesTableOffset + offset / datum->dim * 2, SEEK_SET);
mas01cr@498 180 write_or_goto_error(adb->fd, datum->times, sizeof(double) * datum->nvectors * 2);
mas01cr@498 181 }
mas01cr@498 182 }
mas01cr@498 183
mas01cr@498 184 /* 7. if O2_FLAG_L2NORM and !O2_FLAG_LARGE_ADB, compute norms and fill
mas01cr@498 185 * in table;
mas01cr@498 186 */
mas01cr@498 187 if((adb->header->flags & O2_FLAG_L2NORM) &&
mas01cr@498 188 !(adb->header->flags & O2_FLAG_LARGE_ADB)) {
mas01cr@498 189 l2norm_buffer = (double *) malloc(datum->nvectors * sizeof(double));
mas01mc@324 190
mas01cr@498 191 audiodb_l2norm_buffer((double *) datum->data, datum->dim, datum->nvectors, l2norm_buffer);
mas01cr@498 192 lseek(adb->fd, adb->header->l2normTableOffset + offset / datum->dim, SEEK_SET);
mas01cr@498 193 write_or_goto_error(adb->fd, l2norm_buffer, sizeof(double) * datum->nvectors);
mas01cr@498 194 free(l2norm_buffer);
mas01cr@498 195 l2norm_buffer = NULL;
mas01cr@498 196 }
mas01cr@498 197
mas01cr@498 198 /* 8. update adb->keys, adb->keymap, adb->track_lengths,
mas01cr@498 199 * adb->track_offsets and adb->header;
mas01cr@498 200 */
mas01cr@498 201 adb->keys->push_back(datum->key);
mas01cr@498 202 (*adb->keymap)[datum->key] = adb->header->numFiles;
mas01cr@498 203 adb->track_lengths->push_back(datum->nvectors);
mas01cr@498 204 adb->track_offsets->push_back(offset);
mas01cr@498 205 adb->header->numFiles += 1;
mas01cr@498 206 adb->header->length += sizeof(double) * datum->nvectors * datum->dim;
mas01cr@498 207
mas01cr@498 208 /* 9. sync adb->header with disk. */
mas01cr@498 209 return audiodb_sync_header(adb);
mas01cr@498 210
mas01cr@498 211 error:
mas01cr@498 212 if(l2norm_buffer) {
mas01cr@498 213 free(l2norm_buffer);
mas01cr@498 214 }
mas01cr@498 215 return 1;
mas01cr@498 216 }
mas01cr@498 217
mas01cr@498 218 int audiodb_insert_datum(adb_t *adb, const adb_datum_t *datum) {
mas01cr@498 219 if(adb->header->flags & O2_FLAG_LARGE_ADB) {
mas01cr@498 220 return 1;
mas01cr@498 221 } else {
mas01cr@498 222 adb_datum_internal_t d;
mas01cr@498 223 d.nvectors = datum->nvectors;
mas01cr@498 224 d.dim = datum->dim;
mas01cr@498 225 d.key = datum->key;
mas01cr@498 226 d.data = datum->data;
mas01cr@498 227 d.times = datum->times;
mas01cr@498 228 d.power = datum->power;
mas01cr@498 229 return audiodb_insert_datum_internal(adb, &d);
mas01cr@498 230 }
mas01cr@498 231 }
mas01cr@498 232
mas01cr@498 233 int audiodb_insert_reference(adb_t *adb, const adb_reference_t *reference) {
mas01cr@498 234 if(!(adb->header->flags & O2_FLAG_LARGE_ADB)) {
mas01cr@498 235 return 1;
mas01cr@498 236 } else {
mas01cr@498 237 adb_datum_internal_t d;
mas01cr@498 238 struct stat st;
mas01cr@498 239 int fd;
mas01cr@498 240 off_t size;
mas01mc@324 241
mas01cr@498 242 if((fd = open(reference->features, O_RDONLY)) == -1) {
mas01cr@498 243 return 1;
mas01cr@239 244 }
mas01cr@498 245 if(fstat(fd, &st)) {
mas01cr@498 246 goto error;
mas01cr@239 247 }
mas01cr@498 248 read_or_goto_error(fd, &(d.dim), sizeof(uint32_t));
mas01cr@498 249 close(fd);
mas01cr@498 250 fd = 0;
mas01cr@498 251 size = st.st_size - sizeof(uint32_t);
mas01cr@498 252 d.nvectors = size / (sizeof(double) * d.dim);
mas01cr@498 253 d.data = (void *) reference->features;
mas01cr@498 254 if(reference->power) {
mas01cr@498 255 if(stat(reference->power, &st)) {
mas01cr@498 256 return 1;
mas01cr@498 257 }
mas01cr@498 258 }
mas01cr@498 259 d.power = (void *) reference->power;
mas01cr@498 260 if(reference->times) {
mas01cr@498 261 if(stat(reference->times, &st)) {
mas01cr@498 262 return 1;
mas01cr@498 263 }
mas01cr@498 264 }
mas01cr@498 265 d.times = (void *) reference->times;
mas01cr@498 266 d.key = reference->key ? reference->key : reference->features;
mas01cr@498 267 return audiodb_insert_datum_internal(adb, &d);
mas01cr@498 268 error:
mas01cr@498 269 if(fd) {
mas01cr@498 270 close(fd);
mas01cr@498 271 }
mas01cr@498 272 return 1;
mas01cr@498 273 }
mas01cr@498 274 }
mas01cr@498 275
mas01cr@498 276 int audiodb_free_datum(adb_datum_t *datum) {
mas01cr@498 277 if(datum->data) {
mas01cr@498 278 free(datum->data);
mas01cr@498 279 datum->data = NULL;
mas01cr@498 280 }
mas01cr@498 281 if(datum->power) {
mas01cr@498 282 free(datum->power);
mas01cr@498 283 datum->power = NULL;
mas01cr@498 284 }
mas01cr@498 285 if(datum->times) {
mas01cr@498 286 free(datum->times);
mas01cr@498 287 datum->times = NULL;
mas01cr@498 288 }
mas01cr@498 289 return 0;
mas01cr@498 290 }
mas01cr@498 291
mas01cr@498 292 int audiodb_insert_create_datum(adb_insert_t *insert, adb_datum_t *datum) {
mas01cr@498 293 int fd = 0;
mas01cr@498 294 FILE *file = NULL;
mas01cr@498 295 struct stat st;
mas01cr@498 296 off_t size;
mas01cr@498 297
mas01cr@498 298 datum->data = NULL;
mas01cr@498 299 datum->power = NULL;
mas01cr@498 300 datum->times = NULL;
mas01cr@498 301 if((fd = open(insert->features, O_RDONLY)) == -1) {
mas01cr@498 302 goto error;
mas01cr@498 303 }
mas01cr@498 304 if(fstat(fd, &st)) {
mas01cr@498 305 goto error;
mas01cr@498 306 }
mas01cr@498 307 read_or_goto_error(fd, &(datum->dim), sizeof(uint32_t));
mas01cr@498 308 size = st.st_size - sizeof(uint32_t);
mas01cr@498 309 datum->nvectors = size / (sizeof(double) * datum->dim);
mas01cr@498 310 datum->data = (double *) malloc(size);
mas01cr@498 311 if(!datum->data) {
mas01cr@498 312 goto error;
mas01cr@498 313 }
mas01cr@498 314 read_or_goto_error(fd, datum->data, size);
mas01cr@498 315 close(fd);
mas01cr@498 316 fd = 0;
mas01cr@498 317 if(insert->power) {
mas01cr@498 318 int dim;
mas01cr@498 319 if((fd = open(insert->power, O_RDONLY)) == -1) {
mas01cr@498 320 goto error;
mas01cr@498 321 }
mas01cr@498 322 if(fstat(fd, &st)) {
mas01cr@498 323 goto error;
mas01cr@498 324 }
mas01cr@498 325 /* This cast is so non-trivial that it deserves a comment.
mas01cr@498 326 *
mas01cr@498 327 * The data types in this expression, left to right, are: off_t,
mas01cr@498 328 * size_t, off_t, uint32_t. The rules for conversions in
mas01cr@498 329 * arithmetic expressions with mixtures of integral types are
mas01cr@498 330 * essentially that the widest type wins, with unsigned types
mas01cr@498 331 * winning on a tie-break.
mas01cr@498 332 *
mas01cr@498 333 * Because we are enforcing (through the use of sufficient
mas01cr@498 334 * compiler flags, if necessary) that off_t be a (signed) 64-bit
mas01cr@498 335 * type, the only variability in this set of types is in fact the
mas01cr@498 336 * size_t. On 32-bit machines, size_t is uint32_t and so the
mas01cr@498 337 * coercions on both sides of the equality end up promoting
mas01cr@498 338 * everything to int64_t, which is fine. On 64-bit machines,
mas01cr@498 339 * however, the left hand side is promoted to a uint64_t, while
mas01cr@498 340 * the right hand side remains int64_t.
mas01cr@498 341 *
mas01cr@498 342 * The mixture of signed and unsigned types in comparisons is Evil
mas01cr@498 343 * Bad and Wrong, and gcc complains about it. (It's right to do
mas01cr@498 344 * so, actually). Of course in this case it will never matter
mas01cr@498 345 * because of the particular relationships between all of these
mas01cr@498 346 * numbers, so we just cast the left hand side to off_t, which
mas01cr@498 347 * will do the right thing for us on all platforms.
mas01cr@498 348 *
mas01cr@498 349 * I hate C.
mas01cr@498 350 */
mas01cr@498 351 if(((off_t) (st.st_size - sizeof(uint32_t))) != (size / datum->dim)) {
mas01cr@498 352 goto error;
mas01cr@498 353 }
mas01cr@498 354 read_or_goto_error(fd, &dim, sizeof(uint32_t));
mas01cr@498 355 if(dim != 1) {
mas01cr@498 356 goto error;
mas01cr@498 357 }
mas01cr@498 358 datum->power = (double *) malloc(size / datum->dim);
mas01cr@498 359 if(!datum->power) {
mas01cr@498 360 goto error;
mas01cr@498 361 }
mas01cr@498 362 read_or_goto_error(fd, datum->power, size / datum->dim);
mas01cr@498 363 close(fd);
mas01cr@498 364 }
mas01cr@498 365 if(insert->times) {
mas01cr@498 366 double t, *tp;
mas01cr@498 367 if(!(file = fopen(insert->times, "r"))) {
mas01cr@498 368 goto error;
mas01cr@498 369 }
mas01cr@498 370 datum->times = (double *) malloc(2 * size / datum->dim);
mas01cr@498 371 if(!datum->times) {
mas01cr@498 372 goto error;
mas01cr@498 373 }
mas01cr@498 374 if(fscanf(file, " %lf", &t) != 1) {
mas01cr@498 375 goto error;
mas01cr@498 376 }
mas01cr@498 377 tp = datum->times;
mas01cr@498 378 *tp++ = t;
mas01cr@498 379 for(unsigned int n = 0; n < datum->nvectors - 1; n++) {
mas01cr@498 380 if(fscanf(file, " %lf", &t) != 1) {
mas01cr@498 381 goto error;
mas01cr@498 382 }
mas01cr@498 383 *tp++ = t;
mas01cr@498 384 *tp++ = t;
mas01cr@498 385 }
mas01cr@498 386 if(fscanf(file, " %lf", &t) != 1) {
mas01cr@498 387 goto error;
mas01cr@498 388 }
mas01cr@498 389 *tp = t;
mas01cr@498 390 fclose(file);
mas01cr@498 391 }
mas01cr@498 392 datum->key = insert->key ? insert->key : insert->features;
mas01cr@498 393 return 0;
mas01cr@498 394
mas01cr@498 395 error:
mas01cr@498 396 if(fd > 0) {
mas01cr@498 397 close(fd);
mas01cr@498 398 }
mas01cr@498 399 if(file) {
mas01cr@498 400 fclose(file);
mas01cr@498 401 }
mas01cr@498 402 audiodb_free_datum(datum);
mas01cr@498 403 return 1;
mas01cr@498 404 }
mas01cr@498 405
mas01cr@498 406 int audiodb_insert(adb_t *adb, adb_insert_t *insert) {
mas01cr@498 407 if(adb->header->flags & O2_FLAG_LARGE_ADB) {
mas01cr@498 408 adb_reference_t *reference = insert;
mas01cr@498 409 int err;
mas01cr@498 410 err = audiodb_insert_reference(adb, reference);
mas01cr@498 411
mas01cr@498 412 if(err == 2) {
mas01cr@498 413 return 0;
mas01cr@498 414 } else {
mas01cr@498 415 return err;
mas01cr@498 416 }
mas01cr@498 417 } else {
mas01cr@498 418 adb_datum_t datum;
mas01cr@498 419 int err;
mas01cr@498 420
mas01cr@498 421 if(audiodb_insert_create_datum(insert, &datum)) {
mas01cr@498 422 return 1;
mas01cr@498 423 }
mas01cr@498 424 err = audiodb_insert_datum(adb, &datum);
mas01cr@498 425 audiodb_free_datum(&datum);
mas01cr@498 426
mas01cr@498 427 if(err == 2) {
mas01cr@498 428 return 0;
mas01cr@498 429 } else {
mas01cr@498 430 return err;
mas01cr@239 431 }
mas01cr@239 432 }
mas01cr@239 433 }
mas01cr@239 434
mas01cr@498 435 int audiodb_batchinsert(adb_t *adb, adb_insert_t *insert, unsigned int size) {
mas01cr@498 436 int err;
mas01cr@498 437 for(unsigned int n = 0; n < size; n++) {
mas01cr@498 438 if((err = audiodb_insert(adb, &(insert[n])))) {
mas01cr@498 439 return err;
mas01cr@498 440 }
mas01mc@324 441 }
mas01cr@498 442 return 0;
mas01cr@239 443 }