Login   Register  
PHP Classes
elePHPant
Icontem

File: class.aDB.php

Recommend this page to a friend!
Stumble It! Stumble It! Bookmark in del.icio.us Bookmark in del.icio.us
  Classes of Johan Barbier  >  aDB PDO like database abstraction  >  class.aDB.php  >  Download  
File: class.aDB.php
Role: Class source
Content type: text/plain
Description: aDB class
Class: aDB PDO like database abstraction
Database abstraction layer similar to PDO
Author: By
Last change: Added several features : stored procedures, multiple results support, improving bindValue() method...
Most of them have been added on the mssql version as this is the version I use the most.
Date: 6 years ago
Size: 51,720 bytes
 

Contents

Class file image Download
<?php
/**
 * class aDBException extends Exception
 * @author johan <johan.barbier@gmail.com>
 * @version 20070524
 */
class aDBException extends Exception {
	/**
	 * Class in which Exception was caught
	 *
	 * @var string
	 */
	private $sCallerClass = null;

	/**
	 * Method in which Exception was caught
	 *
	 * @var string
	 */
	private $sCallerFunc = null;
	
	/**
	 * public function __construct
	 * Constructor.
	 *
	 * @param string $sMessage : Exception message
	 * @param string $sClass : Class in which Exception was caught
	 * @param string $sFunction : Method in which Exception was caught
	 */
	public function __construct ($sMessage, $iCode, $sClass = 'unknown', $sFunction = 'unknown') {
		$this -> sCallerClass = $sClass;
		$this -> sCallerFunc = $sFunction;
		parent::__construct ($sMessage, $iCode);
	}

	/**
	 * public function __toString
	 * Display Exception message
	 *
	 * @return string
	 */
	public function __toString() {
		$sMsg = '<strong>'.$this -> sCallerClass.'::'.$this -> sCallerFunc.'()</strong><br />';
		$sMsg .= $this->getMessage().' ['.$this->getCode().']<br />';
		$sMsg .= '<em>File</em> : '.$this->getFile().' on line '.$this->getLine().'<br />';
		$sMsg .= '<em>Trace</em> :<br />'.$this->getTraceAsString().'<br />';
		return $sMsg;
	}

}
/**
 * class aDBExceptionIllegalClass extends aDBException
 * @author johan <johan.barbier@gmail.com>
 * @version 20070524
 */
class aDBExceptionIllegalClass extends aDBException {
	/**
	 * Class constants : Exception messages and codes
	 *
	 */
	const ILLEGAL_CLASS_NAME = '{CLASS} is not implemented';
	const UNEXPECTED_INSTANCE_ERROR = 'Unexpected instance error';

	const CODE_ILLEGAL_CLASS_NAME = 0;
	const CODE_UNEXPECTED_INSTANCE_ERROR = 1;
}

/**
 * class aDBExceptionTypesError extends aDBException
 * @author johan <johan.barbier@gmail.com>
 * @version 20070524
 */
class aDBExceptionTypesError extends aDBException {
	/**
	 * Class constants : Exception messages and codes
	 *
	 */
	const MUST_BE_AN_ARRAY = '{PARAM} must be an array';
	const MUST_BE_AN_INT = '{PARAM} must be an integer';
	const MUST_BE_A_STRING = '{PARAM} must be a string';
	const MUST_BE_A_BOOL = '{PARAM} must be a boolean';
	const MUST_BE_A_SCALAR = '{PARAM} must be a scalar value';

	const CODE_MUST_BE_AN_ARRAY = 0;
	const CODE_MUST_BE_AN_INT = 1;
	const CODE_MUST_BE_A_STRING = 2;
	const CODE_MUST_BE_A_BOOL = 3;
	const CODE_MUST_BE_A_SCALAR = 4;
}

/**
 * class aDBExceptionInvalidClassCalls extends aDBException
 * @author johan <johan.barbier@gmail.com>
 * @version 20070524
 */
class aDBExceptionInvalidClassCalls extends aDBException {
	/**
	 * Class constants : Exception messages and codes
	 *
	 */
	const NO_QUERY_TO_PREPARE = 'No query has been prepared';
	const NEEDLE_NOT_FOUND = '{NEEDLE} was not found in prepared query {QUERY}';
	const PARAM_TYPE_NOT_FOUND = 'Parameter type asked for query preparation does not exist';
	const PROP_NOT_GETABLE = '{PROP} is not a getable property';
	const INVALID_OPTION = '{OPTION} is not a valid option';
	const UNSUPPORTED_METHOD = 'This method is not yet supported by this db type';
	const NO_LINK_FOUND_AND_NO_CONFIGURATION_FOUND = 'You try to use an instance which has been destroyed previously';
	const NO_PROC_STMT = 'No statement resource found';
	
	const CODE_NO_QUERY_TO_PREPARE = 0;
	const CODE_NEEDLE_NOT_FOUND = 1;
	const CODE_PARAM_TYPE_NOT_FOUND = 2;
	const CODE_PROP_NOT_GETABLE = 3;
	const CODE_INVALID_OPTION = 4;
	const CODE_UNSUPPORTED_METHOD = 5;
	const CODE_NO_LINK_FOUND_AND_NO_CONFIGURATION_FOUND = 6;
	const CODE_NO_PROC_STMT = 7;
}

/**
 * class aDBExceptionDbConnectorErrors extends aDBException
 * @author johan <johan.barbier@gmail.com>
 * @version 20070524
 */
class aDBExceptionDbConnectorErrors extends aDBException {
	/**
	 * Class constants : Exception messages and codes
	 *
	 */
	const CONNEXION_FAILED = 'Connexion failed with message [{MSG}]';
	const QUERY_FAILED = 'Query [{QRY}] failed with message [{MSG}]';
	const FETCH_FAILED = 'Fetch failed with message [{MSG}]';
	const INVALID_SEEK_POSITION = 'Invalid seek position ({OFFSET})';
	const INVALID_QRY_RESOURCE = 'Invalid query resource';
	const REQUEST_ERROR = 'Undefined error in the request';
	const CONNECTION_LINK_MISSING = 'No database connection found';
	const COULD_NOT_FREE_RESULT = 'Freeing result failed with message [{MSG}]';
	const COULD_NOT_FREE_STMT = 'Freeing statement failed with message [{MSG}]';
	const PROC_FAILED = 'Procedure [{QRY}] failed with message [{MSG}]';

	const CODE_CONNEXION_FAILED = 0;
	const CODE_QUERY_FAILED = 1;
	const CODE_FETCH_FAILED = 2;
	const CODE_INVALID_SEEK_POSITION = 3;
	const CODE_INVALID_QRY_RESOURCE = 4;
	const CODE_REQUEST_ERROR = 5;
	const CODE_CONNECTION_LINK_MISSING = 6;
	const CODE_COULD_NOT_FREE_RESULT = 7;
	const CODE_COULD_NOT_FREE_STMT = 8;
	const CODE_PROC_FAILED = 9;
}

/**
 * class aDBFactory
 * @author johan <johan.barbier@gmail.com>
 * @version 20070524
 */
class aDBFactory {

	/**
	 * static property : array of aDB instances
	 *
	 * @var array of aDB object
	 */
	private static $_instance;
	
	public static $_aInstance;
	
	private static $_aInstances;

