Location: PHPKode > projects > Calia > calia/db_interface.inc
<?php

/**
 * CaliaLib - Database interface specification
 *
 * @package    CaliaLib
 * @subpackage DB-Interface
 * @author     Andrew Gray <hide@address.com>
 * @version    CVS: $Id: db_interface.inc,v 1.3 2010/04/19 21:47:13 blargh2015 Exp $
 *
 * Copyright 2001-2009 Andrew Gray
 *
 * This file is part of CaliaLib.
 *
 * CaliaLib 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 2 of the License, or
 * (at your option) any later version.
 *
 * CaliaLib 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 the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with CaliaLib; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 *
 * Provides interfaces to a database.  In a seperate file solely because its huge, and included from core_interfaces.inc
 *
 * I have been asked, many many times, why I need this module - don't the standard PHP DB classes (and especially the new Pear DB class) abstract enough?
 *
 * No.  They don't.
 *
 * Try, for example, creating a SERIAL row.  Whoops.  Oracle, MySQL, and Postgres all do it differently. 
 * Try even just escaping field names correctly.  Neither class does it right with table.column names.
 * Index specifications? Foreign key support? Ha.
 * Fun row types that, while possibly not directly implemented on everything, could be done with CHECKs and the like? Ha ha.
 * Virtually guaranteeing safe database access? Ha.  Ha ha ha.
 *
 * It is devoutly hoped eventually this module will be obsoleted by Something Better in which case an instance of this class can 
 * simply act as glue and all will be happy.
 * 
 * Issues with current abstraction layers:
 * MDB2 - Very poor data type support (and extending it is non-trivial and poorly documented), no SERIAL-type support that 
 *        automatically calls the sequence (you have to make the sequence call separately).
 *
 * Anyway...
 *
 * Note: Almost all functions will raise exceptions on errors - these should be caught and dealt with by the calling program.
 * Note 2: Auto-commit mode is on by default.  If you want transactions, use the Begin/Commit/Rollback functions.
 *
 * The following variables are common to many functions, and defined here in  detail:
 *
 * $whereClause - A where field string.  This is somewhat different than normal SQL, in part to allow different DB handlers 
 *    to handle escaping their own unique way.  It is an array of elements in prefix order (reverse polish).  Constants are 
 *    prefixed by |, functions prefixed by #<numargs>, NULL is carried through, otherwise strings assumed to be a field name and 
 *    numbers assumed to be numeric constants.   
 *    Functions should ONLY be SQL-spec defined functions.  
 *    Operators permitted:
 *    & - 2 arguments - AND
 *    | - 2 arguments - OR
 *    =,!=,<,>,<=,>= - 2 arguments - equality, non-equality, less than, greater than, lte, gte
 *    +,-,*,/,%,^ - 2 arguments - basic math ops
 *    =I - 2 arguments - case-insensitive equality, !-prefixable
 *    =L - 2 arguments - wildcard equality (%), !-prefixable
 *    ! - 1 argument - NOT
 *    =O - 4 arguments - (a1,a2) OVERLAPS (a3,a4)
 *          
 *    array('=','a','b')                      : WHERE "a" = "b"
 *    array('=','a',2)                        : WHERE "a" = 2
 *    array('=','a','#0NOW')                  : WHERE "a" = NOW()
 *    array('!=','a','b')                     : WHERE "a" <> "b"
 *    array('&','=','a','b','=','c','d')      : WHERE ("a" = "b") AND ("c" = "d")
 *    array('=I','a','b')                     : WHERE UPPER("a") = UPPER("b")
 *    array('=L','a','|%so%')                 : WHERE "a" LIKE '%so%'
 *    array('=S','a','|[0-9]+')               : WHERE "a" SIMILAR TO '[0-9]+'
 *    array('|','&','<','a',2,'>','b',4,'&','<','c',3,'d',5) : WHERE (("a" < 2 AND "b" > 4) OR ("c" < 3 AND "d" > 5))
 *    array('=','a',NULL)                     : WHERE "a" = NULL
 *    array('=','a','|foo')                   : WHERE "a" = 'foo'
 *       
 *    Certain field types must support additional operators:
 *    cidr* : << (contained within), <<= (contained within or equals), >> (contains), >>= (contains or equals) - see 
 *            Postgres docs for details
 *
 *    For simple field=blah wheres, you can instead pass a much-simpler associative array of columnName=>data.  They will be AND'ed together.
 * 
 * $fieldName - Any field name, which will be safed.  Some special characters: + requests concatenation of multiple fields, | prefix is a literal
 *    Ex: 'fieldA+| +fieldB+| +' would get a concatenation of fieldA and fieldB, with a space between.
 *
 * $orderByClause - Either a single string for a single field name, or an array of field names.  Each name may be prefixed 
 *    with '|' to denote a descending sort.
 *
 * $columnSpecs - Array of array of column definitions.  Keyed by column name, each array has elements: Type,Size,Flags,OptionalDefault,OptionalComment
 *    ($columnSpec is only a single array).
 *    Type may be any of the following.  Note some of these may have to be emulated by this layer.  Also note for integers the ranges given are
 *    absolute - numbers outside those ranges must result in an error.  Note that bigint and biguint may be implemented extremely inefficiently
 *    (worst case in SQL is a numeric(20) with a limit check) so should only be used when absolutely necessary.  Note that how integer types deal with
 *    floats (i.e. 0.5) is UNDEFINED - some backends may round, some may error.  This is an unfortuante side effect of some DBMSes implementing ints
 *    using NUMERIC(x,0) which mandates auto-rounding, and some doing it as fixed-point without auto-rounding.  The OptionalDefault can be prefixed
 *    with a # to default to the result of a function (i.e. #NOW())
 *
 *    char      - Fixed length character string
 *    varchar   - Variable length character string
 *    text      - Large variable length character string
 *    binary    - Large variable length binary data (aka BLOB)
 *    tinyint   -   Signed Integer, -128 to 127
 *    tinyuint  - Unsigned Integer, 0 to 255
 *    smallint  -   Signed Integer, -32768 to 32767
 *    smalluint - Unsigned Integer, 0 to 65535
 *    int       -   Signed Integer, -2147483648 to 2147483647
 *    uint      - Unsigned Integer, 0 to 4294967295
 *    bigint    -   Signed Integer, -9223372036854775808 to 9223372036854775807
 *    biguint   - Unsigned Integer, 0 to 18446744073709551615
 *    single    - Single precision IEEE 754 floating point
 *    double    - Double precision IEEE 754 floating point
 *    float     - Variable length floating bit.  Size is the number of binary digits (as per SQL standard)
 *    decimal   - Fixed-length decimal number - size is a string "DigitsBeforeDecimal,DigitsAfterDecimal"
 *    serial    - Automatically maintained, guaranteed table-unique serial number, integer.  Should allow uint-sized numbers at least.
 *    guid      - Automatically maintained, guaranteed database-unique (and possibly world-unique) number.
 *    guidptr   - Same field type as guid, meant for FKing.  Supports special flag C for Cascade deletes from parent GUID (whatever that might be)
 *    ipv4      - IPv4 address (i.e. 192.168.0.1).
 *    cidrv4    - IPv4 CIDR (i.e. 192.168.0.0/24).
 *    ipv6      - IPv6 address (i.e. 2001:fecd:ba23:cd1f:dcb1:1010:9234:4088 or fec0:1::1234 or fe80:0:0:0:200:f8ff:fe21:67cf)
 *    cidrv6    - IPv6 CIDR (i.e. 2001:503:fe39::/48)
 *    ip        - IPv4 or IPv6 address
 *    cidr      - IPv4 or IPv6 CIDR
 *    mac       - MAC address (full 17 bytes, lowercase - 00:0a:bc:de:ff:0a)
 *    timestamp - Timestamp, at least year 1970 to 2038, with at least second-level resolution, must be in format yyyy-mm-dd hh:mm:ss
 *    date      - Date only, at least year 1970 to 2038, must be format yyyy-mm-dd. 
 *    set       - Set of possible values.  "Size" field is an array of the possible attributes.  Any or all of these can be set.
 *    enum      - A single one of possible values.  "Size" field is an array of the possible attributes.  Only one of these can be set.
 *    bool      - Either 't' or 'f' (or NULL if permitted).
 *
 *    Flags may be blank or NULL for none, or any or all of the following characters denoting attributes (as appropriate):
 *    U - Unique.  Ensure all rows in this table have unique values for this column.  Note Unique MUST NOT consider NULLs - i.e. multiple rows with
 *        NULL set (if the NULL flag is set) must be allowed.  (This is as per SQL specifications.)  This is equivalent to doing a TableIndexAdd()
 *        with isUnique = TRUE - use that function to define Uniques across multiple columns (as otherwise what columns are unique with what is
 *        is unclear).
 *    N - Nulls.  Allow NULLs.  (Default MUST NOT allow them).
 *    P - Primary Key.  Primary keys are at least Unique and Not Null.  Only one primary key is permitted per table.  Callers SHOULD define a primary
 *        key per table.  You MAY define this in multiple columns - the combination of fields becomes the primary key.  Note that dynamically adding
 *        and removing columns to the primary key /is/ supported.
 *    A - Audit.  Generate code and what-have-you to support auditing of changes to this field.  Retrieved via FetchAuditLog.  Requires the table
 *        to have a guid (not just serial) row, defined as primary key, to key off of.
 *
 * $columnRow - An array of values, with the column name as the key.
 * $columnRows - An array of $columnRow.
 *
 * $table - Either a string of a single table name, or an array of join specifications.  This is similar to where clauses, 
 *    except with additional operators.  Parameters are T1,T2,condition. 
 *    Note these codes have been chosen to avoid conflicts with (infinitely more common) where clauses.
 *    :I - INNER JOIN - 3 params - For each row R1 of T1, the joined table has a row for each row in T2 that satistifies the 
 *                                join condition with R1.
 *    :LO - LEFT OUTER JOIN - 3 params - INNER JOIN, then for each row in T1 that has no matches, add it with NULLs for the 
 *                                      fields in T2.
 *    :RO - RIGHT OUTER JOIN - 3 params - INNER JOIN, then for each row in T2 that has no matches, add it with NULLs for the 
 *                                       fields in T1.
 *    :FO - FULL OUTER JOIN - 3 params - INNER JOIN, combined with LEFT OUTER and RIGHT OUTER.
 *    :C - CROSS JOIN - 2 params - For each combination of R1 and R2, return a row (thus returning R1*R2 rows).  This can be 
 *                                huge - use with caution.
 *    Examples:
 *    array(':I','table1','table2','=','table1.foo','table2.bla') = "table1" INNER JOIN "table2" ON "table1"."foo" = "table2"."bla"
 *    array(':C',':I','table1','table2','=','table1.foo','table2.bla','table3') =
 *      ("table1" INNER JOIN "table2" ON "table1"."foo" = "table2"."bla") CROSS JOIN "table3"
 */

