Name

SPVM::DBI - Base Class for Database Drivers Providing Common Utilities

Description

DBI class in SPVM provides a database-independent interface for database connections.

This class serves two main purposes:

  • Base Class for Drivers: It acts as a base class for database driver handles. Each driver, such as DBD::SQLite, extends this class and implements its own connect and other database-specific methods.

  • Common Functionality: It provides common fields and protected methods (like "connect_common") that handle shared logic for all drivers, such as option validation and DSN parsing.

Note that while this class contains the logic for driver authors, general users will interact with instances of this class (or its subclasses) to perform database operations.

Caution

SPVM::DBI is under early development. This is an alpha release.

This module is not yet tested and is in a highly experimental stage. The interface and implementation are subject to change without notice. Use this module at your own risk. It is not recommended for production use.

Usage

use DBI;
use DBD::SQLite;
use Go::Context;

my $ctx = Go::Context->new;

# 1. Connect to a database
my $dbh = DBD::SQLite->connect($ctx, "user", "password", {Database => ":memory:"});

# 2. Prepare a statement
my $sql = "SELECT id, name FROM users WHERE id > ?";
my $sth = $dbh->prepare($ctx, $sql);

# 3. Execute with bind values
$sth->execute($ctx, [(object)10]);

# 4. Fetch rows in a while loop (Simple usage)
while (my $row = $sth->fetch($ctx)) {
  my $id   = $row->[0]->(int);
  my $name = $row->[1]->(string);
  
  # Process the data...
}

Fast Fetch with Buffer Reuse:

# Prepare the "vessels" (objects) in advance to avoid allocations inside the loop.
# Use new_string_len to allocate a string buffer without redundant initialization.
my $columns = [(object)Int->new(0), new_string_len 100]; 
my $ret_row = new object[2];

while (my $row = $sth->fetch($ctx, $columns, $ret_row)) {
  # The driver updates the existing objects in $columns.
  # $row is the same as $ret_row.
  my $id   = $row->[0]->(int);
  my $name = $row->[1]->(string);
  
}

Transaction:

# Transaction management
eval {
  $dbh->begin_work($ctx);
  
  # ... execute statements ...
  
  $dbh->commit($ctx);
};
if ($@) {
  $dbh->rollback($ctx);
}

# 3. Disconnect explicitly
$dbh->disconnect;

Modules

Fields

Username

The username for the database connection. This field stores the username extracted from the DSN.

Database

has Database : ro string;

The database name.

Host

has Host : ro string;

The host name of the database server.

Port

has Port : ro int;

The port number of the database server.

has Username : ro string;

AutoCommit

has AutoCommit : ro byte;

The AutoCommit status.

InactiveDestroy

has InactiveDestroy : rw byte;

The InactiveDestroy status.

IdleTimeoutDurationNsec

has IdleTimeoutDurationNsec : rw long;

The maximum duration that a connection can remain idle, in nanoseconds.

ConnectTimeoutDurationNsec

has ConnectTimeoutDurationNsec : rw long;

The timeout value for establishing a new database connection, in nanoseconds.

ReadTimeoutDurationNsec

has ReadTimeoutDurationNsec : rw long;

The timeout value for read operations, in nanoseconds.

WriteTimeoutDurationNsec

has WriteTimeoutDurationNsec : rw long;

The timeout value for write operations, in nanoseconds.

SocketKeepAliveDurationNsec

has SocketKeepAliveDurationNsec : rw long;

The duration for TCP keep-alive idle time, in nanoseconds.

TCPNoDelay

has TCPNoDelay : rw byte;

The TCP_NODELAY status (boolean 1 or 0).

Class Methods

blob

static method blob : DBI::Data ($value : string)

Creates a new DBI::Data object with TYPE_ID_BLOB.

This is a helper method to wrap binary data.

big_int

static method big_int : DBI::Data ($value : string)

Creates a new DBI::Data object with TYPE_ID_BIG_INT.

This is a helper method to wrap a large integer represented as a string (e.g., "170141183460469231731687303715884105727").

big_float

static method big_float : DBI::Data ($value : string)

Creates a new DBI::Data object with TYPE_ID_BIG_FLOAT.

This is a helper method to wrap a high-precision floating-point number represented as a string.

Instance Methods

prepare

method prepare : DBI::St ($ctx : Go::Context, $sql : string, $options : object[] = undef)

Prepares the SQL statement and returns a statement handle (DBI::St).

begin_work

method begin_work : void ($ctx : Go::Context)

Starts a new transaction.

commit

method commit : void ($ctx : Go::Context)

Commits the current transaction.

rollback

method rollback : void ($ctx : Go::Context)

Rolls back the current transaction.

last_insert_id

method last_insert_id : object ($ctx : Go::Context, $catalog : string = undef, $schema : string = undef, $table : string = undef, $field : string = undef, $options : object[] = undef)

Returns the ID of the last inserted row.

ping

method ping : int ($ctx : Go::Context)

Checks if the database connection is still alive.

get_info

method get_info : object ($ctx : Go::Context, $info_type : int)

Returns information about the database.

table_info

method table_info : DBI::St ($ctx : Go::Context, $catalog : string, $schema : string, $table : string, $type : string, $options : object[] = undef)

Returns a statement handle containing information about tables.

column_info