	/**
	 * public static getInstance
	 * Factory.
	 * Checks that the requested DB type is implemented.
	 * Then, checks if there is an existing instance of it. If not, creates it with configuration and options if any.
	 * If yes, gets it! Checks if there is a new configuration to apply and apply it if so. Same story for the options.
	 * Returns the instance...
	 * NEW : if $mIsSingleton is left to true, behaviour is as described above.
	 * If it is false, a new instance is automatically created and stored.
	 * If it is a set to something else (string for example), it is used to store the instance under this name, if it does not already exists, or returns it if it does (must be the same DB type, too).
	 *
	 * @param string $saDBType : name of the requested aDB class
	 * @param array $aConConf : array of aDB connection configuration
	 * @param mixed $mIsSingleton : true if automatic singleton, false if no singleton, scalar value meaning that the instance is in a namespace : singleton on that namespace
	 * @param unknown_type $aOptions : array of aDB options
	 * @return aDB object : the requested aDB instance
	 */
	public static function getInstance ($saDBType, $aConConf = null, $mIsSingleton = true, $bOpenNewConnection = true, $aOptions = null) {
			if(!is_bool($bOpenNewConnection)) {
				throw new aDBExceptionTypesError (str_replace('{PARAM}', '$bOpenNewConnection', aDBExceptionTypesError::MUST_BE_A_BOOL), aDBExceptionTypesError::CODE_MUST_BE_A_BOOL, get_class($this), __FUNCTION__);
			}
		if (!class_exists($saDBType)) {
			throw new aDBExceptionIllegalClass (str_replace ('{CLASS}', $saDBType, aDBExceptionIllegalClass::ILLEGAL_CLASS_NAME), aDBExceptionIllegalClass::CODE_ILLEGAL_CLASS_NAME, get_class($this), __FUNCTION__);
		}
		if(true === $mIsSingleton) {
			if (isset (self::$_instance[$saDBType])) {
				if (!self::$_instance[$saDBType] instanceof $saDBType) {
					throw new aDBExceptionIllegalClass (aDBExceptionIllegalClass::UNEXPECTED_INSTANCE_ERROR, aDBExceptionIllegalClass::CODE_UNEXPECTED_INSTANCE_ERROR, get_class($this), __FUNCTION__);
				} else {
					if (!is_null ($aConConf)) {
						self::$_instance[$saDBType] -> connect ($aConConf, $bOpenNewConnection);
					}
					if (!is_null ($aOptions)) {
						foreach ($aOptions as $sOption => $mValue) {
							self::$_instance[$saDBType] -> setOption ($sOption, $mValue);
						}
					}
					return self::$_instance[$saDBType];
				}
			} else {
				self::$_instance[$saDBType] = new $saDBType ($aConConf, $aOptions);
				return self::$_instance[$saDBType];
			}
		} elseif(false === $mIsSingleton) {
			$iInstance = self::$_aInstances[$saDBType][] = new $saDBType ($aConConf, $aOptions);
			return $iInstance;
		} else {
			if(!is_scalar($mIsSingleton)) {
				throw new aDBExceptionTypesError (str_replace('{PARAM}', '$mIsSingleton', aDBExceptionTypesError::MUST_BE_A_SCALAR), aDBExceptionTypesError::CODE_MUST_BE_A_SCALAR, get_class($this), __FUNCTION__);
			}
			if(!isset(self::$_aInstance[$saDBType][$mIsSingleton]) || !self::$_aInstance[$saDBType][$mIsSingleton] instanceof $saDBType) {
				self::$_aInstance[$saDBType][$mIsSingleton] = new $saDBType ($aConConf, $aOptions, $mIsSingleton);
			} else {
				if (!is_null ($aConConf)) {
					self::$_aInstance[$saDBType][$mIsSingleton] -> connect($aConConf, $bOpenNewConnection);
				}
				if (!is_null ($aOptions)) {
					foreach ($aOptions as $sOption => $mValue) {
						self::$_aInstance[$saDBType][$mIsSingleton] -> setOption ($sOption, $mValue);
					}
				}
			}
			return self::$_aInstance[$saDBType][$mIsSingleton];
		}
	}
}

/**
 * class sqlIterator implements Iterator, SeekableIterator, Countable
 * @author johan <johan.barbier@gmail.com>
 * @version 20070524
 */
class sqlIterator implements Iterator, SeekableIterator {

	/**
	 * Number of items to retrieve
	 *
	 * @var integer
	 */
	private $iCount;

	/**
	 * Starting offset
	 *
	 * @var integer
	 */
	private $iOffset = 0;

	/**
	 * Total number of items for the request
	 *
	 * @var integer
	 */
	private $iMax;

	/**
	 * Current internal position
	 * @var integer
	 */
	private $iPos = -1;

	/**
	 * aDB object
	 *
	 * @var aDB
	 */
	private $aDB;

	/**
	 * Query resource
	 *
	 * @var resource
	 */
	private $rQry;

	/**
	 * fetch mode
	 *
	 * @var aDB class constant
	 */
	private $aDB_MODE;
	private $keptaDB_MODE;

	/**
	 * Output
	 *
	 * @var mixed
	 */
	private $mOutput = false;

	/**
	 * public function __construct
	 * Constructor
	 * set some parameters
	 *
	 * @param aDB $aDB : aDB object
	 * @param resource $rQry : query resource
	 * @param aDB class constant $aDB_MODE : fetch mode
	 * @param integer $iOffset : starting offset
	 * @param integer $iCount : fetch length
	 * @param boolean $bIsSeekable : resource must be rewinded or not
	 */
	public function __construct (aDB $aDB, $rQry, $aDB_MODE = aDB::BOTH, $iOffset = 0, $iCount = null, $bIsSeekable = true) {
		if (!is_int($iOffset)) {
			$this -> aDB -> interceptException ('aDBExceptionTypesError', str_replace ('{PARAM}', '4d parameter', aDBExceptionTypesError::MUST_BE_AN_INT), aDBExceptionTypesError::CODE_MUST_BE_AN_INT, get_class($this), __FUNCTION__);
			$iOffset = 0;
		}
		if (!is_int($iCount) && !is_null ($iCount)) {
			$this -> aDB -> interceptException ('aDBExceptionTypesError', str_replace ('{PARAM}', '5d parameter', aDBExceptionTypesError::MUST_BE_AN_INT), aDBExceptionTypesError::CODE_MUST_BE_AN_INT, get_class($this), __FUNCTION__);
			$iCount = null;
		}
		$this -> keptaDB_MODE = $aDB_MODE;
		if ((aDB::FETCH_GROUP^$aDB_MODE) !== 0 && (aDB::FETCH_GROUP^$aDB_MODE) !== $aDB_MODE && (aDB::FETCH_GROUP^$aDB_MODE) < $aDB_MODE) {
			$this -> aDB_MODE = aDB::FETCH_GROUP^$aDB_MODE;
		} elseif ((aDB::FETCH_GROUP_UNIQUE^$aDB_MODE) !== 0 && (aDB::FETCH_GROUP_UNIQUE^$aDB_MODE) !== $aDB_MODE && (aDB::FETCH_GROUP_UNIQUE^$aDB_MODE) < $aDB_MODE) {
			$this -> aDB_MODE = aDB::FETCH_GROUP_UNIQUE^$aDB_MODE;
		} else {
			$this -> aDB_MODE = $aDB_MODE;
		}
		$this -> rQry = $rQry;
		$this -> aDB = $aDB;
		$this -> iOffset = $iOffset;
		$this -> iCount = $iCount;
		$this -> iMax = $this -> count ();
		if (true === $bIsSeekable && $this -> aDB_MODE !== aDB::FETCH_EXTRACT) {
			$this -> rewind ();
		}
	}

	/**
	 * publid function current
	 * returns current result set
	 *
	 * @return array
	 */
	public function current () {
		if ($this -> aDB_MODE === aDB::FETCH_EXTRACT) {
			if (is_array ($this -> mOutput)) {
				foreach ($this -> mOutput as $sK => $sV) {
					global $$sK;
					$$sK = $sV;
				}
			}
			return true;
		} else {
			switch ($this -> keptaDB_MODE) {
				case aDB::FETCH_GROUP:
				case aDB::FETCH_GROUP|aDB::BOTH:
				case aDB::FETCH_GROUP_UNIQUE|aDB::BOTH:
					$mFirst = array_shift ($this -> mOutput);
					array_shift ($this -> mOutput);
					return array ($mFirst => $this -> mOutput);
					break;
				case aDB::FETCH_GROUP|aDB::FETCH_ASSOC:
				case aDB::FETCH_GROUP|aDB::FETCH_NUM:
				case aDB::FETCH_GROUP_UNIQUE|aDB::FETCH_ASSOC:
				case aDB::FETCH_GROUP_UNIQUE|aDB::FETCH_NUM:
					$mFirst = array_shift ($this -> mOutput);
					return array ($mFirst => $this -> mOutput);
					break;
				default:
					return $this -> mOutput;
					break;
			}
		}
	}

