annotate insert.cpp @ 441:1a1ea05a94ce api-inversion

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