NAME
    DBIx::Wrapper - A wrapper around the DBI

SYNOPSIS
     use DBIx::Wrapper;

     my $db = DBIx::Wrapper->connect($dsn, $user, $auth, \%attr);

     my $db = DBIx::Wrapper->connect($dsn, $user, $auth, \%attr,
              { error_handler => sub { print $DBI::errstr },
                debug_handler => sub { print $DBI::errstr },
              });

     my $db = DBIx::Wrapper->connect_from_config($db_key, $config_file,
              { error_handler => sub { print $DBI::errstr },
                debug_handler => sub { print $DBI::errstr },
              });
          
     my $dbi_obj = DBI->connect(...)
     my $db = DBIx::Wrapper->newFromDBI($dbi_obj);

     my $dbi_obj = $db->getDBI;

     my $rv = $db->insert($table, { id => 5, val => "myval",
                                    the_date => \"NOW()",
                                  });
     my $rv = $db->insert($table, { id => 5, val => "myval",
                                    the_date => $db->command("NOW()"),
                                  });

     my $rv = $db->replace($table, \%data);
     my $rv = $db->smartReplace($table, \%data)
     my $rv = $db->delete($table, \%keys);
     my $rv = $db->update($table, \%keys, \%data);
     my $rv = $db->smartUpdate($table, \%keys, \%data);

     my $row = $db->selectFromHash($table, \%keys, \@cols);
     my $row = $db->selectFromHashMulti($table, \%keys, \@cols);
     my $val = $db->selectValueFromHash($table, \%keys, $col);
     my $vals = $db->selectValueFromHashMulti($table, \%keys, \@cols);
     my $rows = $db->selectAll($table, \@cols);

     my $row = $db->nativeSelect($query, \@exec_args);

     my $loop = $db->nativeSelectExecLoop($query);
     foreach my $val (@vals) {
         my $row = $loop->next([ $val ]);
     }

     my $row = $db->nativeSelectWithArrayRef($query, \@exec_args);

     my $rows = $db->nativeSelectMulti($query, \@exec_args);
     my $rows = $db->nativeSelectMultiOrOne($query, \@exec_args);

     my $loop = $db->nativeSelectMultiExecLoop($query)
     foreach my $val (@vals) {
         my $rows = $loop->next([ $val ]);
     }

     my $rows = $db->nativeSelectMultiWithArrayRef($query, \@exec_args);

     my $hash = $db->nativeSelectMapping($query, \@exec_args);
     my $hash = $db->nativeSelectDynaMapping($query, \@cols, \@exec_args);

     my $hash = $db->nativeSelectRecordMapping($query, \@exec_args);
     my $hash = $db->nativeSelectRecordDynaMapping($query, $col, \@exec_args);

     my $val = $db->nativeSelectValue($query, \@exec_args);
     my $vals = $db->nativeSelectValuesArray($query, \@exec_args);

     my $row = $db->abstractSelect($table, \@fields, \%where, \@order);
     my $rows = $db->abstractSelectMulti($table, \@fields, \%where, \@order);

     my $loop = $db->nativeSelectLoop($query, @exec_args);
     while (my $row = $loop->next) {
         my $id = $$row{id};
     }

     my $rv = $db->nativeQuery($query, @exec_args);

     my $loop = $db->nativeQueryLoop("UPDATE my_table SET value=? WHERE id=?");
     $loop->next([ 'one', 1]);
     $loop->next([ 'two', 2]);

     my $id = $db->getLastInsertId;

     $db->debugOn(\*FILE_HANDLE);

     $db->setNameArg($arg)

     $db->commit();
     $db->ping();
     $db->err();

  Attributes
     Attributes accessed in DBIx::Wrapper object via hash access are
     passed on or retrieved from the underlying DBI object, e.g.,

     $dbi_obj->{RaiseError} = 1

  Named Placeholders
     All native* methods (except for nativeSelectExecLoop) support
     named placeholders.  That is, instead of using ? as a
     placeholder, you can use :name, where name is the name of a key
     in the hash passed to the method.  To use named placeholders,
     pass a hash reference containing the values in place of the
     @exec_args argument.  E.g.,

     my $row = $db->nativeSelect("SELECT * FROM test_table WHERE id=:id", { id => 1 });

     :: in the query string gets converted to : so you can include
     literal colons in the query.  :"var name" and :'var name' are
     also supported so you can use variable names containing spaces.

     The implementation uses ? as placeholders under the hood so that
     quoting is done properly.  So if your database driver does not
     support placeholders, named placeholders will not help you.