	/**
	 * public function next
	 * goes to the next result set
	 *
	 */
	public function next () {
		$this -> iPos ++;
		if ($this -> aDB_MODE === aDB::FETCH_EXTRACT) {
			$this -> mOutput = $this -> aDB -> __fetch ($this -> rQry, aDB::FETCH_ASSOC);
		} else {
			$this -> mOutput = $this -> aDB -> __fetch ($this -> rQry, $this -> aDB_MODE);
		}
		if(false === $this -> mOutput) {
			if(false !== $this->aDB->nextResult($this->rQry)) {
				$this->iMax = $this->count();
				$this->rewind();
			}
		} 

	}

	/**
	 * public function valid
	 * Checks the validity of the current position
	 *
	 * @return boolean
	 */
	public function valid () {
		if (($this -> iOffset + $this -> iPos) >= $this -> iMax) {
			return false;
		}
		if (!is_null ($this -> iCount) && $this -> iCount > 0 && $this -> iPos >= $this -> iCount) {
			return false;
		}

		if (false === $this -> mOutput) {
			$this -> next ();
		}
		return true;
	}

	/**
	 * public function rewind
	 * moves the offset to the first position
	 *
	 */
	public function rewind () {
		$this -> seek ($this -> iOffset);
	}

	/**
	 * public function seek
	 * seeks a given offset
	 *
	 * @param integer $iOffset
	 */
	public function seek ($iOffset) {
		if (false === $this -> aDB -> __seek ($iOffset)) {
			//$this -> aDB -> interceptException ('aDBExceptionDbConnectorErrors', str_replace ('{OFFSET}', $iOffset, aDBExceptionDbConnectorErrors::INVALID_SEEK_POSITION), aDBExceptionDbConnectorErrors::CODE_INVALID_SEEK_POSITION, get_class($this), __FUNCTION__);
			return false;
		}
		$this -> iOffset = $iOffset;
		$this -> iPos = -1;
		return true;
	}
	/**
	 * public function key
	 * Returns the current internal position
	 *
	 * @return integer
	 */
	public function key () {
		return $this -> iPos;
	}

	/**
	 * public function count
	 * count the total number of result sets
	 *
	 * @return integer
	 */
	public function count () {
		return $this -> aDB -> count ($this -> rQry);
	}

	/**
	 * public function getOffset
	 * Returns the current request position
	 *
	 * @return integer
	 */
	public function getOffset () {
		return $this -> iPos + $this -> iOffset;
	}
}

/**
 * abstract class aDB
 * @author johan <johan.barbier@gmail.com>
 * @version 20070521
 */
abstract class aDB {

	/**
	 * fetch modes
	 *
	 */
	const BOTH = 0;
	const FETCH_ASSOC = 1;
	const FETCH_NUM = 2;
	const FETCH_GROUP = 4;
	const FETCH_EXTRACT = 8;
	const FETCH_GROUP_UNIQUE = 16;

	/**
	 * Allowed parameter bindings
	 *
	 */
	const PARAM_STR = 1000;
	const PARAM_INT = 1001;
	const PARAM_FLOAT = 1002;
	const PARAM_BOOL = 1003;

	/**
	 * DB Configuration
	 *
	 * @var array
	 */
	protected $aConConf = array (
	'HOST' => '', 'LOGIN' => '', 'PWD' => '', 'DB' => '');

	/**
	 * aDB options
	 *
	 * @var array
	 */
	protected $aOptions = array (
	'AUTOCONNECT' => true,
	'EXCEPTION_ON_ERROR' => true
	);

	/**
	 * Fetch length
	 *
	 * @var integer
	 */
	protected $iFetchLength;

	/**
	 * Starting offset
	 *
	 * @var integer
	 */
	protected $iOffset = 0;

	/**
	 * DB connection link resource
	 *
	 * @var resource
	 */
	protected $rLink;

	/**
	 * DB query link resource
	 *
	 * @var resource
	 */
	public $rQry;
	
	/**
	 * Statement link resource
	 *
	 * @var resource
	 */
	protected $rStmtLink;
	
	/**
	 * Query
	 *
	 * @var string
	 */
	protected $sQuery;

	/**
	 * Errors log when no exception
	 *
	 * @var array
	 */
	protected static $aErrorLog;

	/**
	 * NameSpace if any
	 *
	 * @var string
	 */
	protected $sNameSpace = null;
	/**
	 * public function __construct
	 * Constructor.
	 * Automatic connection if AUTOCONNECT option is true
	 *
	 * @param array $aConConf
	 * @param array $aOptions
	 */
	public function __construct ($aConConf = null, $aOptions = null, $sNameSpace = null) {
		$this->sNameSpace = $sNameSpace;
		if (is_array ($aOptions)) {
			foreach ($aOptions as $sK => $sV) {
				if (isset ($this -> aOptions[$sK])) {
					$this -> aOptions[$sK] = $sV;
				}
			}
		}
		if(is_null ($aConConf) && is_null($this->rLink)) {
			$this -> interceptException ('aDBExceptionInvalidClassCalls', aDBExceptionInvalidClassCalls::NO_LINK_FOUND_AND_NO_CONFIGURATION_FOUND, aDBExceptionInvalidClassCalls::CODE_NO_LINK_FOUND_AND_NO_CONFIGURATION_FOUND, get_class($this), __FUNCTION__);
		}
		if ((true === $this -> aOptions['AUTOCONNECT'] && !is_null ($aConConf)) || is_null($this->rLink)) {
			$this -> connect ($aConConf);
		}
	}

	/**
	 * public function __destruct
	 * Destructor.
	 * AClose connection
	 *
	 * @@return boolean true on success, false if not
	 */
	public function __destruct() {
		return @$this->close();
	}

	/**
	 * public function set_limit
	 * Sets a limit to the query : starting offset and fetch length
	 * Is this method is called without any parameter, it will cancel previous set_limit call (useful if you used a limitation, and then do not want any more limitation)
	 *
	 * @param integer $iOffset
	 * @param integer $iCount
	 */
	public function set_limit ($iOffset = 0, $iCount = null) {
		if (!is_int($iOffset)) {
			$this -> interceptException ('aDBExceptionTypesError', str_replace ('{PARAM}', '1st parameter', aDBExceptionTypesError::MUST_BE_AN_INT), aDBExceptionTypesError::CODE_MUST_BE_AN_INT, get_class($this), __FUNCTION__);
			return false;
		}
		if (!is_int($iCount) && !is_null ($iCount)) {
			$this -> interceptException ('aDBExceptionTypesError', str_replace ('{PARAM}', '2d parameter', aDBExceptionTypesError::MUST_BE_AN_INT), aDBExceptionTypesError::CODE_MUST_BE_AN_INT, get_class($this), __FUNCTION__);
			return false;
		}
		$this -> iFetchLength = $iCount;
		$this -> iOffset = $iOffset;
		return true;
	}

	/**
	 * public function next_limit
	 * Update the limit : aDB::iFetchLength remains the same, but aDB::iOffset is incremennted with aDB::iFetchLength.
	 * So, the offset is positionned on the very next result set.
	 */
	public function next_limit () {
		if (!is_int($this -> iOffset)) {
			$this -> interceptException ('aDBExceptionTypesError', str_replace ('{PARAM}', '1st parameter', aDBExceptionTypesError::MUST_BE_AN_INT), aDBExceptionTypesError::CODE_MUST_BE_AN_INT, get_class($this), __FUNCTION__);
			return false;
		}
		if (!is_int($this -> iFetchLength) && !is_null ($this -> iFetchLength)) {
			$this -> interceptException ('aDBExceptionTypesError', str_replace ('{PARAM}', '2d parameter', aDBExceptionTypesError::MUST_BE_AN_INT), aDBExceptionTypesError::CODE_MUST_BE_AN_INT, get_class($this), __FUNCTION__);
			return false;
		}
		$this -> iOffset += $this -> iFetchLength;
		return true;
	}

