NAME

SQL::DB - Perl/SQL database interface

VERSION

0.97_3. Development release.

SYNOPSIS

########### The Simple API ###########

use SQL::DB;
my $db = SQL::DB->connect( $dsn, $dbuser, $dbpass );

$db->insert_into('purchases',
    values => {id => 1, count => 1},
);

$db->update('purchases',
    set   => {count => 2},
    where => {id => 1},
);

$db->delete_from('purchases',
    where => {id => 1},
);

my $obj = $db->select( ['id','who','count'],
    from => 'customers',
    where => {id => 1},
);
# print $obj->id, $obj->who etc.


########### The Full-Power API ###########

use SQL::DB qw/:all/;

my $db = SQL::DB->new(
    dsn      => $dsn,
    username => $username,
    password => $password,
    schema   => 'MyApp',    # created with sqldb-schema(1)
);

# Anyone celebrating a birthday today gets a raise, with the
# calculation done inside the database.

my $people = $db->urow('people');

$db->do(
    update => $people,
    set    => $people->salary( $people->salary * 2 ),
    where  => $people->dob == $today,
);

my $purchases = $db->srow('purchases');

my $row = $db->fetch1(
    select    => [ $people->name, $ps->pid ],
    from      => $people,
    left_join => $purchases,
    on        => $purchases->id == $people->id,
    where     => $people->id->in(1,2,3) .AND.
                   $people->name->like('%paul%'),
    limit  => 1,
    offset => 1,
);
# then do stuff with $row->pid, $row->name etc

my @rows = $db->fetch(
    select => [ sql_coalesce($p->pid, $p->cid)->as('pcid') ],
    from   => $p,
    where  => $p->cid->is_not_null,
);
# coalesce column is available as $row->pcid

my $iter = $db->iter( @query ...);
while (my $row = $iter->next) {
    print $row->column(), $row->some_other_column;
}

# If you want the data your own way you can still use the query
# syntax:
my $sth = $db->sth( @query);
map { print join(',',@$_) ."\n" } $sth->fetchall_arrayref;

# Transactions provided by DBIx::Connector
$db->txn( sub {
    # multiple statements
});

DESCRIPTION

SQL::DB is an extension to the Perl Database Interface (DBI). It is designed to handle complicated queries and provide efficient access to the results. With an API that lets you easily write almost-raw SQL, SQL::DB gives you unfettered access to the power and flexibility of your underlying database. It aims to be a tool for programmers who want their databases to work just as hard as their Perl scripts.

SQL::DB is capable of generating aggregate expressions, joins, nested selects, unions and database-side operator invocations. Transactional support is provided via DBIx::Connector. There is some minor cross database support which transparently handles the binding of binary data types, keeping the amount of data- and database-specific code you have to write to a minimum.

Although rows can be retrieved from the database as simple objects, SQL::DB does not attempt to be an Object-Relational-Mapper al-la DBIx::Class; there are no auto-inflating columns or automatic joins and the code size and speed reflect the lack of complexity.

SQL::DB uses the light-weight Log::Any for logging.

Simple API

SQL::DB queries use abstract representations of table rows - objects that can be thought of as matching any row in a table. Abstract rows are obtained using the Schema->arow() method. The objects returned have methods that match the columns of a table, plus some extra SQL syntax/sugar methods.

Full API

The real power of SQL::DB lies in the way that SQL expressions can be constructed using these abstract columns. The abstract column methods do not really act on the abstract row, but intead return an expression object (SQL::DB::Expr). Using Perl's overload feature these objects can be combined and nested in Perl in a way that maps

Abstract Rows and Expressions

SQL::DB queries use abstract representations of table rows - objects that can be thought of as matching any row in a table. Abstract rows are obtained using the Schema->arow() method. The objects returned have methods that match the columns of a table, plus some extra SQL syntax/sugar methods.

my ( $cds, $tracks ) = $db->arow(qw/ cds tracks /);

The real power of SQL::DB lies in the way that SQL expressions can be constructed using these abstract columns. The abstract column methods do not really act on the abstract row, but intead return an expression object (SQL::DB::Expr). Using Perl's overload feature these objects can be combined and nested in Perl in a way that maps very closely to they way the SQL would be written by hand.