define('DB_ERR_INTERNAL',1);
define('DB_ERR_NO_HOST',2);
define('DB_ERR_INVALID_AUTH',3);
define('DB_ERR_NO_RECORD',4);
define('DB_ERR_MULTIPLE_RECORDS',5);
define('DB_ERR_INVALID_WHERE',6);
define('DB_ERR_INVALID_ORDERBY',7);
define('DB_ERR_INVALID_JOIN',8);
define('DB_ERR_INVALID_DATA',9);
define('DB_ERR_NOT_UNIQUE',10);
define('DB_ERR_FOREIGN_KEY',11);
define('DB_ERR_UNKNOWN_COLUMN_TYPE',12);
define('DB_ERR_COLUMN_DOES_NOT_EXIST',13);
define('DB_ERR_COLUMN_ALREADY_EXISTS',14);
define('DB_ERR_COLUMN_NOT_SERIAL',15);
define('DB_ERR_NAME_ALREADY_USED',16);
define('DB_ERR_OBJECT_LOCKED',17);
define('DB_ERR_INVALID_NAME',18);
define('DB_ERR_INVALID_NAME_LENGTH',19);
define('DB_ERR_TABLE_DOES_NOT_EXIST',20);
define('DB_ERR_GENERIC',21);

interface dbInterface extends caliaModuleInterface
{
  /**
   * Start up database interface.  This function should do everything needed to handle queries, updates, inserts, etc. 
   */
  //public function __construct($params);