	/**
	 * public function connect
	 * Connects to the DB server
	 * If DB NAME has been set in the configuration, automatically selects it.
	 *
	 */
	public function connect ($aConConf, $bOpenNewConnection = true) {
		if (is_array ($aConConf)) {
			foreach ($aConConf as $sK => $sV) {
				if (isset ($this -> aConConf[$sK])) {
					$this -> aConConf[$sK] = $sV;
				}
			}
		} else {
			$this -> interceptException ('aDBExceptionTypesError', str_replace ('{PARAM}', '1st parameter', aDBExceptionTypesError::MUST_BE_AN_ARRAY), aDBExceptionTypesError::CODE_MUST_BE_AN_ARRAY, get_class($this), __FUNCTION__);
			return false;
		}
		if(is_null($this->rLink) || true === $bOpenNewConnection) {
			if (false === ($this -> rLink = $this -> _connect ($bOpenNewConnection))) {
				$this -> interceptException ('aDBExceptionDbConnectorErrors', str_replace ('{MSG}', $this -> _errorMsg (), aDBExceptionDbConnectorErrors::CONNEXION_FAILED), aDBExceptionDbConnectorErrors::CODE_CONNEXION_FAILED, get_class($this), __FUNCTION__);
				return false;
			}
		}
		if (!empty ($this -> aConConf['DB'])) {
			$this -> select_db ($this -> aConConf['DB']);
		}
		return true;
	}

	/**
	 * public function select_db
	 * Selects a db
	 *
	 * @param string $sDbName
	 */
	public function select_db ($sDbName = null) {
		if (!isset ($this -> rLink)) {
			$this -> interceptException ('aDBExceptionDbConnectorErrors', aDBExceptionDbConnectorErrors::CONNECTION_LINK_MISSING, aDBExceptionDbConnectorErrors::CODE_CONNECTION_LINK_MISSING, get_class($this), __FUNCTION__);
			return false;
		}
		if (!is_null ($sDbName)) {
			$this -> aConConf['DB'] = $sDbName;
		}
		if (false === $this -> _select_db ($this -> aConConf['DB'])) {
			$this -> interceptException ('aDBExceptionDbConnectorErrors', str_replace ('{MSG}', $this -> _errorMsg (), aDBExceptionDbConnectorErrors::CONNEXION_FAILED), aDBExceptionDbConnectorErrors::CODE_CONNEXION_FAILED, get_class($this), __FUNCTION__);
			return false;
		}
		return true;
	}

	/**
	 * public function query
	 * Queries the DB server
	 *
	 * @param string $sQuery : query string
	 * @param boolean $bOverWriteQry : is sets to true, overwrites aDB::sQuery property; if not, does nothing
	 * @return resource : query resource
	 */
	public function query ($sQuery, $bOverWriteQry = true) {
		if (!isset ($this -> rLink)) {
			$this -> interceptException ('aDBExceptionDbConnectorErrors', aDBExceptionDbConnectorErrors::CONNECTION_LINK_MISSING, aDBExceptionDbConnectorErrors::CODE_CONNECTION_LINK_MISSING, get_class($this), __FUNCTION__);
			return false;
		}
		if (true === $bOverWriteQry) {
			if(!is_null($this->rQry)) {
				$this->freeResult();
			}
		}
		if (false === ($rRes = $this -> _query ($sQuery))) {
			$this -> interceptException ('aDBExceptionDbConnectorErrors', str_replace (array ('{QRY}', '{MSG}'), array ($sQuery, $this -> _errorMsg ()), aDBExceptionDbConnectorErrors::QUERY_FAILED), aDBExceptionDbConnectorErrors::CODE_QUERY_FAILED, get_class($this), __FUNCTION__);
			return false;
		}
		if(true === $bOverWriteQry) {
			$this -> rQry = $rRes;
		}
		return $rRes;
	}

	/**
	 * public function fetch
	 * using current query resource or given query resource, instanciates an iterator to move through result sets
	 *
	 * @param aDB Class Constant $aDB_MODE : fetch mode
	 * @param resource $rQry : query resource
	 * @param boolean $bIsSeekable : if sets to true, query is seekable
	 * @return sqlIterator : the Iterator
	 */
	public function fetch ($aDB_MODE = aDB::BOTH, $rQry = null, $bIsSeekable = true) {
		if (is_null ($rQry) && is_null ($this -> rQry)) {
			$this -> interceptException ('aDBExceptionDbConnectorErrors', aDBExceptionDbConnectorErrors::INVALID_QRY_RESOURCE, aDBExceptionDbConnectorErrors::CODE_INVALID_QRY_RESOURCE, get_class($this), __FUNCTION__);
			return false;
		}
		if (!is_null ($rQry)) {
			return new sqlIterator ($this, $rQry, $aDB_MODE, $this -> iOffset, $this -> iFetchLength, $bIsSeekable);
		} else {
			return new sqlIterator ($this, $this -> rQry, $aDB_MODE, $this -> iOffset, $this -> iFetchLength, $bIsSeekable);
		} 
	}

	/**
	 * public function fetchColumn
	 * using current query resource or given query resource, returns the value of a given column
	 *
	 * @param integer $iColumn : column number
	 * @param resource $rQry : query resource
	 * @param boolean $bIsSeekable : if sets to true, query is seekable
	 * @return mixed : column value
	 */
	public function fetchColumn ( $iColumn = 0, $rQry = null, $bIsSeekable = true) {
		if (!is_int($iColumn)) {
			$this -> interceptException ('aDBExceptionTypesError', str_replace ('{PARAM}', '2d parameter', aDBExceptionTypesError::MUST_BE_AN_INT), aDBExceptionTypesError::CODE_MUST_BE_AN_INT, get_class($this), __FUNCTION__);
			return false;
		}
		if (is_null ($rQry) && is_null ($this -> rQry)  && is_null($this->rProcStmt)) {
			$this -> interceptException ('aDBExceptionDbConnectorErrors', aDBExceptionDbConnectorErrors::INVALID_QRY_RESOURCE, aDBExceptionDbConnectorErrors::CODE_INVALID_QRY_RESOURCE, get_class($this), __FUNCTION__);
			return false;
		}
		if (!is_null ($rQry)) {
			$it = new sqlIterator ($this, $rQry, aDB::FETCH_NUM, $this -> iOffset, null, $bIsSeekable);
		} else {
			$it = new sqlIterator ($this, $this -> rQry, aDB::FETCH_NUM, $this -> iOffset, null, $bIsSeekable);
		}
		$it -> next ();
		$aRes = $it -> current ();
		if (empty ($aRes) || !isset ($aRes[$iColumn])) {
			return false;
		}
		return $aRes[$iColumn];
	}

	/**
	 * public function fetchAll
	 * using current query resource or given query resource, returns an array with all the result sets.
	 * The array's structure depends on the fetch mode.
	 *
	 * @param aDB Class Constant $aDB_MODE
	 * @param resource $rQry
	 * @param boolean $bIsSeekable : if sets to true, query is seekable
	 * @return array
	 */
	public function fetchAll ($aDB_MODE = aDB::BOTH, $rQry = null, $bIsSeekable = true) {
		if (is_null ($rQry) && is_null ($this -> rQry)) {
			$this -> interceptException ('aDBExceptionDbConnectorErrors', aDBExceptionDbConnectorErrors::INVALID_QRY_RESOURCE, aDBExceptionDbConnectorErrors::CODE_INVALID_QRY_RESOURCE, get_class($this), __FUNCTION__);
			return false;
		}
		$aRes = array ();
		if (!is_null ($rQry)) {
			$it = new sqlIterator ($this, $rQry, $aDB_MODE, $this -> iOffset, $this -> iFetchLength, $bIsSeekable);
		} else {
			$it = new sqlIterator ($this, $this -> rQry, $aDB_MODE, $this -> iOffset, $this -> iFetchLength, $bIsSeekable);
		}
		$it -> next ();
		while ($it -> valid ()) {
			switch ($aDB_MODE) {
				case aDB::FETCH_GROUP_UNIQUE:
				case aDB::FETCH_GROUP_UNIQUE|aDB::BOTH:
				case aDB::FETCH_GROUP_UNIQUE|aDB::FETCH_ASSOC:
				case aDB::FETCH_GROUP_UNIQUE|aDB::FETCH_NUM:
					$aTmp = $it -> current ();
					$Ik = key($aTmp);
					$aRes[$Ik] = $aTmp[$Ik];
					break;
				default :
					$aRes[] = $it -> current ();
					break;
			}
			$it -> next ();
		}
		return $aRes;
	}

