Differences Between: [Versions 310 and 311] [Versions 311 and 400] [Versions 311 and 401] [Versions 311 and 402] [Versions 311 and 403] [Versions 39 and 311]
1 <?php 2 /** 3 @version v5.21.0 2021-02-27 4 @copyright (c) 2000-2013 John Lim (jlim#natsoft.com). All rights reserved. 5 @copyright (c) 2014 Damien Regad, Mark Newnham and the ADOdb community 6 Released under both BSD license and Lesser GPL library license. 7 Whenever there is any discrepancy between the two licenses, 8 the BSD license will take precedence. 9 10 Set tabs to 4 for best viewing. 11 12 * Driver for use with IBM DB2 Native Client 13 * 14 * Originally DB2 drivers were dependent on an ODBC driver, and some installations 15 * may still use that. To use an ODBC driver connection, use the odbc_db2 16 * ADOdb driver. For Linux, you need the 'ibm_db2' PECL extension for PHP, 17 * For Windows, you need to locate an appropriate version of the php_ibm_db2.dll, 18 * as well as the IBM data server client software. 19 * This is basically a full rewrite of the original driver, for information 20 * about all the changes, see the update information on the ADOdb website 21 * for version 5.21.0 22 * 23 * @link http://pecl.php.net/package/ibm_db2 Pecl Extension For DB2 24 * @author Mark Newnham 25 */ 26 27 // security - hide paths 28 if (!defined('ADODB_DIR')) die(); 29 30 define("_ADODB_DB2_LAYER", 2 ); 31 32 /*-------------------------------------------------------------------- 33 ----------------------------------------------------------------------*/ 34 35 36 class ADODB_db2 extends ADOConnection { 37 var $databaseType = "db2"; 38 var $fmtDate = "'Y-m-d'"; 39 var $concat_operator = '||'; 40 41 var $sysTime = 'CURRENT TIME'; 42 var $sysDate = 'CURRENT DATE'; 43 var $sysTimeStamp = 'CURRENT TIMESTAMP'; 44 45 var $fmtTimeStamp = "'Y-m-d H:i:s'"; 46 var $replaceQuote = "''"; // string to use to replace quotes 47 var $dataProvider = "db2"; 48 var $hasAffectedRows = true; 49 50 var $binmode = DB2_BINARY; 51 52 /* 53 * setting this to true will make array elements in FETCH_ASSOC 54 * mode case-sensitive breaking backward-compat 55 */ 56 var $useFetchArray = false; 57 var $_bindInputArray = true; 58 var $_genIDSQL = "VALUES NEXTVAL FOR %s"; 59 var $_genSeqSQL = " 60 CREATE SEQUENCE %s START WITH %s 61 NO MAXVALUE NO CYCLE INCREMENT BY 1 NO CACHE 62 "; 63 var $_dropSeqSQL = "DROP SEQUENCE %s"; 64 var $_autocommit = true; 65 var $_lastAffectedRows = 0; 66 var $hasInsertID = true; 67 var $hasGenID = true; 68 69 /* 70 * Character used to wrap column and table names for escaping special 71 * characters in column and table names as well as forcing upper and 72 * lower case 73 */ 74 public $nameQuote = '"'; 75 76 /* 77 * Executed after successful connection 78 */ 79 public $connectStmt = ''; 80 81 /* 82 * Holds the current database name 83 */ 84 private $databaseName = ''; 85 86 /* 87 * Holds information about the stored procedure request 88 * currently being built 89 */ 90 private $storedProcedureParameters = false; 91 92 93 function __construct() {} 94 95 function _insertid() 96 { 97 return ADOConnection::GetOne('VALUES IDENTITY_VAL_LOCAL()'); 98 } 99 100 public function _connect($argDSN, $argUsername, $argPassword, $argDatabasename) 101 { 102 return $this->doDB2Connect($argDSN, $argUsername, $argPassword, $argDatabasename); 103 } 104 105 public function _pconnect($argDSN, $argUsername, $argPassword, $argDatabasename) 106 { 107 return $this->doDB2Connect($argDSN, $argUsername, $argPassword, $argDatabasename,true); 108 } 109 110 private function doDB2Connect($argDSN, $argUsername, $argPassword, $argDatabasename, $persistent=false) 111 { 112 113 if (!function_exists('db2_connect')) { 114 ADOConnection::outp("DB2 extension not installed."); 115 return null; 116 } 117 118 $connectionParameters = $this->unpackParameters($argDSN, 119 $argUsername, 120 $argPassword, 121 $argDatabasename); 122 123 if ($connectionParameters == null) 124 { 125 /* 126 * Error thrown 127 */ 128 return null; 129 } 130 131 $argDSN = $connectionParameters['dsn']; 132 $argUsername = $connectionParameters['uid']; 133 $argPassword = $connectionParameters['pwd']; 134 $argDatabasename = $connectionParameters['database']; 135 $useCataloguedConnection = $connectionParameters['catalogue']; 136 137 if ($this->debug){ 138 if ($useCataloguedConnection){ 139 $connectMessage = "Catalogued connection using parameters: "; 140 $connectMessage .= "DB=$argDatabasename / "; 141 $connectMessage .= "UID=$argUsername / "; 142 $connectMessage .= "PWD=$argPassword"; 143 } 144 else 145 { 146 $connectMessage = "Uncatalogued connection using DSN: $argDSN"; 147 } 148 ADOConnection::outp($connectMessage); 149 } 150 /* 151 * This needs to be set before the connect(). 152 */ 153 ini_set('ibm_db2.binmode', $this->binmode); 154 155 if ($persistent) 156 $db2Function = 'db2_pconnect'; 157 else 158 $db2Function = 'db2_connect'; 159 160 /* 161 * We need to flatten out the connectionParameters 162 */ 163 164 $db2Options = array(); 165 if ($this->connectionParameters) 166 { 167 foreach($this->connectionParameters as $p) 168 foreach($p as $k=>$v) 169 $db2Options[$k] = $v; 170 } 171 172 if ($useCataloguedConnection) 173 $this->_connectionID = $db2Function($argDatabasename, 174 $argUsername, 175 $argPassword, 176 $db2Options); 177 else 178 $this->_connectionID = $db2Function($argDSN, 179 null, 180 null, 181 $db2Options); 182 183 $this->_errorMsg = @db2_conn_errormsg(); 184 185 if ($this->_connectionID && $this->connectStmt) 186 $this->execute($this->connectStmt); 187 188 return $this->_connectionID != false; 189 190 } 191 192 /** 193 * Validates and preprocesses the passed parameters for consistency 194 * 195 * @param string $argDSN Either DSN or database 196 * @param string $argUsername User name or null 197 * @param string $argPassword Password or null 198 * @param string $argDatabasename Either DSN or database 199 * 200 * @return mixed array if correct, null if not 201 */ 202 private function unpackParameters($argDSN, $argUsername, $argPassword, $argDatabasename) 203 { 204 205 $connectionParameters = array('dsn'=>'', 206 'uid'=>'', 207 'pwd'=>'', 208 'database'=>'', 209 'catalogue'=>true 210 ); 211 212 /* 213 * Uou can either connect to a catalogued connection 214 * with a database name e.g. 'SAMPLE' 215 * or an uncatalogued connection with a DSN like connection 216 * DATABASE=database;HOSTNAME=hostname;PORT=port;PROTOCOL=TCPIP;UID=username;PWD=password; 217 */ 218 219 if (!$argDSN && !$argDatabasename) 220 { 221 $errorMessage = 'Supply either catalogued or uncatalogued connection parameters'; 222 $this->_errorMsg = $errorMessage; 223 if ($this->debug) 224 ADOConnection::outp($errorMessage); 225 return null; 226 } 227 228 $useCataloguedConnection = true; 229 $schemaName = ''; 230 231 if ($argDSN && $argDatabasename) 232 { 233 /* 234 * If a catalogued connection if provided, 235 * as well as user and password 236 * that will take priority 237 */ 238 if ($argUsername && $argPassword && !$this->isDsn($argDatabasename)) 239 { 240 if ($this->debug){ 241 $errorMessage = 'Warning: Because you provided user,'; 242 $errorMessage.= 'password and database, DSN connection '; 243 $errorMessage.= 'parameters were discarded'; 244 ADOConnection::outp($errorMessage); 245 246 } 247 $argDSN = ''; 248 } 249 else if ($this->isDsn($argDSN) && $this->isDsn($argDatabasename)) 250 { 251 $errorMessage = 'Supply uncatalogued connection parameters '; 252 $errorMessage.= 'in either the database or DSN arguments, '; 253 $errorMessage.= 'but not both'; 254 if ($this->debug) 255 ADOConnection::outp($errorMessage); 256 return null; 257 } 258 } 259 260 if (!$this->isDsn($argDSN) && $this->isDsn($argDatabasename)) 261 { 262 /* 263 * Switch them around for next test 264 */ 265 $temp = $argDSN; 266 $argDsn = $argDatabasename; 267 $argDatabasenME = $temp; 268 } 269 270 if ($this->isDsn($argDSN)) 271 { 272 273 if (!preg_match('/uid=/i',$argDSN) 274 || !preg_match('/pwd=/i',$argDSN)) 275 { 276 $errorMessage = 'For uncatalogued connections, provide '; 277 $errorMessage.= 'both UID and PWD in the connection string'; 278 if ($this->debug) 279 ADOConnection::outp($errorMessage); 280 return null; 281 } 282 283 if (preg_match('/database=/i',$argDSN)) 284 { 285 if ($argDatabasename) 286 { 287 $argDatabasename = ''; 288 if ($this->debug) 289 { 290 $errorMessage = 'Warning: Because you provided '; 291 $errorMessage.= 'database information in the DSN '; 292 $errorMessage.= 'parameters, the supplied database '; 293 $errorMessage.= 'name was discarded'; 294 ADOConnection::outp($errorMessage); 295 } 296 } 297 $useCataloguedConnection = false; 298 299 } 300 elseif ($argDatabasename) 301 { 302 $this->databaseName = $argDatabasename; 303 $argDSN .= ';database=' . $argDatabasename; 304 $argDatabasename = ''; 305 $useCataloguedConnection = false; 306 307 } 308 else 309 { 310 $errorMessage = 'Uncatalogued connection parameters '; 311 $errorMessage.= 'must contain a database= argument'; 312 if ($this->debug) 313 ADOConnection::outp($errorMessage); 314 return null; 315 } 316 } 317 318 if ($argDSN && !$argDatabasename && $useCataloguedConnection) 319 { 320 $argDatabasename = $argDSN; 321 $argDSN = ''; 322 } 323 324 325 if ($useCataloguedConnection 326 && (!$argDatabasename 327 || !$argUsername 328 || !$argPassword)) 329 { 330 331 $errorMessage = 'For catalogued connections, provide '; 332 $errorMessage.= 'database, username and password'; 333 $this->_errorMsg = $errorMessage; 334 if ($this->debug) 335 ADOConnection::outp($errorMessage); 336 return null; 337 338 } 339 340 if ($argDatabasename) 341 $this->databaseName = $argDatabasename; 342 elseif (!$this->databaseName) 343 $this->databaseName = $this->getDatabasenameFromDsn($argDSN); 344 345 346 $connectionParameters = array('dsn'=>$argDSN, 347 'uid'=>$argUsername, 348 'pwd'=>$argPassword, 349 'database'=>$argDatabasename, 350 'catalogue'=>$useCataloguedConnection 351 ); 352 353 return $connectionParameters; 354 355 } 356 357 /** 358 * Does the provided string look like a DSN 359 * 360 * @param string $dsnString 361 * 362 * @return bool 363 */ 364 private function isDsn($dsnString){ 365 $dsnArray = preg_split('/[;=]+/',$dsnString); 366 if (count($dsnArray) > 2) 367 return true; 368 return false; 369 } 370 371 372 /** 373 * Gets the database name from the DSN 374 * 375 * @param string $dsnString 376 * 377 * @return string 378 */ 379 private function getDatabasenameFromDsn($dsnString){ 380 381 $dsnArray = preg_split('/[;=]+/',$dsnString); 382 $dbIndex = array_search('database',$dsnArray); 383 384 return $dsnArray[$dbIndex + 1]; 385 } 386 387 388 /** 389 * format and return date string in database timestamp format 390 * 391 * @param mixed $ts either a string or a unixtime 392 * @param bool $isField discarded 393 * 394 * @return string 395 */ 396 function dbTimeStamp($ts,$isField=false) 397 { 398 if (empty($ts) && $ts !== 0) return 'null'; 399 if (is_string($ts)) $ts = ADORecordSet::unixTimeStamp($ts); 400 return 'TO_DATE('.adodb_date($this->fmtTimeStamp,$ts).",'YYYY-MM-DD HH24:MI:SS')"; 401 } 402 403 /** 404 * Format date column in sql string given an input format that understands Y M D 405 * 406 * @param string $fmt 407 * @param bool $col 408 * 409 * @return string 410 */ 411 function sqlDate($fmt, $col=false) 412 { 413 if (!$col) $col = $this->sysDate; 414 415 /* use TO_CHAR() if $fmt is TO_CHAR() allowed fmt */ 416 if ($fmt== 'Y-m-d H:i:s') 417 return 'TO_CHAR('.$col.", 'YYYY-MM-DD HH24:MI:SS')"; 418 419 $s = ''; 420 421 $len = strlen($fmt); 422 for ($i=0; $i < $len; $i++) { 423 if ($s) $s .= $this->concat_operator; 424 $ch = $fmt[$i]; 425 switch($ch) { 426 case 'Y': 427 case 'y': 428 if ($len==1) return "year($col)"; 429 $s .= "char(year($col))"; 430 break; 431 case 'M': 432 if ($len==1) return "monthname($col)"; 433 $s .= "substr(monthname($col),1,3)"; 434 break; 435 case 'm': 436 if ($len==1) return "month($col)"; 437 $s .= "right(digits(month($col)),2)"; 438 break; 439 case 'D': 440 case 'd': 441 if ($len==1) return "day($col)"; 442 $s .= "right(digits(day($col)),2)"; 443 break; 444 case 'H': 445 case 'h': 446 if ($len==1) return "hour($col)"; 447 if ($col != $this->sysDate) $s .= "right(digits(hour($col)),2)"; 448 else $s .= "''"; 449 break; 450 case 'i': 451 case 'I': 452 if ($len==1) return "minute($col)"; 453 if ($col != $this->sysDate) 454 $s .= "right(digits(minute($col)),2)"; 455 else $s .= "''"; 456 break; 457 case 'S': 458 case 's': 459 if ($len==1) return "second($col)"; 460 if ($col != $this->sysDate) 461 $s .= "right(digits(second($col)),2)"; 462 else $s .= "''"; 463 break; 464 default: 465 if ($ch == '\\') { 466 $i++; 467 $ch = substr($fmt,$i,1); 468 } 469 $s .= $this->qstr($ch); 470 } 471 } 472 return $s; 473 } 474 475 476 function serverInfo() 477 { 478 $sql = "SELECT service_level, fixpack_num 479 FROM TABLE(sysproc.env_get_inst_info()) 480 AS INSTANCEINFO"; 481 $row = $this->GetRow($sql); 482 483 484 if ($row) { 485 $info['version'] = $row[0].':'.$row[1]; 486 $info['fixpack'] = $row[1]; 487 $info['description'] = ''; 488 } else { 489 return ADOConnection::serverInfo(); 490 } 491 492 return $info; 493 } 494 495 function createSequence($seqname='adodbseq',$start=1) 496 { 497 if (empty($this->_genSeqSQL)) 498 return false; 499 500 $ok = $this->execute(sprintf($this->_genSeqSQL,$seqname,$start)); 501 if (!$ok) 502 return false; 503 return true; 504 } 505 506 function dropSequence($seqname='adodbseq') 507 { 508 if (empty($this->_dropSeqSQL)) return false; 509 return $this->execute(sprintf($this->_dropSeqSQL,$seqname)); 510 } 511 512 function selectLimit($sql,$nrows=-1,$offset=-1,$inputArr=false,$secs2cache=0) 513 { 514 $nrows = (integer) $nrows; 515 516 if ($offset <= 0) 517 { 518 if ($nrows >= 0) 519 $sql .= " FETCH FIRST $nrows ROWS ONLY "; 520 521 $rs = $this->execute($sql,$inputArr); 522 523 } 524 else 525 { 526 if ($offset > 0 && $nrows < 0); 527 528 else 529 { 530 $nrows += $offset; 531 $sql .= " FETCH FIRST $nrows ROWS ONLY "; 532 } 533 534 /* 535 * DB2 has no native support for mid table offset 536 */ 537 $rs = ADOConnection::selectLimit($sql,$nrows,$offset,$inputArr); 538 539 } 540 541 return $rs; 542 } 543 544 545 function errorMsg() 546 { 547 if ($this->_errorMsg !== false) 548 return $this->_errorMsg; 549 550 if (empty($this->_connectionID)) 551 return @db2_conn_errormsg(); 552 553 return @db2_conn_errormsg($this->_connectionID); 554 } 555 556 function errorNo() 557 { 558 559 if ($this->_errorCode !== false) 560 return $this->_errorCode; 561 562 563 if (empty($this->_connectionID)) 564 $e = @db2_conn_error(); 565 566 else 567 $e = @db2_conn_error($this->_connectionID); 568 569 return $e; 570 } 571 572 573 574 function beginTrans() 575 { 576 if (!$this->hasTransactions) 577 return false; 578 if ($this->transOff) 579 return true; 580 581 $this->transCnt += 1; 582 583 $this->_autocommit = false; 584 585 return db2_autocommit($this->_connectionID,false); 586 } 587 588 function CommitTrans($ok=true) 589 { 590 if ($this->transOff) 591 return true; 592 593 if (!$ok) 594 return $this->RollbackTrans(); 595 596 if ($this->transCnt) 597 $this->transCnt -= 1; 598 599 $this->_autocommit = true; 600 $ret = @db2_commit($this->_connectionID); 601 @db2_autocommit($this->_connectionID,true); 602 return $ret; 603 } 604 605 function RollbackTrans() 606 { 607 if ($this->transOff) return true; 608 if ($this->transCnt) $this->transCnt -= 1; 609 $this->_autocommit = true; 610 $ret = @db2_rollback($this->_connectionID); 611 @db2_autocommit($this->_connectionID,true); 612 return $ret; 613 } 614 615 /** 616 * Return a list of Primary Keys for a specified table 617 * 618 * We don't use db2_statistics as the function does not seem to play 619 * well with mixed case table names 620 * 621 * @param string $table 622 * @param bool $primary (optional) only return primary keys 623 * @param bool $owner (optional) not used in this driver 624 * 625 * @return string[] Array of indexes 626 */ 627 public function metaPrimaryKeys($table,$owner=false) 628 { 629 630 $primaryKeys = array(); 631 632 global $ADODB_FETCH_MODE; 633 634 $schema = ''; 635 $this->_findschema($table,$schema); 636 637 $table = $this->getTableCasedValue($table); 638 639 $savem = $ADODB_FETCH_MODE; 640 $ADODB_FETCH_MODE = ADODB_FETCH_NUM; 641 $this->setFetchMode(ADODB_FETCH_NUM); 642 643 644 $sql = "SELECT * 645 FROM syscat.indexes 646 WHERE tabname='$table'"; 647 648 $rows = $this->getAll($sql); 649 650 $this->setFetchMode($savem); 651 $ADODB_FETCH_MODE = $savem; 652 653 if (empty($rows)) 654 return false; 655 656 foreach ($rows as $r) 657 { 658 if ($r[7] != 'P') 659 continue; 660 661 $cols = explode('+',$r[6]); 662 foreach ($cols as $colIndex=>$col) 663 { 664 if ($colIndex == 0) 665 continue; 666 $columnName = $this->getMetaCasedValue($col); 667 $primaryKeys[] = $columnName; 668 } 669 break; 670 } 671 return $primaryKeys; 672 } 673 674 /** 675 * returns assoc array where keys are tables, and values are foreign keys 676 * 677 * @param string $table 678 * @param string $owner [optional][discarded] 679 * @param bool $upper [optional][discarded] 680 * @param bool $associative[optional][discarded] 681 * 682 * @return mixed[] Array of foreign key information 683 */ 684 public function metaForeignKeys($table, $owner = FALSE, $upper = FALSE, $asociative = 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->databaseName); 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 1574 $this->_error = ''; 1575 1576 $db2Options = array(); 1577 /* 1578 * Use DB2 Internal case handling for best speed 1579 */ 1580 switch(ADODB_ASSOC_CASE) 1581 { 1582 case ADODB_ASSOC_CASE_UPPER: 1583 $db2Options = array('db2_attr_case'=>DB2_CASE_UPPER); 1584 $setOption = @db2_set_option($this->_connectionID,$db2Options,1); 1585 break; 1586 1587 case ADODB_ASSOC_CASE_LOWER: 1588 $db2Options = array('db2_attr_case'=>DB2_CASE_LOWER); 1589 $setOption = @db2_set_option($this->_connectionID,$db2Options,1); 1590 break; 1591 1592 default: 1593 $db2Options = array('db2_attr_case'=>DB2_CASE_NATURAL); 1594 $setOption = @db2_set_option($this->_connectionID,$db2Options,1); 1595 } 1596 1597 $db2Options = array('db2_attr_case'=>DB2_CASE_LOWER); 1598 $setOption = @db2_set_option($this->_connectionID,$db2Options,1); 1599 1600 if ($inputarr) 1601 { 1602 if (is_array($sql)) 1603 { 1604 $stmtid = $sql[1]; 1605 } 1606 else 1607 { 1608 $stmtid = @db2_prepare($this->_connectionID,$sql); 1609 1610 if ($stmtid == false) 1611 { 1612 $this->_errorMsg = @db2_stmt_errormsg(); 1613 $this->_errorCode = @db2_stmt_error(); 1614 1615 if ($this->debug) 1616 ADOConnection::outp($this->_errorMsg); 1617 1618 return false; 1619 } 1620 } 1621 1622 if (! @db2_execute($stmtid,$inputarr)) 1623 { 1624 $this->_errorMsg = @db2_stmt_errormsg(); 1625 $this->_errorCode = @db2_stmt_error(); 1626 if ($this->debug) 1627 ADOConnection::outp($this->_errorMsg); 1628 return false; 1629 } 1630 1631 } 1632 else if (is_array($sql)) 1633 { 1634 1635 /* 1636 * Either a prepared statement or a stored procedure 1637 */ 1638 1639 if (is_array($this->storedProcedureParameters) 1640 && is_resource($this->storedProcedureParameters['resource'] 1641 )) 1642 /* 1643 * This is all handled in the separate method for 1644 * readability 1645 */ 1646 return $this->executeStoredProcedure(); 1647 1648 /* 1649 * First, we prepare the statement 1650 */ 1651 $stmtid = @db2_prepare($this->_connectionID,$sql[0]); 1652 if (!$stmtid){ 1653 $this->_errorMsg = @db2_stmt_errormsg(); 1654 $this->_errorCode = @db2_stmt_error(); 1655 if ($this->debug) 1656 ADOConnection::outp("Prepare failed: " . $this->_errorMsg); 1657 1658 return false; 1659 } 1660 /* 1661 * We next bind some input parameters 1662 */ 1663 $ordinal = 1; 1664 foreach ($sql[1] as $psVar=>$psVal){ 1665 ${$psVar} = $psVal; 1666 $ok = @db2_bind_param($stmtid, $ordinal, $psVar, DB2_PARAM_IN); 1667 if (!$ok) 1668 { 1669 $this->_errorMsg = @db2_stmt_errormsg(); 1670 $this->_errorCode = @db2_stmt_error(); 1671 if ($this->debug) 1672 ADOConnection::outp("Bind failed: " . $this->_errorMsg); 1673 return false; 1674 } 1675 } 1676 1677 if (!@db2_execute($stmtid)) 1678 { 1679 $this->_errorMsg = @db2_stmt_errormsg(); 1680 $this->_errorCode = @db2_stmt_error(); 1681 if ($this->debug) 1682 ADOConnection::outp($this->_errorMsg); 1683 return false; 1684 } 1685 1686 return $stmtid; 1687 } 1688 else 1689 { 1690 1691 $stmtid = @db2_exec($this->_connectionID,$sql); 1692 } 1693 $this->_lastAffectedRows = 0; 1694 if ($stmtid) 1695 { 1696 if (@db2_num_fields($stmtid) == 0) 1697 { 1698 $this->_lastAffectedRows = db2_num_rows($stmtid); 1699 $stmtid = true; 1700 } 1701 else 1702 { 1703 $this->_lastAffectedRows = 0; 1704 } 1705 1706 $this->_errorMsg = ''; 1707 $this->_errorCode = 0; 1708 1709 } 1710 else 1711 { 1712 1713 $this->_errorMsg = @db2_stmt_errormsg(); 1714 $this->_errorCode = @db2_stmt_error(); 1715 1716 } 1717 return $stmtid; 1718 } 1719 1720 /* 1721 Insert a null into the blob field of the table first. 1722 Then use UpdateBlob to store the blob. 1723 1724 Usage: 1725 1726 $conn->execute('INSERT INTO blobtable (id, blobcol) VALUES (1, null)'); 1727 $conn->UpdateBlob('blobtable','blobcol',$blob,'id=1'); 1728 */ 1729 function updateBlob($table,$column,$val,$where,$blobtype='BLOB') 1730 { 1731 return $this->execute("UPDATE $table SET $column=? WHERE $where",array($val)) != false; 1732 } 1733 1734 // returns true or false 1735 function _close() 1736 { 1737 $ret = @db2_close($this->_connectionID); 1738 $this->_connectionID = false; 1739 return $ret; 1740 } 1741 1742 function _affectedrows() 1743 { 1744 return $this->_lastAffectedRows; 1745 } 1746 1747 /** 1748 * Gets a meta cased parameter 1749 * 1750 * Receives an input variable to be processed per the metaCasing 1751 * rule, and returns the same value, processed 1752 * 1753 * @param string $value 1754 * 1755 * @return string 1756 */ 1757 final public function getMetaCasedValue($value) 1758 { 1759 global $ADODB_ASSOC_CASE; 1760 1761 switch($ADODB_ASSOC_CASE) 1762 { 1763 case ADODB_ASSOC_CASE_LOWER: 1764 $value = strtolower($value); 1765 break; 1766 case ADODB_ASSOC_CASE_UPPER: 1767 $value = strtoupper($value); 1768 break; 1769 } 1770 return $value; 1771 } 1772 1773 1774 const TABLECASE_LOWER = 0; 1775 const TABLECASE_UPPER = 1; 1776 const TABLECASE_DEFAULT = 2; 1777 1778 /* 1779 * Controls the casing of the table provided to the meta functions 1780 */ 1781 private $tableCase = 2; 1782 1783 /** 1784 * Sets the table case parameter 1785 * 1786 * @param int $caseOption 1787 * @return null 1788 */ 1789 final public function setTableCasing($caseOption) 1790 { 1791 $this->tableCase = $caseOption; 1792 } 1793 1794 /** 1795 * Gets the table casing parameter 1796 * 1797 * @return int $caseOption 1798 */ 1799 final public function getTableCasing() 1800 { 1801 return $this->tableCase; 1802 } 1803 1804 /** 1805 * Gets a table cased parameter 1806 * 1807 * Receives an input variable to be processed per the tableCasing 1808 * rule, and returns the same value, processed 1809 * 1810 * @param string $value 1811 * 1812 * @return string 1813 */ 1814 final public function getTableCasedValue($value) 1815 { 1816 switch($this->tableCase) 1817 { 1818 case self::TABLECASE_LOWER: 1819 $value = strtolower($value); 1820 break; 1821 case self::TABLECASE_UPPER: 1822 $value = strtoupper($value); 1823 break; 1824 } 1825 return $value; 1826 } 1827 1828 } 1829 1830 /*-------------------------------------------------------------------------------------- 1831 Class Name: Recordset 1832 --------------------------------------------------------------------------------------*/ 1833 1834 class ADORecordSet_db2 extends ADORecordSet { 1835 1836 var $bind = false; 1837 var $databaseType = "db2"; 1838 var $dataProvider = "db2"; 1839 var $useFetchArray; 1840 1841 function __construct($id,$mode=false) 1842 { 1843 if ($mode === false) { 1844 global $ADODB_FETCH_MODE; 1845 $mode = $ADODB_FETCH_MODE; 1846 } 1847 $this->fetchMode = $mode; 1848 1849 $this->_queryID = $id; 1850 } 1851 1852 1853 // returns the field object 1854 function fetchField($offset = 0) 1855 { 1856 $o = new ADOFieldObject(); 1857 $o->name = @db2_field_name($this->_queryID,$offset); 1858 $o->type = @db2_field_type($this->_queryID,$offset); 1859 $o->max_length = @db2_field_width($this->_queryID,$offset); 1860 1861 /* 1862 if (ADODB_ASSOC_CASE == 0) 1863 $o->name = strtolower($o->name); 1864 else if (ADODB_ASSOC_CASE == 1) 1865 $o->name = strtoupper($o->name); 1866 */ 1867 return $o; 1868 } 1869 1870 /* Use associative array to get fields array */ 1871 function fields($colname) 1872 { 1873 1874 if ($this->fetchMode & ADODB_FETCH_ASSOC) { 1875 return $this->fields[$colname]; 1876 } 1877 1878 if (!$this->bind) { 1879 $this->bind = array(); 1880 for ($i=0; $i < $this->_numOfFields; $i++) { 1881 $o = $this->FetchField($i); 1882 $this->bind[strtoupper($o->name)] = $i; 1883 } 1884 } 1885 1886 return $this->fields[$this->bind[strtoupper($colname)]]; 1887 } 1888 1889 1890 function _initrs() 1891 { 1892 global $ADODB_COUNTRECS; 1893 $this->_numOfRows = ($ADODB_COUNTRECS) ? @db2_num_rows($this->_queryID) : -1; 1894 1895 $this->_numOfFields = @db2_num_fields($this->_queryID); 1896 1897 // some silly drivers such as db2 as/400 and intersystems cache return _numOfRows = 0 1898 1899 if ($this->_numOfRows == 0) 1900 $this->_numOfRows = -1; 1901 } 1902 1903 function _seek($row) 1904 { 1905 return false; 1906 } 1907 1908 function getArrayLimit($nrows,$offset=0) 1909 { 1910 if ($offset <= 0) { 1911 $rs = $this->GetArray($nrows); 1912 return $rs; 1913 } 1914 1915 $this->Move($offset); 1916 1917 1918 $results = array(); 1919 $cnt = 0; 1920 while (!$this->EOF && $nrows != $cnt) { 1921 $results[$cnt++] = $this->fields; 1922 $this->MoveNext(); 1923 } 1924 1925 return $results; 1926 } 1927 1928 function moveNext() 1929 { 1930 if ($this->EOF || $this->_numOfRows == 0) 1931 return false; 1932 1933 $this->_currentRow++; 1934 1935 $this->processCoreFetch(); 1936 return $this->processMoveRecord(); 1937 1938 } 1939 1940 private function processCoreFetch() 1941 { 1942 switch ($this->fetchMode){ 1943 case ADODB_FETCH_ASSOC: 1944 1945 /* 1946 * Associative array 1947 */ 1948 $this->fields = @db2_fetch_assoc($this->_queryID); 1949 break; 1950 1951 case ADODB_FETCH_BOTH: 1952 /* 1953 * Fetch both numeric and Associative array 1954 */ 1955 $this->fields = @db2_fetch_both($this->_queryID); 1956 break; 1957 default: 1958 /* 1959 * Numeric array 1960 */ 1961 $this->fields = @db2_fetch_array($this->_queryID); 1962 break; 1963 } 1964 } 1965 1966 private function processMoveRecord() 1967 { 1968 if (!$this->fields){ 1969 $this->EOF = true; 1970 return false; 1971 } 1972 1973 return true; 1974 } 1975 1976 function _fetch() 1977 { 1978 $this->processCoreFetch(); 1979 if ($this->fields) 1980 return true; 1981 1982 $this->fields = false; 1983 return false; 1984 } 1985 1986 function _close() 1987 { 1988 $ok = @db2_free_result($this->_queryID); 1989 if (!$ok) 1990 { 1991 $this->_errorMsg = @db2_stmt_errormsg($this->_queryId); 1992 $this->_errorCode = @db2_stmt_error(); 1993 1994 if ($this->debug) 1995 ADOConnection::outp($this->_errorMsg); 1996 return false; 1997 } 1998 1999 } 2000 2001 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body