  /**
   * The database implementations must support serialization that fully restore the connections.
   */
  public function __sleep();
  public function __wakeup();

  /**
   * Returns information on the database we're connected to.
   *
   * @return array                      Array of elements, containing at least:
   *                                    name - A *simple* name of the database software (i.e. 'MySQL', 'PostgreSQL', 'Oracle')
   *                                    version - The version number of the server, or NULL if not available.
   */
  public function ServerInformation();

  /**
   * Table management functions
   **/

  /**
   * Adds a table to the database.
   *
   * @param string  $table              Table name to create.
   * @param array   $columnSpecs        Columns of the new table.
   * @param string  $comment            Optional comment for the created table.
   *
   * @return void
   */
  public function TableAdd($table, $columnSpecs, $comment = NULL);

  /**
   * Removes a table from the database.  Note this does not error if the table is already removed.
   *
   * @param string  $table              Table name to remove.
   *
   * @return void
   */
  public function TableRemove($table);

  /**
   * Does a simple test to see if the table name exists or not.
   *
   * @param string  $table              The table name to look for.
   *
   * @return boolean
   */
  public function TableExists($table);

  /**
   * Gets the current table definition from the database.
   *
   * @param string  $table              Table name to get information on.
   *
   * @return array  Column specifications.
   */
  public function TableQuery($table);