DESCRIPTION
    DBIx::Wrapper provides a wrapper around the DBI that makes it a bit
    easier on the programmer. This module allows you to execute a query with
    a single method call as well as make inserts easier, etc. It also
    supports running hooks at various stages of processing a query (see the
    section on Hooks).

METHODS
    Following are DBIx::Wrapper methods. Any undocumented methods should be
    considered private.

  connect($data_source, $username, $auth, \%attr, \%params)
     Connects to the given database.  The first four parameters are
     the same parameters you would pass to the connect call when
     using DBI directly.  If $data_source is a hash, it will generate
     the dsn for DBI using the values for the keys driver, database,
     host, port.

     The %params hash is optional and contains extra parameters to
     control the behaviour of DBIx::Wrapper itself.  Following are
     the valid parameters.

    error_handler and debug_handler
         These values should either be a reference to a subroutine, or a
         reference to an array whose first element is an object and whose
         second element is a method name to call on that object.  The
         parameters passed to the error_handler callback are the current
         DBIx::Wrapper object and an error string, usually the query if
         appropriate.  The parameters passed to the debug_handler
         callback are the current DBIx::Wrapper object, an error string,
         and the filehandle passed to the debugOn() method (defaults to
         STDERR).  E.g.,

          sub do_error {
              my ($db, $str) = @_;
              print $DBI::errstr;
          }
          sub do_debug {
              my ($db, $str, $fh) = @_;
              print $fh "query was: $str\n";
          }

          my $db = DBIx::Wrapper->connect($ds, $un, $auth, \%attr,
                                          { error_handler => \&do_error,
                                            debug_handler => \&do_debug,
                                          });

    db_style
         Used to control some database specific logic.  The default value
         is 'mysql'.  Currently, this is only used for the
         getLastInsertId() method.  MSSQL is supported with a value of
         mssql for this parameter.

    heavy
         If set to a true value, any hashes returned will actually be
         objects on which you can call methods to get the values back.
         E.g.,

          my $row = $db->nativeSelect($query);
          my $id = $row->id;
          or
          my $id = $row->{id};

    no_placeholders
         If you are unfortunate enough to be using a database that does
         not support placeholders, you can set no_placeholders to a true
         value here.  For non native* methods that generate SQL on their
         own, placeholders are normally used to ensure proper quoting of
         values.  If you set no_placeholders to a true value, DBI's
         quote() method will be used to quote the values instead of using
         placeholders.

  new($data_source, $username, $auth, \%attr, \%params)
     An alias for connect().

  connect_from_config($db_key, $config_file, \%params)
     Like connect(), but the parameters used to connect are taken
     from the given configuration file.  The Config::General module
     must be present for this method to work (it is loaded as
     needed).  $config_file should be the path to a configuration
     file in an Apache-style format.  $db_key is the name of the
     container with the database connection information you wish to
     use.  The %params hash is optional and contains extra parameters
     to control the behaviour of DBIx::Wrapper itself.

     Following is an example configuration file.  Note that the dsn
     can be specified either as a container with each piece named
     separately, or as an option whose value is the full dsn that
     should be based to the underlying DBI object.  Each db container
     specifies one database connection.  Note that, unlike Apache,
     the containers and option names are case-sensitive.

        <db test_db_key>
            <dsn>
                driver mysql
                database test_db
                host example.com
                port 3306
            </dsn>

            user test_user
            password test_pwd

            <attributes>
                RaiseError 0
                PrintError 1
            </attributes>
        </db>

        <db test_db_key2>
            dsn "dbi:mysql:database=test_db;host=example.com;port=3306"

            user test_user
            password test_pwd
        </db>

     Configuration features from Config::General supported:

       * Perl style comments
       * C-style comments
       * Here-documents
       * Apache style Include directive
       * Variable interpolation (see docs for Config::General::Interpolated)

  reconnect()
     Reconnect to the database using the same parameters that were
     given to the connect() method.  It does not try to disconnect
     before attempting to connect again.

  disconnect()
     Disconnect from the database.  This disconnects and frees up the
     underlying DBI object.

  connectOne(\@cfg_list, \%attr)
     Connects to a random database out of the list.  This is useful
     for connecting to a slave database out of a group for read-only
     access.  Ths list should look similar to the following:

        my $cfg_list = [ { driver => 'mysql',
                           host => 'db0.example.com',
                           port => 3306,
                           database => 'MyDB',
                           user => 'dbuser',
                           auth => 'dbpwd',
                           attr => { RaiseError => 1 },
                           weight => 1,
                         },
                         { driver => 'mysql',
                           host => 'db1.example.com',
                           port => 3306,
                           database => 'MyDB',
                           user => 'dbuser',
                           auth => 'dbpwd',
                           attr => { RaiseError => 1 },
                           weight => 2,
                         },
                       ];

     where the weight fields are optional (defaulting to 1).  The
     attr field is also optional and corresponds to the 4th argument
     to DBI's connect() method.  The \%attr passed to this method is
     an optional parameter specifying the defaults for \%attr to be
     passed to the connect() method.  The attr field in the config
     for each database in the list overrides any in the \%attr
     parameter passed into the method.

     You may also pass the DSN string for the connect() method as the
     'dsn' field in each config instead of the separate driver, host,
     port, and database fields, e.g.,

        my $cfg_list = [ { dsn => 'dbi:mysql:host=db0.example.com;database=MyDB;port=3306',
                           user => 'dbuser',
                           auth => 'dbpwd',
                           attr => { RaiseError => 1 },
                           weight => 1,
                         },
                       ];

     Aliases: connect_one

  newFromDBI($dbh)
     Returns a new DBIx::Wrapper object from a DBI object that has
     already been created.  Note that when created this way,
     disconnect() will not be called automatically on the underlying
     DBI object when the DBIx::Wrapper object goes out of scope.

     Aliases: new_from_dbi

  getDBI()
    Return the underlying DBI object used to query the database.

    Aliases: get_dbi, getDbi

  insert($table, \%data)
     Insert the provided row into the database.  $table is the name
     of the table you want to insert into.  %data is the data you
     want to insert -- a hash with key/value pairs representing a row
     to be insert into the database.

  replace($table, \%data)
     Same as insert(), except does a REPLACE instead of an INSERT for
     databases which support it.

  smartReplace($table, \%data)
     This method is MySQL specific.  If $table has an auto_increment
     column, the return value will be the value of the auto_increment
     column.  So if that column was specified in \%data, that value
     will be returned, otherwise, an insert will be performed and the
     value of LAST_INSERT_ID() will be returned.  If there is no
     auto_increment column, but primary keys are provided, the row
     containing the primary keys will be returned.  Otherwise, a true
     value will be returned upon success.

     Aliases: smart_replace

  delete($table, \%keys), delete($table, \@keys)
     Delete rows from table $table using the key/value pairs in %keys
     to specify the WHERE clause of the query.  Multiple key/value
     pairs are joined with 'AND' in the WHERE clause.  The cols
     parameter can optionally be an array ref instead of a hashref.
     E.g.

         $db->delete($table, [ key1 => $val1, key2 => $val2 ])

     This is so that the order of the parameters in the WHERE clause
     are kept in the same order.  This is required to use the correct
     multi field indexes in some databases.

  update($table, \%keys, \%data), update($table, \@keys, \%data)
     Update the table using the key/value pairs in %keys to specify
     the WHERE clause of the query.  %data contains the new values
     for the row(s) in the database.  The keys parameter can
     optionally be an array ref instead of a hashref.  E.g.,

         $db->update($table, [ key1 => $val1, key2 => $val2 ], \%data);

     This is so that the order of the parameters in the WHERE clause
     are kept in the same order.  This is required to use the correct
     multi field indexes in some databases.

  exists($table, \%keys)
     Returns true if one or more records exist with the given column
     values in %keys.  %keys can be recursive as in the
     selectFromHash() method.

  selectFromHash($table, \%keys, \@cols);
     Select from table $table using the key/value pairs in %keys to
     specify the WHERE clause of the query.  Multiple key/value pairs
     are joined with 'AND' in the WHERE clause.  Returns a single row
     as a hashref.  If %keys is empty or not passed, it is treated as
     "SELECT * FROM $table" with no WHERE clause.  @cols is a list of
     columns you want back.  If nothing is passed in @cols, all
     columns will be returned.

     If a value in the %keys hash is an array ref, the resulting
     query will search for records with any of those values. E.g.,

       my $row = $db->selectFromHash('the_table', { id => [ 5, 6, 7 ] });

     will result in a query like

       SELECT * FROM the_table WHERE (id=5 OR id=6 OR id=7)

     The call

       my $row = $db->selectFromHash('the_table', { id => [ 5, 6, 7 ], the_val => 'ten' });

     will result in a query like

       SELECT * FROM the_table WHERE (id=5 OR id=6 OR id=7) AND the_val="ten"

     or, if a value was passed in for \@cols, e.g.,

       my $row = $db->selectFromHash('the_table', { id => [ 5, 6, 7 ], the_val => 'ten' }, [ 'id' ]);

     the resulting query would be

       SELECT id FROM the_table WHERE (id=5 OR id=6 OR id=7) AND the_val="ten"

     Aliases: select_from_hash

  selectFromHashMulti($table, \%keys, \@cols)
     Like selectFromHash(), but returns all rows in the result.
     Returns a reference to an array of hashrefs.

     Aliases: select_from_hash_multi

  selectAll($table, \@cols)
     Selects every row in the given table.  Equivalent to leaving out
     %keys when calling selectFromHashMulti(), e.g.,
     $dbh->selectFromHashMulti($table, undef, \@cols).  The simplest
     case of $dbh->selectAll($table) gets turned into something like
     "SELECT * FROM `$table`"

     Aliases: select_from_all

  selectValueFromHash($table, \%keys, $col)
     Combination of nativeSelectValue() and selectFromHash().
     Returns the first column from the result of a query given by
     $table and %keys, as in selectFromHash().  $col is the column to
     return.

  selectValueFromHashMulti($table, \%keys, \@cols)
     Like selectValueFromhash(), but returns the first column of all
     rows in the result.

     Aliases: select_value_from_hash_multi

  smartUpdate($table, \%keys, \%data)
     Same as update(), except that a check is first made to see if
     there are any rows matching the data in %keys.  If so, update()
     is called, otherwise, insert() is called.

     Aliases: smart_update

  nativeSelect($query, \@exec_args)
     Executes the query in $query and returns a single row result (as
     a hash ref).  If there are multiple rows in the result, the rest
     get silently dropped.  @exec_args are the same arguments you
     would pass to an execute() called on a DBI object.  Returns
     undef on error.

     Aliases: native_select

  nativeSelectExecLoop($query)
     Like nativeSelect(), but returns a loop object that can be used
     to execute the same query over and over with different bind
     parameters.  This does a single DBI prepare() instead of a new
     prepare() for select.

     E.g.,

         my $loop = $db->nativeSelectExecLoop("SELECT * FROM mytable WHERE id=?");
         foreach my $id (@ids) {
             my $row = $loop->next([ $id ]);
         }

     Aliases: native_select_exec_loop

  nativeSelectWithArrayRef($query, \@exec_args)
     Like nativeSelect(), but return a reference to an array instead
     of a hash.  Returns undef on error.  If there are no results
     from the query, a reference to an empty array is returned.

     Aliases: native_select_with_array_ref

  nativeSelectMulti($query, \@exec_args)
     Executes the query in $query and returns an array of rows, where
     each row is a hash representing a row of the result.  Returns
     undef on error.  If there are no results for the query, an empty
     array ref is returned.

     Aliases: native_select_multi

  nativeSelectMultiOrOne($query, \@exec_args)
     Like nativeSelectMulti(), but if there is only one row in the
     result, that row (a hash ref) is returned.  If there are zero
     rows, undef is returned. Otherwise, an array ref is returned.

     Aliases: native_select_multi_or_one

  nativeSelectMultiExecLoop($query)
     Like nativeSelectExecLoop(), but returns an array of rows, where
     each row is a hash representing a row of the result.

     Aliases: native_select_multi_exec_loop

  nativeSelectMultiWithArrayRef($query, \@exec_args)
     Like nativeSelectMulti(), but return a reference to an array of
     arrays instead of to an array of hashes.  Returns undef on error.

     Aliases: native_select_multi_with_array_ref

  nativeSelectMapping($query, \@exec_args)
     Executes the given query and returns a reference to a hash
     containing the first and second columns of the results as
     key/value pairs.

     Aliases: native_select_mapping

  nativeSelectDynaMapping($query, \@cols, \@exec_args)
     Similar to nativeSelectMapping() except you specify which
     columns to use for the key/value pairs in the return hash.  If
     the first element of @cols starts with a digit, then @cols is
     assumed to contain indexes for the two columns you wish to use.
     Otherwise, @cols is assumed to contain the field names for the
     two columns you wish to use.

     For example,

         nativeSelectMapping($query, \@exec_args) is

      equivalent (and in fact calls) to

         nativeSelectDynaMapping($query, [ 0, 1 ], $exec_args).

     Aliases: native_select_dyna_mapping

  nativeSelectRecordMapping($query, \@exec_args)
     Similar to nativeSelectMapping(), except the values in the hash
     are references to the corresponding record (as a hash).

     Aliases: native_select_record_mapping

  nativeSelectRecordDynaMapping($query, $col, \@exec_args)
     Similar to nativeSelectRecordMapping(), except you specify
     which column is the key in each key/value pair in the hash.  If
     $col starts with a digit, then it is assumed to contain the
     index for the column you wish to use.  Otherwise, $col is
     assumed to contain the field name for the two columns you wish
     to use.

  nativeSelectValue($query, \@exec_args)
     Returns a single value, the first column from the first row of
     the result.  Returns undef on error or if there are no rows in
     the result.  Note this may be the same value returned for a NULL
     value in the result.

     Aliases: native_select_value

  nativeSelectValuesArray($query, \@exec_args)
     Like nativeSelectValue(), but return multiple values, e.g.,
     return an array of ids for the query "SELECT id FROM WHERE
     color_pref='red'".

     Aliases: native_select_values_array

  abstractSelect($table, \@fields, \%where, \@order)
     Same as nativeSelect() except uses SQL::Abstract to generate the
     SQL.  See the POD for SQL::Abstract for usage.  You must have
     SQL::Abstract installed for this method to work.

     Aliases: abstract_select

  abstractSelectMulti($table, \@fields, \%where, \@order)
     Same as nativeSelectMulti() except uses SQL::Abstract to
     generate the SQL.  See the POD for SQL::Abstract for usage.  You
     must have SQL::Abstract installed for this method to work.

     Aliases: abstract_select_multi

  nativeSelectLoop($query, @exec_args)
     Executes the query in $query, then returns an object that allows
     you to loop through one result at a time, e.g.,

        my $loop = $db->nativeSelectLoop("SELECT * FROM my_table");
        while (my $row = $loop->next) {
            my $id = $$row{id};
        }

        To get the number of rows selected, you can call the
        rowCountCurrent() method on the loop object, e.g.,

        my $loop = $db->nativeSelectLoop("SELECT * FROM my_table");
        my $rows_in_result = $loop->rowCountCurrent;

        The count() method is an alias for rowCountCurrent().

        To get the number of rows returned by next() so far, use the
        rowCountTotal() method.

     Aliases: native_select_loop

  nativeQuery($query, \@exec_args, \%attr)
     Executes the query in $query and returns true if successful.
     This is typically used for deletes and is a catchall for
     anything the methods provided by this module don't take into
     account.

     Aliases: native_query

  nativeQueryLoop($query)
     A loop on nativeQuery, where any placeholders you have put in
     your query are bound each time you call next().  E.g.,

        my $loop = $db->nativeQueryLoop("UPDATE my_table SET value=? WHERE id=?");
        $loop->next([ 'one', 1]);
        $loop->next([ 'two', 2]);

     Aliases: native_query_loop

  command($cmd_string)
     This creates a literal SQL command for use in insert(),
     update(), and related methods, since if you simply put something
     like "CUR_DATE()" as a value in the %data parameter passed to
     insert, the function will get quoted, and so will not work as
     expected.  Instead, do something like this:

        my $data = { file => 'my_document.txt',
                     the_date => $db->command('CUR_DATE()')
                   };
        $db->insert('my_doc_table', $data);

     This can also be done by passing a reference to a string with
     the SQL command, e.g.,

        my $data = { file => 'my_document.txt',
                     the_date => \'CUR_DATE()'
                   };
        $db->insert('my_doc_table', $data);

     This is currently how command() is implemented.

     Aliases: literal, sql_literal

  debugOn(\*FILE_HANDLE)
    Turns on debugging output. Debugging information will be printed to the
    given filehandle.

  debugOff()
    Turns off debugging output.

  setNameArg($arg)
     This is the argument to pass to the fetchrow_hashref() call on
     the underlying DBI object.  By default, this is 'NAME_lc', so
     that all field names returned are all lowercase to provide for
     portable code.  If you want to make all the field names return
     be uppercase, call $db->setNameArg('NAME_uc') after the
     connect() call.  And if you really want the case of the field
     names to be what the underlying database driveer returns them
     as, call $db->setNameArg('NAME').

     Aliases: set_name_arg

  err()
     Calls err() on the underlying DBI object, which returns the
     native database engine error code from the last driver method
     called.

  errstr()
     Calls errstr() on the underlying DBI object, which returns the
     native database engine error message from the last driver method
     called.

  DBI-compatible methods
     The following method calls use the same interface as the DBI
     method.  However, these are not simply passed through to DBI
     (see DBI methods below), so any hooks you have defined for
     DBIx::Wrapper will be called.

    do

  DBI methods
     The following method calls are just passed through to the
     underlying DBI object for convenience.  See the documentation
     for DBI for details.

    prepare
         This method may call hooks in the future.  Use
         prepare_no_hooks() if you want to ensure that it will be a
         simple DBI call.

    selectrow_arrayref

    selectrow_hashref

    selectall_arrayref

    selectall_hashref

    selectcol_arrayref

    quote

    commit

    begin_work

    rollback

    ping

  getLastInsertId(), get_last_insert_id(), last_insert_id()
     Returns the last_insert_id.  The default is to be MySQL
     specific.  It just runs the query "SELECT LAST_INSERT_ID()".
     However, it will also work with MSSQL with the right parameters
     (see the db_style parameter in the section explaining the
     connect() method).

  Hooks
    DBIx::Wrapper supports hooks that get called just before and just after
    various query operations. The add*Hook methods take a single argument
    that is either a code reference (e.g., anonymous subroutine reference),
    or an array whose first element is an object and whose second element is
    the name of a method to call on that object.

    The hooks will be called with a request object as the first argument.
    See DBIx::Wrapper::Request.

    The two expected return values are $request->OK and $request->DECLINED.
    The first tells DBIx::Wrapper that the current hook has done everything
    that needs to be done and doesn't call any other hooks in the stack for
    the current request. DECLINED tells DBIx::Wrapper to continue down the
    hook stack as if the current handler was never invoked.

    See DBIx::Wrapper::Request for example hooks.

   addPrePrepareHook($hook)
    Specifies a hook to be called just before any SQL statement is
    prepare()'d.

   addPostPrepareHook($hook)
    Specifies a hook to be called just after any SQL statement is
    prepare()'d.

   addPreExecHook($hook)
    Specifies a hook to be called just before any SQL statement is
    execute()'d.

   addPostExecHook($hook)
    Adds a hook to be called just after a statement is execute()'d.

   addPreFetchHook($hook)
    Adds a hook to be called just before data is fetch()'d from the server.

   addPostFetchHook($hook)
    Adds a hook to be called just after data is fetch()'d from the server.

  There are also underscore_separated versions of these methods.
        E.g., nativeSelectLoop() becomes native_select_loop()

DEPENDENCIES
        DBI

ACKNOWLEDGEMENTS
        Others who have contributed ideas and/or code for this module:

        Kevin Wilson
        Mark Stosberg
        David Bushong

AUTHOR
        Don Owens <don@owensnet.com>

LICENSE AND COPYRIGHT
    Copyright (c) 2003-2006 Don Owens (don@owensnet.com). All rights
    reserved.

    This free software; you can redistribute it and/or modify it under the
    same terms as Perl itself. See perlartistic.

    This program is distributed in the hope that it will be useful, but
    WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

SEE ALSO
        DBI, perl

VERSION
        0.23