	/**
	 * public function count
	 * count the total number of result sets of the given query
	 *
	 * @param resource $rQry
	 * @return integer
	 */
	public function count ($rQry = null) {
		if (is_null ($rQry) && is_null ($this -> rQry)) {
			$this -> interceptException ('aDBExceptionDbConnectorErrors', aDBExceptionDbConnectorErrors::INVALID_QRY_RESOURCE, aDBExceptionDbConnectorErrors::CODE_INVALID_QRY_RESOURCE, get_class($this), __FUNCTION__);
			return false;
		}
		if (!is_null ($rQry)) {
			return (int)@$this -> _count ($rQry);
		} else {
			return (int)@$this -> _count ($this -> rQry);
		}
	}
	
	/**
	 * public function tableExist
	 * Verifie l'existence d'une table
	 *
	 * @param resource $rQry
	 * @return boolean
	 */
	public function tableExists ($sTableName) {
		if (!is_string($sTableName)) {
			$this -> interceptException ('aDBExceptionTypesError', str_replace('{PARAM}', '1st parameter', aDBExceptionTypesError::MUST_BE_A_STRING), aDBExceptionTypesError::CODE_MUST_BE_A_STRING, get_class($this), __FUNCTION__);
			return false;
		}
		return @$this -> _tableExists ($sTableName);
	}

	/**
	 * public function prepare
	 * Prepare the given query
	 *
	 * @param string $sQuery
	 */
	public function prepare ($sQuery) {
		$this -> sQuery = $this -> _escape ($sQuery);
		return true;
	}

	/**
	 * public function bindValue
	 * Binds a value and a type to a needle
	 *
	 * @param string $sNeedle : string to be replaced
	 * @param mixed $mValue : value
	 * @param aDB Class Constant $cType : defines the type of the value
	 */
	public function bindValue ($sNeedle, $mValue, $cType = null) {
		if (is_null ($this -> sQuery)) {
			$this -> interceptException ('aDBExceptionInvalidClassCalls', aDBExceptionInvalidClassCalls::NO_QUERY_TO_PREPARE, aDBExceptionInvalidClassCalls::CODE_NO_QUERY_TO_PREPARE, get_class($this), __FUNCTION__);
			return false;
		}
		if (false === strpos($this -> sQuery, $sNeedle)) {
			$this -> interceptException ('aDBExceptionInvalidClassCalls', str_replace (array ('{NEEDLE}', '{QUERY}'), array ($sNeedle, $this -> sQuery), aDBExceptionInvalidClassCalls::NEEDLE_NOT_FOUND), aDBExceptionInvalidClassCalls::CODE_NEEDLE_NOT_FOUND, get_class($this), __FUNCTION__);
			return false;
		}
		if (is_null ($cType)) {
			$sType = gettype ($mValue);
			switch ($sType) {
				case 'integer':
					$cType = aDB::PARAM_INT;
					break;
				case 'double':
					$cType = aDB::PARAM_FLOAT;
					break;
				case 'boolean':
					$cType = aDB::PARAM_BOOL;
					break;
				case 'string':
					$cType = aDB::PARAM_STR;
					break;
				default:
					$this -> interceptException ('aDBExceptionInvalidClassCalls', aDBExceptionInvalidClassCalls::PARAM_TYPE_NOT_FOUND, aDBExceptionInvalidClassCalls::CODE_PARAM_TYPE_NOT_FOUND, get_class($this), __FUNCTION__);
					return false;
					break;

			}
		}
		switch ($cType) {
			case aDB::PARAM_STR:
				$mValue = $this -> _escape ($mValue);
				$mValue = "'".$mValue."'";
				$this -> sQuery = preg_replace('`(\b|[^_])('.$sNeedle.')(\b|[^_])`m', '$1'.$mValue.'$3', $this -> sQuery);
				break;
			case aDB::PARAM_INT:
			case aDB::PARAM_FLOAT:
			case aDB::PARAM_BOOL:
				$this -> sQuery = preg_replace('`(\b|[^_])('.$sNeedle.')(\b|[^_])`m', '${1}'.$mValue.'${3}', $this -> sQuery);
				break;
			default:
				$this -> interceptException ('aDBExceptionInvalidClassCalls', aDBExceptionInvalidClassCalls::PARAM_TYPE_NOT_FOUND, aDBExceptionInvalidClassCalls::CODE_PARAM_TYPE_NOT_FOUND, get_class($this), __FUNCTION__);
				return false;
				break;
		}
		return true;
	}

	/**
	 * public function execute
	 * Execute a prepared query
	 *
	 */
	public function execute ($bOverWriteQry = true) {
		if (is_null ($this -> sQuery)) {
			$this -> interceptException ('aDBExceptionInvalidClassCalls', aDBExceptionInvalidClassCalls::NO_QUERY_TO_PREPARE, aDBExceptionInvalidClassCalls::CODE_NO_QUERY_TO_PREPARE, get_class($this), __FUNCTION__);
			return false;
		}
		$this -> query ($this -> sQuery, $bOverWriteQry);
		return true;
	}

	/**
	 * public function call
	 * Call a stored procedure
	 *
	 */
	public function call($sProcName) {
		if (!is_string ($sProcName)) {
			$this -> interceptException ('aDBExceptionTypesError', aDBExceptionTypesError::MUST_BE_A_STRING , aDBExceptionTypesError::CODE_MUST_BE_A_STRING, get_class($this), __FUNCTION__);
			return false;
		}
		return $this->rStmtLink = $this->_call ($sProcName);
	}
	
	/**
	 * public function bindParam
	 * Binds parameters for a stored procedure
	 *
	 */
	public function bindParam($sParam, $mValue, $cType = null) {
		if((is_null($this->rStmtLink) || !is_resource($this->rStmtLink))) {
			$this -> interceptException ('aDBExceptionInvalidClassCalls', aDBExceptionInvalidClassCalls::NO_PROC_STMT, aDBExceptionInvalidClassCalls::CODE_NO_PROC_STMT, get_class($this), __FUNCTION__);
			return false;
		}
		if(is_null($cType)) {
			$cType = gettype($mValue);
		}
		return $this -> _bindParam ($sParam, $mValue, $cType);
	}
	
	/**
	 * public function procExec
	 * Executes a stored procedure
	 *
	 */
	public function procExec($bOverWriteQry = true) {
		if((is_null($this->rStmtLink) || !is_resource($this->rStmtLink))) {
			$this -> interceptException ('aDBExceptionInvalidClassCalls', aDBExceptionInvalidClassCalls::NO_PROC_STMT, aDBExceptionInvalidClassCalls::CODE_NO_PROC_STMT, get_class($this), __FUNCTION__);
			return false;
		}
		if(true === $bOverWriteQry) {
			if(!is_null($this->rQry)) {
				$this->freeResult();
			}
		}
		if(false === ($rRes = $this -> _procExec())) {
			$this -> interceptException ('aDBExceptionDbConnectorErrors', str_replace (array ('{QRY}', '{MSG}'), array ($sQuery, $this -> _errorMsg ()), aDBExceptionDbConnectorErrors::PROC_FAILED), aDBExceptionDbConnectorErrors::CODE_PROC_FAILED, get_class($this), __FUNCTION__);
			return false;
		}
		if(true === $bOverWriteQry) {
			$this -> rQry = $rRes;
		}
		return $rRes;
	}
	