  /**
   * Adds a column to an existing table.
   *
   * @param string  $table              Table name to modify.
   * @param string  $columnName         Column name to add.
   * @param array   $columnSpec         Column specification.
   *
   * @return void
   */
  public function TableColumnAdd($table, $columnName, $columnSpec);
 
  /**
   * Removes a column from the table. Note this does not error if the column is already removed.
   *
   * @param string  $table              Table name to modify.
   * @param string  $columnName         Column name to remove.
   *
   * @return void
   */
  public function TableColumnRemove($table, $columnName);

  /**
   * Attempts to alter a column on a table.  This can fail in a lot of different ways.
   *
   * @param string  $table              Table name to modify.
   * @param string  $columnName         Column name to modify.
   * @param array   $columnSpec         New column specification.
   *
   * @return void
   */
  public function TableColumnAlter($table, $columnName, $columnSpec);

  /**
   * Creates an index on a table.
   *   
   * @param string  $table              Table name to modify.
   * @param string  $columnName         Column to index on.  Can be an array of column names for multi-column indexes.
   * @param string  $optionalFunction   Function name to index on. i.e. 'UPPER' creates an index on UPPER(fieldname).
   * @param boolean $isUnique           Should this be a UNIQUE index?
   *
   * @return void
   */
  public function TableIndexAdd($table, $columnName, $optionalFunction = NULL, $isUnique = FALSE);

  /**
   * Removes an index on a table.
   *   
   * @param string  $table              Table name to modify.
   * @param string  $columnName         Column to index on.  Can be an array of column names for multi-column indexes.
   * @param string  $optionalFunction   Function name to index on. i.e. 'UPPER' removes an index on UPPER(fieldname).
   *
   * @return void
   */
  public function TableIndexRemove($table, $columnName, $optionalFunction = NULL);
  
  /**
   * Creates a foreign key dependency.
   *
   * @param string  $table              Table to add the key check to
   * @param string  $columnName         Column being checked
   * @param string  $refTable           Table being referenced
   * @param string  $refColumnName      Column being referenced
   * @param string  $onUpdate           Action to take when referenced row is updated.  C = Cascade, R = Restrict, N = Set Null, D =  Set Default, 0 = No Action
   * @param string  $onDelete           Action to take when referenced row is deleted.  C = Cascade, R = Restrict, N = Set Null, D =  Set Default, 0 = No Action
   *
   * @return void
   */
  public function TableForeignKeyAdd($table, $columnName, $refTable, $refColumName, $onUpdate = 'C', $onDelete = 'C');

  /**
   * Removes a foreign key dependency.
   *
   * @param string  $table              Table to add the key check to
   * @param string  $columnName         Column being checked
   * @param string  $refTable           Table being referenced
   * @param string  $refColumnName      Column being referenced
   *
   * @return void
   */
  public function TableForeignKeyRemove($table, $columnName, $refTable, $refColumName);
  
