blob: a14aaa1f32e2e3bd12d41141f016d7d37315bfcf [file] [log] [blame]
Derek Allard2067d1a2008-11-13 22:59:24 +00001<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
2/**
3 * CodeIgniter
4 *
5 * An open source application development framework for PHP 4.3.2 or newer
6 *
7 * @package CodeIgniter
8 * @author ExpressionEngine Dev Team
9 * @copyright Copyright (c) 2008, EllisLab, Inc.
10 * @license http://codeigniter.com/user_guide/license.html
11 * @link http://codeigniter.com
12 * @since Version 1.0
13 * @filesource
14 */
15
16// ------------------------------------------------------------------------
17
18/**
19 * ODBC Database Adapter Class
20 *
21 * Note: _DB is an extender class that the app controller
22 * creates dynamically based on whether the active record
23 * class is being used or not.
24 *
25 * @package CodeIgniter
26 * @subpackage Drivers
27 * @category Database
28 * @author ExpressionEngine Dev Team
29 * @link http://codeigniter.com/user_guide/database/
30 */
31class CI_DB_odbc_driver extends CI_DB {
32
33 var $dbdriver = 'odbc';
34
35 // the character used to excape - not necessary for ODBC
36 var $_escape_char = '';
Derek Jonese4ed5832009-02-20 21:44:59 +000037
38 // clause and character used for LIKE escape sequences
39 var $_like_escape_str = " {escape '%s'} ";
40 var $_like_escape_chr = '!';
41
Derek Allard2067d1a2008-11-13 22:59:24 +000042 /**
43 * The syntax to count rows is slightly different across different
44 * database engines, so this string appears in each driver and is
45 * used for the count_all() and count_all_results() functions.
46 */
47 var $_count_string = "SELECT COUNT(*) AS ";
48 var $_random_keyword;
49
50
51 function CI_DB_odbc_driver($params)
52 {
53 parent::CI_DB($params);
54
55 $this->_random_keyword = ' RND('.time().')'; // database specific random keyword
56 }
57
58 /**
59 * Non-persistent database connection
60 *
61 * @access private called by the base class
62 * @return resource
63 */
64 function db_connect()
65 {
66 return @odbc_connect($this->hostname, $this->username, $this->password);
67 }
68
69 // --------------------------------------------------------------------
70
71 /**
72 * Persistent database connection
73 *
74 * @access private called by the base class
75 * @return resource
76 */
77 function db_pconnect()
78 {
79 return @odbc_pconnect($this->hostname, $this->username, $this->password);
80 }
81
82 // --------------------------------------------------------------------
83
84 /**
85 * Select the database
86 *
87 * @access private called by the base class
88 * @return resource
89 */
90 function db_select()
91 {
92 // Not needed for ODBC
93 return TRUE;
94 }
95
96 // --------------------------------------------------------------------
97
98 /**
99 * Set client character set
100 *
101 * @access public
102 * @param string
103 * @param string
104 * @return resource
105 */
106 function db_set_charset($charset, $collation)
107 {
108 // @todo - add support if needed
109 return TRUE;
110 }
111
112 // --------------------------------------------------------------------
113
114 /**
115 * Version number query string
116 *
117 * @access public
118 * @return string
119 */
120 function _version()
121 {
122 return "SELECT version() AS ver";
123 }
124
125 // --------------------------------------------------------------------
126
127 /**
128 * Execute the query
129 *
130 * @access private called by the base class
131 * @param string an SQL query
132 * @return resource
133 */
134 function _execute($sql)
135 {
136 $sql = $this->_prep_query($sql);
137 return @odbc_exec($this->conn_id, $sql);
138 }
139
140 // --------------------------------------------------------------------
141
142 /**
143 * Prep the query
144 *
145 * If needed, each database adapter can prep the query string
146 *
147 * @access private called by execute()
148 * @param string an SQL query
149 * @return string
150 */
151 function _prep_query($sql)
152 {
153 return $sql;
154 }
155
156 // --------------------------------------------------------------------
157
158 /**
159 * Begin Transaction
160 *
161 * @access public
162 * @return bool
163 */
164 function trans_begin($test_mode = FALSE)
165 {
166 if ( ! $this->trans_enabled)
167 {
168 return TRUE;
169 }
170
171 // When transactions are nested we only begin/commit/rollback the outermost ones
172 if ($this->_trans_depth > 0)
173 {
174 return TRUE;
175 }
176
177 // Reset the transaction failure flag.
178 // If the $test_mode flag is set to TRUE transactions will be rolled back
179 // even if the queries produce a successful result.
180 $this->_trans_failure = ($test_mode === TRUE) ? TRUE : FALSE;
181
182 return odbc_autocommit($this->conn_id, FALSE);
183 }
184
185 // --------------------------------------------------------------------
186
187 /**
188 * Commit Transaction
189 *
190 * @access public
191 * @return bool
192 */
193 function trans_commit()
194 {
195 if ( ! $this->trans_enabled)
196 {
197 return TRUE;
198 }
199
200 // When transactions are nested we only begin/commit/rollback the outermost ones
201 if ($this->_trans_depth > 0)
202 {
203 return TRUE;
204 }
205
206 $ret = odbc_commit($this->conn_id);
207 odbc_autocommit($this->conn_id, TRUE);
208 return $ret;
209 }
210
211 // --------------------------------------------------------------------
212
213 /**
214 * Rollback Transaction
215 *
216 * @access public
217 * @return bool
218 */
219 function trans_rollback()
220 {
221 if ( ! $this->trans_enabled)
222 {
223 return TRUE;
224 }
225
226 // When transactions are nested we only begin/commit/rollback the outermost ones
227 if ($this->_trans_depth > 0)
228 {
229 return TRUE;
230 }
231
232 $ret = odbc_rollback($this->conn_id);
233 odbc_autocommit($this->conn_id, TRUE);
234 return $ret;
235 }
236
237 // --------------------------------------------------------------------
238
239 /**
240 * Escape String
241 *
242 * @access public
243 * @param string
Derek Jonese4ed5832009-02-20 21:44:59 +0000244 * @param bool whether or not the string will be used in a LIKE condition
Derek Allard2067d1a2008-11-13 22:59:24 +0000245 * @return string
246 */
Derek Jonese4ed5832009-02-20 21:44:59 +0000247 function escape_str($str, $like = FALSE)
Derek Allard2067d1a2008-11-13 22:59:24 +0000248 {
Derek Jonese4ed5832009-02-20 21:44:59 +0000249 if (is_array($str))
250 {
251 foreach($str as $key => $val)
252 {
253 $str[$key] = $this->escape_str($val, $like);
254 }
255
256 return $str;
257 }
258
Derek Allard2067d1a2008-11-13 22:59:24 +0000259 // Access the CI object
260 $CI =& get_instance();
Derek Jonese4ed5832009-02-20 21:44:59 +0000261
Derek Allard2067d1a2008-11-13 22:59:24 +0000262 // ODBC doesn't require escaping
Derek Jonese4ed5832009-02-20 21:44:59 +0000263 $str = $CI->input->_remove_invisible_characters($str);
264
265 // escape LIKE condition wildcards
266 if ($like === TRUE)
267 {
268 $str = str_replace( array('%', '_', $this->_like_escape_chr),
269 array($this->_like_escape_chr.'%', $this->_like_escape_chr.'_', $this->_like_escape_chr.$this->_like_escape_chr),
270 $str);
271 }
272
273 return $str;
Derek Allard2067d1a2008-11-13 22:59:24 +0000274 }
275
276 // --------------------------------------------------------------------
277
278 /**
279 * Affected Rows
280 *
281 * @access public
282 * @return integer
283 */
284 function affected_rows()
285 {
286 return @odbc_num_rows($this->conn_id);
287 }
288
289 // --------------------------------------------------------------------
290
291 /**
292 * Insert ID
293 *
294 * @access public
295 * @return integer
296 */
297 function insert_id()
298 {
299 return @odbc_insert_id($this->conn_id);
300 }
301
302 // --------------------------------------------------------------------
303
304 /**
305 * "Count All" query
306 *
307 * Generates a platform-specific query string that counts all records in
308 * the specified database
309 *
310 * @access public
311 * @param string
312 * @return string
313 */
314 function count_all($table = '')
315 {
316 if ($table == '')
Derek Allarde37ab382009-02-03 16:13:57 +0000317 {
318 return 0;
319 }
320
321 $query = $this->query($this->_count_string . $this->_protect_identifiers('numrows') . " FROM " . $this->_protect_identifiers($table, TRUE, NULL, FALSE));
322
Derek Allard2067d1a2008-11-13 22:59:24 +0000323 if ($query->num_rows() == 0)
Derek Allarde37ab382009-02-03 16:13:57 +0000324 {
325 return 0;
326 }
Derek Allard2067d1a2008-11-13 22:59:24 +0000327
328 $row = $query->row();
Derek Allarde37ab382009-02-03 16:13:57 +0000329 return (int) $row->numrows;
Derek Allard2067d1a2008-11-13 22:59:24 +0000330 }
331
332 // --------------------------------------------------------------------
333
334 /**
335 * Show table query
336 *
337 * Generates a platform-specific query string so that the table names can be fetched
338 *
339 * @access private
340 * @param boolean
341 * @return string
342 */
343 function _list_tables($prefix_limit = FALSE)
344 {
345 $sql = "SHOW TABLES FROM `".$this->database."`";
346
347 if ($prefix_limit !== FALSE AND $this->dbprefix != '')
348 {
349 //$sql .= " LIKE '".$this->dbprefix."%'";
350 return FALSE; // not currently supported
351 }
352
353 return $sql;
354 }
355
356 // --------------------------------------------------------------------
357
358 /**
359 * Show column query
360 *
361 * Generates a platform-specific query string so that the column names can be fetched
362 *
363 * @access public
364 * @param string the table name
365 * @return string
366 */
367 function _list_columns($table = '')
368 {
369 return "SHOW COLUMNS FROM ".$table;
370 }
371
372 // --------------------------------------------------------------------
373
374 /**
375 * Field data query
376 *
377 * Generates a platform-specific query so that the column data can be retrieved
378 *
379 * @access public
380 * @param string the table name
381 * @return object
382 */
383 function _field_data($table)
384 {
385 return "SELECT TOP 1 FROM ".$table;
386 }
387
388 // --------------------------------------------------------------------
389
390 /**
391 * The error message string
392 *
393 * @access private
394 * @return string
395 */
396 function _error_message()
397 {
398 return odbc_errormsg($this->conn_id);
399 }
400
401 // --------------------------------------------------------------------
402
403 /**
404 * The error message number
405 *
406 * @access private
407 * @return integer
408 */
409 function _error_number()
410 {
411 return odbc_error($this->conn_id);
412 }
413
414 // --------------------------------------------------------------------
415
416 /**
417 * Escape the SQL Identifiers
418 *
419 * This function escapes column and table names
420 *
421 * @access private
422 * @param string
423 * @return string
424 */
425 function _escape_identifiers($item)
426 {
427 if ($this->_escape_char == '')
428 {
429 return $item;
430 }
431
432 foreach ($this->_reserved_identifiers as $id)
433 {
434 if (strpos($item, '.'.$id) !== FALSE)
435 {
436 $str = $this->_escape_char. str_replace('.', $this->_escape_char.'.', $item);
437
438 // remove duplicates if the user already included the escape
439 return preg_replace('/['.$this->_escape_char.']+/', $this->_escape_char, $str);
440 }
441 }
442
443 if (strpos($item, '.') !== FALSE)
444 {
445 $str = $this->_escape_char.str_replace('.', $this->_escape_char.'.'.$this->_escape_char, $item).$this->_escape_char;
446 }
447 else
448 {
449 $str = $this->_escape_char.$item.$this->_escape_char;
450 }
451
452 // remove duplicates if the user already included the escape
453 return preg_replace('/['.$this->_escape_char.']+/', $this->_escape_char, $str);
454 }
455
456 // --------------------------------------------------------------------
457
458 /**
459 * From Tables
460 *
461 * This function implicitly groups FROM tables so there is no confusion
462 * about operator precedence in harmony with SQL standards
463 *
464 * @access public
465 * @param type
466 * @return type
467 */
468 function _from_tables($tables)
469 {
470 if ( ! is_array($tables))
471 {
472 $tables = array($tables);
473 }
474
475 return '('.implode(', ', $tables).')';
476 }
477
478 // --------------------------------------------------------------------
479
480 /**
481 * Insert statement
482 *
483 * Generates a platform-specific insert string from the supplied data
484 *
485 * @access public
486 * @param string the table name
487 * @param array the insert keys
488 * @param array the insert values
489 * @return string
490 */
491 function _insert($table, $keys, $values)
492 {
493 return "INSERT INTO ".$table." (".implode(', ', $keys).") VALUES (".implode(', ', $values).")";
494 }
495
496 // --------------------------------------------------------------------
497
498 /**
499 * Update statement
500 *
501 * Generates a platform-specific update string from the supplied data
502 *
503 * @access public
504 * @param string the table name
505 * @param array the update data
506 * @param array the where clause
507 * @param array the orderby clause
508 * @param array the limit clause
509 * @return string
510 */
511 function _update($table, $values, $where, $orderby = array(), $limit = FALSE)
512 {
513 foreach($values as $key => $val)
514 {
515 $valstr[] = $key." = ".$val;
516 }
517
518 $limit = ( ! $limit) ? '' : ' LIMIT '.$limit;
519
520 $orderby = (count($orderby) >= 1)?' ORDER BY '.implode(", ", $orderby):'';
521
522 $sql = "UPDATE ".$table." SET ".implode(', ', $valstr);
523
524 $sql .= ($where != '' AND count($where) >=1) ? " WHERE ".implode(" ", $where) : '';
525
526 $sql .= $orderby.$limit;
527
528 return $sql;
529 }
530
531
532 // --------------------------------------------------------------------
533
534 /**
535 * Truncate statement
536 *
537 * Generates a platform-specific truncate string from the supplied data
538 * If the database does not support the truncate() command
539 * This function maps to "DELETE FROM table"
540 *
541 * @access public
542 * @param string the table name
543 * @return string
544 */
545 function _truncate($table)
546 {
547 return $this->_delete($table);
548 }
549
550 // --------------------------------------------------------------------
551
552 /**
553 * Delete statement
554 *
555 * Generates a platform-specific delete string from the supplied data
556 *
557 * @access public
558 * @param string the table name
559 * @param array the where clause
560 * @param string the limit clause
561 * @return string
562 */
563 function _delete($table, $where = array(), $like = array(), $limit = FALSE)
564 {
565 $conditions = '';
566
567 if (count($where) > 0 OR count($like) > 0)
568 {
569 $conditions = "\nWHERE ";
570 $conditions .= implode("\n", $this->ar_where);
571
572 if (count($where) > 0 && count($like) > 0)
573 {
574 $conditions .= " AND ";
575 }
576 $conditions .= implode("\n", $like);
577 }
578
579 $limit = ( ! $limit) ? '' : ' LIMIT '.$limit;
580
581 return "DELETE FROM ".$table.$conditions.$limit;
582 }
583
584 // --------------------------------------------------------------------
585
586 /**
587 * Limit string
588 *
589 * Generates a platform-specific LIMIT clause
590 *
591 * @access public
592 * @param string the sql query string
593 * @param integer the number of rows to limit the query to
594 * @param integer the offset value
595 * @return string
596 */
597 function _limit($sql, $limit, $offset)
598 {
599 // Does ODBC doesn't use the LIMIT clause?
600 return $sql;
601 }
602
603 // --------------------------------------------------------------------
604
605 /**
606 * Close DB Connection
607 *
608 * @access public
609 * @param resource
610 * @return void
611 */
612 function _close($conn_id)
613 {
614 @odbc_close($conn_id);
615 }
616
617
618}
619
620
621
622/* End of file odbc_driver.php */
Derek Jonesa3ffbbb2008-05-11 18:18:29 +0000623/* Location: ./system/database/drivers/odbc/odbc_driver.php */