Location: PHPKode > scripts > pdbc > pdbc/PreparedStatement.class.php
<?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;
		}
	}
?>
Return current item: pdbc