Pgsql.php

浏览该文件的文档。
00001 <?php
00003 // FleaPHP Framework
00004 //
00005 // 该文件由“夜猫子”共享,特此感谢!
00007 
00026 class FLEA_Db_Driver_Pgsql
00027 {
00031     var $NEXT_ID_SQL    = "SELECT NEXTVAL('%s')";
00032     var $CREATE_SEQ_SQL = "CREATE SEQUENCE %s START %s";
00033     var $DROP_SEQ_SQL   = "DROP SEQUENCE %s";
00034 
00038     var $TRUE_VALUE  = 1;
00039     var $FALSE_VALUE = 0;
00040     var $NULL_VALUE = 'NULL';
00041 
00045     var $META_COLUMNS_SQL = "SELECT a.attname,t.typname,a.attlen,a.atttypmod,a.attnotnull,a.atthasdef,a.attnum FROM pg_class c, pg_attribute a,pg_type t WHERE relkind in ('r','v') AND (c.relname='%s' or c.relname = lower('%s')) and a.attname not like '....%%' AND a.attnum > 0 AND a.atttypid = t.oid AND a.attrelid = c.oid ORDER BY a.attnum";
00046 
00047     // 用于获取元数据的 SQL 查询语句(定义了 Schema 时使用)
00048     var $META_COLUMNS_SQL1 = "SELECT a.attname, t.typname, a.attlen, a.atttypmod, a.attnotnull, a.atthasdef, a.attnum FROM pg_class c, pg_attribute a, pg_type t, pg_namespace n WHERE relkind in ('r','v') AND (c.relname='%s' or c.relname = lower('%s')) and c.relnamespace=n.oid and n.nspname='%s' and a.attname not like '....%%' AND a.attnum > 0 AND a.atttypid = t.oid AND a.attrelid = c.oid ORDER BY a.attnum";
00049 
00050     // 获取主键字段的查询语句
00051     var $META_KEY_SQL = "SELECT ic.relname AS index_name, a.attname AS column_name,i.indisunique AS unique_key, i.indisprimary AS primary_key FROM pg_class bc, pg_class ic, pg_index i, pg_attribute a WHERE bc.oid = i.indrelid AND ic.oid = i.indexrelid AND (i.indkey[0] = a.attnum OR i.indkey[1] = a.attnum OR i.indkey[2] = a.attnum OR i.indkey[3] = a.attnum OR i.indkey[4] = a.attnum OR i.indkey[5] = a.attnum OR i.indkey[6] = a.attnum OR i.indkey[7] = a.attnum) AND a.attrelid = bc.oid AND bc.relname = '%s'";
00052 
00053     // 获取字段默认值的查询语句
00054     var $META_DEFAULT_SQL = "SELECT d.adnum as num, d.adsrc as def from pg_attrdef d, pg_class c where d.adrelid=c.oid and c.relname='%s' order by d.adnum";
00055 
00061     var $dsn = null;
00062 
00068     var $conn = null;
00069 
00075     var $log = array();
00076 
00082     var $enableLog = false;
00083 
00089     var $lasterr = null;
00090 
00096     var $lasterrcode = null;
00097 
00103     var $_transCount = 0;
00104 
00110     var $_transCommit = true;
00111 
00117     var $_lastrs = null;
00118 
00124     function FLEA_Db_Driver_Pgsql($dsn = false)
00125     {
00126         $tmp = (array)$dsn;
00127         unset($tmp['password']);
00128         $this->dsn = $dsn;
00129         $this->enableLog = !defined('DEPLOY_MODE') || DEPLOY_MODE != true;
00130         if (!function_exists('log_message')) {
00131             $this->enableLog = false;
00132         }
00133     }
00134 
00142     function connect($dsn = false)
00143     {
00144         $this->lasterr = null;
00145         $this->lasterrcode = null;
00146 
00147         if ($this->conn && $dsn == false) { return true; }
00148         if (!$dsn) {
00149             $dsn = $this->dsn;
00150         } else {
00151             $this->dsn = $dsn;
00152         }
00153         $dsnstring = '';
00154         if (isset($dsn['host'])) {
00155             $dsnstring = 'host=' . $this->_addslashes($dsn['host']);
00156         }
00157         if (isset($dsn['port'])) {
00158             $dsnstring .= ' port=' . $this->_addslashes($dsn['port']);
00159         }
00160         if (isset($dsn['login'])) {
00161             $dsnstring .= ' user=' . $this->_addslashes($dsn['login']);
00162         }
00163         if (isset($dsn['password'])) {
00164             $dsnstring .= ' password=' . $this->_addslashes($dsn['password']);
00165         }
00166         if (isset($dsn['database'])) {
00167             $dsnstring .= ' dbname=' . $this->_addslashes($dsn['database']);
00168         }
00169         $dsnstring .= ' ';
00170 
00171         if (isset($dsn['options'])) {
00172             $this->conn = pg_connect($dsnstring, $dsn['options']);
00173         } else {
00174             $this->conn = pg_connect($dsnstring);
00175         }
00176 
00177         if (!$this->conn) {
00178             FLEA::loadClass('FLEA_Db_Exception_SqlQuery');
00179             $pos = strpos($dsnstring, 'password=');
00180             if ($pos !== false) {
00181                 $dsnstring = substr($dsnstring, 0, $pos - 1) . substr($dsnstring, strpos($dsnstring, ' ', $pos + 1));
00182             }
00183             __THROW(new FLEA_Db_Exception_SqlQuery("pg_connect(\"{$dsnstring}\") failed!"));
00184             return false;
00185         }
00186 
00187         if (!$this->execute("set datestyle='ISO'")) { return false; }
00188 
00189         if (isset($dsn['charset']) && $dsn['charset'] != '') {
00190             $charset = $dsn['charset'];
00191         } else {
00192             $charset = FLEA::getAppInf('databaseCharset');
00193         }
00194         if (strtoupper($charset) == 'GB2312') { $charset = 'GBK'; }
00195         if ($charset != '') {
00196             pg_set_client_encoding($this->conn, $charset);
00197         }
00198 
00199         return true;
00200     }
00201 
00205     function close()
00206     {
00207         if ($this->conn) {
00208             pg_close($this->conn);
00209         }
00210         $this->conn = null;
00211         $this->lasterr = null;
00212         $this->lasterrcode = null;
00213         $this->_transCount = 0;
00214         $this->_transCommit = true;
00215     }
00216 
00226     function execute($sql, $inputarr = null, $throw = true)
00227     {
00228         if (is_array($inputarr)) {
00229             $sql = $this->_prepareSql($sql, $inputarr);
00230         }
00231         if ($this->enableLog) {
00232             $this->log[] = $sql;
00233             log_message("sql: {$sql}", 'debug');
00234         }
00235         $this->_lastrs = @pg_exec($this->conn, $sql);
00236         if ($this->_lastrs !== false) {
00237             $this->lasterr = null;
00238             $this->lasterrcode = null;
00239             return $this->_lastrs;
00240         }
00241         $this->lasterr = pg_errormessage($this->conn);
00242         $this->lasterrcode = null;
00243         if (!$throw) { return false; }
00244 
00245         FLEA::loadClass('FLEA_Db_Exception_SqlQuery');
00246         __THROW(new FLEA_Db_Exception_SqlQuery($sql, $this->lasterr));
00247         return false;
00248     }
00249 
00257     function qstr($value)
00258     {
00259         if (is_bool($value)) { return $value ? $this->TRUE_VALUE : $this->FALSE_VALUE; }
00260         if (is_null($value)) { return $this->NULL_VALUE; }
00261         return "'" . pg_escape_string($value) . "'";
00262     }
00263 
00271     function qtable($tableName)
00272     {
00273         if (substr($tableName, 0, 1) == '"') { return $tableName; }
00274         return '"' . $tableName . '"';
00275     }
00276 
00285     function qfield($fieldName, $tableName = null)
00286     {
00287         $pos = strpos($fieldName, '.');
00288         if ($pos !== false) {
00289             $tableName = substr($fieldName, 0, $pos);
00290             $fieldName = substr($fieldName, $pos + 1);
00291         }
00292         if ($tableName != "") {
00293             return "\"{$tableName}\".\"{$fieldName}\"";
00294         } else {
00295             return "\"{$fieldName}\"";
00296         }
00297     }
00298 
00307     function qfields($fields, $tableName = null)
00308     {
00309         if (!is_array($fields)) {
00310             $fields = explode(',', $fields);
00311         }
00312         $return = array();
00313         foreach ($fields as $fieldName) {
00314             $fieldName = trim($fieldName);
00315             if ($fieldName == '') { continue; }
00316             $pos = strpos($fieldName, '.');
00317             if ($pos !== false) {
00318                 $tableName = substr($fieldName, 0, $pos);
00319                 $fieldName = substr($fieldName, $pos + 1);
00320             }
00321             if ($tableName != '') {
00322                 $return[] = "\"{$tableName}\".\"{$fieldName}\"";
00323             } else {
00324                 $return[] = "\"{$fieldName}\"";
00325             }
00326         }
00327         return implode(', ', $return);
00328     }
00329 
00338     function nextId($seqName = 'sdbo_seq', $startValue = 1)
00339     {
00340         $getNextId = sprintf($this->NEXT_ID_SQL, $seqName);
00341         $result = $this->execute($getNextId, null, false);
00342         if ($result == false) {
00343             // 序列不存在,建立该序列
00344             if (!$this->createSeq($seqName, $startValue)) { return false; }
00345             if (!$result = $this->execute($getNextId)) { return false; }
00346         }
00347 
00348         $row = $this->fetchRow($result);
00349         $this->freeRes($result);
00350         return reset($row);
00351     }
00352 
00361     function createSeq($seqName = 'sdbo_seq', $startValue = 1)
00362     {
00363         return $this->execute(sprintf($this->CREATE_SEQ_SQL, $seqName, $startValue));
00364     }
00365 
00371     function dropSeq($seqName = 'sdbo_seq')
00372     {
00373         return $this->execute(sprintf($this->DROP_SEQ_SQL, $seqName));
00374     }
00375 
00383     function insertId()
00384     {
00385         require_once(FLEA_DIR . '/Exception/NotImplemented.php');
00386         __THROW(new FLEA_Exception_NotImplemented('insertId()', 'FLEA_Db_Driver_Pgsql'));
00387         return false;
00388     }
00389 
00395     function affectedRows()
00396     {
00397         return pg_affected_rows($this->_lastrs);
00398     }
00399 
00407     function fetchRow($res)
00408     {
00409         return pg_fetch_row($res);
00410     }
00411 
00419     function fetchAssoc($res)
00420     {
00421         return pg_fetch_assoc($res);
00422     }
00423 
00429     function freeRes($res)
00430     {
00431         pg_free_result($res);
00432     }
00433 
00441     function selectLimit($sql, $length = 'ALL', $offset = 0)
00442     {
00443         if (strtoupper($length) != 'ALL') { $length = (int)$length; }
00444         $sql = sprintf('%s LIMIT %d OFFSET %d', $sql, $length, (int)$offset);
00445         return $this->execute($sql);
00446     }
00447 
00455     function & getAll($sql)
00456     {
00457         if (is_resource($sql)) {
00458             $res = $sql;
00459         } else {
00460             $res = $this->execute($sql);
00461         }
00462         $data = array();
00463         while ($row = pg_fetch_assoc($res)) {
00464             $data[] = $row;
00465         }
00466         pg_free_result($res);
00467         return $data;
00468     }
00469 
00481     function & getAllGroupBy($sql, & $groupBy)
00482     {
00483         if (is_resource($sql)) {
00484             $res = $sql;
00485         } else {
00486             $res = $this->execute($sql);
00487         }
00488         $data = array();
00489         $row = pg_fetch_assoc($res);
00490         if ($row != false) {
00491             if ($groupBy === true) {
00492                 $groupBy = key($row);
00493             }
00494             do {
00495                 $rkv = $row[$groupBy];
00496                 unset($row[$groupBy]);
00497                 $data[$rkv][] = $row;
00498             } while ($row = pg_fetch_assoc($res));
00499         }
00500         pg_free_result($res);
00501         return $data;
00502     }
00503 
00514     function getAllWithFieldRefs($sql, $field, & $fieldValues, & $reference)
00515     {
00516         if (is_resource($sql)) {
00517             $res = $sql;
00518         } else {
00519             $res = $this->execute($sql);
00520         }
00521 
00522         $fieldValues = array();
00523         $reference = array();
00524         $offset = 0;
00525         $data = array();
00526         while ($row = pg_fetch_assoc($res)) {
00527             $fieldValue = $row[$field];
00528             unset($row[$field]);
00529             $data[$offset] = $row;
00530             $fieldValues[$offset] = $fieldValue;
00531             $reference[$fieldValue] =& $data[$offset];
00532             $offset++;
00533         }
00534         pg_free_result($res);
00535         return $data;
00536     }
00537 
00548     function assemble($sql, & $assocRowset, $mappingName, $oneToOne, $refKeyName, $limit = null)
00549     {
00550         if (is_resource($sql)) {
00551             $res = $sql;
00552         } else {
00553             if (!is_null($limit)) {
00554                 if (is_array($limit)) {
00555                     list($length, $offset) = $limit;
00556                 } else {
00557                     $length = $limit;
00558                     $offset = 0;
00559                 }
00560                 $res = $this->selectLimit($sql, $length, $offset);
00561             } else {
00562                 $res = $this->execute($sql);
00563             }
00564         }
00565         if ($oneToOne) {
00566             // 一对一组装数据
00567             while ($row = pg_fetch_assoc($res)) {
00568                 $rkv = $row[$refKeyName];
00569                 unset($row[$refKeyName]);
00570                 $assocRowset[$rkv][$mappingName] = $row;
00571             }
00572         } else {
00573             // 一对多组装数据,需要检查是否有全 NULL 的记录
00574             while ($row = pg_fetch_assoc($res)) {
00575                 $rkv = $row[$refKeyName];
00576                 unset($row[$refKeyName]);
00577                 $assocRowset[$rkv][$mappingName][] = $row;
00578             }
00579         }
00580 
00581         pg_free_result($res);
00582     }
00583 
00591     function getOne($sql)
00592     {
00593         if (is_resource($sql)) {
00594             $res = $sql;
00595         } else {
00596             $res = $this->execute($sql);
00597         }
00598         $row = pg_fetch_row($res);
00599         pg_free_result($res);
00600         return isset($row[0]) ? $row[0] : null;
00601     }
00602 
00610     function & getRow($sql)
00611     {
00612         if (is_resource($sql)) {
00613             $res = $sql;
00614         } else {
00615             $res = $this->execute($sql);
00616         }
00617         $row = pg_fetch_assoc($res);
00618         pg_free_result($res);
00619         return $row;
00620     }
00621 
00630     function & getCol($sql, $col = 0)
00631     {
00632         if (is_resource($sql)) {
00633             $res = $sql;
00634         } else {
00635             $res = $this->execute($sql);
00636         }
00637         $data = array();
00638         while ($row = pg_fetch_row($res)) {
00639             $data[] = $row[$col];
00640         }
00641         pg_free_result($res);
00642         return $data;
00643     }
00644 
00670     function & metaColumns($table, $normalize = true)
00671     {
00672         static $typeMap = array(
00673             'MONEY' => 'C',
00674             'INTERVAL' => 'C',
00675             'CHAR' => 'C',
00676             'CHARACTER' => 'C',
00677             'VARCHAR' => 'C',
00678             'NAME' => 'C',
00679             'BPCHAR' => 'C',
00680             '_VARCHAR' => 'C',
00681             'INET' => 'C',
00682             'MACADDR' => 'C',
00683 
00684             'TEXT' => 'X',
00685             'IMAGE' => 'B',
00686             'BLOB' => 'B',
00687             'BIT' => 'B',
00688             'VARBIT' => 'B',
00689             'BYTEA' => 'B',
00690 
00691             'BOOL' => 'L',
00692             'BOOLEAN' => 'L',
00693 
00694             'DATE' => 'D',
00695 
00696             'TIMESTAMP WITHOUT TIME ZONE' => 'T',
00697             'TIME' => 'T',
00698             'DATETIME' => 'T',
00699             'TIMESTAMP' => 'T',
00700             'TIMESTAMPTZ' => 'T',
00701 
00702             'SMALLINT' => 'I',
00703             'BIGINT' => 'I',
00704             'INTEGER' => 'I',
00705             'INT8' => 'I',
00706             'INT4' => 'I',
00707             'INT2' => 'I',
00708 
00709             'OID' => 'R',
00710             'SERIAL' => 'R',
00711         );
00712 
00713         $schema = false;
00714         $this->_findschema($table, $schema);
00715 
00716         if (!empty($this->META_KEY_SQL)) {
00717             // If we want the primary keys, we have to issue a separate query
00718             // Of course, a modified version of the metaColumnsSQL query using a
00719             // LEFT JOIN would have been much more elegant, but postgres does
00720             // not support OUTER JOINS. So here is the clumsy way.
00721             // fetch all result in once for performance.
00722             $keys = $this->getAll(sprintf($this->META_KEY_SQL, $table));
00723         }
00724 
00725         $rsdefa = array();
00726         if (!empty($this->META_DEFAULT_SQL)) {
00727             $sql = sprintf($this->META_DEFAULT_SQL, $table);
00728             $rsdef = $this->execute($sql);
00729             if ($rsdef) {
00730                 while ($row = pg_fetch_assoc($rsdef)) {
00731                     $num = $row['num'];
00732                     $s = $row['def'];
00733                     if (strpos($s, '::') === false && strpos($s, "'") === 0) {
00734                         /* quoted strings hack... for now... fixme */
00735                         $s = substr($s, 1);
00736                         $s = substr($s, 0, strlen($s) - 1);
00737                     }
00738 
00739                     $rsdefa[$num] = $s;
00740                 }
00741                 pg_free_result($rsdef);
00742             }
00743             unset($rsdef);
00744         }
00745 
00746         if ($schema) {
00747             $rs = $this->execute(sprintf($this->META_COLUMNS_SQL1, $table, $table, $schema));
00748         } else {
00749             $rs = $this->execute(sprintf($this->META_COLUMNS_SQL, $table, $table));
00750         }
00751         if (!$rs) { return false; }
00752 
00753         $retarr = array();
00754         while (($row = pg_fetch_row($rs))) {
00755             $field = array();
00756             $field['name'] = $row[0];
00757             $field['type'] = $row[1];
00758             $field['maxLength'] = $row[2];
00759             $field['attnum'] = $row[6];
00760 
00761             if ($field['maxLength'] <= 0) {
00762                 $field['maxLength'] = $row[3] - 4;
00763             }
00764             if ($field['maxLength'] <= 0) {
00765                 $field['maxLength'] = -1;
00766             }
00767 
00768             if ($field['type'] == 'numeric') {
00769                 $field['scale'] = $field['maxLength'] & 0xFFFF;
00770                 $field['maxLength'] >>= 16;
00771             }
00772             // dannym
00773             // 5 hasdefault; 6 num-of-column
00774             $field['hasDefault'] = ($row[5] == 't');
00775             if ($field['hasDefault']) {
00776                 $field['defaultValue'] = $rsdefa[$row[6]];
00777             }
00778 
00779             $field['notNull'] = $row[4] == 't';
00780 
00781             if (is_array($keys)) {
00782                 foreach($keys as $key) {
00783                     if ($field['name'] == $key['column_name'] && $key['primary_key'] == 't') {
00784                         $field['primaryKey'] = true;
00785                     } else {
00786                         $field['primaryKey'] = false;
00787                     }
00788                     if ($field['name'] == $key['column_name'] && $key['unique_key'] == 't') {
00789                         $field['unique'] = true; // What name is more compatible?
00790                     } else {
00791                         $field['unique'] = false;
00792                     }
00793                 }
00794             }
00795 
00796             $t = strtoupper($field['type']);
00797             if (isset($typeMap[$t])) {
00798                 $field['simpleType'] = $typeMap[$t];
00799             } else {
00800                 $field['simpleType'] = 'N';
00801             }
00802 
00803             if ($field['simpleType'] == 'I' && ($field['primaryKey'] != false || $field['unique'] != false)) {
00804                 $field['simpleType'] = 'R';
00805             }
00806 
00807             $field['autoIncrement'] = false;
00808 
00809             if ($normalize) {
00810                 $retarr[strtoupper($field['name'])] = $field;
00811             } else {
00812                 $retarr[$field['name']] = $field;
00813             }
00814         }
00815         pg_free_result($rs);
00816         return $retarr;
00817     }
00818 
00824     function dbTimeStamp($timestamp)
00825     {
00826         return date('Y-m-d H:i:s', $timestamp);
00827     }
00828 
00832     function startTrans()
00833     {
00834         $this->_transCount += 1;
00835         if ($this->_transCount == 1) {
00836             $this->execute('BEGIN');
00837         }
00838     }
00839 
00848     function completeTrans($commitOnNoErrors = true)
00849     {
00850         if ($this->_transCount < 1) { return; }
00851         if ($this->_transCount > 1) {
00852             $this->_transCount -= 1;
00853             return;
00854         }
00855         $this->_transCount = 0;
00856 
00857         if ($this->_transCommit && $commitOnNoErrors) {
00858             $this->execute('COMMIT');
00859         } else {
00860             $this->execute('ROLLBACK');
00861         }
00862     }
00863 
00867     function failTrans()
00868     {
00869         $this->_transCommit = false;
00870     }
00871 
00875     function hasFailedTrans()
00876     {
00877         if ($this->_transCount > 0) {
00878             return $this->_transCommit === false;
00879         }
00880         return false;
00881     }
00882 
00891     function _prepareSql($sql, & $inputarr)
00892     {
00893         $sqlarr = explode('?', $sql);
00894         $sql = '';
00895         $ix = 0;
00896         foreach ($inputarr as $v) {
00897             $sql .= $sqlarr[$ix];
00898             $typ = gettype($v);
00899             if ($typ == 'string') {
00900                 $sql .= $this->qstr($v);
00901             } else if ($typ == 'double') {
00902                 $sql .= $this->qstr(str_replace(',', '.', $v));
00903             } else if ($typ == 'boolean') {
00904                 $sql .= $v ? $this->TRUE_VALUE : $this->FALSE_VALUE;
00905             } else if (is_null($v)) {
00906                 $sql .= 'NULL';
00907             } else {
00908                 $sql .= $v;
00909             }
00910             $ix += 1;
00911         }
00912         if (isset($sqlarr[$ix])) {
00913             $sql .= $sqlarr[$ix];
00914         }
00915         return $sql;
00916     }
00917 
00925     function _addslashes($s)
00926     {
00927         $len = strlen($s);
00928         if ($len == 0) return "''";
00929         if (strncmp($s,"'",1) === 0 && substr($s,$len-1) == "'") return $s; // already quoted
00930         return "'".addslashes($s)."'";
00931     }
00932 
00939     function _findschema(& $table, & $schema)
00940     {
00941         if (!$schema && ($at = strpos($table, '.')) !== false) {
00942             $schema = substr($table, 0, $at);
00943             $table = substr($table, $at + 1);
00944         }
00945     }
00946 }

Generated at Sat Feb 2 15:18:51 2008 for FleaPHP by  doxygen 1.5.3