	/**
	 * public function nextResult
	 * Moves to trhe next result set
	 *
	 */
	public function nextResult($rQry = null) {
		if (is_null ($this -> rQry) && is_null ($rQry)) {
			$this -> interceptException ('aDBExceptionDbConnectorErrors', aDBExceptionDbConnectorErrors::INVALID_QRY_RESOURCE, aDBExceptionDbConnectorErrors::CODE_INVALID_QRY_RESOURCE, get_class($this), __FUNCTION__);
			return false;
		}
		if(!is_null($rQry)) {
			return $this->_nextResult($rQry);
		} else {
			return $this->_nextResult($this->rQry);
		}
	}
	
	/**
	 * public function escape
	 * Escapes a string
	 *
	 * @param string $sString
	 */
	public function escape ($sString)  {
		return $this -> _escape ($sString);
	}

	/**
	 * public function startTransaction
	 * Starts a transaction
	 *
	 */
	public function startTransaction ($sTransacName = null)  {
		$this -> _startTransaction ($sTransacName);
		return true;
	}

	/**
	 * public function commitTransaction
	 * Commits a transaction
	 *
	 */
	public function commitTransaction ($sTransacName = null)  {
		$this -> _commitTransaction ($sTransacName);
		return true;
	}

	/**
	 * public function rollbackTransaction
	 * Rolls a transaction back
	 *
	 */
	public function rollbackTransaction ($sTransacName = null)  {
		$this -> _rollbackTransaction ($sTransacName);
		return true;
	}

	/**
	 * public function countTransaction
	 * Returns the number of transactions
	 *
	 * @return integer
	 */
	public function countTransaction () {
		return @$this -> _countTransaction ();
	}

	/**
	 * public function savePoint
	 * Creates a savepoint
	 *
	 */
	public function savePoint ($sSavePointName)  {
		$this -> _savePoint ($sSavePointName);
		return true;
	}

	/**
	 * public function rollbackToSavePoint
	 * Rollbacks to a savepoint
	 *
	 */
	public function rollbackToSavePoint ($sSavePointName)  {
		$this -> _rollbackToSavePoint ($sSavePointName);
		return true;
	}

	/**
	 * public function releaseSavePoint
	 * Releases a savepoint
	 *
	 */
	public function releaseSavePoint ($sSavePointName)  {
		$this -> _releaseSavePoint ($sSavePointName);
		return true;
	}

	/**
	 * public function lastInsertId
	 * Returns the last inserted ID
	 *
	 * @return integer
	 */
	public function lastInsertId () {
		return @$this -> _lastInsertId ();
	}

	/**
	 * public function close
	 * Close connexion
	 *
	 * @return integer
	 */
	public function close($bDestroyInstance = false) {
		$bReturn = @$this -> _close ();
		$this->rLink = null;
		if(true === $bDestroyInstance) {
			if(isset(aDBFactory::$_aInstance[get_class($this)][$this->sNameSpace])) {
				unset(aDBFactory::$_aInstance[get_class($this)][$this->sNameSpace]);
			} 
		}
		return $bReturn;
	}

	/**
	 * public function getIdentityColName
	 * Get table's identity column name
	 *
	 * @param string $sTable : table's name
	 * @return string
	 */
	public function getIdentityColName($sTable) {
		return @$this->_getIdentityColName($sTable);
	}

	/**
	 * public function getColumnProperties
	 * Get the table's columns properties, or the properties of a given column in this table
	 *
	 * @param string $sTable : table's name
	 * @param string $sColumn : column's name 
	 * @return array : associative array with columns properties
	 */
	public function getColumnProperties($sTable, $sColumn = null) {
		return @$this->_getColumnProperties($sTable, $sColumn);
	}
	
	/**
	 * public function freeResult
	 * Free requested query result resource
	 *
	 * @return boolean
	 */
	public function freeResult ($rQry = null) {
		if (is_null ($rQry)) {
			if (false === ($bRes = @$this->_freeResult())) {
				$this -> interceptException ('aDBExceptionDbConnectorErrors', str_replace ('{MSG}', $this -> _errorMsg (), aDBExceptionDbConnectorErrors::COULD_NOT_FREE_RESULT), aDBExceptionDbConnectorErrors::CODE_COULD_NOT_FREE_RESULT, get_class($this), __FUNCTION__);
			}
			$this->rQry = null;
		} else {
			if (false === ($bRes = @$this->_freeResult($rQry))) {
				$this -> interceptException ('aDBExceptionDbConnectorErrors', str_replace ('{MSG}', $this -> _errorMsg (), aDBExceptionDbConnectorErrors::COULD_NOT_FREE_RESULT), aDBExceptionDbConnectorErrors::CODE_COULD_NOT_FREE_RESULT, get_class($this), __FUNCTION__);
			}
		}
		return $bRes;
	}
	
	/**
	 * public function freeStatement
	 * Free requested statement resource
	 *
	 * @return boolean
	 */
	public function freeStatement ($rStmt = null) {

		if (is_null ($rStmt)) {
			if (false === ($bRes = @$this -> _freeStatement())) {
				$this -> interceptException ('aDBExceptionDbConnectorErrors', str_replace ('{MSG}', $this -> _errorMsg (), aDBExceptionDbConnectorErrors::COULD_NOT_FREE_STMT), aDBExceptionDbConnectorErrors::CODE_COULD_NOT_FREE_STMT, get_class($this), __FUNCTION__);
			}
			$this->rStmtLink = null;
		} else {
			if (false === ($bRes = @$this -> _freeStatement($rStmt))) {
				$this -> interceptException ('aDBExceptionDbConnectorErrors', str_replace ('{MSG}', $this -> _errorMsg (), aDBExceptionDbConnectorErrors::COULD_NOT_FREE_STMT), aDBExceptionDbConnectorErrors::CODE_COULD_NOT_FREE_STMT, get_class($this), __FUNCTION__);
			}
		}
		return $bRes;
	}
	
	/**
	 * public function __fetch
	 * public fetch method used by the Iterator
	 *
	 * @param resurce $rQry
	 * @param aDB Class Constant $aDB_MODE
	 * @return array
	 */
	public function __fetch ($rQry, $aDB_MODE) {
		return @$this -> _fetch ($rQry, $aDB_MODE);
	}

	/**
	 * public function __seek
	 * Seek method used by the Iterator
	 *
	 * @param integer $iOffset
	 * @return resource
	 */
	public function __seek ($iOffset) {
		return @$this -> _seek ($iOffset);
	}

	/**
	 * public function errorMsg
	 * Returns db api error message
	 *
	 * @return string
	 */
	public function errorMsg () {
		return $this -> _errorMsg ();
	}

	/**
	 * public function interceptException
	 * If EXCEPTION_ON_ERROR mode is active, throw an aDBException.
	 * If not, logs any error in the aDB::aErrorLogs array
	 *
	 * @param string $sErrorMsg
	 * @param string $sClass
	 * @param string $sFunction
	 */
	public function interceptException ($sExceptionClass, $sErrorMsg, $iCode, $sClass = 'unknown', $sFunction = 'unknown') {
		if (true === $this -> aOptions['EXCEPTION_ON_ERROR']) {
			throw new $sExceptionClass ($sErrorMsg, $iCode, $sClass, $sFunction);
		} else {
			aDB::$aErrorLog[] = $sClass.'::'.$sFunction.'() : '.$sErrorMsg.' ['.$iCode.']';
		}
	}

