setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); $this->setAttribute(PDO::ATTR_STATEMENT_CLASS, array('PDODatabaseStatement', array())); } public function getDSN() { return $this->dsn; } /** * Создает соединение с базой данных */ static function getConnection(array $dsn) { if ($dsn['phptype'] == 'pgsql' || $dsn['phptype'] == 'mysql') { $port = (isset($dsn['port'])) ? "port={$dsn['port']};" : ""; $connection = new Database("{$dsn['phptype']}:host={$dsn['hostspec']}; $port dbname={$dsn['database']}", $dsn['username'], $dsn['password']); $connection->query('SET client_encoding = "UTF-8"'); } if ($dsn['phptype'] == 'sqlite') { $connection = new Database("{$dsn['phptype']}:{$dsn['database']}"); } $connection->dsn = $dsn; return $connection; } public function executeQuery($query) { $stmt = $this->prepare($query); $stmt->setFetchMode(PDO::FETCH_ASSOC); $stmt->execute(); $stmt->cache = $stmt->fetchAll(); return $stmt;//$sth->fetchAll(); } public function prepareStatement($query) { return new DatabaseStatement($query, $this); } // Для совместимости со старым представлением баз данных CIS /** * Извлекает из базы все элементы по запросу */ public function fetchAllArray($query) { $sth = $this->prepare($query); $sth->setFetchMode(PDO::FETCH_ASSOC); $sth->execute(); return $sth->fetchAll(); } /** * Извлекает из базы первый элемент по запросу */ public function fetchOneArray($query) { $sth = $this->prepare($query); $sth->setFetchMode(PDO::FETCH_ASSOC); $sth->execute(); return $sth->fetch(); } private function assignQuote($x, $y) { return $x . "=" . $this->quote($y); } /** * Создает INSERT запрос */ function insertQuery($table, array $values) { return $this->query("INSERT INTO $table (" . implode(",", array_keys($values)) . ") VALUES (" . implode(",", array_map(array($this, 'quote'), array_values($values))) . ")"); } /** * Создает UPDATE запрос */ function updateQuery($table, array $values, $cond) { return $this->query("UPDATE $table SET " . implode(",", array_map(array($this, 'assignQuote'), array_keys($values), array_values($values))) . " WHERE $cond"); } function getIdGenerator() { return new IdGenerator($this); } /** * Замечание: Только для Postgres SQL * @param string $seq Имя последовательности для ключа таблицы * @return int Идентефикатор следующей записи */ function getNextId($seq) { $result = $this->fetchOneArray("SELECT nextval('$seq')"); return $result['nextval']; } function close() { return null; } } class IdGenerator { private $db; function __construct($db) { $this->db = $db; } function isBeforeInsert() { return false; } function isAfterInsert() { return true; } function getId($seq) { $result = $this->db->fetchOneArray("SELECT nextval('$seq')"); return $result['nextval']; // $result = $this->db->fetchOneArray("SELECT last_insert_rowid() AS nextval"); // return $result['nextval']; } } class PDODatabaseStatementIterator implements Iterator { private $result; private $pos = 0; private $fetchmode; private $row_count; private $rs; /** * Construct the iterator. * @param PgSQLResultSet $rs */ public function __construct($rs) { $this->result = $rs; $this->row_count = $rs->getRecordCount(); } function rewind() { $this->pos = 0; } function valid() { return ($this->pos < $this->row_count); } function key() { return $this->pos; } function current() { if (!isset($this->result->cache[$this->pos])) { $this->result->cache[$this->pos] = $this->result->fetch(PDO::FETCH_ASSOC); } return $this->result->cache[$this->pos]; } function next() { $this->pos++; } function seek ( $index ) { $this->pos = $index; } function count ( ) { return $this->row_count; } } class PDODatabaseStatement extends PDOStatement implements IteratorAggregate { protected $cursorPos = 0; public $cache = array(); function getIterator() { return new PDODatabaseStatementIterator($this); } protected function __construct() { } function rewind() { $this->cursorPos = 0; } public function seek($rownum) { if ($rownum < 0) { return false; } // PostgreSQL rows start w/ 0, but this works, because we are // looking to move the position _before_ the next desired position $this->cursorPos = $rownum; return true; } function valid() { return ( true ); } public function first() { if($this->cursorPos !== 0) { $this->seek(0); } return $this->next(); } function next() { if ($this->getRecordCount() > $this->cursorPos) { if (!isset($this->cache[$this->cursorPos])) { $this->cache[$this->cursorPos] = $this->fetch(PDO::FETCH_ASSOC); } $this->fields = $this->cache[$this->cursorPos]; $this->cursorPos++; return true; } else { $this->fields = null; return false; } } function key() { return $this->cursorPos; } function current() { return $this->result->fetch(PDO::FETCH_ASSOC); } function getRow() { return $this->fields; } function getInt($name) { return intval($this->fields[$name]); } function getBlob($name) { return $this->fields[$name]; } function getString($name) { return $this->fields[$name]; } function getBoolean($name) { return (bool)$this->fields[$name]; } function get($name) { return $this->fields[$name]; } function getRecordCount() { return count($this->cache); } } /** * Класс оболочка для PDOStatement для замены Creole */ class DatabaseStatement { protected $limit = null; protected $offset = null; protected $statement = null; protected $binds = array(); protected $conn; protected $query; function __construct($query, $conn) { $this->query = $query; $this->conn = $conn; } function setInt($n, $value) { $this->binds [] = array($n, $value, PDO::PARAM_INT); } function setString($n, $value) { $this->binds [] = array($n, $value, PDO::PARAM_STR); } function setBlob($n, $value) { $this->binds [] = array($n, $value, PDO::PARAM_LOB); } function setLimit($limit) { $this->limit = $limit; } function setOffset($offset) { $this->offset = $offset; } function executeQuery() { if ($this->limit) { $this->query .= " LIMIT {$this->limit} OFFSET {$this->offset}"; } $stmt = $this->conn->prepare($this->query); foreach ($this->binds as $bind) { list($n, $value, $type) = $bind; $stmt->bindValue($n, $value, $type); } $stmt->setFetchMode(PDO::FETCH_ASSOC); $stmt->execute(); $stmt->cache = $stmt->fetchAll(); return $stmt; } }