Perl Expression                     SQL Result
----------------------------------  ---------------------------
$cds                                cds

$cds->title                         cds.title

$tracks->cd                         tracks.cd

$tracks->id->func('count')          count(tracks.cd)

$tracks->set_length(                SET tracks.length =
    $tracks->length + 10 )              tracks.length + 10

( $cds->id == 1 ) .OR.              cds.id = 1 OR
  $cds->title->like( '%Magic%' ) )      cds.title LIKE '%Magic%'

( $cds->id->is_not_null .AND.       cds.id IS NOT NULL AND
  ! $tracks->id->in( 1, 2, 5 ) )        NOT tracks.id IN (1,2,5)

Here is a summary of the default available expression operators and methods. New expression subroutines can be generated in your own code - see SQL::DB::Expr for details.

Perl            SQL             Applies to
---------       -------         ------------
.AND.           AND             All Expressions
.OR.            OR              All Expressions
!               NOT             All Expressions
.CONCAT.        || or CONCAT    All Expressions
==              =               All Expressions
!=              !=              All Expressions

like            LIKE            Column only
in              IN              Column only
not_in          NOT IN          Column only
is_null         IS NULL         Column only
is_not_null     IS NOT NULL     Column only
asc             ASC             Column only
desc            DESC            Column only
sql_count       COUNT           Column only
sql_min         MIN             Column only
sql_max         MAX             Column only
func('x',...)   X(col,...)      Column only

Query Syntax

Here is a better example with multiple functions and multiple tables. For each CD, show me the number of tracks, the length of the longest track, and the total length of the CD in one query:

track = $db->arow('tracks');
@objs = $db->fetch(
    select   => [
        $track->cd->title,
        $track->id->func('count'),
        $track->length->func('max'),
        $track->length->func('sum')
    ],
    group_by  => [
        $track->cd->title,
    ],
);

foreach my $obj (@objs) {
    print 'Title: '            . $obj->title      ."\n";
    print 'Number of Tracks: ' . $obj->count_id   ."\n";
    print 'Longest Track: '    . $obj->max_length ."\n";
    print 'CD Length: '        . $obj->sum_length ."\n\n";
}

CONSTRUCTORS

connect( $dsn, [ $user, $pass, $attrs ] )

Connect to a database and return a new SQL::DB object. This method is a convenience wrapper around new() for those who prefer DBI-style construction.

new( dsn => $dsn, ...)

Connect to a database and return a new SQL::DB object. The 'dsn' argument is mandatory. Also accepted here are 'dbuser', 'dbpass', 'dbattrs', 'debug', 'prepare_mode' and 'schema'. See ATTRIBUTES below for definitions.

ATTRIBUTES

debug <-> Bool

General debugging state (true/false). Debug messages are sent to Log::Any's "debug" method.

dsn <-> Str

The DBI connection string.

dbd -> Str

The DBD driver name ('SQLite', 'mysql', 'Pg' etc) for the type of database we are connected to. Derived from the 'dsn' attribute.

dbuser <-> Str

The DBI::Connector connection username.

dbpass <-> Str

The DBI::Connector connection password.

dbattrs <-> HASHREF

The DBI::Connector connection attributes.

conn -> DBIx::Connector

The handle connecting us to the database.

schema <-> Str

The name of the schema associated with this connection.

prepare_mode <-> Str

One of either 'prepare' or 'prepare_cached' (default). See DBI for details.

METHODS

srow( $name, [...] ) -> SQL::DB::SRow::$name, ...

Returns an object (or objects in array context) representing any row of table $name. This abstraction object is used for building SELECT statements with the 'sth', 'fetch', 'fetch1', 'iter' etc methods. The returned object has a method for each column in the table.

urow( $name, [...] ) -> SQL::DB::URow::$name, ...

Returns an object (or objects in array context) representing any row of table $name. This abstraction object is used for building UPDATE or DELETE statements with the 'do' method. The returned object has a method for each column in the table.

do(@query)

