| 301 | | } |
|---|
| 302 | | |
|---|
| 303 | | class SqlitePreparedStatement : IPreparedStatement |
|---|
| 304 | | { |
|---|
| 305 | | static Logger logger; |
|---|
| 306 | | static this() |
|---|
| 307 | | { |
|---|
| 308 | | logger = Log.getLogger("sendero.data.backends.Sqlite.SqlitePreparedStatement"); |
|---|
| 309 | | } |
|---|
| 310 | | |
|---|
| 311 | | private this(sqlite3_stmt* stmt, sqlite3* db) |
|---|
| 312 | | { |
|---|
| 313 | | this.stmt = stmt; |
|---|
| 314 | | this.db = db; |
|---|
| 315 | | } |
|---|
| 316 | | |
|---|
| 317 | | ~this() |
|---|
| 318 | | { |
|---|
| 319 | | sqlite3_finalize(stmt); |
|---|
| 320 | | } |
|---|
| 321 | | |
|---|
| 322 | | |
|---|
| 323 | | private sqlite3_stmt* stmt; |
|---|
| 324 | | package sqlite3* db; |
|---|
| 325 | | private BindType[] paramTypes; |
|---|
| 326 | | private BindType[] resTypes; |
|---|
| 327 | | private bool row = false; |
|---|
| 328 | | private bool wasReset = false; |
|---|
| 329 | | |
|---|
| 330 | | void setParamTypes(BindType[] paramTypes) |
|---|
| 331 | | { |
|---|
| 332 | | this.paramTypes = paramTypes; |
|---|
| 333 | | } |
|---|
| 334 | | |
|---|
| 335 | | void setResultTypes(BindType[] resTypes) |
|---|
| 336 | | { |
|---|
| 337 | | this.resTypes = resTypes; |
|---|
| 338 | | } |
|---|
| 339 | | |
|---|
| 340 | | bool execute(StatementBinder binder) |
|---|
| 341 | | { |
|---|
| 342 | | uint i = 0; |
|---|
| 343 | | foreach(p; paramTypes) |
|---|
| 344 | | { |
|---|
| 345 | | void* x; |
|---|
| 346 | | size_t len; |
|---|
| 347 | | binder(i, p, x, len); |
|---|
| 348 | | switch(p) |
|---|
| 349 | | { |
|---|
| 350 | | case BindType.Bool: |
|---|
| 351 | | if(sqlite3_bind_int(stmt, index + 1, *(cast(bool*)x)) != SQLITE_OK) return false; |
|---|
| 352 | | break; |
|---|
| 353 | | case BindType.Byte: |
|---|
| 354 | | if(sqlite3_bind_int(stmt, index + 1, *(cast(byte*)x)) != SQLITE_OK) return false; |
|---|
| 355 | | break; |
|---|
| 356 | | case BindType.Short: |
|---|
| 357 | | if(sqlite3_bind_int(stmt, index + 1, *(cast(short*)x)) != SQLITE_OK) return false; |
|---|
| 358 | | break; |
|---|
| 359 | | case BindType.Int: |
|---|
| 360 | | if(sqlite3_bind_int(stmt, index + 1, *(cast(int*)x)) != SQLITE_OK) return false; |
|---|
| 361 | | break; |
|---|
| 362 | | case BindType.Long: |
|---|
| 363 | | if(sqlite3_bind_int64(stmt, index + 1, *(cast(long*)x)) != SQLITE_OK) return false; |
|---|
| 364 | | break; |
|---|
| 365 | | case BindType.UByte: |
|---|
| 366 | | if(sqlite3_bind_int(stmt, index + 1, *(cast(bool*)x)) != SQLITE_OK) return false; |
|---|
| 367 | | break; |
|---|
| 368 | | case BindType.UShort: |
|---|
| 369 | | if(sqlite3_bind_int(stmt, index + 1, *(cast(ubyte*)x)) != SQLITE_OK) return false; |
|---|
| 370 | | break; |
|---|
| 371 | | case BindType.UInt: |
|---|
| 372 | | if(sqlite3_bind_int64(stmt, index + 1, *(cast(uint*)x)) != SQLITE_OK) return false; |
|---|
| 373 | | break; |
|---|
| 374 | | case BindType.ULong: |
|---|
| 375 | | if(sqlite3_bind_int64(stmt, index + 1, *(cast(ulong*)x)) != SQLITE_OK) return false; |
|---|
| 376 | | break; |
|---|
| 377 | | case BindType.Float: |
|---|
| 378 | | if(sqlite3_bind_double(stmt, index + 1, *(cast(float*)x)) != SQLITE_OK) return false; |
|---|
| 379 | | break; |
|---|
| 380 | | case BindType.Double: |
|---|
| 381 | | if(sqlite3_bind_double(stmt, index + 1, *(cast(double*)x)) != SQLITE_OK) return false; |
|---|
| 382 | | break; |
|---|
| 383 | | case BindType.String: |
|---|
| 384 | | if(sqlite3_bind_text(stmt, index + 1, *cast(char**)x, len, null) != SQLITE_OK) return false; |
|---|
| 385 | | break; |
|---|
| 386 | | case BindType.UByteArray: |
|---|
| 387 | | case BindType.VoidArray: |
|---|
| 388 | | if(sqlite3_bind_blob(stmt, index + 1, *cast(void**)x, len, null) != SQLITE_OK) return false; |
|---|
| 389 | | break; |
|---|
| 390 | | case BindType.DateTime: |
|---|
| 391 | | break; |
|---|
| 392 | | case BindType.Date: |
|---|
| 393 | | break; |
|---|
| 394 | | case BindType.Time: |
|---|
| 395 | | break; |
|---|
| 396 | | default: |
|---|
| 397 | | debug assert(false); |
|---|
| 398 | | break; |
|---|
| 399 | | } |
|---|
| 400 | | ++i; |
|---|
| 401 | | } |
|---|
| 402 | | |
|---|
| 403 | | int ret = sqlite3_step(stmt); |
|---|
| 404 | | wasReset = false; |
|---|
| 405 | | switch(ret) |
|---|
| 406 | | { |
|---|
| 407 | | case SQLITE_ROW: |
|---|
| 408 | | row = true; |
|---|
| 409 | | return true; |
|---|
| 410 | | case SQLITE_DONE: |
|---|
| 411 | | row = false; |
|---|
| 412 | | return true; |
|---|
| 413 | | case SQLITE_BUSY: |
|---|
| 414 | | default: |
|---|
| 415 | | row = false; |
|---|
| 416 | | return false; |
|---|
| 417 | | } |
|---|
| 418 | | } |
|---|
| 419 | | |
|---|
| 420 | | bool fetch(StatementBinder binder) |
|---|
| 421 | | { |
|---|
| 422 | | if(!row) return false; |
|---|
| 423 | | int ret = sqlite3_step(stmt); |
|---|
| 424 | | wasReset = false; |
|---|
| 425 | | |
|---|
| 426 | | uint index = 0; |
|---|
| 427 | | foreach(r; resTypes) |
|---|
| 428 | | { |
|---|
| 429 | | void* x; |
|---|
| 430 | | size_t len; |
|---|
| 431 | | binder(index, r, x, len); |
|---|
| 432 | | switch(p) |
|---|
| 433 | | { |
|---|
| 434 | | case BindType.Bool: |
|---|
| 435 | | int z = sqlite3_column_int(stmt, index); |
|---|
| 436 | | *cast(bool*)x = cast(bool)z; |
|---|
| 437 | | break; |
|---|
| 438 | | case BindType.Byte: |
|---|
| 439 | | int z = sqlite3_column_int(stmt, index); |
|---|
| 440 | | *cast(byte*)x = cast(byte)z; |
|---|
| 441 | | break; |
|---|
| 442 | | case BindType.Short: |
|---|
| 443 | | int z = sqlite3_column_int(stmt, index); |
|---|
| 444 | | *cast(short*)x = cast(short)z; |
|---|
| 445 | | break; |
|---|
| 446 | | case BindType.Int: |
|---|
| 447 | | int z = sqlite3_column_int(stmt, index); |
|---|
| 448 | | *cast(int*)x = z; |
|---|
| 449 | | break; |
|---|
| 450 | | case BindType.Long: |
|---|
| 451 | | long z = sqlite3_column_int64(stmt, index); |
|---|
| 452 | | *cast(long*)x = z; |
|---|
| 453 | | break; |
|---|
| 454 | | case BindType.UByte: |
|---|
| 455 | | int z = sqlite3_column_int(stmt, index); |
|---|
| 456 | | *cast(ubyte*)x = cast(ubyte)z; |
|---|
| 457 | | break; |
|---|
| 458 | | case BindType.UShort: |
|---|
| 459 | | int z = sqlite3_column_int(stmt, index); |
|---|
| 460 | | *cast(ushort*)x = cast(ushort)z; |
|---|
| 461 | | break; |
|---|
| 462 | | case BindType.UInt: |
|---|
| 463 | | long z = sqlite3_column_int64(stmt, index); |
|---|
| 464 | | *cast(uint*)x = cast(uint)z; |
|---|
| 465 | | break; |
|---|
| 466 | | case BindType.ULong: |
|---|
| 467 | | long z = sqlite3_column_int64(stmt, index); |
|---|
| 468 | | *cast(ulong*)x = cast(ulong)z; |
|---|
| 469 | | break; |
|---|
| 470 | | case BindType.Float: |
|---|
| 471 | | double z = sqlite3_column_int(stmt, index); |
|---|
| 472 | | *cast(float*)x = cast(float)z; |
|---|
| 473 | | break; |
|---|
| 474 | | case BindType.Double: |
|---|
| 475 | | double z = sqlite3_column_int(stmt, index); |
|---|
| 476 | | *cast(double*)x = z; |
|---|
| 477 | | break; |
|---|
| 478 | | case BindType.String: |
|---|
| 479 | | char[] z = fromCStringz(sqlite3_column_text(stmt, index)); |
|---|
| 480 | | *cast(char**)x = z.ptr; |
|---|
| 481 | | len = z.length; |
|---|
| 482 | | break; |
|---|
| 483 | | case BindType.UByteArray: |
|---|
| 484 | | case BindType.VoidArray: |
|---|
| 485 | | void* res = sqlite3_column_blob(stmt, index); |
|---|
| 486 | | len = sqlite3_column_bytes(stmt, index); |
|---|
| 487 | | *cast(char**)x = len ? res[0 .. len] : null; |
|---|
| 488 | | break; |
|---|
| 489 | | case BindType.DateTime: |
|---|
| 490 | | break; |
|---|
| 491 | | case BindType.Date: |
|---|
| 492 | | break; |
|---|
| 493 | | case BindType.Time: |
|---|
| 494 | | break; |
|---|
| 495 | | default: |
|---|
| 496 | | debug assert(false); |
|---|
| 497 | | break; |
|---|
| 498 | | } |
|---|
| 499 | | ++i; |
|---|
| 500 | | } |
|---|
| 501 | | |
|---|
| 502 | | row = (ret == SQLITE_ROW); |
|---|
| 503 | | return true; |
|---|
| 504 | | } |
|---|
| 505 | | |
|---|
| 506 | | void reset() |
|---|
| 507 | | { |
|---|
| 508 | | if(!wasReset) { |
|---|
| 509 | | sqlite3_reset(stmt); |
|---|
| 510 | | wasReset = true; |
|---|
| 511 | | } |
|---|
| 512 | | } |
|---|
| 513 | | |
|---|
| 514 | | ulong getLastInsertID() |
|---|
| 515 | | { |
|---|
| 516 | | long id = sqlite3_last_insert_rowid(db); |
|---|
| 517 | | return cast(ulong)id; |
|---|
| 518 | | } |
|---|
| 519 | | } |
|---|
| 520 | | |
|---|
| 521 | | static this() { |
|---|
| 522 | | auto logger = Log.getLogger("dbi.sqlite"); |
|---|
| 523 | | logger.trace("Attempting to register SqliteDatabase in Registry"); |
|---|
| 524 | | registerDatabase(new SqliteRegister()); |
|---|