forked from Samuel-BF/atk
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathCompatStatement.php
162 lines (137 loc) · 5.13 KB
/
CompatStatement.php
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
<?php
namespace Sintattica\Atk\Db\Statement;
use Sintattica\Atk\Core\Tools;
use Sintattica\Atk\Db\Db;
/**
* Base statement class used for database drivers which don't have their own
* implementation.
*
* Bind parameters are replaced by their value before executing the query
* using the database driver. This means you can still use bind parameters but
* you don't have the performance benefits or real prepared statement.
*
* @author Peter C. Verhage <[email protected]>
*/
class CompatStatement extends Statement
{
/**
* Query resource.
*
* @var mixed
*/
private $m_resource;
/**
* Prepares the statement for execution.
*/
protected function _prepare()
{
if ($this->getDb()->connect() != Db::DB_SUCCESS) {
throw new StatementException('Cannot connect to database.', StatementException::NO_DATABASE_CONNECTION);
}
Tools::atkdebug('Prepare query: '.$this->_getParsedQuery());
}
/**
* Replace the bind parameters in the parsed query with their escaped values.
*
* @param array $params parameters
*
* @return string query
*/
protected function _bindParams($params)
{
$query = $this->_getParsedQuery();
Tools::atkdebug('Binding parameters for query: '.$this->_getParsedQuery());
foreach (array_values($this->_getBindPositions()) as $i => $param) {
Tools::atkdebug("Bind param {$i}: ".($params[$param] === null ? 'NULL' : $params[$param]));
}
foreach (array_reverse($this->_getBindPositions(), true) as $position => $param) {
$query = substr($query, 0, $position).($params[$param] === null ? 'NULL' : "'".$this->getDb()->escapeSQL($params[$param])."'").substr($query,
$position + 1);
}
return $query;
}
/**
* Executes the statement using the given bind parameters.
*
* @param array $params bind parameters
*
* @throws StatementException
*/
protected function _execute($params)
{
// replace the bind parameters with their values
$query = $this->_bindParams($params);
// store the current query resource
$oldId = $this->getDb()->getQueryId();
$oldHaltOnError = $this->getDb()->getHaltOnError();
// execute the query using the driver
$this->getDb()->setHaltOnError(false);
$result = $this->getDb()->query($query);
// retrieve and reset the query resource so we can use it later on and
// the database driver won't free/close it unless we want it
$this->m_resource = $this->getDb()->getQueryId();
$this->getDb()->resetQueryId();
// restore the old query resource
$this->getDb()->setQueryId($oldId);
$this->getDb()->setHaltOnError($oldHaltOnError);
if (!$result) {
$this->m_resource = null;
throw new StatementException('Cannot execute statement: '.$query, StatementException::STATEMENT_ERROR);
}
}
/**
* Fetches the next row from the result set.
*
* @return array|false next row from the result set (false if no other rows exist)
*/
protected function _fetch()
{
// store the current query resource
$oldId = $this->getDb()->getQueryId();
// set our own query resource in the database driver so we can use
// the Db::next_record() method and retrieve the new record
$this->getDb()->setQueryId($this->m_resource);
$this->getDb()->next_record();
$row = $this->getDb()->m_record;
// restore the old query resource
$this->getDb()->setQueryId($oldId);
return $row;
}
/**
* Resets the statement so that it can be re-used again.
*/
protected function _reset()
{
$this->m_resource = null;
}
/**
* Frees up all resources for this statement. The statement cannot be
* re-used anymore.
*/
public function _close()
{
// There is no proper way to do this which is compatible with all drivers
// because there is no Db::free() method. We could retrieve all rows,
// which automatically closes the current resource, but that's not very
// efficient. We can also execute a dummy query but the same query should
// work for all drivers... So instead we simply leak a resource which is
// cleaned at the end of the execution of this PHP script.
$this->m_resource = null;
}
/**
* Returns the number of affected rows in case of an INSERT, UPDATE
* or DELETE query. Called immediately after Statement::_execute().
*/
protected function _getAffectedRowCount()
{
// store the current query resource
$oldId = $this->getDb()->getQueryId();
// set our own query resource in the database driver so we can use
// the Db::affected_rows() method and retrieve the affected row count
$this->getDb()->setQueryId($this->m_resource);
$result = $this->getDb()->affected_rows();
// restore the old query resource
$this->getDb()->setQueryId($oldId);
return $result;
}
}