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