	/**
	 * public function server_info
	 * Gets server info if any
	 *
	 * @param resource $rQry
	 * @return mixed
	 */
	public function server_info ($rLink = null) {
		if (!is_null ($rLink)) {
			if (false === ($mInfos = @$this -> _server_info ($rLink))) {
				$this -> interceptException ('aDBExceptionDbConnectorErrors', aDBExceptionDbConnectorErrors::REQUEST_ERROR, aDBExceptionDbConnectorErrors::CODE_REQUEST_ERROR, get_class($this), __FUNCTION__);
				return false;
			}
			return $mInfos;
		} else {
			if (false === ($mInfos = @$this -> _server_info ($this ->rLink))) {
				$this -> interceptException ('aDBExceptionDbConnectorErrors', aDBExceptionDbConnectorErrors::REQUEST_ERROR, aDBExceptionDbConnectorErrors::CODE_REQUEST_ERROR, get_class($this), __FUNCTION__);
				return false;
			}
			return $mInfos;
		}
	}

	/**
	 * public function setOption
	 * Sets an existing option
	 *
	 * @param string $sOption
	 * @param mixed $mValue
	 */
	public function setOption ($sOption, $mValue) {
		if (false === array_key_exists ($sOption, $this -> aOptions)) {
			$this -> interceptException ('aDBExceptionInvalidClassCalls', str_replace ('{OPTION}', $sOption, aDBExceptionInvalidClassCalls::INVALID_OPTION), aDBExceptionInvalidClassCalls::CODE_INVALID_OPTION, get_class($this), __FUNCTION__);
			return false;
		}
		$this -> aOptions[$sOption] = $mValue;
		return true;
	}

	/**
	 * public function __get
	 * returns an authorized property value
	 *
	 * @param string $sProp
	 * @return mixed
	 */
	public function __get ($sProp) {
		switch ($sProp) {
			case 'QUERY':
				return $this -> sQuery;
				break;
			case 'ERRORS':
				return $this -> aErrorLog;
				break;
			case 'CONF':
				return $this -> aConConf;
				break;
			case 'NAMESPACE':
				return $this -> sNameSpace;
				break;
			case 'LAST_ERROR':
				if (is_array($this -> aOptions['EXCEPTION_ON_ERROR'])) {
					return end($this -> aErrorLog);
				}
				return false;
				break;
			default:
				$this -> interceptException ('aDBExceptionInvalidClassCalls', str_replace ('{PROP}', $sProp, aDBExceptionInvalidClassCalls::PROP_NOT_GETABLE), aDBExceptionInvalidClassCalls::CODE_PROP_NOT_GETABLE, get_class($this), __FUNCTION__);
				return false;
				break;
		}
	}

	abstract protected function _connect ($bOpenNewConnection = true);
	abstract protected function _errorMsg ();
	abstract protected function _select_db ($sDbName);
	abstract protected function _seek ($iOffset);
	abstract protected function _query ($sQuery);
	abstract protected function _fetch ($rQry, $aDB_MODE);
	abstract protected function _count ($rQry);
	abstract protected function _lastInsertId ();
	abstract protected function _startTransaction ($sTransacName = null);
	abstract protected function _commitTransaction ($sTransacName = null);
	abstract protected function _rollbackTransaction ($sTransacName = null);
	abstract protected function _countTransaction ();
	abstract protected function _escape ($sString);
	abstract protected function _server_info ($rLink);
	abstract protected function _freeResult ($rQry = null);
	abstract protected function _freeStatement ($rStmt = null);
	abstract protected function _savePoint ($sSavePointName);
	abstract protected function _rollbackToSavePoint ($sSavePointName);
	abstract protected function _releaseSavePoint ($sSavePointName);
	abstract protected function _close ();
	abstract protected function _getIdentityColName($sTable);
	abstract protected function _tableExists($sTable);
	abstract protected function _getColumnProperties($sTable, $sColumn = null);
	abstract protected function _call($sProcName);
	abstract protected function _bindParam($sParam, $mValue, $cType);
	abstract protected function _procExec();
	abstract protected function _nextResult($rQry);
}

class mssql extends aDB {

	protected function _connect ($bOpenNewConnection = true) {
		return @mssql_connect ($this -> aConConf['HOST'], $this -> aConConf['LOGIN'], $this -> aConConf['PWD'], $bOpenNewConnection);
	}

	protected function _errorMsg () {
		return @mssql_get_last_message();
	}

	protected function _select_db ($sDbName) {
		return @mssql_select_db ($sDbName, $this -> rLink);
	}

	protected function _seek ($iOffset) {
		return @mssql_data_seek ($this -> rQry, $iOffset);
	}

	protected function _query ($sQuery) {
		return @mssql_query ($sQuery, $this -> rLink);
	}

	protected function _fetch ($rQry, $aDB_MODE) {
		switch ($aDB_MODE) {
			case aDB::FETCH_ASSOC:
				$sMode = 'MSSQL_ASSOC';
				break;
			case aDB::FETCH_NUM:
				$sMode = 'MSSQL_NUM';
				break;
			default:
				$sMode = 'MSSQL_BOTH';
				break;
		}
		if (defined ('MSSQL_ASSOC')) {
			return @mssql_fetch_array ($rQry, constant ($sMode));
		} else {
			$aRes = @mssql_fetch_array ($rQry);
			if(false !== $aRes) {
				if ($sMode === 'MSSQL_NUM') {
					$aRes = self::phpBadGirl ($aRes, 0);
				}
				if ($sMode === 'MSSQL_ASSOC') {
					$aRes = self::phpBadGirl ($aRes, 1);
				}
			}
			return $aRes;
		}
	}

	protected static function phpBadGirl ($aTmp, $iMode) {
		$aNew = array ();
		if(is_array($aTmp)) {
			switch ($iMode) {
				case 0:
					foreach ($aTmp as $mK => $mV) {
						if (is_int ($mK)) {
							$aNew[$mK] = $mV;
						}
					}
					break;
				case 1:
					foreach ($aTmp as $mK => $mV) {
						if (is_string ($mK)) {
							$aNew[$mK] = $mV;
						}
					}
					break;
			}
		}
		if (empty ($aNew)) {
			return $aTmp;
		}
		return $aNew;
	}

	protected function _count ($rQry) {
		return @mssql_num_rows ($rQry);
	}

	protected function _lastInsertId () {
		$sQuery = 'SELECT @@IDENTITY';
		$rQry = $this -> query ($sQuery, false);
		return $this -> fetchColumn (0, $rQry, false);
	}

	protected function _startTransaction ($sTransacName = null)  {
		$sQuery = 'BEGIN TRANSACTION';
		if(!is_null($sTransacName)) {
			$sQuery .= ' '.$this->escape($sTransacName);
		}
		$rQry = $this -> query ($sQuery, false);
		return $rQry;
	}

	protected function _commitTransaction ($sTransacName = null)  {
		$sQuery = 'COMMIT TRANSACTION';
		if(!is_null($sTransacName)) {
			$sQuery .= ' '.$this->escape($sTransacName);
		}
		$rQry = $this -> query ($sQuery, false);
		return $rQry;
	}

	protected function _rollbackTransaction ($sTransacName = null)  {
		$sQuery = 'ROLLBACK TRANSACTION';
		if(!is_null($sTransacName)) {
			$sQuery .= ' '.$this->escape($sTransacName);
		}
		$rQry = $this -> query ($sQuery, false);
		return $rQry;
	}

	protected function _countTransaction () {
		$sQuery = 'SELECT @@TRANCOUNT';
		$rQry = $this -> query ($sQuery, false);
		return (int)$this -> fetchColumn (0, $rQry, false);
	}

	protected function _escape ($sString) {
		return @str_replace ("'", "''", $sString);
	}

	protected function _server_info ($rLink) {
		throw new aDBExceptionInvalidClassCalls(aDBExceptionInvalidClassCalls::UNSUPPORTED_METHOD, aDBExceptionInvalidClassCalls::CODE_UNSUPPORTED_METHOD, get_class($this), __FUNCTION__);
	}

	protected function _freeResult ($rQry = null) {
		if(!is_null($rQry) && is_resource($rQry) && get_resource_type($rQry) === 'mssql result') {
			return @mssql_free_result ($rQry);
		} elseif (is_resource($this->rQry) && get_resource_type($this->rQry) === 'mssql result') {
			return @mssql_free_result ($this->rQry);
		} else {
			return true;
		}
	}
	

