|
26 | 26 | import android.database.sqlite.SQLiteCantOpenDatabaseException; |
27 | 27 | import android.database.sqlite.SQLiteCursor; |
28 | 28 | import android.database.sqlite.SQLiteDatabase; |
| 29 | +import android.database.sqlite.SQLiteStatement; |
29 | 30 | import android.os.Build; |
30 | 31 | import android.util.Log; |
31 | 32 |
|
@@ -431,6 +432,28 @@ private boolean executeOrError(Operation operation) { |
431 | 432 | } |
432 | 433 | } |
433 | 434 |
|
| 435 | + private void bindArgs(SQLiteStatement stmt, Object[] args) { |
| 436 | + for (int i = 0; i < args.length; i++) { |
| 437 | + Object arg = args[i]; |
| 438 | + int index = i + 1; // SQLite parameters are 1-based |
| 439 | + |
| 440 | + if (arg == null) { |
| 441 | + stmt.bindNull(index); |
| 442 | + } else if (arg instanceof byte[]) { |
| 443 | + stmt.bindBlob(index, (byte[]) arg); |
| 444 | + } else if (arg instanceof Double || arg instanceof Float) { |
| 445 | + stmt.bindDouble(index, ((Number) arg).doubleValue()); |
| 446 | + } else if (arg instanceof Number) { |
| 447 | + stmt.bindLong(index, ((Number) arg).longValue()); |
| 448 | + } else if (arg instanceof Boolean) { |
| 449 | + stmt.bindLong(index, ((Boolean) arg) ? 1 : 0); |
| 450 | + } else { |
| 451 | + stmt.bindString(index, arg.toString()); |
| 452 | + } |
| 453 | + } |
| 454 | + } |
| 455 | + |
| 456 | + |
434 | 457 | /** |
435 | 458 | * Handle inTransactionChange |
436 | 459 | * |
@@ -481,98 +504,55 @@ public void insert(final Operation operation) { |
481 | 504 |
|
482 | 505 | // Return true on success |
483 | 506 | private boolean doInsert(final Operation operation) { |
484 | | - if (!executeOrError(operation)) { |
485 | | - return false; |
486 | | - } |
487 | | - // don't get last id if not expected |
488 | | - if (operation.getNoResult()) { |
489 | | - operation.success(null); |
490 | | - return true; |
| 507 | + SqlCommand command = operation.getSqlCommand(); |
| 508 | + if (LogLevel.hasSqlLevel(logLevel)) { |
| 509 | + Log.d(TAG, getThreadLogPrefix() + command); |
491 | 510 | } |
492 | 511 |
|
493 | | - Cursor cursor = null; |
494 | | - // Read both the changes and last insert row id in on sql call |
495 | | - String sql = "SELECT changes(), last_insert_rowid()"; |
496 | | - |
497 | | - // Handle ON CONFLICT but ignore error, issue #164 |
498 | | - // Read the number of changes before getting the inserted id |
499 | 512 | try { |
500 | 513 | SQLiteDatabase db = getWritableDatabase(); |
501 | | - |
502 | | - cursor = db.rawQuery(sql, null); |
503 | | - if (cursor != null && cursor.getCount() > 0 && cursor.moveToFirst()) { |
504 | | - final int changed = cursor.getInt(0); |
505 | | - |
506 | | - // If the change count is 0, assume the insert failed |
507 | | - // and return null |
508 | | - if (changed == 0) { |
509 | | - if (LogLevel.hasSqlLevel(logLevel)) { |
510 | | - Log.d(TAG, getThreadLogPrefix() + "no changes (id was " + cursor.getLong(1) + ")"); |
511 | | - } |
512 | | - operation.success(null); |
513 | | - return true; |
514 | | - } else { |
515 | | - final long id = cursor.getLong(1); |
516 | | - if (LogLevel.hasSqlLevel(logLevel)) { |
517 | | - Log.d(TAG, getThreadLogPrefix() + "inserted " + id); |
518 | | - } |
519 | | - operation.success(id); |
520 | | - return true; |
521 | | - } |
| 514 | + /// create statement |
| 515 | + SQLiteStatement statement = db.compileStatement(command.getSql()); |
| 516 | + bindArgs(statement, command.getSqlArguments()); |
| 517 | + long id = statement.executeInsert(); |
| 518 | + if (operation.getNoResult()) { |
| 519 | + operation.success(null); |
522 | 520 | } else { |
523 | | - Log.e(TAG, getThreadLogPrefix() + "fail to read changes for Insert"); |
| 521 | + operation.success(id); |
524 | 522 | } |
525 | | - operation.success(null); |
526 | 523 | return true; |
527 | 524 | } catch (Exception exception) { |
528 | 525 | handleException(exception, operation); |
529 | 526 | return false; |
530 | | - } finally { |
531 | | - if (cursor != null) { |
532 | | - cursor.close(); |
533 | | - } |
534 | 527 | } |
535 | 528 | } |
536 | 529 |
|
537 | | - |
538 | 530 | public void update(final @NonNull Operation operation) { |
539 | 531 | wrapSqlOperationHandler(operation, () -> doUpdate(operation)); |
540 | 532 | } |
541 | 533 |
|
542 | 534 | // Return true on success |
543 | 535 | private boolean doUpdate(final Operation operation) { |
544 | | - if (!executeOrError(operation)) { |
545 | | - return false; |
546 | | - } |
547 | | - // don't get last id if not expected |
548 | | - if (operation.getNoResult()) { |
549 | | - operation.success(null); |
550 | | - return true; |
| 536 | + SqlCommand command = operation.getSqlCommand(); |
| 537 | + if (LogLevel.hasSqlLevel(logLevel)) { |
| 538 | + Log.d(TAG, getThreadLogPrefix() + command); |
551 | 539 | } |
552 | | - Cursor cursor = null; |
| 540 | + |
553 | 541 | try { |
554 | 542 | SQLiteDatabase db = getWritableDatabase(); |
555 | | - |
556 | | - cursor = db.rawQuery("SELECT changes()", null); |
557 | | - if (cursor != null && cursor.getCount() > 0 && cursor.moveToFirst()) { |
558 | | - final int changed = cursor.getInt(0); |
559 | | - if (LogLevel.hasSqlLevel(logLevel)) { |
560 | | - Log.d(TAG, getThreadLogPrefix() + "changed " + changed); |
561 | | - } |
562 | | - operation.success(changed); |
563 | | - return true; |
| 543 | + /// create statement |
| 544 | + SQLiteStatement statement = db.compileStatement(command.getSql()); |
| 545 | + bindArgs(statement, command.getSqlArguments()); |
| 546 | + int count = statement.executeUpdateDelete(); |
| 547 | + if (operation.getNoResult()) { |
| 548 | + operation.success(null); |
564 | 549 | } else { |
565 | | - Log.e(TAG, getThreadLogPrefix() + "fail to read changes for Update/Delete"); |
| 550 | + operation.success(count); |
566 | 551 | } |
567 | | - operation.success(null); |
568 | 552 | return true; |
569 | | - } catch (Exception e) { |
570 | | - handleException(e, operation); |
| 553 | + } catch (Exception exception) { |
| 554 | + handleException(exception, operation); |
571 | 555 | return false; |
572 | | - } finally { |
573 | | - if (cursor != null) { |
574 | | - cursor.close(); |
575 | | - } |
576 | 556 | } |
577 | 557 | } |
578 | 558 |
|
@@ -627,6 +607,7 @@ void batch(final MethodCall call, final MethodChannel.Result result) { |
627 | 607 | return; |
628 | 608 | } |
629 | 609 | break; |
| 610 | + /// Handle both UPDATE and DELETE |
630 | 611 | case METHOD_UPDATE: |
631 | 612 | if (doUpdate(operation)) { |
632 | 613 | //devLog(TAG, "results: " + operation.getBatchResults()); |
|
0 commit comments