<?php /** * 数据库封装对象,对Mysql的一个操作封装 * */ class CoreDB { /** * 数据库操作实用工具对象 * * @var CoreDbUtils */ protected $_dbUtils = NULL; /** * 链接资源标志 * * @var resource */ protected $_link_identifier = NULL ; protected $_dsn = null; /** * 执行的查询计数 * * @var int */ protected $querycount = 0; /** * 最后一次数据库操作的错误信息 * * @var mixed */ public $lasterr = null; /** * 最后一次数据库操作的错误代码 * * @var mixed */ public $lasterrcode = null; /** * 最近一次插入操作或者 lastInsertId() 操作返回的插入 ID * * @var mixed */ protected $_lastInsertId = null; /** * 指示数据库是否支持事务 * * @var boolean */ protected $_has_transaction = false; /** * 指示数据库是否支持事务中的 SAVEPOINT 功能 * * @var boolean */ protected $_has_savepoint = false; /** * 指示事务启动次数 * * @var int */ protected $_trans_count = 0; /** * 指示事务执行期间是否发生了错误 * * @var boolean */ protected $_has_failed_query = false; /** * SAVEPOINT 堆栈 * * @var array */ protected $_savepoint_stack = array(); /** * 数据库程序版本号 */ private $_version = NULL; function __construct(array $dsn,$doParse=true){ $this->_dsn = $doParse ? self::parseDSN($dsn) : $dsn; } /** * 连接数据库 * * @return bool * @throw SqlQueryException */ function connect(){ if (is_resource($this->_link_identifier)) return; $host = $this->_dsn['host'] . ( empty($this->_dsn['port']) ? '' : ":{$this->_dsn['port']}" ); if (!empty($this->_dsn['options'])) { $this->_link_identifier = @mysql_connect($host, $dsn['login'], $dsn['password'], false, $this->_dsn['options']); } else { $this->_link_identifier = @mysql_connect($host,$this->_dsn['login'] ,$this->_dsn['password']); } // $this->_log_($this->_link_identifier); if (!$this->_link_identifier){ $this->lasterr = mysql_error(); $this->lasterrcode = mysql_errno(); throw new SqlQueryException("connect('{$host}','{$this->_dsn['login']}') failed!", $this->lasterr, $this->lasterrcode); } if (!empty($this->_dsn['database'])) { $this->selectDb($this->_dsn['database']); } $this->_version = $this->getOne('SELECT VERSION()'); if ($this->_version >= '5.0') { $this->_has_transaction = true; } // 设置字符集 if (!empty($this->_dsn['charset'])) { $this->execute("SET NAMES '{$this->_dsn['charset']}'"); } return true; } /** * 关闭数据库连接 */ function close(){ if($this->_link_identifier){ mysql_close($this->_link_identifier); } $this->_link_identifier = NULL ; $this->_lastInsertId = null; $this->_trans_count = 0; } /** * 选择要操作的数据库 * * @param string $database * * @return boolean */ function selectDb($database) { if (!mysql_select_db($database, $this->_link_identifier)) { $this->lasterr = mysql_error($this->_link_identifier); $this->lasterrcode = mysql_errno($this->_link_identifier); throw new SqlQueryException("SELECT DATABASE: '{$database}' FAILED!", $this->lasterr,$this->lasterrcode); } return true; } /** * 启动事务 */ function startTrans() { if ($this->_has_transaction){ if ($this->_trans_count == 0) { $this->execute('START TRANSACTION'); $this->_has_failed_query = false; } $this->_trans_count++; if ($this->_trans_count > 1 && $this->_has_savepoint) { $savepoint = 'savepoint_' . $this->_trans_count; $this->execute("SAVEPOINT {$savepoint}"); array_push($this->_savepoint_stack, $savepoint); } } } /** * 完成事务,根据查询是否出错决定是提交事务还是回滚事务 * * 如果 $commitOnNoErrors 参数为 true,当事务中所有查询都成功完成时,则提交事务,否则回滚事务 * 如果 $commitOnNoErrors 参数为 false,则强制回滚事务 * * @param $commitOnNoErrors 指示在没有错误时是否提交事务 */ function completeTrans($commitOnNoErrors = true) { if ($this->_has_transaction && $this->_trans_count > 0){ $this->_trans_count--; if ($this->_trans_count > 0 && $this->_has_savepoint) { $savepoint = array_pop($this->_savepoint_stack); if ($this->_has_failed_query || $commitOnNoErrors == false) { $this->execute("ROLLBACK TO SAVEPOINT {$savepoint}"); } } else { if ($this->_has_failed_query == false && $commitOnNoErrors) { $this->execute('COMMIT'); } else { $this->execute('ROLLBACK'); } } } } /** * 强制指示在调用 completeTrans() 时回滚事务 */ function failTrans() { $this->_has_failed_query = true; } /** * 返回事务是否失败的状态 */ function hasFailedTrans() { return $this->_has_failed_query; } /** * 执行一个查询,返回一个 resource 或者 boolean 值 * * @param string $sql * @param array $inputarr * @param boolean $throw 指示查询出错时是否抛出异常 * * @return resource|boolean */ function execute($sql, $inputarr = null, $throw = true) { if (is_array($inputarr)) { $sql = $this->bind($sql, $inputarr); } $this->_log_($sql); $this->querycount++; $result = mysql_query($sql, $this->_link_identifier); if ($result !== false) { return $result; } $this->lasterr = mysql_error($this->_link_identifier); $this->lasterrcode = mysql_errno($this->_link_identifier); if ($throw) { throw new SqlQueryException($sql, $this->lasterr, $this->lasterrcode); } return false; } /** * 返回最近一次数据库操作受到影响的记录数 * * @return int */ function lastQueryAffectedRows(){ return mysql_affected_rows($this->_link_identifier); } /** * 获取最后一次 nextId 操作获得的值 * * @return int */ function lastInsertId(){ return mysql_insert_id($this->_link_identifier); } /** * 执行一个查询,返回查询结果记录集 * * @param string|resource $sql * * @return array */ function getAll($sql) { $res = is_resource($sql) ? $sql : $this->execute($sql); $rowset = array(); while ($row = mysql_fetch_assoc($res)) { $rowset[] = $row; } mysql_free_result($res); return $rowset; } /** * 执行查询,返回第一条记录的第一个字段 * * @param string|resource $sql * * @return mixed */ function getOne($sql) { $res = is_resource($sql) ? $sql : $this->execute($sql); $row = mysql_fetch_row($res); mysql_free_result($res); return isset($row[0]) ? $row[0] : null; } /** * 执行查询,返回第一条记录 * * @param string|resource $sql * * @return mixed */ function getRow($sql) { $res = is_resource($sql) ? $sql : $this->execute($sql); $row = mysql_fetch_assoc($res); mysql_free_result($res); return $row; } /** * 执行查询,返回结果集的指定列 * * @param string|resource $sql * @param int $col 要返回的列,0 为第一列 * * @return mixed */ function getCol($sql, $col = 0) { $res = is_resource($sql) ? $sql : $this->execute($sql); $data = array(); while ($row = mysql_fetch_row($res)) { $data[] = $row[$col]; } mysql_free_result($res); return $data; } /** * 从记录集中返回一行数据 * * @param resouce $res * * @return array */ function fetchRow($res) { return mysql_fetch_row($res); } /** * 从记录集中返回一行数据,字段名作为键名 * * @param resouce $res * * @return array */ function fetchAssoc($res) { return mysql_fetch_assoc($res); } /** * 释放查询句柄 * * @param resource $res * * @return boolean */ function freeRes($res) { return mysql_free_result($res); } /** * 转义字符串 * * @param string $value * * @return mixed */ function qstr($value) { if (is_int($value) || is_float($value)) { return $value; } if (is_bool($value)) { return $value ? 1 : 0; } if (is_null($value)) { return 'NULL'; } return "'" . mysql_real_escape_string($value, $this->_link_identifier) . "'"; } /** * 执行一个查询,返回分组后的查询结果记录集 * * $groupBy 参数如果为字符串或整数,表示结果集根据 $groupBy 参数指定的字段进行分组。 * 如果 $groupBy 参数为 true,则表示根据每行记录的第一个字段进行分组。 * * @param string|resource $sql * @param string $groupBy * * @return array */ function getAllGroupBy($sql, & $groupBy) { $res = is_resource($sql) ? $sql : $this->execute($sql); $data = array(); $row = mysql_fetch_assoc($res); if ($row != false) { if (empty($groupBy)) { $groupBy = key($row); } do { $rkv = $row[$groupBy]; unset($row[$groupBy]); $data[$rkv][] = $row; } while ($row = mysql_fetch_assoc($res)); } mysql_free_result($res); return $data; } /** * 分析 DSN 数组,返回包含 DSN 连接信息的数组,失败返回 false * * @param array $dsn * * @return array */ static function parseDSN(array $dsn) { if (empty($dsn)) return NULL; $dsn['host'] = isset($dsn['host']) ? $dsn['host'] : ''; $dsn['port'] = isset($dsn['port']) ? $dsn['port'] : ''; $dsn['login'] = isset($dsn['login']) ? $dsn['login'] : ''; $dsn['password'] = isset($dsn['password']) ? $dsn['password'] : ''; $dsn['database'] = isset($dsn['database']) ? $dsn['database'] : ''; $dsn['charset'] = isset($dsn['charset']) ? $dsn['charset'] : 'utf8'; $dsn['options'] = isset($dsn['options']) ? $dsn['options'] : ''; $dsn['prefix'] = isset($dsn['prefix']) ? $dsn['prefix'] : ''; $dsn['schema'] = isset($dsn['schema']) ? $dsn['schema'] : ''; $dsnid = "mysql://{$dsn['login']}:{$dsn['password']}@{$dsn['host']}_{$dsn['prefix']}/{$dsn['database']}/{$dsn['schema']}/{$dsn['options']}"; $dsn['id'] = $dsnid; return $dsn; } /** * 返回数据库访问对象实例 * * 必须提供 $dsn 参数 * * DSN 是 Database Source Name 的缩写,可以理解为数据源名字。 * DSN 是一个数组,包含了连接数据库需要的各种信息,例如主机、用户名、密码等。 * * DSN 的正确写法: * * example: * <code> * $dsn = array( * 'host' => 'localhost', * 'login' => 'username', * 'password' => 'password', * 'database' => 'test_db', * 'charset' => 'utf8', * ); * * $dbo = CoreDB::instance($dsn); * </code> * * @param array $dsn * * @return CoreDB */ static function instance(array $dsn) { $dsn = self::parseDSN($dsn); $dsnid = "core-db/[{$dsn['id']}]"; if (App::isRegistered($dsnid)) return App::registry($dsnid); return App::register(new self($dsn,false),$dsnid); } /** * 返回 数据库操作工具对象 * * @return CoreDbUtils */ function getDbUtils(){ if (!$this->_dbUtils){ $this->_dbUtils = new CoreDbUtils($this); } return $this->_dbUtils; } private function _log_($statement) { App::$_logWriter_->append($statement,'sql','debug'); } } /** * InvalidDSNException 异常指示没有提供有效的 DSN 设置 * */ class InvalidDSNException extends Exception { public $dsn; /** * 构造函数 * * @param array $dsn */ function __construct(array $dsn) { unset($dsn['password']); $this->dsn = $dsn; parent::__construct('无效的数据源名称“Data-Source-Name (DSN)”.'); } } /** * SqlQueryException 异常指示一个 SQL 语句执行错误 * */ class SqlQueryException extends Exception { public $sql; public $error; public $errno; /** * 构造函数 * * @param string $sql sql语句 * @param string $error 错误文本 * @param int $errno 错误号 */ function __construct($sql, $error ,$errno) { $this->sql = $sql; $this->error = $error; $this->errno = $errno; $msg = sprintf('SQL: "%s"\nError: "%s"\nErrno: "%s"', $sql, $error ,$errno); parent::__construct($msg); } } require_once 'dbutils.php';
<?php /** * CoreDb 工具 * */ final class CoreDbUtils { /** * @var CoreDb */ private $_dbo = NULL; function __construct(CoreDb $dbo){ $this->_dbo = $dbo; } /** * C CHAR 或 VARCHAR 类型字段 * X TEXT 或 CLOB 类型字段 * B 二进制数据(BLOB) * N 数值或者浮点数 * D 日期 * T TimeStamp * L 逻辑布尔值 * I 整数 * R 自动增量或计数器 */ private static $typeMap = array( 'BIT' => 'I', 'TINYINT' => 'I', 'BOOL' => 'L', 'BOOLEAN' => 'L', 'SMALLINT' => 'I', 'MEDIUMINT' => 'I', 'INT' => 'I', 'INTEGER' => 'I', 'BIGINT' => 'I', 'FLOAT' => 'N', 'DOUBLE' => 'N', 'DOUBLEPRECISION' => 'N', 'FLOAT' => 'N', 'DECIMAL' => 'N', 'DEC' => 'N', 'DATE' => 'D', 'DATETIME' => 'T', 'TIMESTAMP' => 'T', 'TIME' => 'T', 'YEAR' => 'I', 'CHAR' => 'C', 'NCHAR' => 'C', 'VARCHAR' => 'C', 'NVARCHAR' => 'C', 'BINARY' => 'B', 'VARBINARY' => 'B', 'TINYBLOB' => 'X', 'TINYTEXT' => 'X', 'BLOB' => 'X', 'TEXT' => 'X', 'MEDIUMBLOB' => 'X', 'MEDIUMTEXT' => 'X', 'LONGBLOB' => 'X', 'LONGTEXT' => 'X', 'ENUM' => 'C', 'SET' => 'C', ); /** * 按照指定的类型,返回值 * * @param mixed $value * @param string $type * * @return mixed */ static function setValueByType($value, $type) { /** * C CHAR 或 VARCHAR 类型字段 * X TEXT 或 CLOB 类型字段 * B 二进制数据(BLOB) * N 数值或者浮点数 * D 日期 * T TimeStamp * L 逻辑布尔值 * I 整数 * R 自动增量或计数器 */ switch (strtoupper($type)) { case 'I': return (int)$value; case 'N': return (float)$value; case 'L': return (bool)$value; default: return $value; } } /** * 返回指定表(或者视图)的元数据 * * 部分代码参考 ADOdb 实现。 * * 每个字段包含下列属性: * * name: 字段名 * scale: 小数位数 * type: 字段类型 * simpleType: 简单字段类型(与数据库无关) * maxLength: 最大长度 * notNull: 是否不允许保存 NULL 值 * primaryKey: 是否是主键 * autoIncrement: 是否是自动增量字段 * binary: 是否是二进制数据 * unsigned: 是否是无符号数值 * hasDefault: 是否有默认值 * defaultValue: 默认值 * * @param string $table * * @return array */ function metaColumns($table) { $rs = $this->_dbo->execute(sprintf('SHOW FULL COLUMNS FROM %s', $table)); if (!$rs) { return false; } $retarr = array(); while (($row = $this->_dbo->fetchAssoc($rs))) { $field = array(); $field['name'] = $row['Field']; $type = $row['Type']; $field['scale'] = null; $queryArray = false; if (preg_match('/^(.+)\((\d+),(\d+)/', $type, $queryArray)) { $field['type'] = $queryArray[1]; $field['maxLength'] = is_numeric($queryArray[2]) ? $queryArray[2] : -1; $field['scale'] = is_numeric($queryArray[3]) ? $queryArray[3] : -1; } elseif (preg_match('/^(.+)\((\d+)/', $type, $queryArray)) { $field['type'] = $queryArray[1]; $field['maxLength'] = is_numeric($queryArray[2]) ? $queryArray[2] : -1; } elseif (preg_match('/^(enum)\((.*)\)$/i', $type, $queryArray)) { $field['type'] = $queryArray[1]; $arr = explode(",",$queryArray[2]); $field['enums'] = $arr; $zlen = max(array_map("strlen",$arr)) - 2; // PHP >= 4.0.6 $field['maxLength'] = ($zlen > 0) ? $zlen : 1; } else { $field['type'] = $type; $field['maxLength'] = -1; } $field['simpleType'] = self::$typeMap[strtoupper($field['type'])]; // if ($field['simpleType'] == 'C' && $field['maxLength'] > 250) { // $field['simpleType'] = 'X'; // } $field['notNull'] = ($row['Null'] != 'YES'); $field['primaryKey'] = ($row['Key'] == 'PRI'); $field['autoIncrement'] = (strpos($row['Extra'], 'auto_increment') !== false); if ($field['autoIncrement']) { $field['simpleType'] = 'R'; } $field['binary'] = (strpos($type,'blob') !== false); $field['unsigned'] = (strpos($type,'unsigned') !== false); if ($field['type'] == 'tinyint' && $field['maxLength'] == 1) { $field['simpleType'] = 'L'; } if (!$field['binary']) { $d = $row['Default']; if ($d != '' && $d != 'NULL') { $field['hasDefault'] = true; $field['defaultValue'] = self::setValueByType($d, $field['simpleType']); } else { $field['hasDefault'] = false; } } $field['description'] = isset($row['Comment']) ? $row['Comment'] : ''; $retarr[strtoupper($field['name'])] = $field; } $this->_dbo->freeRes($rs); return $retarr; } /** * 获得所有数据表的名称 * * @param string $pattern * @param string $schema * * @return array */ function metaTables($pattern = null, $schema = null) { $sql = 'SHOW TABLES'; if (!empty($schema)) { $sql .= " FROM {$schema}"; } if (!empty($pattern)) { $sql .= ' LIKE ' . $this->_dbo->qstr($schema); } $res = $this->_dbo->execute($sql, null, false); $tables = array(); while (($row = $this->_dbo->fetchRow($res))) { $tables[] = reset($row); } $this->_dbo->freeRes($res); return $tables; } /** * 为数据表产生下一个序列值 * * @param string $seqName * @param string $startValue * * @return int */ function nextId($seqName = 'coredb_seq', $startValue = 1) { $getNextIdSql = sprintf('UPDATE %s SET id = LAST_INSERT_ID(id + 1)', $seqName); $result = $this->_dbo->execute($getNextIdSql, null, false); if (!$result) { if (!$this->createSeq($seqName, $startValue)) { return false; } $result = $this->_dbo->execute($getNextIdSql); if (!$result) { return false; } } return $this->_dbo->lastInsertId(); } /** * 创建一个新的序列,成功返回 true,失败返回 false * * @param string $seqName * @param int $startValue * * @return boolean */ function createSeq($seqName = 'coredb_seq', $startValue = 1) { if ($this->_dbo->execute(sprintf('CREATE TABLE %s (id INT NOT NULL)', $seqName))) { return $this->_dbo->execute(sprintf('INSERT INTO %s VALUES (%s)', $seqName, $startValue - 1)); } else { return false; } } /** * 删除一个序列 * * @param string $seqName */ function dropSeq($seqName = 'coredb_seq') { return $this->_dbo->execute(sprintf('DROP TABLE %s', $seqName)); } /** * 执行一个查询,返回查询结果记录集、指定字段的值集合以及以该字段值分组后的记录集 * * @param string|resource $sql * @param string $field * @param array $fieldValues * @param array $reference * * @return array */ function getAllWithFieldRefs($sql, $field, & $fieldValues, & $reference) { $res = is_resource($sql) ? $sql : $this->_dbo->execute($sql); $fieldValues = array(); $reference = array(); $offset = 0; $data = array(); while ($row = $this->_dbo->fetchAssoc($res)) { $fieldValue = $row[$field]; unset($row[$field]); $data[$offset] = $row; $fieldValues[$offset] = $fieldValue; $reference[$fieldValue] =& $data[$offset]; $offset++; } $this->_dbo->freeRes($res); return $data; } /** * 执行一个查询,并将数据按照指定字段分组后与 $assocRowset 记录集组装在一起 * * @param string|resource $sql * @param array $assocRowset * @param string $mappingName * @param boolean $oneToOne * @param string $refKeyName * @param mixed $limit */ function assemble($sql, & $assocRowset, $mappingName, $oneToOne, $refKeyName, $limit = null) { if (is_resource($sql)) { $res = $sql; } else { if (!is_null($limit)) { if (is_array($limit)) { list($length, $offset) = $limit; } else { $length = $limit; $offset = 0; } $res = $this->_dbo->selectLimit($sql, $length, $offset); } else { $res = $this->_dbo->execute($sql); } } if ($oneToOne) { // 一对一组装数据 while ($row = $this->_dbo->fetchAssoc($res)) { $rkv = $row[$refKeyName]; unset($row[$refKeyName]); $assocRowset[$rkv][$mappingName] = $row; } } else { // 一对多组装数据 while ($row = $this->_dbo->fetchAssoc($res)) { $rkv = $row[$refKeyName]; unset($row[$refKeyName]); $assocRowset[$rkv][$mappingName][] = $row; } } $this->_dbo->freeRes($res); } } /** * SqlHelper 类提供了各种生成 SQL 语句的辅助方法 * */ final class CoreDbSqlHelper { /** * 分析查询条件 * * @param CoreDb $dbo * @param mixed $conditions * * @return string */ static function parseConditions(CoreDb $dbo, $conditions) { // 对于 NULL,直接返回 NULL if (is_null($conditions)) { return null; } // 如果是字符串,则假定为自定义条件 if (is_string($conditions)) { return $conditions; } // 如果不是数组,说明提供的查询条件有误 if (!is_array($conditions)) { return null; } $where = ''; $expr = ''; /** * 不过何种条件形式,一律为 字段名 => (值, 操作, 连接运算符, 值是否是SQL命令) 的形式 */ foreach ($conditions as $field => $cond) { $expr = 'AND'; if (!is_string($field)) { continue; } if (!is_array($cond)) { // 字段名 => 值 $cond = array($cond); } reset($cond); // 第一个元素是值 if (!isset($cond[1])) { $cond[1] = '='; } if (!isset($cond[2])) { $cond[2] = $expr; } if (!isset($cond[3])) { $cond[3] = false; } list($value, $op, $expr, $isCommand) = $cond; if (is_array($value)){ $value = '(' . implode(',',array_map(array($dbo, 'qstr'),$value)) . ')' ; $op = 'IN'; $isCommand = true; } if (!$isCommand) { $value = $dbo->qstr($value); } $where .= "{$field} {$op} {$value} {$expr} "; } $where = substr($where, 0, - (strlen($expr) + 2)); return $where; } /** * 返回 limit sql字串 * * @param int|array $limit * @return string */ static function getLimitSql($limit){ if (is_null($limit)) return ''; if (is_array($limit)) { list($length, $offset) = $limit; } else { $length = $limit; $offset = null; } if (!is_null($offset)) { $sql = " LIMIT " . (int)$offset; if (!is_null($length)) { $sql .= ', ' . (int)$length; } else { $sql .= ', 4294967294'; } } elseif (!is_null($length)) { $sql = " LIMIT " . (int)$length; } return $sql; } /** * 返回数据库可以接受的日期格式 * * @param int $timestamp * @return string */ static function dbTimeStamp($timestamp) { return date('Y-m-d H:i:s', $timestamp); } /** * 将数据表名字转换为完全限定名 * * @param string $tableName * @param string $schema * * @return string */ static function qtable($tableName, $schema = null) { return $schema != '' ? "`{$schema}`.`{$tableName}`" : "`{$tableName}`"; } /** * 将字段名转换为完全限定名,避免因为字段名和数据库关键词相同导致的错误 * * @param string $fieldName * @param string $tableName * @param string $schema * * @return string */ static function qfield($fieldName, $tableName = null, $schema = null) { $fieldName = ($fieldName == '*') ? '*' : "`{$fieldName}`"; return $tableName != '' ? self::qtable($tableName, $schema) . '.' . $fieldName : $fieldName; } /** * 一次性将多个字段名转换为完全限定名 * * @param string|array $fields * @param string $tableName * @param string $schema * @param boolean $returnArray * * @return string */ static function qfields($fields, $tableName = null, $schema = null, $returnArray = false) { if (!is_array($fields)) { $fields = explode(',', $fields); $fields = array_map('trim', $fields); } $return = array(); foreach ($fields as $fieldName) { $return[] = self::qfield($fieldName, $tableName, $schema); } return $returnArray ? $return : implode(', ', $return); } /** * 根据 SQL 语句和提供的参数数组,生成最终的 SQL 语句 * * @param CoreDb $dbo * @param string $sql * @param array $inputarr * * @return string */ static function bind(CoreDb $dbo, $sql, & $inputarr) { $arr = explode('?', $sql); $sql = array_shift($arr); foreach ($inputarr as $value) { if (isset($arr[0])) { $sql .= $dbo->qstr($value) . array_shift($arr); } } return $sql; } /** * 根据包含记录内容的数组返回一条有效的 SQL 插入记录语句 * * @param array $row * @param string $table 要插入的数据表 * @param string $schema * * @return string */ static function getInsertSQL(& $row, $table, $schema = null) { list($holders, $values) = self::getPlaceholder($row); $holders = implode(',', $holders); $fields = self::qfields(array_keys($values)); $table = self::qtable($table, $schema); $sql = "INSERT INTO {$table} ({$fields}) VALUES ({$holders})"; return $sql; } /** * 根据包含记录内容的数组返回一条有效的 SQL 更新记录语句 * * @param CoreDb $dbo * @param array $row * @param array $pk 表主键字段 * @param string $table 要插入的数据表 * @param string $schema * * @return string */ static function getUpdateSQL(CoreDb $dbo, & $row, $pk, $table, $schema = null) { $pkv = $row[$pk]; unset($row[$pk]); list($pairs, $values) = self::getPlaceholderPair($dbo,$row); $row[$pk] = $pkv; $pairs = implode(',', $pairs); $table = self::qtable($table, $schema); $pk = self::qfield($pk); $sql = "UPDATE {$table} SET {$pairs} WHERE {$pk} = " . $dbo->qstr($pkv); return $sql; } /** * 根据参数占位符样式,返回包含参数占位符及有效数据的数组 * * @param array $inputarr * @param array $fields * * @return array */ static function getPlaceholder(& $inputarr, $fields = null) { $holders = array(); $values = array(); if (is_array($fields)) { $fields = array_change_key_case(array_flip($fields), CASE_LOWER); foreach (array_keys($inputarr) as $key) { if (!isset($fields[strtolower($key)])) { continue; } $holders[] = '?'; $values[$key] =& $inputarr[$key]; } } else { foreach (array_keys($inputarr) as $key) { $holders[] = '?'; $values[$key] =& $inputarr[$key]; } } return array($holders, $values); } /** * 根据驱动的参数占位符样式,返回包含参数及占位符字符串对、有效数据的数组 * * @param CoreDb $dbo * @param array $inputarr * @param array $fields * * @return array */ static function getPlaceholderPair(CoreDb $dbo, & $inputarr, $fields = null) { $pairs = array(); $values = array(); if (is_array($fields)) { $fields = array_change_key_case(array_flip($fields), CASE_LOWER); foreach (array_keys($inputarr) as $key) { if (!isset($fields[strtolower($key)])) { continue; } $qkey = $this->qfield($key); $pairs[] = "{$qkey}=?"; $values[$key] =& $inputarr[$key]; } } else { foreach (array_keys($inputarr) as $key) { $qkey = $this->qfield($key); $pairs[] = "{$qkey}=?"; $values[$key] =& $inputarr[$key]; } } return array($pairs, $values); } }
代码例子:
$dbo = CoreDB::instance(App::ini('_dsn/default')); $dbo->connect(); // // $sqlCond = SqlHelper::parseConditions(array( // 'name' => 'asfdfds', // 'id' => array(array(123),'IN','OR'), // 'role.name' => array('%ha%','Like') // ),$dbo); $row = array( 'name' => 'asfdfds', 'id' => 112.5 ); $sqlCond = CoreDbSqlHelper::getInsertSQL($row,'users'); $sqlCond = CoreDbSqlHelper::bind($dbo,$sqlCond,$row); dump($dbo->getCol('show tables'),$sqlCond); dump($dbo->getDbUtils()->metaTables(),'metaTables');