Class: Extralite::Database

Inherits:
Object
  • Object
show all
Defined in:
lib/extralite.rb,
ext/extralite/database.c

Defined Under Namespace

Classes: Rollback

Instance Method Summary collapse

Constructor Details

#initialize(path) ⇒ void #initialize(path, gvl_release_threshold: , on_progress: , read_only: , wal: ) ⇒ void

Initializes a new SQLite database with the given path and options:

  • :gvl_release_threshold (Integer): sets the GVL release threshold (see #gvl_release_threshold=).
  • :pragma (Hash): one or more pragmas to set upon opening the database.
  • :read_only (true/false): opens the database in read-only mode if true.
  • :wal (true/false): sets up the database for WAL journaling mode by setting PRAGMA journal_mode=wal and PRAGMA synchronous=1.

Overloads:

  • #initialize(path) ⇒ void

    Parameters:

    • path (String)

      file path (or ':memory:' for memory database)

  • #initialize(path, gvl_release_threshold: , on_progress: , read_only: , wal: ) ⇒ void

    Parameters:

    • path (String)

      file path (or ':memory:' for memory database)

    • options (Hash)

      options for opening the database



182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
# File 'ext/extralite/database.c', line 182

VALUE Database_initialize(int argc, VALUE *argv, VALUE self) {
  Database_t *db = self_to_database(self);
  VALUE path;
  VALUE opts = Qnil;

  rb_scan_args(argc, argv, "11", &path, &opts);
  int flags = db_open_flags_from_opts(opts);

  int rc = sqlite3_open_v2(StringValueCStr(path), &db->sqlite3_db, flags, NULL);
  if (rc) {
    sqlite3_close_v2(db->sqlite3_db);
    db->sqlite3_db = NULL;
    rb_raise(cError, "%s", sqlite3_errstr(rc));
  }

  // Enable extended result codes
  rc = sqlite3_extended_result_codes(db->sqlite3_db, 1);
  if (rc) {
    sqlite3_close_v2(db->sqlite3_db);
    rb_raise(cError, "%s", sqlite3_errmsg(db->sqlite3_db));
  }

#ifdef HAVE_SQLITE3_ENABLE_LOAD_EXTENSION
  rc = sqlite3_enable_load_extension(db->sqlite3_db, 1);
  if (rc) {
    sqlite3_close_v2(db->sqlite3_db);
    rb_raise(cError, "%s", sqlite3_errmsg(db->sqlite3_db));
  }
#endif

  db->trace_proc = Qnil;
  db->gvl_release_threshold = DEFAULT_GVL_RELEASE_THRESHOLD;

  db->progress_handler = global_progress_handler;
  db->progress_handler.tick_count = 0;
  db->progress_handler.call_count = 0;
  if (db->progress_handler.mode != PROGRESS_NONE) {
      db->gvl_release_threshold = -1;
    if (db->progress_handler.mode != PROGRESS_ONCE)
      sqlite3_progress_handler(db->sqlite3_db, db->progress_handler.tick, &Database_progress_handler, db);
    sqlite3_busy_handler(db->sqlite3_db, &Database_busy_handler, db);
  }

  if (!NIL_P(opts)) Database_apply_opts(self, db, opts);
  return Qnil;
}

Instance Method Details

#backup(*args) {|remaining, total| ... } ⇒ Extralite::Database

Creates a backup of the database to the given destination, which can be either a filename or a database instance. In order to monitor the backup progress you can pass a block that will be called periodically by the backup method with two arguments: the remaining page count, and the total page count, which can be used to display the progress to the user or to collect statistics.

db_src.backup(db_dest) do |remaining, total|
  puts "Backing up #{remaining}/#{total}"
end

Parameters:

  • dest (String, Extralite::Database)

    backup destination

  • src_db_name (String)

    source database name (default: "main")

  • dst_db_name (String)

    Destination database name (default: "main")

Yield Parameters:

  • remaining (Integer)

    remaining page count

  • total (Integer)

    total page count

Returns:



886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
# File 'ext/extralite/database.c', line 886

VALUE Database_backup(int argc, VALUE *argv, VALUE self) {
  VALUE dst;
  VALUE src_name;
  VALUE dst_name;
  rb_scan_args(argc, argv, "12", &dst, &src_name, &dst_name);
  if (src_name == Qnil) src_name = rb_str_new_literal("main");
  if (dst_name == Qnil) dst_name = rb_str_new_literal("main");

  int dst_is_fn = TYPE(dst) == T_STRING;

  Database_t *src = self_to_open_database(self);
  sqlite3 *dst_db;

  if (dst_is_fn) {
    int rc = sqlite3_open(StringValueCStr(dst), &dst_db);
    if (rc) {
      sqlite3_close_v2(dst_db);
      rb_raise(cError, "%s", sqlite3_errmsg(dst_db));
    }
  }
  else {
    Database_t *dst_struct = self_to_open_database(dst);
    dst_db = dst_struct->sqlite3_db;
  }

  // TODO: add possibility to use different src and dest db names (main, tmp, or
  // attached db's).
  sqlite3_backup *backup;
  backup = sqlite3_backup_init(dst_db, StringValueCStr(dst_name), src->sqlite3_db, StringValueCStr(src_name));
  if (!backup) {
    if (dst_is_fn)
      sqlite3_close_v2(dst_db);
    rb_raise(cError, "%s", sqlite3_errmsg(dst_db));
  }

  backup_ctx ctx = { dst_db, dst_is_fn, backup, rb_block_given_p(), 0 };
  rb_ensure(SAFE(backup_safe_iterate), (VALUE)&ctx, SAFE(backup_cleanup), (VALUE)&ctx);

  RB_GC_GUARD(src_name);
  RB_GC_GUARD(dst_name);

  return self;
}

#batch_execute(sql, params_source) ⇒ Integer Also known as: execute_multi

Executes the given query for each list of parameters in the paramter source. If an enumerable is given, it is iterated and each of its values is used as the parameters for running the query. If a callable is given, it is called repeatedly and each of its return values is used as the parameters, until nil is returned.

Returns the number of changes effected. This method is designed for inserting multiple records or performing other mass operations.

records = [
  [1, 2, 3],
  [4, 5, 6]
]
db.batch_execute('insert into foo values (?, ?, ?)', records)

source = [
  [1, 2, 3],
  [4, 5, 6]
]
db.batch_execute('insert into foo values (?, ?, ?)', -> { records.shift })

Parameters:

  • sql (String)

    query SQL

  • parameters (Array<Array, Hash>, Enumerable, Enumerator, Callable)

    parameters to run query with

Returns:

  • (Integer)

    Total number of changes effected



527
528
529
530
531
532
533
534
535
536
537
538
539
540
# File 'ext/extralite/database.c', line 527

VALUE Database_batch_execute(VALUE self, VALUE sql, VALUE parameters) {
  Database_t *db = self_to_open_database(self);
  sqlite3_stmt *stmt;

  if (RSTRING_LEN(sql) == 0) return Qnil;

  prepare_single_stmt(DB_GVL_MODE(db), db->sqlite3_db, &stmt, sql);
  query_ctx ctx = QUERY_CTX(
    self, sql, db, stmt, parameters,
    Qnil, QUERY_HASH, ROW_MULTI, ALL_ROWS
  );

  return rb_ensure(SAFE(safe_batch_execute), (VALUE)&ctx, SAFE(cleanup_stmt), (VALUE)&ctx);
}

#batch_query(sql, params_source) ⇒ Array<Hash>, Integer #batch_query(sql, params_source) {|rows| ... } ⇒ Array<Hash>, Integer #batch_query_hash(sql, params_source) ⇒ Array<Hash>, Integer #batch_query_hash(sql, params_source) {|rows| ... } ⇒ Array<Hash>, Integer

Executes the given query for each list of parameters in the given paramter source. If a block is given, it is called with the resulting rows for each invocation of the query, and the total number of changes is returned. Otherwise, an array containing the resulting rows for each invocation is returned.

records = [
  [1, 2],
  [3, 4]
]
db.batch_query('insert into foo values (?, ?) returning bar, baz', records)
#=> [{ bar: 1, baz: 2 }, { bar: 3, baz: 4}]

*

Overloads:

  • #batch_query(sql, params_source) {|rows| ... } ⇒ Array<Hash>, Integer

    Yields:

    • (rows)
  • #batch_query_hash(sql, params_source) {|rows| ... } ⇒ Array<Hash>, Integer

    Yields:

    • (rows)

Parameters:

  • sql (String)

    query SQL

  • parameters (Array<Array, Hash>, Enumerable, Enumerator, Callable)

    parameters to run query with

Returns:

  • (Array<Hash>, Integer)

    Total number of changes effected



565
566
567
568
569
570
571
572
573
574
575
576
# File 'ext/extralite/database.c', line 565

VALUE Database_batch_query(VALUE self, VALUE sql, VALUE parameters) {
  Database_t *db = self_to_open_database(self);
  sqlite3_stmt *stmt;

  prepare_single_stmt(DB_GVL_MODE(db), db->sqlite3_db, &stmt, sql);
  query_ctx ctx = QUERY_CTX(
    self, sql, db, stmt, parameters,
    Qnil, QUERY_HASH, ROW_MULTI, ALL_ROWS
  );

  return rb_ensure(SAFE(safe_batch_query), (VALUE)&ctx, SAFE(cleanup_stmt), (VALUE)&ctx);
}

#batch_query_array(sql, params_source) ⇒ Array<Array>, Integer #batch_query_array(sql, params_source) {|rows| ... } ⇒ Array<Array>, Integer

Executes the given query for each list of parameters in the given paramter source. If a block is given, it is called with the resulting rows for each invocation of the query, and the total number of changes is returned. Otherwise, an array containing the resulting rows for each invocation is returned. Rows are represented as arrays.

records = [
  [1, 2],
  [3, 4]
]
db.batch_query_array('insert into foo values (?, ?) returning bar, baz', records)
#=> [[1, 2], [3, 4]]

*

Overloads:

  • #batch_query_array(sql, params_source) {|rows| ... } ⇒ Array<Array>, Integer

    Yields:

    • (rows)

Parameters:

  • sql (String)

    query SQL

  • parameters (Array<Array, Hash>, Enumerable, Enumerator, Callable)

    parameters to run query with

Returns:

  • (Array<Array>, Integer)

    Total number of changes effected



599
600
601
602
603
604
605
606
607
608
609
610
# File 'ext/extralite/database.c', line 599

VALUE Database_batch_query_array(VALUE self, VALUE sql, VALUE parameters) {
  Database_t *db = self_to_open_database(self);
  sqlite3_stmt *stmt;

  prepare_single_stmt(DB_GVL_MODE(db), db->sqlite3_db, &stmt, sql);
  query_ctx ctx = QUERY_CTX(
    self, sql, db, stmt, parameters,
    Qnil, QUERY_ARRAY, ROW_MULTI, ALL_ROWS
  );

  return rb_ensure(SAFE(safe_batch_query_array), (VALUE)&ctx, SAFE(cleanup_stmt), (VALUE)&ctx);
}

#batch_query(sql, params_source) ⇒ Array<Hash>, Integer #batch_query(sql, params_source) {|rows| ... } ⇒ Array<Hash>, Integer #batch_query_hash(sql, params_source) ⇒ Array<Hash>, Integer #batch_query_hash(sql, params_source) {|rows| ... } ⇒ Array<Hash>, Integer

Executes the given query for each list of parameters in the given paramter source. If a block is given, it is called with the resulting rows for each invocation of the query, and the total number of changes is returned. Otherwise, an array containing the resulting rows for each invocation is returned.

records = [
  [1, 2],
  [3, 4]
]
db.batch_query('insert into foo values (?, ?) returning bar, baz', records)
#=> [{ bar: 1, baz: 2 }, { bar: 3, baz: 4}]

*

Overloads:

  • #batch_query(sql, params_source) {|rows| ... } ⇒ Array<Hash>, Integer

    Yields:

    • (rows)
  • #batch_query_hash(sql, params_source) {|rows| ... } ⇒ Array<Hash>, Integer

    Yields:

    • (rows)

Parameters:

  • sql (String)

    query SQL

  • parameters (Array<Array, Hash>, Enumerable, Enumerator, Callable)

    parameters to run query with

Returns:

  • (Array<Hash>, Integer)

    Total number of changes effected



565
566
567
568
569
570
571
572
573
574
575
576
# File 'ext/extralite/database.c', line 565

VALUE Database_batch_query(VALUE self, VALUE sql, VALUE parameters) {
  Database_t *db = self_to_open_database(self);
  sqlite3_stmt *stmt;

  prepare_single_stmt(DB_GVL_MODE(db), db->sqlite3_db, &stmt, sql);
  query_ctx ctx = QUERY_CTX(
    self, sql, db, stmt, parameters,
    Qnil, QUERY_HASH, ROW_MULTI, ALL_ROWS
  );

  return rb_ensure(SAFE(safe_batch_query), (VALUE)&ctx, SAFE(cleanup_stmt), (VALUE)&ctx);
}

#batch_query_splat(sql, params_source) ⇒ Array<any>, Integer #batch_query_splat(sql, params_source) {|rows| ... } ⇒ Array<any>, Integer

Executes the given query for each list of parameters in the given paramter source. If a block is given, it is called with the resulting rows for each invocation of the query, and the total number of changes is returned. Otherwise, an array containing the resulting rows for each invocation is returned. Rows are single values.

records = [
  [1, 2],
  [3, 4]
]
db.batch_query_splat('insert into foo values (?, ?) returning baz', records)
#=> [2, 4]

*

Overloads:

  • #batch_query_splat(sql, params_source) {|rows| ... } ⇒ Array<any>, Integer

    Yields:

    • (rows)

Parameters:

  • sql (String)

    query SQL

  • parameters (Array<Array, Hash>, Enumerable, Enumerator, Callable)

    parameters to run query with

Returns:

  • (Array<any>, Integer)

    Total number of changes effected



633
634
635
636
637
638
639
640
641
642
643
644
# File 'ext/extralite/database.c', line 633

VALUE Database_batch_query_splat(VALUE self, VALUE sql, VALUE parameters) {
  Database_t *db = self_to_open_database(self);
  sqlite3_stmt *stmt;

  prepare_single_stmt(DB_GVL_MODE(db), db->sqlite3_db, &stmt, sql);
  query_ctx ctx = QUERY_CTX(
    self, sql, db, stmt, parameters,
    Qnil, QUERY_SPLAT, ROW_MULTI, ALL_ROWS
  );

  return rb_ensure(SAFE(safe_batch_query_splat), (VALUE)&ctx, SAFE(cleanup_stmt), (VALUE)&ctx);
}

#busy_timeout=(sec) ⇒ Extralite::Database

Sets the busy timeout for the database, in seconds or fractions thereof. To disable the busy timeout, set it to 0 or nil. When the busy timeout is set to a value larger than zero, running a query when the database is locked will cause the program to wait for the database to become available. If the database is still locked when the timeout period has elapsed, the query will fail with a Extralite::BusyError exception.

Setting the busy timeout allows other threads to run while waiting for the database to become available. See also #on_progress.

Parameters:

  • sec (Number, nil)

    timeout value

Returns:



1025
1026
1027
1028
1029
1030
1031
1032
1033
# File 'ext/extralite/database.c', line 1025

VALUE Database_busy_timeout_set(VALUE self, VALUE sec) {
  Database_t *db = self_to_open_database(self);

  int ms = (sec == Qnil) ? 0 : (int)(NUM2DBL(sec) * 1000);
  int rc = sqlite3_busy_timeout(db->sqlite3_db, ms);
  if (rc != SQLITE_OK) rb_raise(cError, "Failed to set busy timeout");

  return self;
}

#changesInteger

Returns the number of changes made to the database by the last operation.

Returns:

  • (Integer)

    number of changes



668
669
670
671
672
# File 'ext/extralite/database.c', line 668

VALUE Database_changes(VALUE self) {
  Database_t *db = self_to_open_database(self);

  return INT2FIX(sqlite3_changes(db->sqlite3_db));
}

#closeExtralite::Database

Closes the database.

Returns:



243
244
245
246
247
248
249
250
251
252
253
254
# File 'ext/extralite/database.c', line 243

VALUE Database_close(VALUE self) {
  int rc;
  Database_t *db = self_to_database(self);

  rc = sqlite3_close_v2(db->sqlite3_db);
  if (rc) {
    rb_raise(cError, "%s", sqlite3_errmsg(db->sqlite3_db));
  }

  db->sqlite3_db = NULL;
  return self;
}

#closed?Boolean

Returns true if the database is closed.

Returns:

  • (Boolean)

Returns:

  • (bool)

    is database closed



263
264
265
266
# File 'ext/extralite/database.c', line 263

VALUE Database_closed_p(VALUE self) {
  Database_t *db = self_to_database(self);
  return db->sqlite3_db ? Qfalse : Qtrue;
}

#columns(sql) ⇒ Array<String>

Returns the column names for the given query, without running it.

Returns:

  • (Array<String>)

    column names



650
651
652
# File 'ext/extralite/database.c', line 650

VALUE Database_columns(VALUE self, VALUE sql) {
  return Database_perform_query(1, &sql, self, safe_query_columns, QUERY_HASH);
}

#errcodeInteger

Returns the last error code for the database.

Returns:

  • (Integer)

    last error code



1324
1325
1326
1327
1328
# File 'ext/extralite/database.c', line 1324

VALUE Database_errcode(VALUE self) {
  Database_t *db = self_to_open_database(self);

  return INT2NUM(sqlite3_errcode(db->sqlite3_db));
}

#errmsgString

Returns the last error message for the database.

Returns:

  • (String)

    last error message



1334
1335
1336
1337
1338
# File 'ext/extralite/database.c', line 1334

VALUE Database_errmsg(VALUE self) {
  Database_t *db = self_to_open_database(self);

  return rb_str_new2(sqlite3_errmsg(db->sqlite3_db));
}

#error_offsetInteger

Returns the offset for the last error. This is useful for indicating where in the SQL string an error was encountered.

Returns:

  • (Integer)

    offset in the last submitted SQL string



1346
1347
1348
1349
1350
# File 'ext/extralite/database.c', line 1346

VALUE Database_error_offset(VALUE self) {
  Database_t *db = self_to_open_database(self);

  return INT2NUM(sqlite3_error_offset(db->sqlite3_db));
}

#execute(sql, *parameters) ⇒ Integer?

Runs a query returning the total changes effected. This method should be used for data- or schema-manipulation queries.

Query parameters to be bound to placeholders in the query can be specified as a list of values or as a hash mapping parameter names to values. When parameters are given as an array, the query should specify parameters using ?:

db.execute('update foo set x = ? where y = ?', 42, 43)

Named placeholders are specified using :. The placeholder values are specified using keyword arguments:

db.execute('update foo set x = :bar', bar: 42)

Parameters:

  • sql (String)

    query SQL

  • parameters (Array, Hash)

    parameters to run query with

Returns:

  • (Integer, nil)

    Total number of changes effected or nil if the query ends with a comment.



495
496
497
# File 'ext/extralite/database.c', line 495

VALUE Database_execute(int argc, VALUE *argv, VALUE self) {
  return Database_perform_query(argc, argv, self, safe_query_changes, QUERY_HASH);
}

#filenameString #filename(db_name) ⇒ String

Returns the database filename. If db_name is given, returns the filename for the respective attached database.

Overloads:

  • #filenameString

    Returns database filename.

    Returns:

    • (String)

      database filename

  • #filename(db_name) ⇒ String

    Returns database filename.

    Parameters:

    • db_name (String)

      attached database name

    Returns:

    • (String)

      database filename



683
684
685
686
687
688
689
690
691
692
# File 'ext/extralite/database.c', line 683

VALUE Database_filename(int argc, VALUE *argv, VALUE self) {
  const char *db_name;
  const char *filename;
  Database_t *db = self_to_open_database(self);

  rb_check_arity(argc, 0, 1);
  db_name = (argc == 1) ? StringValueCStr(argv[0]) : "main";
  filename = sqlite3_db_filename(db->sqlite3_db, db_name);
  return filename ? rb_str_new_cstr(filename) : Qnil;
}

#gvl_release_thresholdInteger

Returns the database's GVL release threshold.

Returns:

  • (Integer)

    GVL release threshold



1375
1376
1377
1378
# File 'ext/extralite/database.c', line 1375

VALUE Database_gvl_release_threshold_get(VALUE self) {
  Database_t *db = self_to_open_database(self);
  return INT2NUM(db->gvl_release_threshold);
}

#gvl_release_threshold=(value) ⇒ Integer

Sets the database's GVL release threshold. The release policy changes according to the given value:

  • Less than 0: the GVL is never released while running queries. This is the policy used when a progress handler is set. For more information see #on_progress.
  • 0: The GVL is released while preparing queries, but held when iterating through records.
  • Greater than 0: the GVL is released while preparing queries, and released periodically while iterating through records, according to the given period. A value of 1 will release the GVL on every iterated record. A value of 100 will release the GVL once for every 100 records.

A value of nil sets the threshold to the default value, which is currently 1000.

Parameters:

  • threshold (Integer, nil)

    GVL release threshold

Returns:

  • (Integer)

    GVL release threshold



1399
1400
1401
1402
1403
1404
1405
1406
1407
1408
1409
1410
1411
1412
1413
1414
1415
1416
1417
1418
1419
1420
1421
1422
# File 'ext/extralite/database.c', line 1399

VALUE Database_gvl_release_threshold_set(VALUE self, VALUE value) {
  Database_t *db = self_to_open_database(self);

  switch (TYPE(value)) {
    case T_FIXNUM:
      {
        int value_int = NUM2INT(value);
        if (value_int < -1)
          rb_raise(eArgumentError, "Invalid GVL release threshold value (expect integer >= -1)");

        if (value_int > -1 && db->progress_handler.mode != PROGRESS_NONE)
          Database_reset_progress_handler(self, db);
        db->gvl_release_threshold = value_int;
        break;
      }
    case T_NIL:
      db->gvl_release_threshold = DEFAULT_GVL_RELEASE_THRESHOLD;
      break;
    default:
      rb_raise(eArgumentError, "Invalid GVL release threshold value (expect integer or nil)");
  }

  return INT2NUM(db->gvl_release_threshold);
}

#inspectString

Returns a short string representation of the database instance, including the database filename.

Returns:

  • (String)

    string representation



1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
# File 'ext/extralite/database.c', line 1358

VALUE Database_inspect(VALUE self) {
  Database_t *db = self_to_database(self);
  VALUE cname = rb_class_name(CLASS_OF(self));

  if (!(db)->sqlite3_db)
    return rb_sprintf("#<%"PRIsVALUE":%p (closed)>", cname, (void*)self);
  else {
    VALUE filename = Database_filename(0, NULL, self);
    if (RSTRING_LEN(filename) == 0) filename = rb_str_new_literal(":memory:");
    return rb_sprintf("#<%"PRIsVALUE":%p %"PRIsVALUE">", cname, (void*)self, filename);
  }
}

#interruptExtralite::Database

Interrupts a long running query. This method is to be called from a different thread than the one running the query. Upon calling #interrupt the running query will stop and raise an Extralite::InterruptError exception.

It is not safe to call #interrupt on a database that is about to be closed. For more information, consult the sqlite3 API docs.

Returns:



796
797
798
799
800
801
# File 'ext/extralite/database.c', line 796

VALUE Database_interrupt(VALUE self) {
  Database_t *db = self_to_open_database(self);

  sqlite3_interrupt(db->sqlite3_db);
  return self;
}

#last_insert_rowidInteger

Returns the rowid of the last inserted row.

Returns:

  • (Integer)

    last rowid



658
659
660
661
662
# File 'ext/extralite/database.c', line 658

VALUE Database_last_insert_rowid(VALUE self) {
  Database_t *db = self_to_open_database(self);

  return INT2FIX(sqlite3_last_insert_rowid(db->sqlite3_db));
}

#limit(category) ⇒ Integer #limit(category, new_value) ⇒ Integer

Returns the current limit for the given category. If a new value is given, sets the limit to the new value and returns the previous value.

Overloads:

  • #limit(category) ⇒ Integer

    Returns limit value.

    Parameters:

    • category (Integer)

      category

    Returns:

    • (Integer)

      limit value

  • #limit(category, new_value) ⇒ Integer

    Returns old value.

    Parameters:

    • category (Integer)

      category

    • new_value (Integer)

      new value

    Returns:

    • (Integer)

      old value



998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
# File 'ext/extralite/database.c', line 998

VALUE Database_limit(int argc, VALUE *argv, VALUE self) {
  VALUE category, new_value;

  rb_scan_args(argc, argv, "11", &category, &new_value);

  Database_t *db = self_to_open_database(self);

  int value = sqlite3_limit(db->sqlite3_db, NUM2INT(category), RTEST(new_value) ? NUM2INT(new_value) : -1);

  if (value == -1) rb_raise(cError, "Invalid limit category");

  return INT2NUM(value);
}

#load_extension(path) ⇒ Extralite::Database

Loads an extension with the given path.

Parameters:

  • path (String)

    extension file path

Returns:



710
711
712
713
714
715
716
717
718
719
720
721
722
# File 'ext/extralite/database.c', line 710

VALUE Database_load_extension(VALUE self, VALUE path) {
  Database_t *db = self_to_open_database(self);
  char *err_msg;

  int rc = sqlite3_load_extension(db->sqlite3_db, RSTRING_PTR(path), 0, &err_msg);
  if (rc != SQLITE_OK) {
    VALUE error = rb_exc_new2(cError, err_msg);
    sqlite3_free(err_msg);
    rb_exc_raise(error);
  }

  return self;
}

#on_progress(*args) ⇒ Extralite::Database

Installs or removes a progress handler that will be executed periodically while a query is running. This method can be used to support switching between fibers and threads or implementing timeouts for running queries.

The period parameter specifies the approximate number of SQLite virtual machine instructions that are evaluated between successive invocations of the progress handler. A period of less than 1 removes the progress handler. The default period value is 1000.

The optional tick parameter specifies the granularity of how often the progress handler is called. The default tick value is 10, which means that Extralite's underlying progress callback will be called every 10 SQLite VM instructions. The given progress proc, however, will be only called every period (cumulative) VM instructions. This allows the progress handler to work correctly also when running simple queries that don't include many VM instructions. If the tick value is greater than the period value it is automatically capped to the period value.

The mode parameter controls the progress handler mode, which is one of the following:

  • :normal (default): the progress handler proc is invoked on query progress.
  • :once: the progress handler proc is invoked only once, when preparing the query.
  • :at_least_once: the progress handler proc is invoked when prearing the query, and on query progress.

The progress handler is called also when the database is busy. This lets the application perform work while waiting for the database to become unlocked, or implement a timeout. Note that setting the database's busy_timeout after setting a progress handler may lead to undefined behaviour in a concurrent application. When busy, the progress handler proc is passed true as the first argument.

When the progress handler is set, the gvl release threshold value is set to -1, which means that the GVL will not be released at all when preparing or running queries. It is the application's responsibility to let other threads or fibers run by calling e.g. Thread.pass:

db.on_progress do
  do_something_interesting
  Thread.pass # let other threads run
end

Note that the progress handler is set globally for the database and that Extralite does provide any hooks for telling which queries are currently running or at what time they were started. This means that you'll need to wrap the stock #query_xxx and #execute methods with your own code that calculates timeouts, for example:

def setup_progress_handler
  @db.on_progress do
    raise TimeoutError if Time.now - @t0 >= @timeout
    Thread.pass
  end
end

def query(sql, *)
  @t0 = Time.now
  @db.query(sql, *)
end

If the gvl release threshold is set to a value equal to or larger than 0 after setting the progress handler, the progress handler will be reset.

Parameters:

  • period (Integer)

    progress handler period

  • opts (Hash)

    progress options

Returns:



1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
# File 'ext/extralite/database.c', line 1219

VALUE Database_on_progress(int argc, VALUE *argv, VALUE self) {
  Database_t *db = self_to_open_database(self);
  VALUE opts;
  struct progress_handler prog;

  rb_scan_args(argc, argv, "00:", &opts);
  prog = parse_progress_handler_opts(opts);

  if (prog.mode == PROGRESS_NONE) {
    Database_reset_progress_handler(self, db);
    db->gvl_release_threshold = DEFAULT_GVL_RELEASE_THRESHOLD;
    return self;
  }

  db->gvl_release_threshold = -1;
  db->progress_handler.mode       = prog.mode;
  RB_OBJ_WRITE(self, &db->progress_handler.proc, prog.proc);
  db->progress_handler.period     = prog.period;
  db->progress_handler.tick       = prog.tick;
  db->progress_handler.tick_count = 0;
  db->progress_handler.call_count = 0;

  // The PROGRESS_ONCE mode works by invoking the progress handler proc exactly
  // once, before iterating over the result set, so in that mode we don't
  // actually need to set the progress handler at the sqlite level.
  if (prog.mode != PROGRESS_ONCE)
    sqlite3_progress_handler(db->sqlite3_db, prog.tick, &Database_progress_handler, db);
  if (prog.mode != PROGRESS_NONE)
    sqlite3_busy_handler(db->sqlite3_db, &Database_busy_handler, db);

  return self;
}

#pragma(value) ⇒ Hash

Gets or sets one or more database pragmas. For a list of available pragmas see: https://sqlite.org/pragma.html#toc

db.pragma(:cache_size) # get
db.pragma(cache_size: -2000) # set

Parameters:

  • value (Symbol, String, Hash)

    pragma name or hash mapping names to values

Returns:

  • (Hash)

    query result



214
215
216
# File 'lib/extralite.rb', line 214

def pragma(value)
  value.is_a?(Hash) ? pragma_set(value) : pragma_get(value)
end

#prepare(sql) ⇒ Extralite::Query #prepare(sql, *params) ⇒ Extralite::Query #prepare(sql, *params) { ... } ⇒ Extralite::Query

Creates a prepared query with the given SQL query in hash mode. If query parameters are given, they are bound to the query. If a block is given, it is used as a transform proc.

Overloads:

Parameters:

  • sql (String)

    SQL statement

  • *params (Array<any>)

    parameters to bind

Returns:



748
749
750
# File 'ext/extralite/database.c', line 748

VALUE Database_prepare_hash(int argc, VALUE *argv, VALUE self) {
  return Database_prepare(argc, argv, self, SYM_hash);
}

#prepare_array(sql) ⇒ Extralite::Query #prepare_array(sql, *params) ⇒ Extralite::Query #prepare_array(sql, *params) { ... } ⇒ Extralite::Query

Creates a prepared query with the given SQL query in array mode. If query parameters are given, they are bound to the query. If a block is given, it is used as a transform proc.

Overloads:

Parameters:

  • sql (String)

    SQL statement

  • *params (Array<any>)

    parameters to bind

Returns:



782
783
784
# File 'ext/extralite/database.c', line 782

VALUE Database_prepare_array(int argc, VALUE *argv, VALUE self) {
  return Database_prepare(argc, argv, self, SYM_array);
}

#prepare(sql) ⇒ Extralite::Query #prepare(sql, *params) ⇒ Extralite::Query #prepare(sql, *params) { ... } ⇒ Extralite::Query

Creates a prepared query with the given SQL query in hash mode. If query parameters are given, they are bound to the query. If a block is given, it is used as a transform proc.

Overloads:

Parameters:

  • sql (String)

    SQL statement

  • *params (Array<any>)

    parameters to bind

Returns:



748
749
750
# File 'ext/extralite/database.c', line 748

VALUE Database_prepare_hash(int argc, VALUE *argv, VALUE self) {
  return Database_prepare(argc, argv, self, SYM_hash);
}

#prepare_splat(sql) ⇒ Extralite::Query #prepare_splat(sql, *params) ⇒ Extralite::Query #prepare_splat(sql, *params) { ... } ⇒ Extralite::Query

Creates a prepared query with the given SQL query in argv mode. If query parameters are given, they are bound to the query. If a block is given, it is used as a transform proc.

Overloads:

Parameters:

  • sql (String)

    SQL statement

  • *params (Array<any>)

    parameters to bind

Returns:



765
766
767
# File 'ext/extralite/database.c', line 765

VALUE Database_prepare_splat(int argc, VALUE *argv, VALUE self) {
  return Database_prepare(argc, argv, self, SYM_splat);
}

#query(sql, ...) ⇒ Array<Hash>, Integer #query(transform, sql, ...) ⇒ Array<Hash>, Integer #query(sql, *parameters, &block) ⇒ Array #query_hash(sql, *parameters, &block) ⇒ Array

Runs a query returning rows as hashes (with symbol keys). If a block is given, it will be called for each row. Otherwise, an array containing all rows is returned.

Query parameters to be bound to placeholders in the query can be specified as a list of values or as a hash mapping parameter names to values. When parameters are given as an array, the query should specify parameters using ?:

db.query('select * from foo where x = ?', 42)

Named placeholders are specified using :. The placeholder values are specified using keyword arguments:

db.query('select * from foo where x = :bar', bar: 42)

Overloads:

  • #query(sql, ...) ⇒ Array<Hash>, Integer

    Returns rows or total changes.

    Parameters:

    • sql (String)

      SQL statement

    Returns:

    • (Array<Hash>, Integer)

      rows or total changes

  • #query(transform, sql, ...) ⇒ Array<Hash>, Integer

    Returns rows or total changes.

    Parameters:

    • transform (Proc)

      transform proc

    • sql (String)

      SQL statement

    Returns:

    • (Array<Hash>, Integer)

      rows or total changes

  • #query(sql, *parameters, &block) ⇒ Array

    Returns:

    • (Array)
  • #query_hash(sql, *parameters, &block) ⇒ Array

    Returns:

    • (Array)


338
339
340
# File 'ext/extralite/database.c', line 338

VALUE Database_query(int argc, VALUE *argv, VALUE self) {
  return Database_perform_query(argc, argv, self, safe_query_hash, QUERY_HASH);
}

#query_array(sql, ...) ⇒ Array<Array>, Integer #query_array(transform, sql, ...) ⇒ Array<Array>, Integer

Runs a query returning rows as arrays. If a block is given, it will be called for each row. Otherwise, an array containing all rows is returned.

Query parameters to be bound to placeholders in the query can be specified as a list of values or as a hash mapping parameter names to values. When parameters are given as an array, the query should specify parameters using ?:

db.query_array('select * from foo where x = ?', 42)

Named placeholders are specified using :. The placeholder values are specified using a hash, where keys are either strings are symbols. String keys can include or omit the : prefix. The following are equivalent:

db.query_array('select * from foo where x = :bar', bar: 42)
db.query_array('select * from foo where x = :bar', 'bar' => 42)
db.query_array('select * from foo where x = :bar', ':bar' => 42)

Overloads:

  • #query_array(sql, ...) ⇒ Array<Array>, Integer

    Returns rows or total changes.

    Parameters:

    • sql (String)

      SQL statement

    Returns:

    • (Array<Array>, Integer)

      rows or total changes

  • #query_array(transform, sql, ...) ⇒ Array<Array>, Integer

    Returns rows or total changes.

    Parameters:

    • transform (Proc)

      transform proc

    • sql (String)

      SQL statement

    Returns:

    • (Array<Array>, Integer)

      rows or total changes



391
392
393
# File 'ext/extralite/database.c', line 391

VALUE Database_query_array(int argc, VALUE *argv, VALUE self) {
  return Database_perform_query(argc, argv, self, safe_query_array, QUERY_ARRAY);
}

#query(sql, ...) ⇒ Array<Hash>, Integer #query(transform, sql, ...) ⇒ Array<Hash>, Integer #query(sql, *parameters, &block) ⇒ Array #query_hash(sql, *parameters, &block) ⇒ Array

Runs a query returning rows as hashes (with symbol keys). If a block is given, it will be called for each row. Otherwise, an array containing all rows is returned.

Query parameters to be bound to placeholders in the query can be specified as a list of values or as a hash mapping parameter names to values. When parameters are given as an array, the query should specify parameters using ?:

db.query('select * from foo where x = ?', 42)

Named placeholders are specified using :. The placeholder values are specified using keyword arguments:

db.query('select * from foo where x = :bar', bar: 42)

Overloads:

  • #query(sql, ...) ⇒ Array<Hash>, Integer

    Returns rows or total changes.

    Parameters:

    • sql (String)

      SQL statement

    Returns:

    • (Array<Hash>, Integer)

      rows or total changes

  • #query(transform, sql, ...) ⇒ Array<Hash>, Integer

    Returns rows or total changes.

    Parameters:

    • transform (Proc)

      transform proc

    • sql (String)

      SQL statement

    Returns:

    • (Array<Hash>, Integer)

      rows or total changes

  • #query(sql, *parameters, &block) ⇒ Array

    Returns:

    • (Array)
  • #query_hash(sql, *parameters, &block) ⇒ Array

    Returns:

    • (Array)


338
339
340
# File 'ext/extralite/database.c', line 338

VALUE Database_query(int argc, VALUE *argv, VALUE self) {
  return Database_perform_query(argc, argv, self, safe_query_hash, QUERY_HASH);
}

#query_single(sql, ...) ⇒ Array, any #query_single(transform, sql, ...) ⇒ Array, any

Runs a query returning a single row as a hash.

Query parameters to be bound to placeholders in the query can be specified as a list of values or as a hash mapping parameter names to values. When parameters are given as an array, the query should specify parameters using ?:

db.query_single('select * from foo where x = ?', 42)

Named placeholders are specified using :. The placeholder values are specified using keyword arguments:

db.query_single('select * from foo where x = :bar', bar: 42)

Overloads:

  • #query_single(sql, ...) ⇒ Array, any

    Returns row.

    Parameters:

    • sql (String)

      SQL statement

    Returns:

    • (Array, any)

      row

  • #query_single(transform, sql, ...) ⇒ Array, any

    Returns row.

    Parameters:

    • transform (Proc)

      transform proc

    • sql (String)

      SQL statement

    Returns:

    • (Array, any)

      row



417
418
419
# File 'ext/extralite/database.c', line 417

VALUE Database_query_single(int argc, VALUE *argv, VALUE self) {
  return Database_perform_query(argc, argv, self, safe_query_single_row_hash, QUERY_HASH);
}

#query_single_array(sql, ...) ⇒ Array, any #query_single_array(transform, sql, ...) ⇒ Array, any

Runs a query returning a single row as an array.

Query parameters to be bound to placeholders in the query can be specified as a list of values or as a hash mapping parameter names to values. When parameters are given as an array, the query should specify parameters using ?:

db.query_single_array('select * from foo where x = ?', 42)

Named placeholders are specified using :. The placeholder values are specified using keyword arguments:

db.query_single_array('select * from foo where x = :bar', bar: 42)

Overloads:

  • #query_single_array(sql, ...) ⇒ Array, any

    Returns row.

    Parameters:

    • sql (String)

      SQL statement

    Returns:

    • (Array, any)

      row

  • #query_single_array(transform, sql, ...) ⇒ Array, any

    Returns row.

    Parameters:

    • transform (Proc)

      transform proc

    • sql (String)

      SQL statement

    Returns:

    • (Array, any)

      row



469
470
471
# File 'ext/extralite/database.c', line 469

VALUE Database_query_single_array(int argc, VALUE *argv, VALUE self) {
  return Database_perform_query(argc, argv, self, safe_query_single_row_array, QUERY_ARRAY);
}

#query_single(sql, ...) ⇒ Array, any #query_single(transform, sql, ...) ⇒ Array, any

Runs a query returning a single row as a hash.

Query parameters to be bound to placeholders in the query can be specified as a list of values or as a hash mapping parameter names to values. When parameters are given as an array, the query should specify parameters using ?:

db.query_single('select * from foo where x = ?', 42)

Named placeholders are specified using :. The placeholder values are specified using keyword arguments:

db.query_single('select * from foo where x = :bar', bar: 42)

Overloads:

  • #query_single(sql, ...) ⇒ Array, any

    Returns row.

    Parameters:

    • sql (String)

      SQL statement

    Returns:

    • (Array, any)

      row

  • #query_single(transform, sql, ...) ⇒ Array, any

    Returns row.

    Parameters:

    • transform (Proc)

      transform proc

    • sql (String)

      SQL statement

    Returns:

    • (Array, any)

      row



417
418
419
# File 'ext/extralite/database.c', line 417

VALUE Database_query_single(int argc, VALUE *argv, VALUE self) {
  return Database_perform_query(argc, argv, self, safe_query_single_row_hash, QUERY_HASH);
}

#query_single_splat(sql, ...) ⇒ Array, any #query_single_splat(transform, sql, ...) ⇒ Array, any

Runs a query returning a single row as an array or a single value.

Query parameters to be bound to placeholders in the query can be specified as a list of values or as a hash mapping parameter names to values. When parameters are given as an array, the query should specify parameters using ?:

db.query_single_splat('select * from foo where x = ?', 42)

Named placeholders are specified using :. The placeholder values are specified using keyword arguments:

db.query_single_splat('select * from foo where x = :bar', bar: 42)

Overloads:

  • #query_single_splat(sql, ...) ⇒ Array, any

    Returns row.

    Parameters:

    • sql (String)

      SQL statement

    Returns:

    • (Array, any)

      row

  • #query_single_splat(transform, sql, ...) ⇒ Array, any

    Returns row.

    Parameters:

    • transform (Proc)

      transform proc

    • sql (String)

      SQL statement

    Returns:

    • (Array, any)

      row



443
444
445
# File 'ext/extralite/database.c', line 443

VALUE Database_query_single_splat(int argc, VALUE *argv, VALUE self) {
  return Database_perform_query(argc, argv, self, safe_query_single_row_splat, QUERY_SPLAT);
}

#query_splat(sql, ...) ⇒ Array<Array, any>, Integer #query_splat(transform, sql, ...) ⇒ Array<Array, any>, Integer

Runs a query and transforms rows through the given transform poc. Each row is provided to the transform proc as a list of values. If a block is given, it will be called for each row. Otherwise, an array containing all rows is returned.

If a transform block is given, it is called for each row, with the row values splatted:

transform = ->(a, b, c) { a * 100 + b * 10 + c }
db.query_splat(transform, 'select a, b, c from foo where c = ?', 42)

Overloads:

  • #query_splat(sql, ...) ⇒ Array<Array, any>, Integer

    Returns rows or total changes.

    Parameters:

    • sql (String)

      SQL statement

    Returns:

    • (Array<Array, any>, Integer)

      rows or total changes

  • #query_splat(transform, sql, ...) ⇒ Array<Array, any>, Integer

    Returns rows or total changes.

    Parameters:

    • transform (Proc)

      transform proc

    • sql (String)

      SQL statement

    Returns:

    • (Array<Array, any>, Integer)

      rows or total changes



361
362
363
# File 'ext/extralite/database.c', line 361

VALUE Database_query_splat(int argc, VALUE *argv, VALUE self) {
  return Database_perform_query(argc, argv, self, safe_query_splat, QUERY_SPLAT);
}

#read_only?boolean

Returns true if the database was open for read only access.

Returns:

  • (boolean)

    true if database is open for read only access



233
234
235
236
237
# File 'ext/extralite/database.c', line 233

VALUE Database_read_only_p(VALUE self) {
  Database_t *db = self_to_database(self);
  int open = sqlite3_db_readonly(db->sqlite3_db, "main");
  return (open == 1) ? Qtrue : Qfalse;
}

#release(name) ⇒ Extralite::Database

Release a savepoint with the given name. For more information on savepoints see: https://sqlite.org/lang_savepoint.html

Parameters:

  • name (String, Symbol)

    savepoint name

Returns:



268
269
270
271
# File 'lib/extralite.rb', line 268

def release(name)
  execute "release #{name}"
  self
end

#rollback!Extralite::Database

Rolls back the currently active transaction. This method should only be called from within a block passed to Database#transaction. This method raises a Extralite::Rollback exception, which will stop execution of the transaction block without propagating the exception.

db.transaction do
  db.execute('insert into foo (42)')
  db.rollback!
end

Parameters:

  • name (String, Symbol)

    savepoint name

Returns:

Raises:



295
296
297
# File 'lib/extralite.rb', line 295

def rollback!
  raise Rollback
end

#rollback_to(name) ⇒ Extralite::Database

Rolls back changes to a savepoint with the given name. For more information on savepoints see: https://sqlite.org/lang_savepoint.html

Parameters:

  • name (String, Symbol)

    savepoint name

Returns:



278
279
280
281
# File 'lib/extralite.rb', line 278

def rollback_to(name)
  execute "rollback to #{name}"
  self
end

#savepoint(name) ⇒ Extralite::Database

Creates a savepoint with the given name. For more information on savepoints see: https://sqlite.org/lang_savepoint.html

db.savepoint(:savepoint1)
db.execute('insert into foo values (42)')
db.rollback_to(:savepoint1)
db.release(:savepoint1)

Parameters:

  • name (String, Symbol)

    savepoint name

Returns:



258
259
260
261
# File 'lib/extralite.rb', line 258

def savepoint(name)
  execute "savepoint #{name}"
  self
end

#status(op) ⇒ Array<Integer> #status(op, reset) ⇒ Array<Integer>

Returns database status values for the given op as an array containing the current value and the high water mark value. To reset the high water mark, pass true as reset.

Overloads:

  • #status(op) ⇒ Array<Integer>

    Returns array containing the value and high water mark.

    Parameters:

    • op (Integer)

      op

    Returns:

    • (Array<Integer>)

      array containing the value and high water mark

  • #status(op, reset) ⇒ Array<Integer>

    Returns array containing the value and high water mark.

    Parameters:

    • op (Integer)

      op

    • reset (Integer, bool)

      reset flag

    Returns:

    • (Array<Integer>)

      array containing the value and high water mark



973
974
975
976
977
978
979
980
981
982
983
984
985
# File 'ext/extralite/database.c', line 973

VALUE Database_status(int argc, VALUE *argv, VALUE self) {
  VALUE op, reset;
  int cur, hwm;

  rb_scan_args(argc, argv, "11", &op, &reset);

  Database_t *db = self_to_open_database(self);

  int rc = sqlite3_db_status(db->sqlite3_db, NUM2INT(op), &cur, &hwm, RTEST(reset) ? 1 : 0);
  if (rc != SQLITE_OK) rb_raise(cError, "%s", sqlite3_errstr(rc));

  return rb_ary_new3(2, INT2NUM(cur), INT2NUM(hwm));
}

#tables(db = 'main') ⇒ Array

Returns the list of currently defined tables. If a database name is given, returns the list of tables for the relevant attached database.

Parameters:

  • db (String) (defaults to: 'main')

    name of attached database

Returns:

  • (Array)

    list of tables



202
203
204
# File 'lib/extralite.rb', line 202

def tables(db = 'main')
  query_splat(format(TABLES_SQL, db: db))
end

#total_changesInteger

Returns the total number of changes made to the database since opening it.

Returns:

  • (Integer)

    total changes



1039
1040
1041
1042
1043
1044
# File 'ext/extralite/database.c', line 1039

VALUE Database_total_changes(VALUE self) {
  Database_t *db = self_to_open_database(self);

  int value = sqlite3_total_changes(db->sqlite3_db);
  return INT2NUM(value);
}

#traceExtralite::Database

Installs or removes a block that will be invoked for every SQL statement executed. To stop tracing, call #trace without a block.

Returns:



1051
1052
1053
1054
1055
1056
# File 'ext/extralite/database.c', line 1051

VALUE Database_trace(VALUE self) {
  Database_t *db = self_to_open_database(self);

  RB_OBJ_WRITE(self, &db->trace_proc, rb_block_given_p() ? rb_block_proc() : Qnil);
  return self;
}

#track_changes(*tables) { ... } ⇒ Extralite::Changeset

Tracks changes to the database and returns a changeset. The changeset can then be used to store the changes to a file, apply them to another database, or undo the changes. The given table names specify which tables should be tracked for changes. Passing a value of nil causes all tables to be tracked.

changeset = db.track_changes(:foo, :bar) do
  perform_a_bunch_of_queries
end

File.open('my.changes', 'w+') { |f| f << changeset.to_blob }

Yields:

  • []

Parameters:

  • *tables (Array<String, Symbol>)

    table(s) to track

Returns:



1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
# File 'ext/extralite/database.c', line 1076

VALUE Database_track_changes(int argc, VALUE *argv, VALUE self) {
  self_to_open_database(self);

  VALUE changeset = rb_funcall(cChangeset, ID_new, 0);
  VALUE tables = rb_ary_new_from_values(argc, argv);

  rb_funcall(changeset, ID_track, 2, self, tables);

  RB_GC_GUARD(changeset);
  RB_GC_GUARD(tables);
  return changeset;
}

#transaction(mode = :immediate) ⇒ Any

Starts a transaction and runs the given block. If an exception is raised in the block, the transaction is rolled back. Otherwise, the transaction is commited after running the block.

db.transaction do
  db.execute('insert into foo values (1, 2, 3)')
  raise if db.query_single_value('select x from bar') > 42
end

For more information on transactions see: https://sqlite.org/lang_transaction.html

Parameters:

  • mode (Symbol, String) (defaults to: :immediate)

    transaction mode (deferred, immediate or exclusive).

Returns:

  • (Any)

    the given block's return value



237
238
239
240
241
242
243
244
245
246
# File 'lib/extralite.rb', line 237

def transaction(mode = :immediate)
  abort = false
  execute "begin #{mode} transaction"    
  yield self
rescue => e
  abort = true
  e.is_a?(Rollback) ? nil : raise
ensure
  execute(abort ? 'rollback' : 'commit')
end

#transaction_active?bool

Returns true if a transaction is currently in progress.

Returns:

  • (bool)

    is transaction in progress



698
699
700
701
702
# File 'ext/extralite/database.c', line 698

VALUE Database_transaction_active_p(VALUE self) {
  Database_t *db = self_to_open_database(self);

  return sqlite3_get_autocommit(db->sqlite3_db) ? Qfalse : Qtrue;
}

#wal_checkpoint(mode) ⇒ Array<int> #wal_checkpoint(mode, db_name) ⇒ Array<int>

Runs a WAL checkpoint operation with the given mode. If a database name is given, the checkpoint operation is ran on the corresponding attached database, otherwise it is run on the main database. Returns an array containing the total number of frames in the WAL file, and the number of frames checkpointed. For more information see: https://sqlite.org/c3ref/wal_checkpoint_v2.html

Overloads:

  • #wal_checkpoint(mode) ⇒ Array<int>

    Returns total and checkpointed frame count.

    Parameters:

    • mode (Symbol)

      checkpoint mode (:passive, :full, :restart, :truncate)

    Returns:

    • (Array<int>)

      total and checkpointed frame count

  • #wal_checkpoint(mode, db_name) ⇒ Array<int>

    Returns total and checkpointed frame count.

    Parameters:

    • mode (Symbol)

      checkpoint mode (:passive, :full, :restart, :truncate)

    • db_name (String)

      attached database name

    Returns:

    • (Array<int>)

      total and checkpointed frame count



1448
1449
1450
1451
1452
1453
1454
1455
1456
1457
1458
1459
1460
1461
1462
1463
1464
1465
1466
1467
1468
1469
# File 'ext/extralite/database.c', line 1448

VALUE Database_wal_checkpoint(int argc, VALUE *argv, VALUE self) {
  Database_t *db = self_to_open_database(self);
  VALUE mode = Qnil;
  VALUE db_name = Qnil;
  int total_frames;
  int checkpointed_frames;

  rb_scan_args(argc, argv, "11", &mode, &db_name);

  int mode_int = checkpoint_mode_symbol_to_int(mode);
  int rc = sqlite3_wal_checkpoint_v2(
    db->sqlite3_db,
    NIL_P(db_name) ? NULL : StringValueCStr(db_name),
    mode_int,
    &total_frames,
    &checkpointed_frames
  );
  if (rc != SQLITE_OK)
    rb_raise(cError, "Failed to perform WAL checkpoint: %s", sqlite3_errstr(rc));
  
  return rb_ary_new3(2, INT2NUM(total_frames), INT2NUM(checkpointed_frames));
}