  /**
   * Data retrieval functions
   */

  /**
   * Very simple fetch-single-value function.  Possible exceptions raised: ERR_ROW_NOT_FOUND, ERR_MULTIPLE_ROWS.
   * 
   * @param string  $table              Table name to fetch from.
   * @param string  $keyField           Name of field to key off of.
   * @param string  $keyValue           Value of keyField to fetch.
   * @param string  $dataField          Data field to return
   *
   * @return mixed  The requested data.
   */
  public function FetchValue($table, $keyField, $keyValue, $dataField);

  /**
   * Very simple fetch-single-record function.  Possible exceptions raised: ERR_ROW_NOT_FOUND, ERR_MULTIPLE_ROWS.
   * 
   * @param string  $table              Table name to fetch from.
   * @param string  $keyField           Name of field to key off of.
   * @param string  $keyValue           Value of keyField to fetch.
   *
   * @return array  Array of columnNames=>columnData
   */
  public function FetchRecord($table, $keyField, $keyValue);

  /**
   * More complicated fetch-single-record function.  Possible exceptions raised: ERR_ROW_NOT_FOUND, ERR_MULTIPLE_ROWS.
   *
   * @param string  $table              Table name to fetch from.
   * @param array   $whereClause        WHERE clause (see header)
   *
   * @return array  Array of columnNames=>columnData
   */
  public function FetchRecordA($table, $whereClause);

  /**
   * Fetch an array of keyValue=>dataValues.  Note that returning an empty array (no values found) is permissible here.
   *
   * @param string  $table              Table name to fetch from. 
   * @param string  $keyField           Field to use as key
   * @param string  $dataField          Field to use as data
   * @param array   $whereClause        WHERE clause (see header)
   * @param array   $orderByClause      ORDER BY clause (see header)
   *
   * @return array  Array of zero or more keyField=>dataField values.
   */
  public function Fetch1DArray($table, $keyField, $dataField, $whereClause = NULL, $orderByClause = NULL);

  /**
   * Fetch an array of keyValue=>columnRows.  Note that returning an empty array (no values found) is permissible here.
   *
   * @param string  $table              Table name to fetch from. 
   * @param string  $keyField           Field to use as key
   * @param array   $whereClause        WHERE clause (see header)
   * @param array   $orderByClause      ORDER BY clause (see header)
   *
   * @return array  Array of zero or more keyField=>columnRows
   */
  public function Fetch2DArray($table, $keyField, $whereClause = NULL, $orderByClause = NULL);

  /**
   * Fetch an array of keyValue=>columnRows, but only selected fields of those rows.  Note that returning an empty array 
   * (no values found) is permissible here.
   *
   * @param string  $table              Table name to fetch from. 
   * @param string  $keyField           Field to use as key
   * @param array   $dataFields         What fields to select
   * @param array   $whereClause        WHERE clause (see header)
   * @param array   $orderByClause      ORDER BY clause (see header)
   *
   * @return array  Array of zero or more keyField=>columnRows
   */
  public function Fetch2DArraySpecific($table, $keyField, $dataFields, $whereClause = NULL, $orderByClause = NULL);

  /**
   * Fetch an entire table, with nothing special used as the key field.
   *
   * @param string  $table              Table name to fetch from. 
   * @param array   $whereClause        WHERE clause (see header)
   * @param array   $orderByClause      ORDER BY clause (see header)
   *
   * @return array  Array of zero or more columnRows.
   */
  public function FetchTable($table, $whereClause = NULL, $orderByClase = NULL);

  /**
   * Quick function to return a count of the number of rows matching a where clause.
   *
   * @param string  $table              Table name to fetch from. 
   * @param array   $whereClause        WHERE clause (see header)
   *
   * @return integer Number of matching rows.
   */
  public function FetchCount($table, $whereClause);

  /**
   * Data modification functions
   */

  /**
   * Insert row or rows into a table.  Note the entire operation is put into a transaction - all inserts either succeed or fail as a batch.
   *
   * @param string  $table              Table to insert into.
   * @param array   $columnRows         EITHER a 1D array of columnNames=>columnData for a single row, 
   *                                    OR an array of 1D arrays for multiple rows.
   *
   * @return integer     Number of rows inserted.
   */
  public function Insert($table, $columnRows);

