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:



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
929
930
# File 'ext/extralite/database.c', line 888

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



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

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



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

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



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

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



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

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



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

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:



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

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



670
671
672
673
674
# File 'ext/extralite/database.c', line 670

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



652
653
654
# File 'ext/extralite/database.c', line 652

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



1330
1331
1332
1333
1334
# File 'ext/extralite/database.c', line 1330

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



1340
1341
1342
1343
1344
# File 'ext/extralite/database.c', line 1340

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



1352
1353
1354
1355
1356
# File 'ext/extralite/database.c', line 1352

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.



497
498
499
# File 'ext/extralite/database.c', line 497

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



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

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



1381
1382
1383
1384
# File 'ext/extralite/database.c', line 1381

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



1405
1406
1407
1408
1409
1410
1411
1412
1413
1414
1415
1416
1417
1418
1419
1420
1421
1422
1423
1424
1425
1426
1427
1428
# File 'ext/extralite/database.c', line 1405

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



1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
# File 'ext/extralite/database.c', line 1364

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:



798
799
800
801
802
803
# File 'ext/extralite/database.c', line 798

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



660
661
662
663
664
# File 'ext/extralite/database.c', line 660

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



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

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:



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

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:



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
1251
1252
1253
1254
1255
1256
# File 'ext/extralite/database.c', line 1225

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:



750
751
752
# File 'ext/extralite/database.c', line 750

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:



784
785
786
# File 'ext/extralite/database.c', line 784

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:



750
751
752
# File 'ext/extralite/database.c', line 750

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:



767
768
769
# File 'ext/extralite/database.c', line 767

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)


340
341
342
# File 'ext/extralite/database.c', line 340

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



393
394
395
# File 'ext/extralite/database.c', line 393

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)


340
341
342
# File 'ext/extralite/database.c', line 340

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



419
420
421
# File 'ext/extralite/database.c', line 419

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



471
472
473
# File 'ext/extralite/database.c', line 471

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



419
420
421
# File 'ext/extralite/database.c', line 419

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



445
446
447
# File 'ext/extralite/database.c', line 445

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



363
364
365
# File 'ext/extralite/database.c', line 363

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



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

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



1041
1042
1043
1044
1045
1046
# File 'ext/extralite/database.c', line 1041

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:



1053
1054
1055
1056
1057
1058
# File 'ext/extralite/database.c', line 1053

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:



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

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



700
701
702
703
704
# File 'ext/extralite/database.c', line 700

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



1454
1455
1456
1457
1458
1459
1460
1461
1462
1463
1464
1465
1466
1467
1468
1469
1470
1471
1472
1473
1474
1475
# File 'ext/extralite/database.c', line 1454

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));
}