<?php
/*
* Copyright (C) 2002-2004
* @author chenxi
* @version $Id: PreparedStatement.class.php,v 0.1 2004/11/06 13:29:50
*/
require_once ('Object.class.php');
require_once ('pdbc/mysql/Statement.class.php');
class mysql_PreparedStatement extends mysql_Statement {
/* Êý¾Ý¿âÁ¬½ÓʵÀý */
var $conn = null;
/* ±¾´Î»á»°µÄÅúÁ¿²éѯÓï¾ä¼¯ºÏ */
var $sqlBatch = array();
/* ±¾´Î»á»°µÄÅúÁ¿²éѯ½á¹û¼¯¼¯ºÏ */
var $resultBatch = array();
/* µ±Ç°ÅúÁ¿²éѯ½á¹û¼¯µÄÓαê */
var $current_result_offset = 0;
/* µ±Ç°µÄ²éѯ½á¹û¼¯ */
var $currentResult = null;
/* mysql_PreparedStatementʵÀý */
var $pstmt = null;
/* mysql_ResultSetʵÀý */
var $result = null;
/* Óɵ±Ç°PreparedStatement¶ÔÏó´´½¨µÄResultSet¶ÔÏó¼¯ºÏ */
var $openResults = null;
/* Êý¾Ý¿âÁ¬½ÓÊÇ·ñ¿ÉÓñêʶ */
var $isClosed = true;
/* Ò»¸ö»á»°ÆÚ¼äÄڰ󶨵ÄSQL²ÎÊýÊý×é */
var $bindParams = array();
/* Document me */
var $_bindInputArray = false;
/* Òª°ó¶¨µÄSQLÓï¾ä²ÎÊý¸öÊý */
var $bindParamCount = 0;
/* ÔʼµÄ²éѯÓï¾ä */
var $original_sql = '';
/* Ô¤²éѯ´¦ÀíºóµÄSQLÓï¾ä */
var $prepared_sql = '';
/* Êý¾Ý¿â²éѯ³¬Ê±Ê±¼ä£¬Ä¬ÈÏ5ÃëÖÓ */
var $queryTimeout = 5;
/**
* ¹¹Ô캯Êý
*/
function mysql_PreparedStatement(&$conn, $sql) {
$this->checkDbh($conn);
$this->checkNullOrEmptyQuery($sql);
$this->conn = $conn;
$this->original_sql = $sql;
$this->isClosed = false;
if ($GLOBALS['debug'] && (int)4 >= $GLOBALS['debug'])
$this->debug('oringinal_sql: '.$this->original_sql);
}
/**
* Îö¹¹º¯Êý
*/
function __destruct() {
$this->conn = null;
$this->pstmt = null;
$this->result = null;
$this->bindParamCount = 0;
$this->original_sql = null;
#$this->sqlBatch = null;
$this->resultBatch = null;
$this->isClosed = true;
}
/*
* ½«µ±Ç°»á»°ÖеÄsqlÃüÁîÌí¼Óµ½µ±Ç°Statement¶ÔÏóµÄsqlÃüÁîÁбíÖÐ
* @return void
* @access private
*/
function addBatch() {
$sql = $this->prepareSql($this->original_sql);
if ($sql)
$this->sqlBatch[sizeof($this->sqlBatch)] = $sql;
// Çå¿Õµ±Ç°°ó¶¨²ÎÊýÊý×é
$this->bindParams = array();
}
/**
* ¼ì²éµ±Ç°Êý¾Ý¿âÁ¬½ÓÊÇ·ñÒѹرÕ
* @return void
* @access private
*/
function checkClosed() {
if ($this->isClosed)
$this->throws('No operations allowed after PreparedStatement closed.', null, EXCEPTION_DIE);
}
/**
* ¼ì²édbhÊÇ·ñºÏ·¨
*/
function checkDbh($dbh) {
if (is_null($dbh))
trigger_error('dbh is null', E_USER_ERROR);
if (!is_object($dbh))
trigger_error('dbh is not a object', E_USER_ERROR);
if (!is_a($dbh, 'mysql_Connection'))
trigger_error('dbh is not a mysql_Connection object', E_USER_ERROR);
}
/**
* ¼ì²ésqlÊÇ·ñΪ¿Õ
* @param String $sql SQLÓï¾ä
* @return void
* @access private
*/
function checkNullOrEmptyQuery($sql=null) {
if (null === $sql)
$this->throws('sqlΪ¿Õ', null, EXCEPTION_DIE, null, __FILE__, __LINE__);
if ((int)0 == strlen(trim($sql)))
$this->throws('sql³¤¶ÈΪ0', null, EXCEPTION_DIE);
}
/**
* Êͷŵ±Ç°µÄÔ¤²éѯ
* @return void
* @access private
*/
function close() {
$this->realClose(true);
}
/**
* ¹Ø±Õµ±Ç°ËùÓлµÄResultSet¶ÔÏó
* @return void
* @access private
*/
function closeAllOpenResults() {
if (null !== $this->openResults) {
for ($i = 0; $i < $this->openResults->size(); $i++) {
$currentOpenResult = $this->openResults->get($i);
$ret = $currentOpenResult->realClose();
if (is_a($ret, 'EXCEPTION'))
$exp = $ret;
}
if (isset($exp))
$this->throws($exp->getMessage(), $exp->getCode(), $exp->getMode());
}
}
/**
* Ö´ÐÐSQLÓï¾ä
* @see com.shine.pdbc.mysql.mysql_PreparedStatement.executeQuery() OR
* com.shine.pdbc.mysql.mysql_PreparedStatement.executeUpdate()
* @return com.shine.pdbc.mysql.mysql_ResultSet;
* true³É¹¦£¬falseʧ°Ü;
*/
function execute($sql=null) {
$this->checkClosed();
$this->checkNullOrEmptyQuery($sql);
$firstNonWsChar = StringUtils::firstNonWsChar($this->original_sql);
$isSelect = true;
if ('S' != $firstNonWsChar) {
$isSelect = false;
if ($this->conn->isReadOnly())
return false;
#trigger_error('Connection is in readonly mode', E_USER_ERROR);
$this->executeUpdate();
}
return $this->executeQuery();
}
/*
* Ö´ÐÐÅúÁ¿²éѯ
* @return array<int> update counts
*/
function executeBatch() {
if (!is_array($this->sqlBatch) || (int)0 == sizeof($this->sqlBatch)) {
$errbuf = new StringBuffer('no sql in Batch');
$this->throws($errbuf->toString(), null, EXCEPTION_DIE, NULL, 'Exceptions', __FILE__, __LINE__);
}
$updateCounts = array();
foreach ($this->sqlBatch as $num => $sql) {
if ($sql) {
if (!$this->realExecuteSQL($sql)) {
$updateCounts[$num] = -1;
$this->resultBatch[$num] = false;
} else {
if (is_resource($this->result)) {
$this->resultBatch[$num] = $this->getResultSet();
} else {
$this->resultBatch[$num] = $this->result;
}
$updateCounts[$num] = $this->getUpdateCount();
}
}
}
#print_r($this->resultBatch);
return $updateCounts;
}
/**
* ³õʼ»¯Ô¤²éѯ°ó¶¨µÄ²ÎÊýÊý×é
*/
function initBindParams() {
if (!$this->bindParams)
$this->bindParams = array();
}
/**
* ·µ»Øµ±Ç°Á¬½ÓÊÇ·ñ¹Ø±ÕµÄ±êʶ
*/
function isClosed() {
return $this->isClosed;
}
/**
* °ó¶¨Ô¤²éѯµÄ²ÎÊý
* @param int $parameterIndex
* @param mixed $parameter
* @param string $baseType
* @return void
*/
function bindParam($parameterIndex, $parameter, $baseType) {
if (!is_int($parameterIndex))
trigger_error('parameterIndex('.$parameterIndex.') is not compitible with integer', E_USER_ERROR);
$is_fun = 'is_'.$baseType;
if (!$is_fun($parameter))
trigger_error('parameter('.$parameter.') is not compitible with '.$baseType, E_USER_ERROR);
$size = sizeof($this->bindParams);
#print '<br/>'.$size.' : '.$parameterIndex.' : '.$parameter.' : '.$baseType.'<br/>';
if ($parameterIndex != ($size + 1))
$this->throws('index('.$parameterIndex.') is invalidate', null, EXCEPTION_DIE);
$this->bindParams[--$parameterIndex] = $parameter;
return true;
}
function getBindParamCount($sql) {
$count = 0;
for ($i = 0; $i < strlen($sql); $i++) {
if ('?' == $sql[$i])
$count++;
}
return $count;
}
/**
* ÒÆ¶¯µ½µ±Ç°Statement¶ÔÏóµÄÏÂÒ»¸öResultSet¶ÔÏó
* @param integer
* @return boolean
*/
function getMoreResults($current=CLOSE_CURRENT_RESULT) {
switch ($current) {
case CLOSE_CURRENT_RESULT :
break;
case CLOSE_ALL_RESULTS :
break;
case KEEP_CURRENT_RESULT :
break;
}
foreach ($this->resultBatch as $num => $result) {
if (is_resource($result)) {
$this->current_result_offset = $i;
return true;
} else {
$this->current_result_offset = $i;
return false;
}
}
}
/**
* ½«ÔʼԤ²éѯSQLÓï¾ä½âÎöΪºÏ·¨µÄSQLÓï¾ä
* @param String $sql
*/
function prepareSql($sql) {
$this->bindParamCount = $this->getBindParamCount($sql);
$bindParams =& $this->bindParams;
if ($bindParams && ($this->bindParamCount > 0)) {
if (!is_array($bindParams)) {
$bindParams = array($bindParams);
}
$element0 = reset($bindParams);
# is_object check because oci8 descriptors can be passed in
$array_2d = is_array($element0) && !is_object(reset($element0));
if (!is_array($sql) && !$this->_bindInputArray) {
$sqlarr = explode('?', $sql);
if (!$array_2d) {
$bindParams = array($this->bindParams);
}
foreach ($bindParams as $arr) {
$sql = '';
$i = 0;
foreach ($arr as $v) {
$sql .= $sqlarr[$i];
if (gettype($v) == 'string') {
$sql .= $this->qstr($v);
} else if ($v === null) {
//$sql .= 'null';
$sql .= '""';
} else {
$sql .= $v;
}
$i += 1;
}
$sql .= $sqlarr[$i];
if ($i+1 != sizeof($sqlarr)) {
$errbuf = new StringBuffer();
$errbuf->append("mysql_PreparedStatement->prepareSql(): ¸ø¶¨µÄ²ÎÊýÊýÁ¿Óë'?'µÄÊýÁ¿²»ÏàÆ¥Åä");
$errbuf->appendEnter();
$errbuf->append($sql);
$this->throws($errbuf->toString(), null, EXCEPTION_DIE);
}
#print '1:'.$sql;
return $sql;
}
} else {
if ($array_2d) {
foreach ($bindParams as $arr) {
#print '2:'.$sql;
return $sql;
}
} else {
#print '3:'.$sql;
return $sql;
}
}
} else {
#print '4:'.$sql;
return $sql;
}
}
/**
* ת»»SQLÓï¾äÖеÄÌØÊâ×Ö·û
* @param String $str
* @param boolean $magic_quotes
*/
function qstr($str, $magic_quotes=false) {
if (!$magic_quotes) {
if ($this->replaceQuote[0] == '\\'){
$str = str_replace("\0","\\\0", str_replace('\\', '\\\\', $str));
}
return "'".str_replace("'", "\\'", $str)."'";
}
$str = str_replace('\\"', '"', $str);
if ($this->replaceQuote == "\\'") {
return "'$str'";
} else {
// change \' to '' for sybase/mssql
$str = str_replace('\\\\', '\\', $str);
return "'".str_replace("\\'", "\\'", $str)."'";
}
}
/**
* Ö´ÐÐSELECT²éѯ
* @return mysql_ResultSet
*/
function executeQuery() {
$this->realExecuteSQL();
return $this->getResultSet();
}
/**
* Ö´ÐÐINPUT, UPDATE, DELETEµÈSQLÓï¾ä
* @return boolean true/false
*/
function executeUpdate() {
return $this->realExecuteSQL();
}
/**
* »ñÈ¡Êý¾Ý¿âÁ¬½Ó¾ä±ú(mysql)
* @return Object mysql
*/
function getConnection() {
return $this->conn;
}
/**
* Document me
*/
function getFetchSize() {
//not implement yet
}
/**
* »ñÈ¡²éѯ³¬Ê±Ê±¼ä
* @return int queryTimeout
*/
function getQueryTimeout() {
return $this->queryTimeout;
}
/**
* »ñÈ¡±¾´Î»á»°µÄ²éѯ½á¹û¼¯
*/
function getResultSet() {
return new mysql_ResultSet($this->result);
}
/**
* Document me
*/
function getUpdateCount() {
if (!$this->isSelect && is_bool($this->result))
return mysql_affected_rows($this->conn->getConnection());
return -1;
}
/**
* Document me
*/
function getWarnings() {
//not implement yet
}
/**
* ¹Ø±ÕÊý¾Ý¿âÁ¬½Ó
*/
function realClose($calledExplicitly=false) {
if ($this->isClosed)
return;
$this->closeAllOpenResults();
$this->openResults = null;
$this->result = null;
$this->bindParams = array();
$this->bindParamCount = 0;
$this->conn->closePrepareStatement();
$this->isClosed = true;
}
/**
* Ö´ÐлỰÆÚ¼äÄڵIJéѯ
* @return Object mysql_ResultSet
* @return boolean true/false
*/
function realExecuteSQL() {
$this->checkClosed();
$firstNonWsChar = StringUtils::firstNonWsChar($this->original_sql);
if ('S' != $firstNonWsChar) {
$this->isSelect = false;
if ($this->conn->isReadOnly())
return false;
#trigger_error('Connection is in readonly mode', E_USER_ERROR);
}
$this->prepared_sql = $this->prepareSql($this->original_sql);
if ($GLOBALS['debug'] && (int)4 >= $GLOBALS['debug'])
$this->debug('prepared_sql: '.$this->prepared_sql);
$this->result = mysql_query($this->prepared_sql);
if ($GLOBALS['debug'] && (int)3 >= $GLOBALS['debug'])
$this->debug(var_dump($this->result));
if ($this->result) {
return true;
} else {
$errbuf = new StringBuffer();
$errbuf->append('#ErrorNo '.mysql_errno($this->conn->getConnection()).': ');
$errbuf->append(mysql_error($this->conn->getConnection()));
trigger_error($errbuf->toString(), E_USER_ERROR);
}
return false;
}
/**
* Document me
*/
function setFetchSize($rows) {
//not implement yes
}
/**
* ÉèÖÃÔ¤²éѯÀàÐÍΪIntegerµÄ°ó¶¨²ÎÊý
*/
function setInt($parameterIndex, $int) {
$ret = $this->bindParam($parameterIndex, $int, 'integer');
if (!$ret)
trigger_error('mysql_PreparedStatement->setInt(): bind param error', E_USER_ERROR);
}
/**
* Document me
*/
function setFloat($parameterIndex, $float) {
//not implement yes
}
/**
* Document me
*/
function setDate($parameterIndex, $date) {
//not implement yes
}
/**
* Document me
*/
function setDouble($parameterIndex, $double) {
//not implement yes
}
/**
* Document me
*/
function setNull($parameterIndex, $null) {
//not implement yes
}
/**
* Document me
*/
function setObject($parameterIndex, $object) {
//not implement yes
}
/**
* ÉèÖÃÔ¤²éѯÀàÐÍΪStringµÄ°ó¶¨²ÎÊý
*/
function setString($parameterIndex, $string) {
$ret = $this->bindParam($parameterIndex, $string, 'string');
if (!$ret)
trigger_error('mysql_PreparedStatement->setString(): bind param error', E_USER_ERROR);
}
/**
* Document me
*/
function setTime($parameterIndex, $time) {
//not implement yes
}
/**
* ÉèÖòéѯ³¬Ê±Ê±³¤
*/
function setQueryTimeout($timeout) {
$timeout = StringUtils::isNumeric($timeout);
if ($timeout) {
$this->queryTimeout = $timeout;
ini_set('mysql.connect_timeout', $timeout);
} else {
$this->queryTimeout = 60;
}
}
/**
* Document me
*/
function setOriginalSQL($sql) {
$this->original_sql = $sql;
}
}
?>