  /**
   * Fetch the ID number associated with the previous insert for a serial field.
   * 
   * @param string  $table              Table name
   * @param string  $column             Column name of the serial field
   *
   * @return void
   */
  public function GetInsertId($table, $column);

  /**
   * Fetch the ID number associated with the previous insert for a guid field.
   * 
   * @param string  $table              Table name
   * @param string  $column             Column name of the guid field
   *
   * @return string      The GUID of the last insert.  
   */
  public function GetInsertGuid($table, $column);

  /**
   * Update information in a table.   Note that in multiple-update mode the keys used for whereClauses must match with
   * the ones in columnRows.
   *
   * @param string  $table              Table name
   * @param array   $whereClauses       EITHER a single WHERE clause for a single row, or an array of 
   *                                    where clauses for multiple rows.
   * @param array   $columnRows         EITHER a 1D array of columnNames=>columnData for a single row, 
   *                                    OR an array of 1D arrays for multiple rows.
   *
   * @return integer     Number of rows updated.
   */
  public function Update($table, $whereClauses, $columnRows);

  /**
   * Replace information in a table.  The row MAY already exist - it should be deleted before this row is inserted if it is.  
   *
   * @param string  $table              Table name
   * @param array   $whereClause        WHERE clause
   * @param array   $columnRow          Array of columnName=>columnData to change rows into.
   *
   * @return integer     Number of rows updated.
   */
  public function Replace($table, $whereClause, $row);

  /**
   * Replace multiple rows in the table.  Note the entire operation is put into a transaction - all replaces either succeed or fail as a batch.
   *
   * @param string  $table              Table name
   * @param string  $keyField           Key field to use to select which row(s) to update.
   * @param array   $columnRows         Array of keyData=>columnRow to change rows into.
   *
   * @return integer     Number of rows updated.
   */
  public function ReplaceMulti($table, $keyField, $rows);

  /**
   * Delete rows from a table.
   *
   * @param string  $table              Table name
   * @param array   $whereClause        WHERE clause (see header)
   *
   * @return integer     Number of rows deleted.
   */ 
  public function Delete($table, $whereClause);

  /**
   * BLOB functions
   */

  /**
   * Stores a binary large object (BLOB).
   *
   * @param mixed   $object             The object to store.  This can be anything - it will be serialize'd if need-be.
   * 
   * @return integer     An int4 number to use to retreive this BLOB in the future.
   */
  public function BlobSave($object);

  /**
   * Retrieves a binary large object (BLOB).
   *
   * @param integer $id                 The ID number to load.
   * 
   * @return mixed       The stored object.
   */
  public function BlobLoad($id);

  /**
   * Deletes a binary large object (BLOB).
   *
   * @param integer $id                 The ID number to delete.
   *
   * @return void
   */
  public function BlobDelete($id);

  /**
   * Audit control functions
   */

  /**
   * Sets the userdata to be stored with all audit logs generated during this session.
   *
   * @param string  $data               The data to be stored.
   *
   * @return void
   */
  public function SetAuditSessionData($data);

  /**
   * Retrieves the audit data for a particular GUID.
   *
   * @param mixed   $guid               The GUID to retrieve.
   *
   * @return array                      Array of array of changes, in the following format, ordered by timestamp:
   *                                    (timestamp, userdata, changetype, changedata).
   *                                    Changetype is I for Insert, U for Update, or D for Delete of the row.
   *                                    Changedata is a string of ['fieldname','old','new'], quote-escaped, seperated by commas.
   */
  public function GetAuditLog($guid);

  /**
   * Transaction functions
   */
  
  /**
   * Begin a transaction.
   *
   * @return void
   */
  public function Begin();

  /**
   * Commit a transaction.
   *
   * @return void
   */
  public function Commit();

  /**
   * Rollback a transaction.
   *
   * @return void
   */
  public function Rollback();  

