source: pro-violet-viettel/sourcecode/application/libraries/Doctrine/DBAL/Driver/OCI8/OCI8Statement.php @ 347

Last change on this file since 347 was 345, checked in by quyenla, 11 years ago

collaborator page

File size: 7.9 KB
Line 
1<?php
2/*
3 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
4 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
5 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
6 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
7 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
8 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
9 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
10 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
11 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
12 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
13 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
14 *
15 * This software consists of voluntary contributions made by many individuals
16 * and is licensed under the LGPL. For more information, see
17 * <http://www.doctrine-project.org>.
18 */
19
20namespace Doctrine\DBAL\Driver\OCI8;
21
22use PDO;
23use IteratorAggregate;
24use Doctrine\DBAL\Driver\Statement;
25
26/**
27 * The OCI8 implementation of the Statement interface.
28 *
29 * @since 2.0
30 * @author Roman Borschel <roman@code-factory.org>
31 */
32class OCI8Statement implements \IteratorAggregate, Statement
33{
34    /** Statement handle. */
35    protected $_dbh;
36    protected $_sth;
37    protected $_executeMode;
38    protected static $_PARAM = ':param';
39    protected static $fetchStyleMap = array(
40        PDO::FETCH_BOTH => OCI_BOTH,
41        PDO::FETCH_ASSOC => OCI_ASSOC,
42        PDO::FETCH_NUM => OCI_NUM,
43        PDO::PARAM_LOB => OCI_B_BLOB,
44    );
45    protected $_defaultFetchStyle = PDO::FETCH_BOTH;
46    protected $_paramMap = array();
47
48    /**
49     * Creates a new OCI8Statement that uses the given connection handle and SQL statement.
50     *
51     * @param resource $dbh The connection handle.
52     * @param string $statement The SQL statement.
53     */
54    public function __construct($dbh, $statement, $executeMode)
55    {
56        list($statement, $paramMap) = self::convertPositionalToNamedPlaceholders($statement);
57        $this->_sth = oci_parse($dbh, $statement);
58        $this->_dbh = $dbh;
59        $this->_paramMap = $paramMap;
60        $this->_executeMode = $executeMode;
61    }
62
63    /**
64     * Convert positional (?) into named placeholders (:param<num>)
65     *
66     * Oracle does not support positional parameters, hence this method converts all
67     * positional parameters into artificially named parameters. Note that this conversion
68     * is not perfect. All question marks (?) in the original statement are treated as
69     * placeholders and converted to a named parameter.
70     *
71     * The algorithm uses a state machine with two possible states: InLiteral and NotInLiteral.
72     * Question marks inside literal strings are therefore handled correctly by this method.
73     * This comes at a cost, the whole sql statement has to be looped over.
74     *
75     * @todo extract into utility class in Doctrine\DBAL\Util namespace
76     * @todo review and test for lost spaces. we experienced missing spaces with oci8 in some sql statements.
77     * @param string $statement The SQL statement to convert.
78     * @return string
79     */
80    static public function convertPositionalToNamedPlaceholders($statement)
81    {
82        $count = 1;
83        $inLiteral = false; // a valid query never starts with quotes
84        $stmtLen = strlen($statement);
85        $paramMap = array();
86        for ($i = 0; $i < $stmtLen; $i++) {
87            if ($statement[$i] == '?' && !$inLiteral) {
88                // real positional parameter detected
89                $paramMap[$count] = ":param$count";
90                $len = strlen($paramMap[$count]);
91                $statement = substr_replace($statement, ":param$count", $i, 1);
92                $i += $len-1; // jump ahead
93                $stmtLen = strlen($statement); // adjust statement length
94                ++$count;
95            } else if ($statement[$i] == "'" || $statement[$i] == '"') {
96                $inLiteral = ! $inLiteral; // switch state!
97            }
98        }
99
100        return array($statement, $paramMap);
101    }
102
103    /**
104     * {@inheritdoc}
105     */
106    public function bindValue($param, $value, $type = null)
107    {
108        return $this->bindParam($param, $value, $type);
109    }
110
111    /**
112     * {@inheritdoc}
113     */
114    public function bindParam($column, &$variable, $type = null)
115    {
116        $column = isset($this->_paramMap[$column]) ? $this->_paramMap[$column] : $column;
117
118        if ($type == \PDO::PARAM_LOB) {
119            $lob = oci_new_descriptor($this->_dbh, OCI_D_LOB);
120            $lob->writeTemporary($variable, OCI_TEMP_BLOB);
121
122            return oci_bind_by_name($this->_sth, $column, $lob, -1, OCI_B_BLOB);
123        } else {
124            return oci_bind_by_name($this->_sth, $column, $variable);
125        }
126    }
127
128    /**
129     * Closes the cursor, enabling the statement to be executed again.
130     *
131     * @return boolean              Returns TRUE on success or FALSE on failure.
132     */
133    public function closeCursor()
134    {
135        return oci_free_statement($this->_sth);
136    }
137
138    /**
139     * {@inheritdoc}
140     */
141    public function columnCount()
142    {
143        return oci_num_fields($this->_sth);
144    }
145
146    /**
147     * {@inheritdoc}
148     */
149    public function errorCode()
150    {
151        $error = oci_error($this->_sth);
152        if ($error !== false) {
153            $error = $error['code'];
154        }
155        return $error;
156    }
157
158    /**
159     * {@inheritdoc}
160     */
161    public function errorInfo()
162    {
163        return oci_error($this->_sth);
164    }
165
166    /**
167     * {@inheritdoc}
168     */
169    public function execute($params = null)
170    {
171        if ($params) {
172            $hasZeroIndex = array_key_exists(0, $params);
173            foreach ($params as $key => $val) {
174                if ($hasZeroIndex && is_numeric($key)) {
175                    $this->bindValue($key + 1, $val);
176                } else {
177                    $this->bindValue($key, $val);
178                }
179            }
180        }
181
182        $ret = @oci_execute($this->_sth, $this->_executeMode);
183        if ( ! $ret) {
184            throw OCI8Exception::fromErrorInfo($this->errorInfo());
185        }
186        return $ret;
187    }
188
189    /**
190     * {@inheritdoc}
191     */
192    public function setFetchMode($fetchStyle = PDO::FETCH_BOTH)
193    {
194        $this->_defaultFetchStyle = $fetchStyle;
195    }
196
197    /**
198     * {@inheritdoc}
199     */
200    public function getIterator()
201    {
202        $data = $this->fetchAll($this->_defaultFetchStyle);
203        return new \ArrayIterator($data);
204    }
205
206    /**
207     * {@inheritdoc}
208     */
209    public function fetch($fetchStyle = null)
210    {
211        $fetchStyle = $fetchStyle ?: $this->_defaultFetchStyle;
212        if ( ! isset(self::$fetchStyleMap[$fetchStyle])) {
213            throw new \InvalidArgumentException("Invalid fetch style: " . $fetchStyle);
214        }
215
216        return oci_fetch_array($this->_sth, self::$fetchStyleMap[$fetchStyle] | OCI_RETURN_NULLS | OCI_RETURN_LOBS);
217    }
218
219    /**
220     * {@inheritdoc}
221     */
222    public function fetchAll($fetchStyle = null)
223    {
224        $fetchStyle = $fetchStyle ?: $this->_defaultFetchStyle;
225        if ( ! isset(self::$fetchStyleMap[$fetchStyle])) {
226            throw new \InvalidArgumentException("Invalid fetch style: " . $fetchStyle);
227        }
228
229        $result = array();
230        if (self::$fetchStyleMap[$fetchStyle] === OCI_BOTH) {
231            while ($row = $this->fetch($fetchStyle)) {
232                $result[] = $row;
233            }
234        } else {
235            oci_fetch_all($this->_sth, $result, 0, -1,
236                self::$fetchStyleMap[$fetchStyle] | OCI_RETURN_NULLS | OCI_FETCHSTATEMENT_BY_ROW | OCI_RETURN_LOBS);
237        }
238
239        return $result;
240    }
241
242    /**
243     * {@inheritdoc}
244     */
245    public function fetchColumn($columnIndex = 0)
246    {
247        $row = oci_fetch_array($this->_sth, OCI_NUM | OCI_RETURN_NULLS | OCI_RETURN_LOBS);
248        return $row[$columnIndex];
249    }
250
251    /**
252     * {@inheritdoc}
253     */
254    public function rowCount()
255    {
256        return oci_num_rows($this->_sth);
257    }
258}
Note: See TracBrowser for help on using the repository browser.