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
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
<?php
/*
* $Id: Mock.php 1080 2007-02-10 18:17:08Z romanb $
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* This software consists of voluntary contributions made by many individuals
* and is licensed under the LGPL. For more information, see
* <http://www.phpdoctrine.com>.
*/
Doctrine::autoload('Doctrine_Adapter');
/**
* Doctrine_Adapter_Db2
* IBM DB2 Adapter [BORROWED FROM ZEND FRAMEWORK]
*
* @package Doctrine
* @subpackage Doctrine_Adapter
* @author Konsta Vesterinen <kvesteri@cc.hut.fi>
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
* @category Object Relational Mapping
* @link www.phpdoctrine.com
* @since 1.0
* @version $Revision: 1080 $
*/
class Doctrine_Adapter_Db2 extends Doctrine_Adapter
{
/**
* User-provided configuration.
*
* Basic keys are:
*
* username => (string) Connect to the database as this username.
* password => (string) Password associated with the username.
* host => (string) What host to connect to (default 127.0.0.1)
* dbname => (string) The name of the database to user
* protocol => (string) Protocol to use, defaults to "TCPIP"
* port => (integer) Port number to use for TCP/IP if protocol is "TCPIP"
* persistent => (boolean) Set TRUE to use a persistent connection (db2_pconnect)
*
* @var array
*/
protected $_config = array(
'dbname' => null,
'username' => null,
'password' => null,
'host' => 'localhost',
'port' => '50000',
'protocol' => 'TCPIP',
'persistent' => false
);
/**
* Execution mode
*
* @var int execution flag (DB2_AUTOCOMMIT_ON or DB2_AUTOCOMMIT_OFF)
* @access protected
*/
protected $_execute_mode = DB2_AUTOCOMMIT_ON;
/**
* Table name of the last accessed table for an insert operation
* This is a DB2-Adapter-specific member variable with the utmost
* probability you might not find it in other adapters...
*
* @var string
* @access protected
*/
protected $_lastInsertTable = null;
/**
* Constructor.
*
* $config is an array of key/value pairs containing configuration
* options. These options are common to most adapters:
*
* dbname => (string) The name of the database to user
* username => (string) Connect to the database as this username.
* password => (string) Password associated with the username.
* host => (string) What host to connect to, defaults to localhost
* port => (string) The port of the database, defaults to 50000
* persistent => (boolean) Whether to use a persistent connection or not, defaults to false
* protocol => (string) The network protocol, defaults to TCPIP
* options => (array) Other database options such as autocommit, case, and cursor options
*
* @param array $config An array of configuration keys.
*/
public function __construct(array $config)
{
if ( ! isset($config['password'])) {
throw new Doctrine_Adapter_Db2_Exception("Configuration array must have a key for 'password' for login credentials.");
}
if ( ! isset($config['username'])) {
throw new Doctrine_Adapter_Db2_Exception("Configuration array must have a key for 'username' for login credentials.");
}
if ( ! isset($config['dbname'])) {
throw new Doctrine_Adapter_Db2_Exception("Configuration array must have a key for 'dbname' that names the database instance.");
}
// keep the config
$this->_config = array_merge($this->_config, (array) $config);
// create a profiler object
$enabled = false;
if (array_key_exists('profiler', $this->_config)) {
$enabled = (bool) $this->_config['profiler'];
unset($this->_config['profiler']);
}
$this->_profiler = new Doctrine_Profiler($enabled);
}
/**
* Creates a connection resource.
*
* @return void
*/
protected function _connect()
{
if (is_resource($this->_connection)) {
// connection already exists
return;
}
if ( ! extension_loaded('ibm_db2')) {
throw new Doctrine_Adapter_Db2_Exception('The IBM DB2 extension is required for this adapter but not loaded');
}
if ($this->_config['persistent']) {
// use persistent connection
$conn_func_name = 'db2_pconnect';
} else {
// use "normal" connection
$conn_func_name = 'db2_connect';
}
if ( ! isset($this->_config['options'])) {
// config options were not set, so set it to an empty array
$this->_config['options'] = array();
}
if ( ! isset($this->_config['options']['autocommit'])) {
// set execution mode
$this->_config['options']['autocommit'] = &$this->_execute_mode;
}
if ($this->_config['host'] !== 'localhost') {
// if the host isn't localhost, use extended connection params
$dbname = 'DRIVER={IBM DB2 ODBC DRIVER}' .
';DATABASE=' . $this->_config['dbname'] .
';HOSTNAME=' . $this->_config['host'] .
';PORT=' . $this->_config['port'] .
';PROTOCOL=' . $this->_config['protocol'] .
';UID=' . $this->_config['username'] .
';PWD=' . $this->_config['password'] .';';
$this->_connection = $conn_func_name(
$dbname,
null,
null,
$this->_config['options']
);
} else {
// host is localhost, so use standard connection params
$this->_connection = $conn_func_name(
$this->_config['dbname'],
$this->_config['username'],
$this->_config['password'],
$this->_config['options']
);
}
// check the connection
if ( ! $this->_connection) {
throw new Doctrine_Adapter_Db2_Exception(db2_conn_errormsg(), db2_conn_error());
}
}
/**
* Force the connection to close.
*
* @return void
*/
public function closeConnection()
{
db2_close($this->_connection);
$this->_connection = null;
}
/**
* Returns an SQL statement for preparation.
*
* @param string $sql The SQL statement with placeholders.
* @return Doctrine_Statement_Db2
*/
public function prepare($sql)
{
$this->_connect();
$stmt = new Doctrine_Statement_Db2($this, $sql);
$stmt->setFetchMode($this->_fetchMode);
return $stmt;
}
/**
* Gets the execution mode
*
* @return int the execution mode (DB2_AUTOCOMMIT_ON or DB2_AUTOCOMMIT_OFF)
*/
public function _getExecuteMode()
{
return $this->_execute_mode;
}
/**
* @param integer $mode
* @return void
*/
public function _setExecuteMode($mode)
{
switch ($mode) {
case DB2_AUTOCOMMIT_OFF:
case DB2_AUTOCOMMIT_ON:
$this->_execute_mode = $mode;
db2_autocommit($this->_connection, $mode);
break;
default:
throw new Doctrine_Adapter_Db2_Exception("execution mode not supported");
break;
}
}
/**
* Quote a raw string.
*
* @param string $value Raw string
* @return string Quoted string
*/
protected function _quote($value)
{
/**
* Some releases of the IBM DB2 extension appear
* to be missing the db2_escape_string() method.
* The method was added in ibm_db2.c revision 1.53
* according to cvs.php.net. But the function is
* not present in my build of PHP 5.2.1.
*/
if (function_exists('db2_escape_string')) {
return db2_escape_string($value);
}
return parent::_quote($value);
}
/**
* @return string
*/
public function getQuoteIdentifierSymbol()
{
$info = db2_server_info($this->_connection);
$identQuote = $info->IDENTIFIER_QUOTE_CHAR;
return $identQuote;
}
/**
* Begin a transaction.
*
* @return void
*/
protected function _beginTransaction()
{
$this->_setExecuteMode(DB2_AUTOCOMMIT_OFF);
}
/**
* Commit a transaction.
*
* @return void
*/
protected function _commit()
{
if ( ! db2_commit($this->_connection)) {
throw new Doctrine_Adapter_Db2_Exception(
db2_conn_errormsg($this->_connection),
db2_conn_error($this->_connection));
}
$this->_setExecuteMode(DB2_AUTOCOMMIT_ON);
}
/**
* Rollback a transaction.
*
* @return void
*/
protected function _rollBack()
{
if ( ! db2_rollback($this->_connection)) {
throw new Doctrine_Adapter_Db2_Exception(
db2_conn_errormsg($this->_connection),
db2_conn_error($this->_connection));
}
$this->_setExecuteMode(DB2_AUTOCOMMIT_ON);
}
/**
* Set the fetch mode.
*
* @param integer $mode
* @return void
*/
public function setFetchMode($mode)
{
switch ($mode) {
case Doctrine::FETCH_NUM: // seq array
case Doctrine::FETCH_ASSOC: // assoc array
case Doctrine::FETCH_BOTH: // seq+assoc array
case Doctrine::FETCH_OBJ: // object
$this->_fetchMode = $mode;
break;
default:
throw new Doctrine_Adapter_Db2_Exception('Invalid fetch mode specified');
break;
}
}
}