  /**
   * Execute a SQL command.  For gods sakes, don't use this.  Ever.  Really.  There's enough support functions above for 99.9999% of tasks,
   * in a nice, portable format.   About the only exception at the moment is creating functions and triggers server side since every database
   * is so different in that regard it is hard to abstract.  
   * But, seriously, if you're looking at using this for SELECT * FROM foo... you need to re-read the above.  
   * It has a long name specifically to discourage general use, too.
   *
   * @return integer     Number of rows affected.
   */
  public function DirectQueryToDatabase($sql);

  /**
   * Get statistics on this session of the database.  Must return an array of keys SELECT, INSERT, UPDATE, DELETE, and other, with the summed
   * affected rows for each.
   *
   * @return array       See above.
   */
  public function GetStats();

  /**
   * Resets the connection.  Should completely drop and then reconnect.
   **/
  public function Reconnect();
}

class dbException extends Exception
{
  var $internalErr;
  var $failedQuery;

  public function __construct($codeNumber, $internalErr, $failedQuery)
  {
    $this->internalErr = $internalErr;
    $this->failedQuery = $failedQuery;

    switch($codeNumber)
      {
      case DB_ERR_INTERNAL: $errStr = dgettext('CaliaLib', 'The database reported an internal error.'); break;
      case DB_ERR_NO_HOST: $errStr = dgettext('CaliaLib', 'The database server is not available.'); break;
      case DB_ERR_INVALID_AUTH: $errStr = dgettext('CaliaLib', 'The credentials supplied to the database were rejected.'); break;
      case DB_ERR_NO_RECORD: $errStr = dgettext('CaliaLib', 'No records matching the search criteria were found.'); break;
      case DB_ERR_MULTIPLE_RECORDS: $errStr = dgettext('CaliaLib', 'Multiple records matching the search criteria were found.'); break;
      case DB_ERR_INVALID_WHERE: $errStr = dgettext('CaliaLib', 'An invalid WHERE condition was supplied.'); break;
      case DB_ERR_INVALID_ORDERBY: $errStr = dgettext('CaliaLib', 'An invalid ORDER BY condition was supplied.'); break;
      case DB_ERR_INVALID_JOIN: $errStr = dgettext('CaliaLib', 'An invalid JOIN condition was supplied.'); break;
      case DB_ERR_INVALID_DATA: $errStr = dgettext('CaliaLib', 'Invalid data was supplied.'); break;
      case DB_ERR_NOT_UNIQUE: $errStr = dgettext('CaliaLib', 'Data was supplied that would have violated a uniqueness constraint.'); break;
      case DB_ERR_FOREIGN_KEY: $errStr = dgettext('CaliaLib', 'Data was supplied that would have violated a foreign key constraint.'); break;
      case DB_ERR_UNKNOWN_COLUMN_TYPE: $errStr = dgettext('CaliaLib', 'A column type was specified that is unknown.'); break;
      case DB_ERR_COLUMN_DOES_NOT_EXIST: $errStr = dgettext('CaliaLib', 'The requested column name does not exist.'); break;
      case DB_ERR_COLUMN_ALREADY_EXISTS: $errStr = dgettext('CaliaLib', 'The requested column name already exists.'); break;
      case DB_ERR_COLUMN_NOT_SERIAL: $errStr = dgettext('CaliaLib', 'The requested column name is not a serial type.'); break;
      case DB_ERR_NAME_ALREADY_USED: $errStr = dgettext('CaliaLib', 'The requested name is already in use.'); break;
      case DB_ERR_OBJECT_LOCKED: $errStr = dgettext('CaliaLib', 'The requested object is locked by another process.'); break;
      case DB_ERR_INVALID_NAME: $errStr = dgettext('CaliaLib', 'The requested name is invalid to the database.'); break;
      case DB_ERR_INVALID_NAME_LENGTH: $errStr = dgettext('CaliaLib', 'The requested name is too long for the database.'); break;
      case DB_ERR_TABLE_DOES_NOT_EXIST: $errStr = dgettext('CaliaLib', 'The requested table does not exist.'); break;

      case DB_ERR_GENERIC: 
      default: 
	$errStr = dgettext('CaliaLib', 'An unknown database error occurred.'); break;
      }

    parent::__construct($errStr, $codeNumber);
  }

  public function InternalError()
  {
    return $this->internalErr;
  }

  public function FailedQuery()
  {
    return $this->failedQuery;
  }
}

?>
Return current item: Calia