|
|
|
|
@ -91,7 +91,7 @@ class MDB2_Driver_sqlite3 extends MDB2_Driver_Common
|
|
|
|
|
$this->supported['auto_increment'] = true;
|
|
|
|
|
$this->supported['primary_key'] = false; // requires alter table implementation
|
|
|
|
|
$this->supported['result_introspection'] = false; // not implemented
|
|
|
|
|
$this->supported['prepared_statements'] = 'emulated';
|
|
|
|
|
$this->supported['prepared_statements'] = true;
|
|
|
|
|
$this->supported['identifier_quoting'] = true;
|
|
|
|
|
$this->supported['pattern_escaping'] = false;
|
|
|
|
|
$this->supported['new_link'] = false;
|
|
|
|
|
@ -511,7 +511,6 @@ class MDB2_Driver_sqlite3 extends MDB2_Driver_Common
|
|
|
|
|
$result = $is_manip ? 0 : null;
|
|
|
|
|
return $result;
|
|
|
|
|
}
|
|
|
|
|
// print_r(debug_backtrace());
|
|
|
|
|
$result=$this->connection->query($query.';');
|
|
|
|
|
$this->_lasterror = $this->connection->lastErrorMsg();
|
|
|
|
|
|
|
|
|
|
@ -814,6 +813,118 @@ class MDB2_Driver_sqlite3 extends MDB2_Driver_Common
|
|
|
|
|
$query = "SELECT MAX($seqcol_name) FROM $sequence_name";
|
|
|
|
|
return $this->queryOne($query, 'integer');
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Prepares a query for multiple execution with execute().
|
|
|
|
|
* With some database backends, this is emulated.
|
|
|
|
|
* prepare() requires a generic query as string like
|
|
|
|
|
* 'INSERT INTO numbers VALUES(?,?)' or
|
|
|
|
|
* 'INSERT INTO numbers VALUES(:foo,:bar)'.
|
|
|
|
|
* The ? and :name and are placeholders which can be set using
|
|
|
|
|
* bindParam() and the query can be sent off using the execute() method.
|
|
|
|
|
* The allowed format for :name can be set with the 'bindname_format' option.
|
|
|
|
|
*
|
|
|
|
|
* @param string $query the query to prepare
|
|
|
|
|
* @param mixed $types array that contains the types of the placeholders
|
|
|
|
|
* @param mixed $result_types array that contains the types of the columns in
|
|
|
|
|
* the result set or MDB2_PREPARE_RESULT, if set to
|
|
|
|
|
* MDB2_PREPARE_MANIP the query is handled as a manipulation query
|
|
|
|
|
* @param mixed $lobs key (field) value (parameter) pair for all lob placeholders
|
|
|
|
|
* @return mixed resource handle for the prepared query on success, a MDB2
|
|
|
|
|
* error on failure
|
|
|
|
|
* @access public
|
|
|
|
|
* @see bindParam, execute
|
|
|
|
|
*/
|
|
|
|
|
function &prepare($query, $types = null, $result_types = null, $lobs = array())
|
|
|
|
|
{
|
|
|
|
|
if ($this->options['emulate_prepared']
|
|
|
|
|
|| $this->supported['prepared_statements'] !== true
|
|
|
|
|
) {
|
|
|
|
|
$obj =& parent::prepare($query, $types, $result_types, $lobs);
|
|
|
|
|
return $obj;
|
|
|
|
|
}
|
|
|
|
|
$this->last_query = $query;
|
|
|
|
|
$is_manip = ($result_types === MDB2_PREPARE_MANIP);
|
|
|
|
|
$offset = $this->offset;
|
|
|
|
|
$limit = $this->limit;
|
|
|
|
|
$this->offset = $this->limit = 0;
|
|
|
|
|
$query = $this->_modifyQuery($query, $is_manip, $limit, $offset);
|
|
|
|
|
$result = $this->debug($query, __FUNCTION__, array('is_manip' => $is_manip, 'when' => 'pre'));
|
|
|
|
|
if ($result) {
|
|
|
|
|
if (PEAR::isError($result)) {
|
|
|
|
|
return $result;
|
|
|
|
|
}
|
|
|
|
|
$query = $result;
|
|
|
|
|
}
|
|
|
|
|
$placeholder_type_guess = $placeholder_type = null;
|
|
|
|
|
$question = '?';
|
|
|
|
|
$colon = ':';
|
|
|
|
|
$positions = array();
|
|
|
|
|
$position = 0;
|
|
|
|
|
while ($position < strlen($query)) {
|
|
|
|
|
$q_position = strpos($query, $question, $position);
|
|
|
|
|
$c_position = strpos($query, $colon, $position);
|
|
|
|
|
if ($q_position && $c_position) {
|
|
|
|
|
$p_position = min($q_position, $c_position);
|
|
|
|
|
} elseif ($q_position) {
|
|
|
|
|
$p_position = $q_position;
|
|
|
|
|
} elseif ($c_position) {
|
|
|
|
|
$p_position = $c_position;
|
|
|
|
|
} else {
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
if (is_null($placeholder_type)) {
|
|
|
|
|
$placeholder_type_guess = $query[$p_position];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$new_pos = $this->_skipDelimitedStrings($query, $position, $p_position);
|
|
|
|
|
if (PEAR::isError($new_pos)) {
|
|
|
|
|
return $new_pos;
|
|
|
|
|
}
|
|
|
|
|
if ($new_pos != $position) {
|
|
|
|
|
$position = $new_pos;
|
|
|
|
|
continue; //evaluate again starting from the new position
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if ($query[$position] == $placeholder_type_guess) {
|
|
|
|
|
if (is_null($placeholder_type)) {
|
|
|
|
|
$placeholder_type = $query[$p_position];
|
|
|
|
|
$question = $colon = $placeholder_type;
|
|
|
|
|
}
|
|
|
|
|
if ($placeholder_type == ':') {
|
|
|
|
|
$regexp = '/^.{'.($position+1).'}('.$this->options['bindname_format'].').*$/s';
|
|
|
|
|
$parameter = preg_replace($regexp, '\\1', $query);
|
|
|
|
|
if ($parameter === '') {
|
|
|
|
|
$err =& $this->raiseError(MDB2_ERROR_SYNTAX, null, null,
|
|
|
|
|
'named parameter name must match "bindname_format" option', __FUNCTION__);
|
|
|
|
|
return $err;
|
|
|
|
|
}
|
|
|
|
|
$positions[$p_position] = $parameter;
|
|
|
|
|
$query = substr_replace($query, '?', $position, strlen($parameter)+1);
|
|
|
|
|
} else {
|
|
|
|
|
$positions[$p_position] = count($positions);
|
|
|
|
|
}
|
|
|
|
|
$position = $p_position + 1;
|
|
|
|
|
} else {
|
|
|
|
|
$position = $p_position;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
$connection = $this->getConnection();
|
|
|
|
|
if (PEAR::isError($connection)) {
|
|
|
|
|
return $connection;
|
|
|
|
|
}
|
|
|
|
|
$statement =$this->connection->prepare($query);
|
|
|
|
|
if (!$statement) {
|
|
|
|
|
return $this->db->raiseError(MDB2_ERROR_NOT_FOUND, null, null,
|
|
|
|
|
'unable to prepare statement: '.$query);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$class_name = 'MDB2_Statement_'.$this->phptype;
|
|
|
|
|
$obj = new $class_name($this, $statement, $positions, $query, $types, $result_types, $is_manip, $limit, $offset);
|
|
|
|
|
$this->debug($query, __FUNCTION__, array('is_manip' => $is_manip, 'when' => 'post', 'result' => $obj));
|
|
|
|
|
return $obj;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
@ -1018,7 +1129,223 @@ class MDB2_BufferedResult_sqlite3 extends MDB2_Result_sqlite3
|
|
|
|
|
*/
|
|
|
|
|
class MDB2_Statement_sqlite3 extends MDB2_Statement_Common
|
|
|
|
|
{
|
|
|
|
|
// }}}
|
|
|
|
|
// {{{ function bindValue($parameter, &$value, $type = null)
|
|
|
|
|
|
|
|
|
|
private function getParamType($type){
|
|
|
|
|
switch(strtolower($type)){
|
|
|
|
|
case 'text':
|
|
|
|
|
return SQLITE3_TEXT;
|
|
|
|
|
case 'boolean':
|
|
|
|
|
case 'integer':
|
|
|
|
|
return SQLITE3_INTEGER;
|
|
|
|
|
case 'float':
|
|
|
|
|
return SQLITE3_FLOAT;
|
|
|
|
|
case 'blob':
|
|
|
|
|
return SQLITE3_BLOB;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
/**
|
|
|
|
|
* Set the value of a parameter of a prepared query.
|
|
|
|
|
*
|
|
|
|
|
* @param int the order number of the parameter in the query
|
|
|
|
|
* statement. The order number of the first parameter is 1.
|
|
|
|
|
* @param mixed value that is meant to be assigned to specified
|
|
|
|
|
* parameter. The type of the value depends on the $type argument.
|
|
|
|
|
* @param string specifies the type of the field
|
|
|
|
|
*
|
|
|
|
|
* @return mixed MDB2_OK on success, a MDB2 error on failure
|
|
|
|
|
*
|
|
|
|
|
* @access public
|
|
|
|
|
*/
|
|
|
|
|
function bindValue($parameter, $value, $type = null){
|
|
|
|
|
if($type){
|
|
|
|
|
$type=$this->getParamType($type);
|
|
|
|
|
$this->statement->bindValue($parameter,$value,$type);
|
|
|
|
|
}else{
|
|
|
|
|
$this->statement->bindValue($parameter,$value);
|
|
|
|
|
}
|
|
|
|
|
return MDB2_OK;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Bind a variable to a parameter of a prepared query.
|
|
|
|
|
*
|
|
|
|
|
* @param int the order number of the parameter in the query
|
|
|
|
|
* statement. The order number of the first parameter is 1.
|
|
|
|
|
* @param mixed variable that is meant to be bound to specified
|
|
|
|
|
* parameter. The type of the value depends on the $type argument.
|
|
|
|
|
* @param string specifies the type of the field
|
|
|
|
|
*
|
|
|
|
|
* @return mixed MDB2_OK on success, a MDB2 error on failure
|
|
|
|
|
*
|
|
|
|
|
* @access public
|
|
|
|
|
*/
|
|
|
|
|
function bindParam($parameter, &$value, $type = null){
|
|
|
|
|
if($type){
|
|
|
|
|
$type=$this->getParamType($type);
|
|
|
|
|
$this->statement->bindParam($parameter,$value,$type);
|
|
|
|
|
}else{
|
|
|
|
|
$this->statement->bindParam($parameter,$value);
|
|
|
|
|
}
|
|
|
|
|
return MDB2_OK;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Release resources allocated for the specified prepared query.
|
|
|
|
|
*
|
|
|
|
|
* @return mixed MDB2_OK on success, a MDB2 error on failure
|
|
|
|
|
* @access public
|
|
|
|
|
*/
|
|
|
|
|
function free()
|
|
|
|
|
{
|
|
|
|
|
$this->statement->close();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Execute a prepared query statement helper method.
|
|
|
|
|
*
|
|
|
|
|
* @param mixed $result_class string which specifies which result class to use
|
|
|
|
|
* @param mixed $result_wrap_class string which specifies which class to wrap results in
|
|
|
|
|
*
|
|
|
|
|
* @return mixed MDB2_Result or integer (affected rows) on success,
|
|
|
|
|
* a MDB2 error on failure
|
|
|
|
|
* @access private
|
|
|
|
|
*/
|
|
|
|
|
function &_execute($result_class = true, $result_wrap_class = false){
|
|
|
|
|
if (is_null($this->statement)) {
|
|
|
|
|
$result =& parent::_execute($result_class, $result_wrap_class);
|
|
|
|
|
return $result;
|
|
|
|
|
}
|
|
|
|
|
$this->db->last_query = $this->query;
|
|
|
|
|
$this->db->debug($this->query, 'execute', array('is_manip' => $this->is_manip, 'when' => 'pre', 'parameters' => $this->values));
|
|
|
|
|
if ($this->db->getOption('disable_query')) {
|
|
|
|
|
$result = $this->is_manip ? 0 : null;
|
|
|
|
|
return $result;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$connection = $this->db->getConnection();
|
|
|
|
|
if (PEAR::isError($connection)) {
|
|
|
|
|
return $connection;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$result = $this->statement->execute();
|
|
|
|
|
if ($result==false) {
|
|
|
|
|
$err =$this->db->raiseError(MDB2_ERROR_NEED_MORE_DATA, null, null,
|
|
|
|
|
'cant execute statement', __FUNCTION__);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if ($this->is_manip) {
|
|
|
|
|
$affected_rows = $this->db->_affectedRows($connection, $result);
|
|
|
|
|
return $affected_rows;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$result =& $this->db->_wrapResult($result, $this->result_types,
|
|
|
|
|
$result_class, $result_wrap_class, $this->limit, $this->offset);
|
|
|
|
|
$this->db->debug($this->query, 'execute', array('is_manip' => $this->is_manip, 'when' => 'post', 'result' => $result));
|
|
|
|
|
return $result;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Set the values of multiple a parameter of a prepared query in bulk.
|
|
|
|
|
*
|
|
|
|
|
* @param array specifies all necessary information
|
|
|
|
|
* for bindValue() the array elements must use keys corresponding to
|
|
|
|
|
* the number of the position of the parameter.
|
|
|
|
|
* @param array specifies the types of the fields
|
|
|
|
|
*
|
|
|
|
|
* @return mixed MDB2_OK on success, a MDB2 error on failure
|
|
|
|
|
*
|
|
|
|
|
* @access public
|
|
|
|
|
* @see bindParam()
|
|
|
|
|
*/
|
|
|
|
|
function bindValueArray($values, $types = null)
|
|
|
|
|
{
|
|
|
|
|
$types = is_array($types) ? array_values($types) : array_fill(0, count($values), null);
|
|
|
|
|
$parameters = array_keys($values);
|
|
|
|
|
foreach ($parameters as $key => $parameter) {
|
|
|
|
|
$this->db->pushErrorHandling(PEAR_ERROR_RETURN);
|
|
|
|
|
$this->db->expectError(MDB2_ERROR_NOT_FOUND);
|
|
|
|
|
$err = $this->bindValue($parameter+1, $values[$parameter], $types[$key]);
|
|
|
|
|
$this->db->popExpect();
|
|
|
|
|
$this->db->popErrorHandling();
|
|
|
|
|
if (PEAR::isError($err)) {
|
|
|
|
|
if ($err->getCode() == MDB2_ERROR_NOT_FOUND) {
|
|
|
|
|
//ignore (extra value for missing placeholder)
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
return $err;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return MDB2_OK;
|
|
|
|
|
}
|
|
|
|
|
// }}}
|
|
|
|
|
// {{{ function bindParamArray(&$values, $types = null)
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Bind the variables of multiple a parameter of a prepared query in bulk.
|
|
|
|
|
*
|
|
|
|
|
* @param array specifies all necessary information
|
|
|
|
|
* for bindParam() the array elements must use keys corresponding to
|
|
|
|
|
* the number of the position of the parameter.
|
|
|
|
|
* @param array specifies the types of the fields
|
|
|
|
|
*
|
|
|
|
|
* @return mixed MDB2_OK on success, a MDB2 error on failure
|
|
|
|
|
*
|
|
|
|
|
* @access public
|
|
|
|
|
* @see bindParam()
|
|
|
|
|
*/
|
|
|
|
|
function bindParamArray(&$values, $types = null)
|
|
|
|
|
{
|
|
|
|
|
$types = is_array($types) ? array_values($types) : array_fill(0, count($values), null);
|
|
|
|
|
$parameters = array_keys($values);
|
|
|
|
|
foreach ($parameters as $key => $parameter) {
|
|
|
|
|
$err = $this->bindParam($parameter+1, $values[$parameter], $types[$key]);
|
|
|
|
|
if (PEAR::isError($err)) {
|
|
|
|
|
return $err;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return MDB2_OK;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// }}}
|
|
|
|
|
// {{{ function &execute($values = null, $result_class = true, $result_wrap_class = false)
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Execute a prepared query statement.
|
|
|
|
|
*
|
|
|
|
|
* @param array specifies all necessary information
|
|
|
|
|
* for bindParam() the array elements must use keys corresponding
|
|
|
|
|
* to the number of the position of the parameter.
|
|
|
|
|
* @param mixed specifies which result class to use
|
|
|
|
|
* @param mixed specifies which class to wrap results in
|
|
|
|
|
*
|
|
|
|
|
* @return mixed MDB2_Result or integer (affected rows) on success,
|
|
|
|
|
* a MDB2 error on failure
|
|
|
|
|
* @access public
|
|
|
|
|
*/
|
|
|
|
|
function &execute($values = null, $result_class = true, $result_wrap_class = false)
|
|
|
|
|
{
|
|
|
|
|
if (is_null($this->positions)) {
|
|
|
|
|
return $this->db->raiseError(MDB2_ERROR, null, null,
|
|
|
|
|
'Prepared statement has already been freed', __FUNCTION__);
|
|
|
|
|
}
|
|
|
|
|
$values = (array)$values;
|
|
|
|
|
if (!empty($values)) {
|
|
|
|
|
if(count($this->types)){
|
|
|
|
|
$types=$this->types;
|
|
|
|
|
}else{
|
|
|
|
|
$types=null;
|
|
|
|
|
}
|
|
|
|
|
$err = $this->bindValueArray($values,$types);
|
|
|
|
|
if (PEAR::isError($err)) {
|
|
|
|
|
return $this->db->raiseError(MDB2_ERROR, null, null,
|
|
|
|
|
'Binding Values failed with message: ' . $err->getMessage(), __FUNCTION__);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
$result =$this->_execute($result_class, $result_wrap_class);
|
|
|
|
|
return $result;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
?>
|