method column_info : DBI::St ($ctx : Go::Context, $catalog : string, $schema : string, $table : string, $column : string)

Returns a statement handle containing information about columns.

quote

method quote : string ($ctx : Go::Context, $str : string, $type : int = -1)

Quotes a string for use in a SQL statement.

quote_identifier

method quote_identifier : string ($ctx : Go::Context, $catalog : string, $schema : string, $table : string, $options : object[] = undef)

Quotes an identifier for use in a SQL statement.

disconnect

method disconnect : void ()

Disconnects from the database.

DESTROY

method DESTROY : void ()

The destructor. Unless "InactiveDestroy" is true, it calls "disconnect".

For Driver Authors

Extending DBI

The following example shows how to implement a specific database driver (DBD) by extending the DBI class.

class DBD::MyDriver extends DBI {
  
  # Implement the connect method
  static method connect : DBD::MyDriver ($ctx : Go::Context, $user : string = undef, $password : string = undef, $options : object[] = undef) {
    
    my $self = DBD::MyDriver->new;
    
    # Call the common connection logic provided by the base class.
    # This validates options and stores them into the database handle ($dbh).
    $self->connect_common($dbh, $ctx, $user, $password, $options);
    
    # Implement the driver-specific logic to connect to a database.
    # Apply network-related settings using the values stored in $dbh.
    # ...
    
    return $self;
  }
  
  # Overriding prepare method
  method prepare : DBI::St ($ctx : Go::Context, $sql : string, $options : object[] = undef) {
    
    my $sth = DBD::MyDriver::St->new;
    
    # Call the common preparation logic provided by the base class.
    $self->prepare_common($sth, $ctx, $sql, $options);
    
    # Implement the driver-specific logic to prepare a statement.
    # ...
    
    return $sth;
  }
  
}

Implementing connect

When implementing connect method, driver authors are responsible for the following:

static method connect : DBI ($ctx : Go::Context, $user : string = undef, $password : string = undef, $options : object[] = undef)

Establishes a connection to the database and returns a database handle (DBI).

The following options can be specified in $options.

  • ConnectTimeoutDurationNsec

    The maximum time to wait for the database connection to be established, specified in nanoseconds.

  • TCPNoDelay

    A boolean value (0 or 1) to disable Nagle's algorithm. Set to 1 to reduce latency for small packets by sending them immediately.

  • SocketKeepAliveDurationNsec

    The interval for TCP keep-alive probes, specified in nanoseconds. This is useful for maintaining long-lived connections through firewalls or load balancers.

  • IdleTimeoutDurationNsec

    The duration a connection can remain idle before it is considered expired and closed by the driver, specified in nanoseconds.

  • InactiveDestroy

    A boolean value. If set to 1, the disconnect method will not be called automatically when the database handle object is destroyed.

Abstract Methods

The following methods are intended to be overridden in child classes. If a method is not overridden, it throws a DBI::Error::SQLState exception with SQLSTATE "IM001" (Driver does not support this function):

"prepare", "begin_work", "commit", "rollback", "last_insert_id", "ping", "get_info", "table_info", "column_info", "quote", "quote_identifier", "disconnect".

Available Instance Methods

connect_common

protected method connect_common : void ($ctx : Go::Context, $user : string = undef, $password : string = undef, $options : object[] = undef)

Provides common initialization logic for a database handle. This method is intended to be called by driver authors within their own connect implementation.

It performs the following tasks:

  • Validates the option names in $options by calling Fn#check_option_names with the names returned by option_names.

  • Initializes the following fields using the provided arguments and options:

    • Username

      Set to the value of $user.

    • Host, Port, Database

      Set to the values of Host, Port, and Database from $options if they exist.

    • AutoCommit

      Always set to 1.

    • InactiveDestroy, TCPNoDelay

      Set to the values of InactiveDestroy and TCPNoDelay from $options if they exist.

    • IdleTimeoutDurationNsec, ConnectTimeoutDurationNsec, ReadTimeoutDurationNsec, WriteTimeoutDurationNsec, SocketKeepAliveDurationNsec

      Set to the respective duration values (as long) from $options if they exist.

prepare_common

protected method prepare_common : void ($sth : DBI::St, $ctx : Go::Context, $sql : string, $options : object[] = undef)

Provides common initialization logic for a statement handle. This method is intended to be called by driver authors within their own prepare implementation.

It performs the following tasks:

  • Validates the option names in $options by calling Fn#check_option_names with the names returned by the statement handle's option_names method.

  • Initializes the following fields of the statement handle $sth:

    • Database

      Set the DBI::St#Database field to the current database handle (the instance of DBI that called the prepare method).

    • Statement

      Set the DBI::St#Statement field to the SQL string provided as $sql.

Overridable Instance Methods

option_names

protected method option_names : string[] ()

Returns an array of supported option names for the database handle. In the base class, this returns default options like InactiveDestroy, TCPNoDelay, and several *DurationNsec options.

Driver authors can override this method to add driver-specific options. These names are used by "connect_common" or prepare_common via Fn#check_option_names.

Override this method if your database handle supports specific options. These names are used by "prepare_common" to validate the options passed by the user.

See Also

Go::Context

Repository

https://github.com/yuki-kimoto/SPVM-DBI

Author

Yuki Kimoto kimoto.yuki@gmail.com

Copyright & License

Copyright (c) 2026 Yuki Kimoto

MIT License