. */ /** * This class implements many shared or common methods needed by resultset drivers. * * This class may (optionally) be extended by driver classes simply to make it easier * to create driver classes. This is also useful in the early stages of Creole development * as it means that API changes affect fewer files. As Creole matures/stabalizes having * a common class may become less useful, as drivers may have their own ways of doing things * (and we'll have a solid unit test framework to make sure drivers conform to the API * described by the interfaces). * * The get*() methods in this class will format values before returning them. Note * that if they will return null if the database returned NULL * which makes these functions easier to use than simply typecasting the values from the * db. If the requested column does not exist than an exception (SQLException) will be thrown. * * * $rs = $conn->executeQuery("SELECT MAX(stamp) FROM event", ResultSet::FETCHMODE_NUM); * $rs->next(); * * $max_stamp = $rs->getTimestamp(1, "d/m/Y H:i:s"); * // $max_stamp will be date string or null if no MAX(stamp) was found * * $max_stamp = $rs->getTimestamp("max(stamp)", "d/m/Y H:i:s"); * // will THROW EXCEPTION, because the resultset was fetched using numeric indexing * // SQLException: Invalid resultset column: max(stamp) * * * @author Hans Lellelid * @version $Revision: 1.9 $ * @package creole.common */ abstract class ResultSetCommon { /** * The fetchmode for this recordset. * @var int */ protected $fetchmode; /** * DB connection. * @var Connection */ protected $conn; /** * Resource identifier used for native result set handling. * @var resource */ protected $result; /** * The current cursor position (row number). First row is 1. Before first row is 0. * @var int */ protected $cursorPos = 0; /** * The current unprocessed record/row from the db. * @var array */ protected $fields; /** * Whether to convert assoc col case. * @var boolean */ protected $lowerAssocCase = false; /** * Whether to apply rtrim() to strings. * @var boolean */ protected $rtrimString = false; /** * Constructor. */ public function __construct(Connection $conn, $result, $fetchmode = null) { $this->conn = $conn; $this->result = $result; if ($fetchmode !== null) { $this->fetchmode = $fetchmode; } else { $this->fetchmode = ResultSet::FETCHMODE_ASSOC; // default } $this->lowerAssocCase = (($conn->getFlags() & Creole::COMPAT_ASSOC_LOWER) === Creole::COMPAT_ASSOC_LOWER); $this->rtrimString = (($conn->getFlags() & Creole::COMPAT_RTRIM_STRING) === Creole::COMPAT_RTRIM_STRING); } /** * Destructor * * Free db result resource. */ public function __destruct() { $this->close(); } /** * @see ResultSet::getIterator() */ public function getIterator() { require_once 'creole/ResultSetIterator.php'; return new ResultSetIterator($this); } /** * @see ResultSet::getResource() */ public function getResource() { return $this->result; } /** * @see ResultSet::isLowereAssocCase() */ public function isLowerAssocCase() { return $this->lowerAssocCase; } /** * @see ResultSet::setFetchmode() */ public function setFetchmode($mode) { $this->fetchmode = $mode; } /** * @see ResultSet::getFetchmode() */ public function getFetchmode() { return $this->fetchmode; } /** * @see ResultSet::previous() */ public function previous() { // Go back 2 spaces so that we can then advance 1 space. $ok = $this->seek($this->cursorPos - 2); if ($ok === false) { $this->beforeFirst(); return false; } return $this->next(); } /** * @see ResultSet::isBeforeFirst() */ public function relative($offset) { // which absolute row number are we seeking $pos = $this->cursorPos + ($offset - 1); $ok = $this->seek($pos); if ($ok === false) { if ($pos < 0) { $this->beforeFirst(); } else { $this->afterLast(); } } else { $ok = $this->next(); } return $ok; } /** * @see ResultSet::absolute() */ public function absolute($pos) { $ok = $this->seek( $pos - 1 ); // compensate for next() factor if ($ok === false) { if ($pos - 1 < 0) { $this->beforeFirst(); } else { $this->afterLast(); } } else { $ok = $this->next(); } return $ok; } /** * @see ResultSet::first() */ public function first() { if($this->cursorPos !== 0) { $this->seek(0); } return $this->next(); } /** * @see ResultSet::last() */ public function last() { if($this->cursorPos !== ($last = $this->getRecordCount() - 1)) { $this->seek( $last ); } return $this->next(); } /** * @see ResultSet::beforeFirst() */ public function beforeFirst() { $this->cursorPos = 0; } /** * @see ResultSet::afterLast() */ public function afterLast() { $this->cursorPos = $this->getRecordCount() + 1; } /** * @see ResultSet::isAfterLast() */ public function isAfterLast() { return ($this->cursorPos === $this->getRecordCount() + 1); } /** * @see ResultSet::isBeforeFirst() */ public function isBeforeFirst() { return ($this->cursorPos === 0); } /** * @see ResultSet::getCursorPos() */ public function getCursorPos() { return $this->cursorPos; } /** * @see ResultSet::getRow() */ public function getRow() { return $this->fields; } /** * @see ResultSet::get() */ public function get($column) { $idx = (is_int($column) ? $column - 1 : $column); if (!array_key_exists($idx, $this->fields)) { throw new SQLException("Invalid resultset column: " . $column); } return $this->fields[$idx]; } /** * @see ResultSet::getArray() */ public function getArray($column) { $idx = (is_int($column) ? $column - 1 : $column); if (!array_key_exists($idx, $this->fields)) { throw new SQLException("Invalid resultset column: " . $column); } if ($this->fields[$idx] === null) { return null; } return (array) unserialize($this->fields[$idx]); } /** * @see ResultSet::getBoolean() */ public function getBoolean($column) { $idx = (is_int($column) ? $column - 1 : $column); if (!array_key_exists($idx, $this->fields)) { throw new SQLException("Invalid resultset column: " . $column); } if ($this->fields[$idx] === null) { return null; } return (boolean) $this->fields[$idx]; } /** * @see ResultSet::getBlob() */ public function getBlob($column) { $idx = (is_int($column) ? $column - 1 : $column); if (!array_key_exists($idx, $this->fields)) { throw new SQLException("Invalid resultset column: " . $column); } if ($this->fields[$idx] === null) { return null; } require_once 'creole/util/Blob.php'; $b = new Blob(); $b->setContents($this->fields[$idx]); return $b; } /** * @see ResultSet::getClob() */ public function getClob($column) { $idx = (is_int($column) ? $column - 1 : $column); if (!array_key_exists($idx, $this->fields)) { throw new SQLException("Invalid resultset column: " . $column); } if ($this->fields[$idx] === null) { return null; } require_once 'creole/util/Clob.php'; $c = new Clob(); $c->setContents($this->fields[$idx]); return $c; } /** * @see ResultSet::getDate() */ public function getDate($column, $format = '%x') { $idx = (is_int($column) ? $column - 1 : $column); if (!array_key_exists($idx, $this->fields)) { throw new SQLException("Invalid resultset column: " . $column); } if ($this->fields[$idx] === null) { return null; } $ts = strtotime($this->fields[$idx]); if ($ts === -1 || $ts === false) { // in PHP 5.1 return value changes to FALSE throw new SQLException("Unable to convert value at column " . $column . " to timestamp: " . $this->fields[$idx]); } if ($format === null) { return $ts; } if (strpos($format, '%') !== false) { return strftime($format, $ts); } else { return date($format, $ts); } } /** * @see ResultSet::getFloat() */ public function getFloat($column) { $idx = (is_int($column) ? $column - 1 : $column); if (!array_key_exists($idx, $this->fields)) { throw new SQLException("Invalid resultset column: " . $column); } if ($this->fields[$idx] === null) { return null; } return (float) $this->fields[$idx]; } /** * @see ResultSet::getInt() */ public function getInt($column) { $idx = (is_int($column) ? $column - 1 : $column); if (!array_key_exists($idx, $this->fields)) { throw new SQLException("Invalid resultset column: " . $column); } if ($this->fields[$idx] === null) { return null; } return (int) $this->fields[$idx]; } /** * @see ResultSet::getString() */ public function getString($column) { $idx = (is_int($column) ? $column - 1 : $column); if (!array_key_exists($idx, $this->fields)) { throw new SQLException("Invalid resultset column: " . $column); } if ($this->fields[$idx] === null) { return null; } return ($this->rtrimString ? rtrim($this->fields[$idx]) : (string) $this->fields[$idx]); } /** * @see ResultSet::getTime() */ public function getTime($column, $format = '%X') { $idx = (is_int($column) ? $column - 1 : $column); if (!array_key_exists($idx, $this->fields)) { throw new SQLException("Invalid resultset column: " . $column); } if ($this->fields[$idx] === null) { return null; } $ts = strtotime($this->fields[$idx]); if ($ts === -1 || $ts === false) { // in PHP 5.1 return value changes to FALSE throw new SQLException("Unable to convert value at column " . (is_int($column) ? $column + 1 : $column) . " to timestamp: " . $this->fields[$idx]); } if ($format === null) { return $ts; } if (strpos($format, '%') !== false) { return strftime($format, $ts); } else { return date($format, $ts); } } /** * @see ResultSet::getTimestamp() */ public function getTimestamp($column, $format = 'Y-m-d H:i:s') { $idx = (is_int($column) ? $column - 1 : $column); if (!array_key_exists($idx, $this->fields)) { throw new SQLException("Invalid resultset column: " . $column); } if ($this->fields[$idx] === null) { return null; } $ts = strtotime($this->fields[$idx]); if ($ts === -1 || $ts === false) { // in PHP 5.1 return value changes to FALSE throw new SQLException("Unable to convert value at column " . $column . " to timestamp: " . $this->fields[$idx]); } if ($format === null) { return $ts; } if (strpos($format, '%') !== false) { return strftime($format, $ts); } else { return date($format, $ts); } } }