Differences Between: [Versions 310 and 400] [Versions 311 and 400] [Versions 39 and 400] [Versions 400 and 401] [Versions 400 and 402] [Versions 400 and 403]
1 <?php 2 /** 3 * IBM DB2 Native Client driver. 4 * 5 * Originally DB2 drivers were dependent on an ODBC driver, and some installations 6 * may still use that. To use an ODBC driver connection, use the odbc_db2 7 * ADOdb driver. For Linux, you need the 'ibm_db2' PECL extension for PHP, 8 * For Windows, you need to locate an appropriate version of the php_ibm_db2.dll, 9 * as well as the IBM data server client software. 10 * This is basically a full rewrite of the original driver, for information 11 * about all the changes, see the update information on the ADOdb website 12 * for version 5.21.0. 13 * 14 * @link http://pecl.php.net/package/ibm_db2 PECL Extension For DB2 15 * 16 * This file is part of ADOdb, a Database Abstraction Layer library for PHP. 17 * 18 * @package ADOdb 19 * @link https://adodb.org Project's web site and documentation 20 * @link https://github.com/ADOdb/ADOdb Source code and issue tracker 21 * 22 * The ADOdb Library is dual-licensed, released under both the BSD 3-Clause 23 * and the GNU Lesser General Public Licence (LGPL) v2.1 or, at your option, 24 * any later version. This means you can use it in proprietary products. 25 * See the LICENSE.md file distributed with this source code for details. 26 * @license BSD-3-Clause 27 * @license LGPL-2.1-or-later 28 * 29 * @copyright 2000-2013 John Lim 30 * @copyright 2014 Damien Regad, Mark Newnham and the ADOdb community 31 * @author Mark Newnham 32 */ 33 34 // security - hide paths 35 if (!defined('ADODB_DIR')) die(); 36 37 define("_ADODB_DB2_LAYER", 2 ); 38 39 40 class ADODB_db2 extends ADOConnection { 41 var $databaseType = "db2"; 42 var $fmtDate = "'Y-m-d'"; 43 var $concat_operator = '||'; 44 45 var $sysTime = 'CURRENT TIME'; 46 var $sysDate = 'CURRENT DATE'; 47 var $sysTimeStamp = 'CURRENT TIMESTAMP'; 48 49 var $fmtTimeStamp = "'Y-m-d H:i:s'"; 50 var $replaceQuote = "''"; // string to use to replace quotes 51 var $dataProvider = "db2"; 52 var $hasAffectedRows = true; 53 54 var $binmode = DB2_BINARY; 55 56 /* 57 * setting this to true will make array elements in FETCH_ASSOC 58 * mode case-sensitive breaking backward-compat 59 */ 60 var $useFetchArray = false; 61 var $_bindInputArray = true; 62 var $_genIDSQL = "VALUES NEXTVAL FOR %s"; 63 var $_genSeqSQL = " 64 CREATE SEQUENCE %s START WITH %s 65 NO MAXVALUE NO CYCLE INCREMENT BY 1 NO CACHE 66 "; 67 var $_dropSeqSQL = "DROP SEQUENCE %s"; 68 var $_autocommit = true; 69 var $_lastAffectedRows = 0; 70 var $hasInsertID = true; 71 var $hasGenID = true; 72 73 /* 74 * Character used to wrap column and table names for escaping special 75 * characters in column and table names as well as forcing upper and 76 * lower case 77 */ 78 public $nameQuote = '"'; 79 80 /* 81 * Executed after successful connection 82 */ 83 public $connectStmt = ''; 84 85 /* 86 * Holds the current database name 87 */ 88 private $databaseName = ''; 89 90 /* 91 * Holds information about the stored procedure request 92 * currently being built 93 */ 94 private $storedProcedureParameters = false; 95 96 97 function __construct() {} 98 99 protected function _insertID($table = '', $column = '') 100 { 101 return ADOConnection::GetOne('VALUES IDENTITY_VAL_LOCAL()'); 102 } 103 104 public function _connect($argDSN, $argUsername, $argPassword, $argDatabasename) 105 { 106 return $this->doDB2Connect($argDSN, $argUsername, $argPassword, $argDatabasename); 107 } 108 109 public function _pconnect($argDSN, $argUsername, $argPassword, $argDatabasename) 110 { 111 return $this->doDB2Connect($argDSN, $argUsername, $argPassword, $argDatabasename,true); 112 } 113 114 private function doDB2Connect($argDSN, $argUsername, $argPassword, $argDatabasename, $persistent=false) 115 { 116 117 if (!function_exists('db2_connect')) { 118 ADOConnection::outp("DB2 extension not installed."); 119 return null; 120 } 121 122 $connectionParameters = $this->unpackParameters($argDSN, 123 $argUsername, 124 $argPassword, 125 $argDatabasename); 126 127 if ($connectionParameters == null) 128 { 129 /* 130 * Error thrown 131 */ 132 return null; 133 } 134 135 $argDSN = $connectionParameters['dsn']; 136 $argUsername = $connectionParameters['uid']; 137 $argPassword = $connectionParameters['pwd']; 138 $argDatabasename = $connectionParameters['database']; 139 $useCataloguedConnection = $connectionParameters['catalogue']; 140 141 if ($this->debug){ 142 if ($useCataloguedConnection){ 143 $connectMessage = "Catalogued connection using parameters: "; 144 $connectMessage .= "DB=$argDatabasename / "; 145 $connectMessage .= "UID=$argUsername / "; 146 $connectMessage .= "PWD=$argPassword"; 147 } 148 else 149 { 150 $connectMessage = "Uncatalogued connection using DSN: $argDSN"; 151 } 152 ADOConnection::outp($connectMessage); 153 } 154 /* 155 * This needs to be set before the connect(). 156 */ 157 ini_set('ibm_db2.binmode', $this->binmode); 158 159 if ($persistent) 160 $db2Function = 'db2_pconnect'; 161 else 162 $db2Function = 'db2_connect'; 163 164 /* 165 * We need to flatten out the connectionParameters 166 */ 167 168 $db2Options = array(); 169 if ($this->connectionParameters) 170 { 171 foreach($this->connectionParameters as $p) 172 foreach($p as $k=>$v) 173 $db2Options[$k] = $v; 174 } 175 176 if ($useCataloguedConnection) 177 $this->_connectionID = $db2Function($argDatabasename, 178 $argUsername, 179 $argPassword, 180 $db2Options); 181 else 182 $this->_connectionID = $db2Function($argDSN, 183 null, 184 null, 185 $db2Options); 186 187 $this->_errorMsg = @db2_conn_errormsg(); 188 189 if ($this->_connectionID && $this->connectStmt) 190 $this->execute($this->connectStmt); 191 192 return $this->_connectionID != false; 193 194 } 195 196 /** 197 * Validates and preprocesses the passed parameters for consistency 198 * 199 * @param string $argDSN Either DSN or database 200 * @param string $argUsername User name or null 201 * @param string $argPassword Password or null 202 * @param string $argDatabasename Either DSN or database 203 * 204 * @return mixed array if correct, null if not 205 */ 206 private function unpackParameters($argDSN, $argUsername, $argPassword, $argDatabasename) 207 { 208 209 $connectionParameters = array('dsn'=>'', 210 'uid'=>'', 211 'pwd'=>'', 212 'database'=>'', 213 'catalogue'=>true 214 ); 215 216 /* 217 * Uou can either connect to a catalogued connection 218 * with a database name e.g. 'SAMPLE' 219 * or an uncatalogued connection with a DSN like connection 220 * DATABASE=database;HOSTNAME=hostname;PORT=port;PROTOCOL=TCPIP;UID=username;PWD=password; 221 */ 222 223 if (!$argDSN && !$argDatabasename) 224 { 225 $errorMessage = 'Supply either catalogued or uncatalogued connection parameters'; 226 $this->_errorMsg = $errorMessage; 227 if ($this->debug) 228 ADOConnection::outp($errorMessage); 229 return null; 230 } 231 232 $useCataloguedConnection = true; 233 $schemaName = ''; 234 235 if ($argDSN && $argDatabasename) 236 { 237 /* 238 * If a catalogued connection if provided, 239 * as well as user and password 240 * that will take priority 241 */ 242 if ($argUsername && $argPassword && !$this->isDsn($argDatabasename)) 243 { 244 if ($this->debug){ 245 $errorMessage = 'Warning: Because you provided user,'; 246 $errorMessage.= 'password and database, DSN connection '; 247 $errorMessage.= 'parameters were discarded'; 248 ADOConnection::outp($errorMessage); 249 250 } 251 $argDSN = ''; 252 } 253 else if ($this->isDsn($argDSN) && $this->isDsn($argDatabasename)) 254 { 255 $errorMessage = 'Supply uncatalogued connection parameters '; 256 $errorMessage.= 'in either the database or DSN arguments, '; 257 $errorMessage.= 'but not both'; 258 if ($this->debug) 259 ADOConnection::outp($errorMessage); 260 return null; 261 } 262 } 263 264 if (!$this->isDsn($argDSN) && $this->isDsn($argDatabasename)) 265 { 266 /* 267 * Switch them around for next test 268 */ 269 $temp = $argDSN; 270 $argDsn = $argDatabasename; 271 $argDatabasenME = $temp; 272 } 273 274 if ($this->isDsn($argDSN)) 275 { 276 277 if (!preg_match('/uid=/i',$argDSN) 278 || !preg_match('/pwd=/i',$argDSN)) 279 { 280 $errorMessage = 'For uncatalogued connections, provide '; 281 $errorMessage.= 'both UID and PWD in the connection string'; 282 if ($this->debug) 283 ADOConnection::outp($errorMessage); 284 return null; 285 } 286 287 if (preg_match('/database=/i',$argDSN)) 288 { 289 if ($argDatabasename) 290 { 291 $argDatabasename = ''; 292 if ($this->debug) 293 { 294 $errorMessage = 'Warning: Because you provided '; 295 $errorMessage.= 'database information in the DSN '; 296 $errorMessage.= 'parameters, the supplied database '; 297 $errorMessage.= 'name was discarded'; 298 ADOConnection::outp($errorMessage); 299 } 300 } 301 $useCataloguedConnection = false; 302 303 } 304 elseif ($argDatabasename) 305 { 306 $this->databaseName = $argDatabasename; 307 $argDSN .= ';database=' . $argDatabasename; 308 $argDatabasename = ''; 309 $useCataloguedConnection = false; 310 311 } 312 else 313 { 314 $errorMessage = 'Uncatalogued connection parameters '; 315 $errorMessage.= 'must contain a database= argument'; 316 if ($this->debug) 317 ADOConnection::outp($errorMessage); 318 return null; 319 } 320 } 321 322 if ($argDSN && !$argDatabasename && $useCataloguedConnection) 323 { 324 $argDatabasename = $argDSN; 325 $argDSN = ''; 326 } 327 328 329 if ($useCataloguedConnection 330 && (!$argDatabasename 331 || !$argUsername 332 || !$argPassword)) 333 { 334 335 $errorMessage = 'For catalogued connections, provide '; 336 $errorMessage.= 'database, username and password'; 337 $this->_errorMsg = $errorMessage; 338 if ($this->debug) 339 ADOConnection::outp($errorMessage); 340 return null; 341 342 } 343 344 if ($argDatabasename) 345 $this->databaseName = $argDatabasename; 346 elseif (!$this->databaseName) 347 $this->databaseName = $this->getDatabasenameFromDsn($argDSN); 348 349 350 $connectionParameters = array('dsn'=>$argDSN, 351 'uid'=>$argUsername, 352 'pwd'=>$argPassword, 353 'database'=>$argDatabasename, 354 'catalogue'=>$useCataloguedConnection 355 ); 356 357 return $connectionParameters; 358 359 } 360 361 /** 362 * Does the provided string look like a DSN 363 * 364 * @param string $dsnString 365 * 366 * @return bool 367 */ 368 private function isDsn($dsnString){ 369 $dsnArray = preg_split('/[;=]+/',$dsnString); 370 if (count($dsnArray) > 2) 371 return true; 372 return false; 373 } 374 375 376 /** 377 * Gets the database name from the DSN 378 * 379 * @param string $dsnString 380 * 381 * @return string 382 */ 383 private function getDatabasenameFromDsn($dsnString){ 384 385 $dsnArray = preg_split('/[;=]+/',$dsnString); 386 $dbIndex = array_search('database',$dsnArray); 387 388 return $dsnArray[$dbIndex + 1]; 389 } 390 391 392 /** 393 * format and return date string in database timestamp format 394 * 395 * @param mixed $ts either a string or a unixtime 396 * @param bool $isField discarded 397 * 398 * @return string 399 */ 400 function dbTimeStamp($ts,$isField=false) 401 { 402 if (empty($ts) && $ts !== 0) return 'null'; 403 if (is_string($ts)) $ts = ADORecordSet::unixTimeStamp($ts); 404 return 'TO_DATE('.adodb_date($this->fmtTimeStamp,$ts).",'YYYY-MM-DD HH24:MI:SS')"; 405 } 406 407 /** 408 * Format date column in sql string given an input format that understands Y M D 409 * 410 * @param string $fmt 411 * @param bool $col 412 * 413 * @return string 414 */ 415 function sqlDate($fmt, $col=false) 416 { 417 if (!$col) $col = $this->sysDate; 418 419 /* use TO_CHAR() if $fmt is TO_CHAR() allowed fmt */ 420 if ($fmt== 'Y-m-d H:i:s') 421 return 'TO_CHAR('.$col.", 'YYYY-MM-DD HH24:MI:SS')"; 422 423 $s = ''; 424 425 $len = strlen($fmt); 426 for ($i=0; $i < $len; $i++) { 427 if ($s) $s .= $this->concat_operator; 428 $ch = $fmt[$i]; 429 switch($ch) { 430 case 'Y': 431 case 'y': 432 if ($len==1) return "year($col)"; 433 $s .= "char(year($col))"; 434 break; 435 case 'M': 436 if ($len==1) return "monthname($col)"; 437 $s .= "substr(monthname($col),1,3)"; 438 break; 439 case 'm': 440 if ($len==1) return "month($col)"; 441 $s .= "right(digits(month($col)),2)"; 442 break; 443 case 'D': 444 case 'd': 445 if ($len==1) return "day($col)"; 446 $s .= "right(digits(day($col)),2)"; 447 break; 448 case 'H': 449 case 'h': 450 if ($len==1) return "hour($col)"; 451 if ($col != $this->sysDate) $s .= "right(digits(hour($col)),2)"; 452 else $s .= "''"; 453 break; 454 case 'i': 455 case 'I': 456 if ($len==1) return "minute($col)"; 457 if ($col != $this->sysDate) 458 $s .= "right(digits(minute($col)),2)"; 459 else $s .= "''"; 460 break; 461 case 'S': 462 case 's': 463 if ($len==1) return "second($col)"; 464 if ($col != $this->sysDate) 465 $s .= "right(digits(second($col)),2)"; 466 else $s .= "''"; 467 break; 468 default: 469 if ($ch == '\\') { 470 $i++; 471 $ch = substr($fmt,$i,1); 472 } 473 $s .= $this->qstr($ch); 474 } 475 } 476 return $s; 477 } 478 479 480 function serverInfo() 481 { 482 $sql = "SELECT service_level, fixpack_num 483 FROM TABLE(sysproc.env_get_inst_info()) 484 AS INSTANCEINFO"; 485 $row = $this->GetRow($sql); 486 487 488 if ($row) { 489 $info['version'] = $row[0].':'.$row[1]; 490 $info['fixpack'] = $row[1]; 491 $info['description'] = ''; 492 } else { 493 return ADOConnection::serverInfo(); 494 } 495 496 return $info; 497 } 498 499 function createSequence($seqname='adodbseq',$start=1) 500 { 501 if (empty($this->_genSeqSQL)) 502 return false; 503 504 $ok = $this->execute(sprintf($this->_genSeqSQL,$seqname,$start)); 505 if (!$ok) 506 return false; 507 return true; 508 } 509 510 function dropSequence($seqname='adodbseq') 511 { 512 if (empty($this->_dropSeqSQL)) return false; 513 return $this->execute(sprintf($this->_dropSeqSQL,$seqname)); 514 } 515 516 function selectLimit($sql,$nrows=-1,$offset=-1,$inputArr=false,$secs2cache=0) 517 { 518 $nrows = (integer) $nrows; 519 520 if ($offset <= 0) 521 { 522 if ($nrows >= 0) 523 $sql .= " FETCH FIRST $nrows ROWS ONLY "; 524 525 $rs = $this->execute($sql,$inputArr); 526 527 } 528 else 529 { 530 if ($offset > 0 && $nrows < 0); 531 532 else 533 { 534 $nrows += $offset; 535 $sql .= " FETCH FIRST $nrows ROWS ONLY "; 536 } 537 538 /* 539 * DB2 has no native support for mid table offset 540 */ 541 $rs = ADOConnection::selectLimit($sql,$nrows,$offset,$inputArr); 542 543 } 544 545 return $rs; 546 } 547 548 549 function errorMsg() 550 { 551 if ($this->_errorMsg !== false) 552 return $this->_errorMsg; 553 554 if (empty($this->_connectionID)) 555 return @db2_conn_errormsg(); 556 557 return @db2_conn_errormsg($this->_connectionID); 558 } 559 560 function errorNo() 561 { 562 563 if ($this->_errorCode !== false) 564 return $this->_errorCode; 565 566 567 if (empty($this->_connectionID)) 568 $e = @db2_conn_error(); 569 570 else 571 $e = @db2_conn_error($this->_connectionID); 572 573 return $e; 574 } 575 576 577 578 function beginTrans() 579 { 580 if (!$this->hasTransactions) 581 return false; 582 if ($this->transOff) 583 return true; 584 585 $this->transCnt += 1; 586 587 $this->_autocommit = false; 588 589 return db2_autocommit($this->_connectionID,false); 590 } 591 592 function CommitTrans($ok=true) 593 { 594 if ($this->transOff) 595 return true; 596 597 if (!$ok) 598 return $this->RollbackTrans(); 599 600 if ($this->transCnt) 601 $this->transCnt -= 1; 602 603 $this->_autocommit = true; 604 $ret = @db2_commit($this->_connectionID); 605 @db2_autocommit($this->_connectionID,true); 606 return $ret; 607 } 608 609 function RollbackTrans() 610 { 611 if ($this->transOff) return true; 612 if ($this->transCnt) $this->transCnt -= 1; 613 $this->_autocommit = true; 614 $ret = @db2_rollback($this->_connectionID); 615 @db2_autocommit($this->_connectionID,true); 616 return $ret; 617 } 618 619 /** 620 * Return a list of Primary Keys for a specified table 621 * 622 * We don't use db2_statistics as the function does not seem to play 623 * well with mixed case table names 624 * 625 * @param string $table 626 * @param bool $primary (optional) only return primary keys 627 * @param bool $owner (optional) not used in this driver 628 * 629 * @return string[] Array of indexes 630 */ 631 public function metaPrimaryKeys($table,$owner=false) 632 { 633 634 $primaryKeys = array(); 635 636 global $ADODB_FETCH_MODE; 637 638 $schema = ''; 639 $this->_findschema($table,$schema); 640 641 $table = $this->getTableCasedValue($table); 642 643 $savem = $ADODB_FETCH_MODE; 644 $ADODB_FETCH_MODE = ADODB_FETCH_NUM; 645 $this->setFetchMode(ADODB_FETCH_NUM); 646 647 648 $sql = "SELECT * 649 FROM syscat.indexes 650 WHERE tabname='$table'"; 651 652 $rows = $this->getAll($sql); 653 654 $this->setFetchMode($savem); 655 $ADODB_FETCH_MODE = $savem; 656 657 if (empty($rows)) 658 return false; 659 660 foreach ($rows as $r) 661 { 662 if ($r[7] != 'P') 663 continue; 664 665 $cols = explode('+',$r[6]); 666 foreach ($cols as $colIndex=>$col) 667 { 668 if ($colIndex == 0) 669 continue; 670 $columnName = $this->getMetaCasedValue($col); 671 $primaryKeys[] = $columnName; 672 } 673 break; 674 } 675 return $primaryKeys; 676 } 677 678 /** 679 * returns assoc array where keys are tables, and values are foreign keys 680 * 681 * @param string $table 682 * @param string $owner [optional][discarded] 683 * @param bool $upper [optional][discarded] 684 * @param bool $associative[optional][discarded] 685 * 686 * @return mixed[] Array of foreign key information 687 */ 688 public function metaForeignKeys($table, $owner = FALSE, $upper = FALSE, $asociative = FALSE ) 689 { 690 691 global $ADODB_FETCH_MODE; 692 693 $schema = ''; 694 $this->_findschema($table,$schema); 695 696 $savem = $ADODB_FETCH_MODE; 697 $ADODB_FETCH_MODE = ADODB_FETCH_NUM; 698 699 $this->setFetchMode(ADODB_FETCH_NUM); 700 701 $sql = "SELECT SUBSTR(tabname,1,20) table_name, 702 SUBSTR(constname,1,20) fk_name, 703 SUBSTR(REFTABNAME,1,12) parent_table, 704 SUBSTR(refkeyname,1,20) pk_orig_table, 705 fk_colnames 706 FROM syscat.references 707 WHERE tabname = '$table'"; 708 709 $results = $this->getAll($sql); 710 711 $ADODB_FETCH_MODE = $savem; 712 $this->setFetchMode($savem); 713 714 if (empty($results)) 715 return false; 716 717 $foreignKeys = array(); 718 719 foreach ($results as $r) 720 { 721 $parentTable = trim($this->getMetaCasedValue($r[2])); 722 $keyName = trim($this->getMetaCasedValue($r[1])); 723 $foreignKeys[$parentTable] = $keyName; 724 } 725 726 return $foreignKeys; 727 } 728 729 /** 730 * Returns a list of tables 731 * 732 * @param string $ttype (optional) 733 * @param string $schema (optional) 734 * @param string $mask (optional) 735 * 736 * @return array 737 */ 738 public function metaTables($ttype=false,$schema=false,$mask=false) 739 { 740 741 global $ADODB_FETCH_MODE; 742 743 $savem = $ADODB_FETCH_MODE; 744 $ADODB_FETCH_MODE = ADODB_FETCH_NUM; 745 746 /* 747 * Values for TABLE_TYPE 748 * --------------------------- 749 * ALIAS, HIERARCHY TABLE, INOPERATIVE VIEW, NICKNAME, 750 * MATERIALIZED QUERY TABLE, SYSTEM TABLE, TABLE, 751 * TYPED TABLE, TYPED VIEW, and VIEW 752 * 753 * If $ttype passed as '', match 'TABLE' and 'VIEW' 754 * If $ttype passed as 'T' it is assumed to be 'TABLE' 755 * if $ttype passed as 'V' it is assumed to be 'VIEW' 756 */ 757 $ttype = strtoupper($ttype); 758 if ($ttype) { 759 /* 760 * @todo We could do valid type checking or array type 761 */ 762 if ($ttype == 'V') 763 $ttype = 'VIEW'; 764 if ($ttype == 'T') 765 $ttype = 'TABLE'; 766 } 767 768 if (!$schema) 769 $schema = '%'; 770 771 if (!$mask) 772 $mask = '%'; 773 774 $qid = @db2_tables($this->_connectionID,NULL,$schema,$mask,$ttype); 775 776 $rs = new ADORecordSet_db2($qid); 777 778 $ADODB_FETCH_MODE = $savem; 779 780 if (!$rs) 781 return false; 782 783 $arr = $rs->getArray(); 784 785 $rs->Close(); 786 787 $tableList = array(); 788 789 /* 790 * Array items 791 * --------------------------------- 792 * 0 TABLE_CAT The catalog that contains the table. 793 * The value is NULL if this table does not have catalogs. 794 * 1 TABLE_SCHEM Name of the schema that contains the table. 795 * 2 TABLE_NAME Name of the table. 796 * 3 TABLE_TYPE Table type identifier for the table. 797 * 4 REMARKS Description of the table. 798 */ 799 800 for ($i=0; $i < sizeof($arr); $i++) 801 { 802 803 $tableRow = $arr[$i]; 804 $tableName = $tableRow[2]; 805 $tableType = $tableRow[3]; 806 807 if (!$tableName) 808 continue; 809 810 if ($ttype == '' && (strcmp($tableType,'TABLE') <> 0 && strcmp($tableType,'VIEW') <> 0)) 811 continue; 812 813 /* 814 * Set metacasing if required 815 */ 816 $tableName = $this->getMetaCasedValue($tableName); 817 818 /* 819 * If we requested a schema, we prepend the schema 820 name to the table name 821 */ 822 if (strcmp($schema,'%') <> 0) 823 $tableName = $schema . '.' . $tableName; 824 825 $tableList[] = $tableName; 826 827 } 828 return $tableList; 829 } 830 831 /** 832 * Return a list of indexes for a specified table 833 * 834 * We don't use db2_statistics as the function does not seem to play 835 * well with mixed case table names 836 * 837 * @param string $table 838 * @param bool $primary (optional) only return primary keys 839 * @param bool $owner (optional) not used in this driver 840 * 841 * @return string[] Array of indexes 842 */ 843 public function metaIndexes($table, $primary = false, $owner = false) { 844 845 global $ADODB_FETCH_MODE; 846 847 /* Array( 848 * [name_of_index] => Array( 849 * [unique] => true or false 850 * [columns] => Array( 851 * [0] => firstcol 852 * [1] => nextcol 853 * [2] => etc........ 854 * ) 855 * ) 856 * ) 857 */ 858 $indices = array(); 859 $primaryKeyName = ''; 860 861 $table = $this->getTableCasedValue($table); 862 863 864 $savem = $ADODB_FETCH_MODE; 865 $ADODB_FETCH_MODE = ADODB_FETCH_NUM; 866 $this->setFetchMode(ADODB_FETCH_NUM); 867 868 $sql = "SELECT * 869 FROM syscat.indexes 870 WHERE tabname='$table'"; 871 872 $rows = $this->getAll($sql); 873 874 $this->setFetchMode($savem); 875 $ADODB_FETCH_MODE = $savem; 876 877 if (empty($rows)) 878 return false; 879 880 foreach ($rows as $r) 881 { 882 883 $primaryIndex = $r[7] == 'P'?1:0; 884 if (!$primary) 885 /* 886 * Primary key not requested, ignore that one 887 */ 888 if ($r[7] == 'P') 889 continue; 890 891 $indexName = $this->getMetaCasedValue($r[1]); 892 if (!isset($indices[$indexName])) 893 { 894 $unique = ($r[7] == 'U')?1:0; 895 $indices[$indexName] = array('unique'=>$unique, 896 'primary'=>$primaryIndex, 897 'columns'=>array() 898 ); 899 } 900 $cols = explode('+',$r[6]); 901 foreach ($cols as $colIndex=>$col) 902 { 903 if ($colIndex == 0) 904 continue; 905 $columnName = $this->getMetaCasedValue($col); 906 $indices[$indexName]['columns'][] = $columnName; 907 } 908 909 } 910 911 return $indices; 912 913 } 914 915 /** 916 * List procedures or functions in an array. 917 * 918 * We interrogate syscat.routines instead of calling the PHP 919 * function procedures because ADOdb requires the type of procedure 920 * this is not available in the php function 921 * 922 * @param string $procedureNamePattern (optional) 923 * @param string $catalog (optional) 924 * @param string $schemaPattern (optional) 925 926 * @return array of procedures on current database. 927 * 928 */ 929 public function metaProcedures($procedureNamePattern = null, $catalog = null, $schemaPattern = null) { 930 931 932 global $ADODB_FETCH_MODE; 933 934 $metaProcedures = array(); 935 $procedureSQL = ''; 936 $catalogSQL = ''; 937 $schemaSQL = ''; 938 939 $savem = $ADODB_FETCH_MODE; 940 $ADODB_FETCH_MODE = ADODB_FETCH_NUM; 941 942 if ($procedureNamePattern) 943 $procedureSQL = "AND ROUTINENAME LIKE " . strtoupper($this->qstr($procedureNamePattern)); 944 945 if ($catalog) 946 $catalogSQL = "AND OWNER=" . strtoupper($this->qstr($catalog)); 947 948 if ($schemaPattern) 949 $schemaSQL = "AND ROUTINESCHEMA LIKE {$this->qstr($schemaPattern)}"; 950 951 952 $fields = " 953 ROUTINENAME, 954 CASE ROUTINETYPE 955 WHEN 'P' THEN 'PROCEDURE' 956 WHEN 'F' THEN 'FUNCTION' 957 ELSE 'METHOD' 958 END AS ROUTINETYPE_NAME, 959 ROUTINESCHEMA, 960 REMARKS"; 961 962 $SQL = "SELECT $fields 963 FROM syscat.routines 964 WHERE OWNER IS NOT NULL 965 $procedureSQL 966 $catalogSQL 967 $schemaSQL 968 ORDER BY ROUTINENAME 969 "; 970 971 $result = $this->execute($SQL); 972 973 $ADODB_FETCH_MODE = $savem; 974 975 if (!$result) 976 return false; 977 978 while ($r = $result->fetchRow()){ 979 $procedureName = $this->getMetaCasedValue($r[0]); 980 $schemaName = $this->getMetaCasedValue($r[2]); 981 $metaProcedures[$procedureName] = array('type'=> $r[1], 982 'catalog' => '', 983 'schema' => $schemaName, 984 'remarks' => $r[3] 985 ); 986 } 987 988 return $metaProcedures; 989 990 } 991 992 /** 993 * Lists databases. Because instances are independent, we only know about 994 * the current database name 995 * 996 * @return string[] 997 */ 998 public function metaDatabases(){ 999 1000 $dbName = $this->getMetaCasedValue($this->databaseName); 1001 1002 return (array)$dbName; 1003 1004 } 1005 1006 1007 1008 1009 /* 1010 See http://msdn.microsoft.com/library/default.asp?url=/library/en-us/db2/htm/db2datetime_data_type_changes.asp 1011 / SQL data type codes / 1012 #define SQL_UNKNOWN_TYPE 0 1013 #define SQL_CHAR 1 1014 #define SQL_NUMERIC 2 1015 #define SQL_DECIMAL 3 1016 #define SQL_INTEGER 4 1017 #define SQL_SMALLINT 5 1018 #define SQL_FLOAT 6 1019 #define SQL_REAL 7 1020 #define SQL_DOUBLE 8 1021 #if (DB2VER >= 0x0300) 1022 #define SQL_DATETIME 9 1023 #endif 1024 #define SQL_VARCHAR 12 1025 1026 1027 / One-parameter shortcuts for date/time data types / 1028 #if (DB2VER >= 0x0300) 1029 #define SQL_TYPE_DATE 91 1030 #define SQL_TYPE_TIME 92 1031 #define SQL_TYPE_TIMESTAMP 93 1032 1033 #define SQL_UNICODE (-95) 1034 #define SQL_UNICODE_VARCHAR (-96) 1035 #define SQL_UNICODE_LONGVARCHAR (-97) 1036 */ 1037 function DB2Types($t) 1038 { 1039 switch ((integer)$t) { 1040 case 1: 1041 case 12: 1042 case 0: 1043 case -95: 1044 case -96: 1045 return 'C'; 1046 case -97: 1047 case -1: //text 1048 return 'X'; 1049 case -4: //image 1050 return 'B'; 1051 1052 case 9: 1053 case 91: 1054 return 'D'; 1055 1056 case 10: 1057 case 11: 1058 case 92: 1059 case 93: 1060 return 'T'; 1061 1062 case 4: 1063 case 5: 1064 case -6: 1065 return 'I'; 1066 1067 case -11: // uniqidentifier 1068 return 'R'; 1069 case -7: //bit 1070 return 'L'; 1071 1072 default: 1073 return 'N'; 1074 } 1075 } 1076 1077 public function metaColumns($table, $normalize=true) 1078 { 1079 global $ADODB_FETCH_MODE; 1080 1081 $savem = $ADODB_FETCH_MODE; 1082 1083 $schema = '%'; 1084 $this->_findschema($table,$schema); 1085 $table = $this->getTableCasedValue($table); 1086 $colname = "%"; 1087 $qid = db2_columns($this->_connectionID, null, $schema, $table, $colname); 1088 if (empty($qid)) 1089 { 1090 if ($this->debug) 1091 { 1092 $errorMessage = @db2_conn_errormsg($this->_connectionID); 1093 ADOConnection::outp($errorMessage); 1094 } 1095 return false; 1096 } 1097 1098 $rs = new ADORecordSet_db2($qid); 1099 1100 if (!$rs) 1101 return false; 1102 1103 $rs->_fetch(); 1104 1105 $retarr = array(); 1106 1107 /* 1108 $rs->fields indices 1109 0 TABLE_QUALIFIER 1110 1 TABLE_SCHEM 1111 2 TABLE_NAME 1112 3 COLUMN_NAME 1113 4 DATA_TYPE 1114 5 TYPE_NAME 1115 6 PRECISION 1116 7 LENGTH 1117 8 SCALE 1118 9 RADIX 1119 10 NULLABLE 1120 11 REMARKS 1121 12 Column Default 1122 13 SQL Data Type 1123 14 SQL DateTime SubType 1124 15 Max length in Octets 1125 16 Ordinal Position 1126 17 Is NULLABLE 1127 */ 1128 while (!$rs->EOF) 1129 { 1130 if ($rs->fields[2] == $table) 1131 { 1132 1133 $fld = new ADOFieldObject(); 1134 $fld->name = $rs->fields[3]; 1135 $fld->type = $this->DB2Types($rs->fields[4]); 1136 1137 // ref: http://msdn.microsoft.com/library/default.asp?url=/archive/en-us/dnaraccgen/html/msdn_odk.asp 1138 // access uses precision to store length for char/varchar 1139 1140 if ($fld->type == 'C' or $fld->type == 'X') { 1141 if ($rs->fields[4] <= -95) // UNICODE 1142 $fld->max_length = $rs->fields[7]/2; 1143 else 1144 $fld->max_length = $rs->fields[7]; 1145 } else 1146 $fld->max_length = $rs->fields[7]; 1147 1148 $fld->not_null = !empty($rs->fields[10]); 1149 $fld->scale = $rs->fields[8]; 1150 $fld->primary_key = false; 1151 1152 //$columnName = $this->getMetaCasedValue($fld->name); 1153 $columnName = strtoupper($fld->name); 1154 $retarr[$columnName] = $fld; 1155 1156 } 1157 else if (sizeof($retarr)>0) 1158 break; 1159 1160 $rs->MoveNext(); 1161 1162 } 1163 1164 $rs->Close(); 1165 if (empty($retarr)) 1166 $retarr = false; 1167 1168 /* 1169 * Now we find out if the column is part of a primary key 1170 */ 1171 1172 $qid = @db2_primary_keys($this->_connectionID, "", $schema, $table); 1173 if (empty($qid)) 1174 return false; 1175 1176 $rs = new ADORecordSet_db2($qid); 1177 1178 if (!$rs) 1179 { 1180 $ADODB_FETCH_MODE = $savem; 1181 return $retarr; 1182 } 1183 $rs->_fetch(); 1184 1185 /* 1186 $rs->fields indices 1187 0 TABLE_CAT 1188 1 TABLE_SCHEM 1189 2 TABLE_NAME 1190 3 COLUMN_NAME 1191 4 KEY_SEQ 1192 5 PK_NAME 1193 */ 1194 while (!$rs->EOF) { 1195 if (strtoupper(trim($rs->fields[2])) == $table 1196 && (!$schema || strtoupper($rs->fields[1]) == $schema)) 1197 { 1198 $retarr[strtoupper($rs->fields[3])]->primary_key = true; 1199 } 1200 else if (sizeof($retarr)>0) 1201 break; 1202 1203 $rs->MoveNext(); 1204 } 1205 $rs->Close(); 1206 1207 $ADODB_FETCH_MODE = $savem; 1208 1209 if (empty($retarr)) 1210 return false; 1211 1212 /* 1213 * If the fetch mode is numeric, return as numeric array 1214 */ 1215 if ($ADODB_FETCH_MODE == ADODB_FETCH_NUM) 1216 $retarr = array_values($retarr); 1217 1218 return $retarr; 1219 } 1220 1221 /** 1222 * In this version if prepareSp, we just check to make sure 1223 * that the name of the stored procedure is correct 1224 * If true, we returns an array 1225 * else false 1226 * 1227 * @param string $procedureName 1228 * @param mixed $parameters (not used in db2 connections) 1229 * @return mixed[] 1230 */ 1231 function prepareSp($procedureName,$parameters=false) { 1232 1233 global $ADODB_FETCH_MODE; 1234 1235 $this->storedProcedureParameters = array('name'=>'', 1236 'resource'=>false, 1237 'in'=>array(), 1238 'out'=>array(), 1239 'index'=>array(), 1240 'parameters'=>array(), 1241 'keyvalue' => array()); 1242 1243 //$procedureName = strtoupper($procedureName); 1244 //$procedureName = $this->getTableCasedValue($procedureName); 1245 1246 $savem = $ADODB_FETCH_MODE; 1247 $ADODB_FETCH_MODE = ADODB_FETCH_NUM; 1248 1249 $qid = db2_procedures($this->_connectionID, NULL , '%' , $procedureName ); 1250 1251 $ADODB_FETCH_MODE = $savem; 1252 1253 if (!$qid) 1254 { 1255 if ($this->debug) 1256 ADOConnection::outp(sprintf('No Procedure of name %s available',$procedureName)); 1257 return false; 1258 } 1259 1260 1261 1262 $this->storedProcedureParameters['name'] = $procedureName; 1263 /* 1264 * Now we know we have a valid procedure name, lets see if it requires 1265 * parameters 1266 */ 1267 $savem = $ADODB_FETCH_MODE; 1268 $ADODB_FETCH_MODE = ADODB_FETCH_NUM; 1269 1270 $qid = db2_procedure_columns($this->_connectionID, NULL , '%' , $procedureName , NULL ); 1271 1272 $ADODB_FETCH_MODE = $savem; 1273 1274 if (!$qid) 1275 { 1276 if ($this->debug) 1277 ADOConnection::outp(sprintf('No columns of name %s available',$procedureName)); 1278 return false; 1279 } 1280 $rs = new ADORecordSet_db2($qid); 1281 if (!$rs) 1282 return false; 1283 1284 $preparedStatement = 'CALL %s(%s)'; 1285 $parameterMarkers = array(); 1286 while (!$rs->EOF) 1287 { 1288 $parameterName = $rs->fields[3]; 1289 if ($parameterName == '') 1290 { 1291 $rs->moveNext(); 1292 continue; 1293 } 1294 $parameterType = $rs->fields[4]; 1295 $ordinalPosition = $rs->fields[17]; 1296 switch($parameterType) 1297 { 1298 case DB2_PARAM_IN: 1299 case DB2_PARAM_INOUT: 1300 $this->storedProcedureParameters['in'][$parameterName] = ''; 1301 break; 1302 case DB2_PARAM_INOUT: 1303 case DB2_PARAM_OUT: 1304 $this->storedProcedureParameters['out'][$parameterName] = ''; 1305 break; 1306 } 1307 $this->storedProcedureParameters['index'][$parameterName] = $ordinalPosition; 1308 $this->storedProcedureParameters['parameters'][$ordinalPosition] = $rs->fields; 1309 $rs->moveNext(); 1310 1311 } 1312 $parameterCount = count($this->storedProcedureParameters['index']); 1313 $parameterMarkers = array_fill(0,$parameterCount,'?'); 1314 1315 /* 1316 * We now know how many parameters to bind to the stored procedure 1317 */ 1318 $parameterList = implode(',',$parameterMarkers); 1319 1320 $sql = sprintf($preparedStatement,$procedureName,$parameterList); 1321 1322 $spResource = @db2_prepare($this->_connectionID,$sql); 1323 1324 if (!$spResource) 1325 { 1326 $errorMessage = @db2_conn_errormsg($this->_connectionID); 1327 $this->_errorMsg = $errorMessage; 1328 1329 if ($this->debug) 1330 ADOConnection::outp($errorMessage); 1331 1332 return false; 1333 } 1334 1335 $this->storedProcedureParameters['resource'] = $spResource; 1336 1337 if ($this->debug) 1338 { 1339 1340 ADOConnection::outp('The following parameters will be used in the SP call'); 1341 ADOConnection::outp(print_r($this->storedProcedureParameters)); 1342 } 1343 /* 1344 * We now have a stored parameter resource 1345 * to bind to. The spResource and sql that is returned are 1346 * not usable, its for dummy compatibility. Everything 1347 * will be handled by the storedProcedureParameters 1348 * array 1349 */ 1350 return array($sql,$spResource); 1351 1352 } 1353 1354 private function storedProcedureParameter(&$stmt, 1355 &$var, 1356 $name, 1357 $isOutput=false, 1358 $maxLen=4000, 1359 $type=false) 1360 { 1361 1362 1363 $name = strtoupper($name); 1364 1365 /* 1366 * Must exist in the list of parameter names for the type 1367 */ 1368 if ($isOutput 1369 && !isset( $this->storedProcedureParameters['out'][$name])) 1370 { 1371 $errorMessage = sprintf('%s is not a valid OUT parameter name',$name); 1372 1373 $this->_errorMsg = $errorMessage; 1374 if ($this->debug) 1375 ADOConnection::outp($errorMessage); 1376 return false; 1377 } 1378 1379 if (!$isOutput 1380 && !isset( $this->storedProcedureParameters['in'][$name])) 1381 { 1382 $errorMessage = sprintf('%s is not a valid IN parameter name',$name); 1383 1384 $this->_errorMsg = $errorMessage; 1385 if ($this->debug) 1386 ADOConnection::outp($errorMessage); 1387 return false; 1388 } 1389 1390 /* 1391 * We will use these values to bind to when we execute 1392 * the query 1393 */ 1394 $this->storedProcedureParameters['keyvalue'][$name] = &$var; 1395 1396 return true; 1397 1398 } 1399 1400 /** 1401 * Executes a prepared stored procedure. 1402 * 1403 * The function uses the previously accumulated information and 1404 * resources in the $storedProcedureParameters array 1405 * 1406 * @return mixed The statement id if successful, or false 1407 */ 1408 private function executeStoredProcedure() 1409 { 1410 1411 /* 1412 * Get the previously built resource 1413 */ 1414 $stmtid = $this->storedProcedureParameters['resource']; 1415 1416 /* 1417 * Bind our variables to the DB2 procedure 1418 */ 1419 foreach ($this->storedProcedureParameters['keyvalue'] as $spName=>$spValue){ 1420 1421 /* 1422 * Get the ordinal position, required for binding 1423 */ 1424 $ordinalPosition = $this->storedProcedureParameters['index'][$spName]; 1425 1426 /* 1427 * Get the db2 column dictionary for the parameter 1428 */ 1429 $columnDictionary = $this->storedProcedureParameters['parameters'][$ordinalPosition]; 1430 $parameterType = $columnDictionary[4]; 1431 $dataType = $columnDictionary[5]; 1432 $precision = $columnDictionary[10]; 1433 $scale = $columnDictionary[9]; 1434 1435 $ok = @db2_bind_param ($this->storedProcedureParameters['resource'], 1436 $ordinalPosition , 1437 $spName, 1438 $parameterType, 1439 $dataType, 1440 $precision, 1441 $scale 1442 ); 1443 1444 if (!$ok) 1445 { 1446 $this->_errorMsg = @db2_stmt_errormsg(); 1447 $this->_errorCode = @db2_stmt_error(); 1448 1449 if ($this->debug) 1450 ADOConnection::outp($this->_errorMsg); 1451 return false; 1452 } 1453 1454 if ($this->debug) 1455 ADOConnection::outp("Correctly Bound parameter $spName to procedure"); 1456 1457 /* 1458 * Build a variable in the current environment that matches 1459 * the parameter name 1460 */ 1461 ${$spName} = $spValue; 1462 1463 } 1464 1465 /* 1466 * All bound, execute 1467 */ 1468 1469 if (!@db2_execute($stmtid)) 1470 { 1471 $this->_errorMsg = @db2_stmt_errormsg(); 1472 $this->_errorCode = @db2_stmt_error(); 1473 1474 if ($this->debug) 1475 ADOConnection::outp($this->_errorMsg); 1476 return false; 1477 } 1478 1479 /* 1480 * We now take the changed parameters back into the 1481 * stored procedures array where we can query them later 1482 * Remember that $spValue was passed in by reference, so we 1483 * can access the value in the variable that was originally 1484 * passed to inParameter or outParameter 1485 */ 1486 foreach ($this->storedProcedureParameters['keyvalue'] as $spName=>$spValue) 1487 { 1488 /* 1489 * We make it available to the environment 1490 */ 1491 $spValue = ${$spName}; 1492 $this->storedProcedureParameters['keyvalue'][$spName] = $spValue; 1493 } 1494 1495 return $stmtid; 1496 } 1497 1498 /** 1499 * 1500 * Accepts an input or output parameter to bind to either a stored 1501 * or prepared statements. For DB2, this should not be called as an 1502 * API. always wrap with inParameter and outParameter 1503 * 1504 * @param mixed[] $stmt Statement returned by Prepare() or PrepareSP(). 1505 * @param mixed $var PHP variable to bind to. Can set to null (for isNull support). 1506 * @param string $name Name of stored procedure variable name to bind to. 1507 * @param int $isOutput optional) Indicates direction of parameter 1508 * 0/false=IN 1=OUT 2= IN/OUT 1509 * This is ignored for Stored Procedures 1510 * @param int $maxLen (optional)Holds an maximum length of the variable. 1511 * This is ignored for Stored Procedures 1512 * @param int $type (optional) The data type of $var. 1513 * This is ignored for Stored Procedures 1514 * 1515 * @return bool Success of the operation 1516 */ 1517 public function parameter(&$stmt, &$var, $name, $isOutput=false, $maxLen=4000, $type=false) 1518 { 1519 1520 /* 1521 * If the $stmt is the name of a stored procedure we are 1522 * setting up, we will process it one way, otherwise 1523 * we assume we are setting up a prepared statement 1524 */ 1525 if (is_array($stmt)) 1526 { 1527 if ($this->debug) 1528 ADOConnection::outp("Adding parameter to stored procedure"); 1529 if ($stmt[1] == $this->storedProcedureParameters['resource']) 1530 return $this->storedProcedureParameter($stmt[1], 1531 $var, 1532 $name, 1533 $isOutput, 1534 $maxLen, 1535 $type); 1536 1537 } 1538 1539 /* 1540 * We are going to add a parameter to a prepared statement 1541 */ 1542 if ($this->debug) 1543 ADOConnection::outp("Adding parameter to prepared statement"); 1544 } 1545 1546 1547 /** 1548 * Prepares a prepared SQL statement, not used for stored procedures 1549 * 1550 * @param string $sql 1551 * 1552 * @return mixed 1553 */ 1554 function prepare($sql) 1555 { 1556 1557 if (! $this->_bindInputArray) return $sql; // no binding 1558 1559 $stmt = @db2_prepare($this->_connectionID,$sql); 1560 if (!$stmt) { 1561 // we don't know whether db2 driver is parsing prepared stmts, so just return sql 1562 return $sql; 1563 } 1564 return array($sql,$stmt,false); 1565 } 1566 1567 /** 1568 * Executes a query 1569 * 1570 * @param mixed $sql 1571 * @param mixed $inputarr An optional array of parameters 1572 * 1573 * @return mixed either the queryID or false 1574 */ 1575 function _query(&$sql,$inputarr=false) 1576 { 1577 1578 $this->_error = ''; 1579 1580 $db2Options = array(); 1581 /* 1582 * Use DB2 Internal case handling for best speed 1583 */ 1584 switch(ADODB_ASSOC_CASE) 1585 { 1586 case ADODB_ASSOC_CASE_UPPER: 1587 $db2Options = array('db2_attr_case'=>DB2_CASE_UPPER); 1588 $setOption = @db2_set_option($this->_connectionID,$db2Options,1); 1589 break; 1590 1591 case ADODB_ASSOC_CASE_LOWER: 1592 $db2Options = array('db2_attr_case'=>DB2_CASE_LOWER); 1593 $setOption = @db2_set_option($this->_connectionID,$db2Options,1); 1594 break; 1595 1596 default: 1597 $db2Options = array('db2_attr_case'=>DB2_CASE_NATURAL); 1598 $setOption = @db2_set_option($this->_connectionID,$db2Options,1); 1599 } 1600 1601 if ($inputarr) 1602 { 1603 if (is_array($sql)) 1604 { 1605 $stmtid = $sql[1]; 1606 } 1607 else 1608 { 1609 $stmtid = @db2_prepare($this->_connectionID,$sql); 1610 1611 if ($stmtid == false) 1612 { 1613 $this->_errorMsg = @db2_stmt_errormsg(); 1614 $this->_errorCode = @db2_stmt_error(); 1615 1616 if ($this->debug) 1617 ADOConnection::outp($this->_errorMsg); 1618 1619 return false; 1620 } 1621 } 1622 1623 if (! @db2_execute($stmtid,$inputarr)) 1624 { 1625 $this->_errorMsg = @db2_stmt_errormsg(); 1626 $this->_errorCode = @db2_stmt_error(); 1627 if ($this->debug) 1628 ADOConnection::outp($this->_errorMsg); 1629 return false; 1630 } 1631 1632 } 1633 else if (is_array($sql)) 1634 { 1635 1636 /* 1637 * Either a prepared statement or a stored procedure 1638 */ 1639 1640 if (is_array($this->storedProcedureParameters) 1641 && is_resource($this->storedProcedureParameters['resource'] 1642 )) 1643 /* 1644 * This is all handled in the separate method for 1645 * readability 1646 */ 1647 return $this->executeStoredProcedure(); 1648 1649 /* 1650 * First, we prepare the statement 1651 */ 1652 $stmtid = @db2_prepare($this->_connectionID,$sql[0]); 1653 if (!$stmtid){ 1654 $this->_errorMsg = @db2_stmt_errormsg(); 1655 $this->_errorCode = @db2_stmt_error(); 1656 if ($this->debug) 1657 ADOConnection::outp("Prepare failed: " . $this->_errorMsg); 1658 1659 return false; 1660 } 1661 /* 1662 * We next bind some input parameters 1663 */ 1664 $ordinal = 1; 1665 foreach ($sql[1] as $psVar=>$psVal){ 1666 ${$psVar} = $psVal; 1667 $ok = @db2_bind_param($stmtid, $ordinal, $psVar, DB2_PARAM_IN); 1668 if (!$ok) 1669 { 1670 $this->_errorMsg = @db2_stmt_errormsg(); 1671 $this->_errorCode = @db2_stmt_error(); 1672 if ($this->debug) 1673 ADOConnection::outp("Bind failed: " . $this->_errorMsg); 1674 return false; 1675 } 1676 } 1677 1678 if (!@db2_execute($stmtid)) 1679 { 1680 $this->_errorMsg = @db2_stmt_errormsg(); 1681 $this->_errorCode = @db2_stmt_error(); 1682 if ($this->debug) 1683 ADOConnection::outp($this->_errorMsg); 1684 return false; 1685 } 1686 1687 return $stmtid; 1688 } 1689 else 1690 { 1691 1692 $stmtid = @db2_exec($this->_connectionID,$sql); 1693 } 1694 $this->_lastAffectedRows = 0; 1695 if ($stmtid) 1696 { 1697 if (@db2_num_fields($stmtid) == 0) 1698 { 1699 $this->_lastAffectedRows = db2_num_rows($stmtid); 1700 $stmtid = true; 1701 } 1702 else 1703 { 1704 $this->_lastAffectedRows = 0; 1705 } 1706 1707 $this->_errorMsg = ''; 1708 $this->_errorCode = 0; 1709 1710 } 1711 else 1712 { 1713 1714 $this->_errorMsg = @db2_stmt_errormsg(); 1715 $this->_errorCode = @db2_stmt_error(); 1716 1717 } 1718 return $stmtid; 1719 } 1720 1721 /* 1722 Insert a null into the blob field of the table first. 1723 Then use UpdateBlob to store the blob. 1724 1725 Usage: 1726 1727 $conn->execute('INSERT INTO blobtable (id, blobcol) VALUES (1, null)'); 1728 $conn->UpdateBlob('blobtable','blobcol',$blob,'id=1'); 1729 */ 1730 function updateBlob($table,$column,$val,$where,$blobtype='BLOB') 1731 { 1732 return $this->execute("UPDATE $table SET $column=? WHERE $where",array($val)) != false; 1733 } 1734 1735 // returns true or false 1736 function _close() 1737 { 1738 $ret = @db2_close($this->_connectionID); 1739 $this->_connectionID = false; 1740 return $ret; 1741 } 1742 1743 function _affectedrows() 1744 { 1745 return $this->_lastAffectedRows; 1746 } 1747 1748 /** 1749 * Gets a meta cased parameter 1750 * 1751 * Receives an input variable to be processed per the metaCasing 1752 * rule, and returns the same value, processed 1753 * 1754 * @param string $value 1755 * 1756 * @return string 1757 */ 1758 final public function getMetaCasedValue($value) 1759 { 1760 global $ADODB_ASSOC_CASE; 1761 1762 switch($ADODB_ASSOC_CASE) 1763 { 1764 case ADODB_ASSOC_CASE_LOWER: 1765 $value = strtolower($value); 1766 break; 1767 case ADODB_ASSOC_CASE_UPPER: 1768 $value = strtoupper($value); 1769 break; 1770 } 1771 return $value; 1772 } 1773 1774 1775 const TABLECASE_LOWER = 0; 1776 const TABLECASE_UPPER = 1; 1777 const TABLECASE_DEFAULT = 2; 1778 1779 /** 1780 * Controls the casing of the table provided to the meta functions 1781 */ 1782 private $tableCase = 2; 1783 1784 /** 1785 * Sets the table case parameter 1786 * 1787 * @param int $caseOption 1788 * @return null 1789 */ 1790 final public function setTableCasing($caseOption) 1791 { 1792 $this->tableCase = $caseOption; 1793 } 1794 1795 /** 1796 * Gets the table casing parameter 1797 * 1798 * @return int $caseOption 1799 */ 1800 final public function getTableCasing() 1801 { 1802 return $this->tableCase; 1803 } 1804 1805 /** 1806 * Gets a table cased parameter 1807 * 1808 * Receives an input variable to be processed per the tableCasing 1809 * rule, and returns the same value, processed 1810 * 1811 * @param string $value 1812 * 1813 * @return string 1814 */ 1815 final public function getTableCasedValue($value) 1816 { 1817 switch($this->tableCase) 1818 { 1819 case self::TABLECASE_LOWER: 1820 $value = strtolower($value); 1821 break; 1822 case self::TABLECASE_UPPER: 1823 $value = strtoupper($value); 1824 break; 1825 } 1826 return $value; 1827 } 1828 1829 } 1830 1831 /*-------------------------------------------------------------------------------------- 1832 Class Name: Recordset 1833 --------------------------------------------------------------------------------------*/ 1834 1835 class ADORecordSet_db2 extends ADORecordSet { 1836 1837 var $bind = false; 1838 var $databaseType = "db2"; 1839 var $dataProvider = "db2"; 1840 var $useFetchArray; 1841 1842 function __construct($id,$mode=false) 1843 { 1844 if ($mode === false) { 1845 global $ADODB_FETCH_MODE; 1846 $mode = $ADODB_FETCH_MODE; 1847 } 1848 $this->fetchMode = $mode; 1849 1850 $this->_queryID = $id; 1851 } 1852 1853 1854 // returns the field object 1855 function fetchField($offset = 0) 1856 { 1857 $o = new ADOFieldObject(); 1858 $o->name = @db2_field_name($this->_queryID,$offset); 1859 $o->type = @db2_field_type($this->_queryID,$offset); 1860 $o->max_length = @db2_field_width($this->_queryID,$offset); 1861 1862 /* 1863 if (ADODB_ASSOC_CASE == 0) 1864 $o->name = strtolower($o->name); 1865 else if (ADODB_ASSOC_CASE == 1) 1866 $o->name = strtoupper($o->name); 1867 */ 1868 return $o; 1869 } 1870 1871 /* Use associative array to get fields array */ 1872 function fields($colname) 1873 { 1874 1875 if ($this->fetchMode & ADODB_FETCH_ASSOC) { 1876 return $this->fields[$colname]; 1877 } 1878 1879 if (!$this->bind) { 1880 $this->bind = array(); 1881 for ($i=0; $i < $this->_numOfFields; $i++) { 1882 $o = $this->FetchField($i); 1883 $this->bind[strtoupper($o->name)] = $i; 1884 } 1885 } 1886 1887 return $this->fields[$this->bind[strtoupper($colname)]]; 1888 } 1889 1890 1891 function _initrs() 1892 { 1893 global $ADODB_COUNTRECS; 1894 $this->_numOfRows = ($ADODB_COUNTRECS) ? @db2_num_rows($this->_queryID) : -1; 1895 1896 $this->_numOfFields = @db2_num_fields($this->_queryID); 1897 1898 // some silly drivers such as db2 as/400 and intersystems cache return _numOfRows = 0 1899 1900 if ($this->_numOfRows == 0) 1901 $this->_numOfRows = -1; 1902 } 1903 1904 function _seek($row) 1905 { 1906 return false; 1907 } 1908 1909 function getArrayLimit($nrows,$offset=0) 1910 { 1911 if ($offset <= 0) { 1912 $rs = $this->GetArray($nrows); 1913 return $rs; 1914 } 1915 1916 $this->Move($offset); 1917 1918 1919 $results = array(); 1920 $cnt = 0; 1921 while (!$this->EOF && $nrows != $cnt) { 1922 $results[$cnt++] = $this->fields; 1923 $this->MoveNext(); 1924 } 1925 1926 return $results; 1927 } 1928 1929 function moveNext() 1930 { 1931 if ($this->EOF || $this->_numOfRows == 0) 1932 return false; 1933 1934 $this->_currentRow++; 1935 1936 $this->processCoreFetch(); 1937 return $this->processMoveRecord(); 1938 1939 } 1940 1941 private function processCoreFetch() 1942 { 1943 switch ($this->fetchMode){ 1944 case ADODB_FETCH_ASSOC: 1945 1946 /* 1947 * Associative array 1948 */ 1949 $this->fields = @db2_fetch_assoc($this->_queryID); 1950 break; 1951 1952 case ADODB_FETCH_BOTH: 1953 /* 1954 * Fetch both numeric and Associative array 1955 */ 1956 $this->fields = @db2_fetch_both($this->_queryID); 1957 break; 1958 default: 1959 /* 1960 * Numeric array 1961 */ 1962 $this->fields = @db2_fetch_array($this->_queryID); 1963 break; 1964 } 1965 } 1966 1967 private function processMoveRecord() 1968 { 1969 if (!$this->fields){ 1970 $this->EOF = true; 1971 return false; 1972 } 1973 1974 return true; 1975 } 1976 1977 function _fetch() 1978 { 1979 $this->processCoreFetch(); 1980 if ($this->fields) 1981 return true; 1982 1983 $this->fields = false; 1984 return false; 1985 } 1986 1987 function _close() 1988 { 1989 $ok = @db2_free_result($this->_queryID); 1990 if (!$ok) 1991 { 1992 $this->_errorMsg = @db2_stmt_errormsg($this->_queryId); 1993 $this->_errorCode = @db2_stmt_error(); 1994 1995 if ($this->debug) 1996 ADOConnection::outp($this->_errorMsg); 1997 return false; 1998 } 1999 2000 } 2001 2002 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body