	protected function _freeStatement ($rStmt = null) {
		if(!is_null($rStmt)) {
			return @mssql_free_statement ($rStmt);
		} else {
			return @mssql_free_statement ($this->rStmtLink);
		}
	}

	protected function _savePoint ($sSavePointName)  {
		$sQuery = 'SAVE TRANSACTION '.$this->_escape($sSavePointName);
		$rQry = $this -> query ($sQuery, false);
		return $rQry;
	}

	protected function _rollbackToSavePoint ($sSavePointName)  {
		$sQuery = 'ROLLBACK TRANSACTION '.$this->_escape($sSavePointName);
		$rQry = $this -> query ($sQuery, false);
		return $rQry;
	}

	protected function _releaseSavePoint ($sSavePointName)  {
		throw new aDBExceptionInvalidClassCalls(aDBExceptionInvalidClassCalls::UNSUPPORTED_METHOD, aDBExceptionInvalidClassCalls::CODE_UNSUPPORTED_METHOD, get_class($this), __FUNCTION__);
	}

	protected function _getIdentityColName($sTable) {
		$sQuery = 'SELECT TOP 1 IDENTITYCOL FROM '.$this->_escape($sTable);
		$rQry = $this -> query ($sQuery, false);
		return @mssql_field_name($rQry);
	}
	
	protected function _tableExists($sTable){
		$sQuery="SELECT * FROM dbo.sysobjects WHERE id = OBJECT_ID(N'$sTable')";
		$rQry = $this -> query ($sQuery, false);
		if ($this->count($rQry)===0){
			return false;
		}
		return true;
	}
	
	protected function _getColumnProperties($sTable, $sColumn = null) {
		$sQuery = "SELECT syscolumns.name as colname, systypes.name, 
			syscolumns.length, syscolumns.isnullable, syscolumns.xprec, syscolumns.collation,
			syscolumns.iscomputed, syscolumns.colorder, syscolumns.autoval
			FROM dbo.systypes systypes
			INNER JOIN dbo.syscolumns syscolumns ON syscolumns.xtype = systypes.xtype
			WHERE syscolumns.id = OBJECT_ID(N'{$sTable}')";
		if(!is_null($sColumn)) {
			$sQuery.= " AND syscolumns.name = '{$sColumn}'";
		}
		$this -> query ($sQuery);
		return $this->fetchAll(aDB::FETCH_ASSOC);
	}

	protected function _close () {
		return @mssql_close ($this->rLink);
	}
	
	protected function _call($sProcName) {
		return @mssql_init($sProcName);
	}
	
	protected function _bindParam($sParam, $mValue, $cType) {
		switch($cType) {
			case aDB::PARAM_INT: 
			case 'integer':
				$sType = SQLINT4;
				break;
			case aDB::PARAM_STR: 
			case 'string':
				$sType = SQLVARCHAR;
				break;
			case aDB::PARAM_FLOAT: 
			case 'float':
				$sType = SQLFLT8;
				break;
			case aDB::PARAM_BOOL: 
			case 'boolean':
				$sType = SQLINT1;
				break;
			default: 
				$this -> interceptException ('aDBExceptionInvalidClassCalls', aDBExceptionInvalidClassCalls::PARAM_TYPE_NOT_FOUND, aDBExceptionInvalidClassCalls::CODE_PARAM_TYPE_NOT_FOUND, get_class($this), __FUNCTION__);
				break;
		}
		return @mssql_bind($this->rStmtLink, $sParam, $mValue, $sType);
	}
	
	protected function _procExec() {
		return @mssql_execute($this->rStmtLink);
	}
	
	protected function _nextResult($rQry) {
		if(function_exists('mssql_next_result')) {
			return @mssql_next_result($rQry);
		} else {
			return false;
		}
	}
	
}

class mysql extends aDB {

	protected function _connect ($bOpenNewConnection = true) {
		return @mysql_connect ($this -> aConConf['HOST'], $this -> aConConf['LOGIN'], $this -> aConConf['PWD']);
	}

	protected function _errorMsg () {
		return @mysql_error();
	}

	protected function _select_db ($sDbName) {
		return @mysql_select_db ($sDbName, $this -> rLink);
	}

	protected function _seek ($iOffset) {
		return @mysql_data_seek ($this -> rQry, $iOffset);
	}

	protected function _query ($sQuery) {
		return @mysql_query ($sQuery, $this -> rLink);
	}

	protected function _fetch ($rQry, $aDB_MODE) {
		switch ($aDB_MODE) {
			case aDB::FETCH_ASSOC:
				$sMode = 'MYSQL_ASSOC';
				break;
			case aDB::FETCH_NUM:
				$sMode = 'MYSQL_NUM';
				break;
			default:
				$sMode = 'MYSQL_BOTH';
				break;
		}
		return @mysql_fetch_array ($rQry, constant ($sMode));
	}

	protected function _count ($rQry) {
		return @mysql_num_rows ($rQry);
	}

	protected function _lastInsertId () {
		return @mysql_insert_id ($this -> rQry);
	}

	protected function _startTransaction ($sTransacName = null)  {
		$sQuery = 'START TRANSACTION';
		$rQry = $this -> query ($sQuery, false);
		return $rQry;
	}

	protected function _commitTransaction ($sTransacName = null)  {
		$sQuery = 'COMMIT';
		$rQry = $this -> query ($sQuery, false);
		return $rQry;
	}

	protected function _rollbackTransaction ($sTransacName = null)  {
		$sQuery = 'ROLLBACK';
		$rQry = $this -> query ($sQuery, false);
		return $rQry;
	}

	protected function _countTransaction ()  {
		throw new aDBExceptionInvalidClassCalls(aDBExceptionInvalidClassCalls::UNSUPPORTED_METHOD, aDBExceptionInvalidClassCalls::CODE_UNSUPPORTED_METHOD, get_class($this), __FUNCTION__);
	}

	protected function _escape ($sString) {
		return @mysql_real_escape_string ($sString, $this -> rLink);
	}

	protected function _server_info ($rLink) {
		return @mysql_get_server_info ($rLink);
	}

	protected function _freeResult ($rQry = null) {
		if(!is_null($rQry)) {
			return @mysql_free_result ($rQry);
		} else {
			return @mysql_free_result ($this->rQry);
		}
	}
	
	protected function _freeStatement ($rStmt = null) {
		//todo
		return false;
	}

	protected function _savePoint ($sSavePointName)  {
		$sQuery = 'SAVEPOINT '.$sSavePointName;
		$rQry = $this -> query ($sQuery, false);
		return $rQry;
	}

	protected function _rollbackToSavePoint ($sSavePointName)  {
		$sQuery = 'ROLLBACK TO SAVEPOINT '.$sSavePointName;
		$rQry = $this -> query ($sQuery, false);
		return $rQry;
	}

	protected function _releaseSavePoint ($sSavePointName)  {
		$sQuery = 'RELEASE SAVEPOINT '.$sSavePointName;
		$rQry = $this -> query ($sQuery, false);
		return $rQry;
	}

	protected function _getIdentityColName($sTable) {
		throw new aDBExceptionInvalidClassCalls(aDBExceptionInvalidClassCalls::UNSUPPORTED_METHOD, aDBExceptionInvalidClassCalls::CODE_UNSUPPORTED_METHOD, get_class($this), __FUNCTION__);
	}
	
	protected function _tableExists($sTable){
		$sQuery="SHOW TABLES LIKE '$sTable'";
		$rQry = $this -> query ($sQuery, false);
		if ($this->count($rQry)===0){
			return false;
		}
		return true;
	}
	
	protected function _getColumnProperties($sTable, $sColumn = null) {
		// todo
		return false;
	}

	protected function _close () {
		return @mysql_close ($this->rLink);
	}
	
	protected function _call($sProcName) {
		//todo
		return false;
	}
	
	protected function _bindParam($sParam, $mValue, $cType) {
		//todo
		return false;
	}
	
	protected function _procExec() {
		//todo
		return false;
	}
	
	protected function _nextResult($rQry) {
		//todo
		return false;
	}
}
?>