annotate insert.cpp @ 473:b2fd8113d8bc api-inversion

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