Constructs a SQL::DB::Query object as defined by @query and runs that query against the connected database. Croaks if an error occurs. This is the method to use for any statement that doesn't retrieve values (eg INSERT, UPDATE and DELETE). Returns whatever value the underlying DBI->do call returns. This method uses "prepare_cached" to prepare the call to the database.

fetch(@query) -> SQL::DB::Cursor | @SQL::DB::Row

Constructs an SQL::DB::Query object as defined by @query and runs that query against the connected database. Croaks if an error occurs. This method should be used for SELECT-type statements that retrieve rows. This method uses "prepare_cached" to prepare the call to the database.

When called in array context returns a list of SQL::DB::Row based objects. The objects have accessors for each column in the query. Be aware that this can consume large amounts of memory if there are lots of rows retrieved.

When called in scalar context returns a query iterator (SQL::DB::Cursor) (with "next", "all" and "reset" methods) to retrieve dynamically constructed objects one at a time.

fetch1(@query) -> SQL::DB::Row

Similar to fetch() but always returns only the first object from the result set. All other rows (if any) can not be retrieved. You should only use this method if you know/expect one result. This method uses "prepare_cached" to prepare the call to the database.

query(@query)

Return an SQL::DB::Query object as defined by @query. This method is useful when creating nested SELECTs, UNIONs, or you can print the returned object if you just want to see what the SQL looks like.

query_as_string($sql, @bind_values)

An internal function for pretty printing SQL queries by inserting the bind values into the SQL itself. Returns a string.

current_timestamp

The current date and time (as a string) that remains fixed within a transaction.

iter( @query )

Runs a query and returns a SQL::DB::Cursor object. You can call next() and all() methods on this object to obtain data.

sth( @query )

Runs a query and returns a DBI::st statement handle. You can call fetchrow_array() and other DBI method on this handle.

insert_into($row)

Insert $row into the database, where $row is an SQL::DB::Row based object returned from row() or fetch() methods.

update($row)

Update $row in the database, where $row is an SQL::DB::Row based object returned from row() or fetch() methods.

delete_from($row) -> Int

Delete $row from the database, where $row is an SQL::DB::Row based object returned from row() or fetch() methods.

select(\@columns, from => $table, where => \%args) -> Obj

Delete $row from the database, where $row is an SQL::DB::Row based object returned from row() or fetch() methods.

txn(&coderef)

Runs the code in &coderef as an SQL transaction. If &coderef does not raise any exceptions then the transaction is commited, otherwise it is rolled back.

This method can be called recursively, but any sub-transaction failure will always result in the outer-most transaction also being rolled back. For savepoint support see DBIx::Connector.

CLASS FUNCTIONS

All of the following functions can be exported individually on demand, or all at once using the ':all' tag.

query( @statements )

Create a new SQL::DB::Expr expression based on the given @statements. Scalars are uppercased with '_' converted to spaces, and ARRAYREF elements are joined together with ','.

sql_and
sql_case
sql_coalesce
sql_cast
sql_concat
sql_count
sql_exists
sql_func
sql_length
sql_lower
sql_max
sql_min
sql_sum
sql_or
sql_substr
sql_upper
sql_values

COMPATABILITY

All SQL::DB releases have so far been DEVELOPMENT!

SQL::DB jumped from version 0.18 to 0.98 due to a complete rewrite based on Moo. Lots of things were simplified, modules deleted, dependencies removed, etc. The API changed enough to almost give this distribution a new name, except I don't know of anyone using this apart from myself. 0.98 will be the last release marked as development, 0.99 will be a release candidate, and 1.00 will be the first stable release.

SEE ALSO

SQL::Sequence, SQL::DB::Deploy, SQL::DB::Expr, SQL::DB::Iter, DBIx::Connector, Log::Any

SUPPORT

Feedback, testing, bug reports and patches are all welcome.

Bug Reporting
https://rt.cpan.org/Public/Bug/Report.html?Queue=SQL-DB
Source Code
git clone git://github.com/mlawren/sql-db.git

AUTHOR

Mark Lawrence <nomad@null.net>

COPYRIGHT AND LICENSE

Copyright (C) 2007-2011 Mark Lawrence <nomad@null.net>

This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version.