PageRenderTime 66ms CodeModel.GetById 21ms RepoModel.GetById 0ms app.codeStats 1ms

/lib/adodb/adodb.inc.php

https://bitbucket.org/moodle/moodle
PHP | 5455 lines | 3159 code | 627 blank | 1669 comment | 632 complexity | 470e7a5f694f8db952c7b9f0472aafa8 MD5 | raw file
Possible License(s): Apache-2.0, LGPL-2.1, BSD-3-Clause, MIT, GPL-3.0

Large files files are truncated, but you can click here to view the full file

  1. <?php
  2. /*
  3. * Set tabs to 4 for best viewing.
  4. *
  5. * Latest version is available at https://adodb.org/
  6. *
  7. * This is the main include file for ADOdb.
  8. * Database specific drivers are stored in the adodb/drivers/adodb-*.inc.php
  9. *
  10. * The ADOdb files are formatted so that doxygen can be used to generate documentation.
  11. * Doxygen is a documentation generation tool and can be downloaded from http://doxygen.org/
  12. */
  13. /**
  14. \mainpage
  15. @version v5.21.0 2021-02-27
  16. @copyright (c) 2000-2013 John Lim (jlim#natsoft.com). All rights reserved.
  17. @copyright (c) 2014 Damien Regad, Mark Newnham and the ADOdb community
  18. Released under both BSD license and Lesser GPL library license. You can choose which license
  19. you prefer.
  20. PHP's database access functions are not standardised. This creates a need for a database
  21. class library to hide the differences between the different database API's (encapsulate
  22. the differences) so we can easily switch databases.
  23. We currently support MySQL, Oracle, Microsoft SQL Server, Sybase, Sybase SQL Anywhere, DB2,
  24. Informix, PostgreSQL, FrontBase, Interbase (Firebird and Borland variants), Foxpro, Access,
  25. ADO, SAP DB, SQLite and ODBC. We have had successful reports of connecting to Progress and
  26. other databases via ODBC.
  27. */
  28. if (!defined('_ADODB_LAYER')) {
  29. define('_ADODB_LAYER',1);
  30. // The ADOdb extension is no longer maintained and effectively unsupported
  31. // since v5.04. The library will not function properly if it is present.
  32. if(defined('ADODB_EXTENSION')) {
  33. $msg = "Unsupported ADOdb Extension (v" . ADODB_EXTENSION . ") detected! "
  34. . "Disable it to use ADOdb";
  35. $errorfn = defined('ADODB_ERROR_HANDLER') ? ADODB_ERROR_HANDLER : false;
  36. if ($errorfn) {
  37. $conn = false;
  38. $errorfn('ADOdb', basename(__FILE__), -9999, $msg, null, null, $conn);
  39. } else {
  40. die($msg . PHP_EOL);
  41. }
  42. }
  43. //==============================================================================================
  44. // CONSTANT DEFINITIONS
  45. //==============================================================================================
  46. /**
  47. * Set ADODB_DIR to the directory where this file resides...
  48. * This constant was formerly called $ADODB_RootPath
  49. */
  50. if (!defined('ADODB_DIR')) {
  51. define('ADODB_DIR',dirname(__FILE__));
  52. }
  53. //==============================================================================================
  54. // GLOBAL VARIABLES
  55. //==============================================================================================
  56. GLOBAL
  57. $ADODB_vers, // database version
  58. $ADODB_COUNTRECS, // count number of records returned - slows down query
  59. $ADODB_CACHE_DIR, // directory to cache recordsets
  60. $ADODB_CACHE,
  61. $ADODB_CACHE_CLASS,
  62. $ADODB_COMPAT_FETCH, // If $ADODB_COUNTRECS and this is true, $rs->fields is available on EOF
  63. $ADODB_FETCH_MODE, // DEFAULT, NUM, ASSOC or BOTH. Default follows native driver default...
  64. $ADODB_GETONE_EOF,
  65. $ADODB_QUOTE_FIELDNAMES; // Allows you to force quotes (backticks) around field names in queries generated by getinsertsql and getupdatesql.
  66. //==============================================================================================
  67. // GLOBAL SETUP
  68. //==============================================================================================
  69. /*********************************************************
  70. * Controls $ADODB_FORCE_TYPE mode. Default is ADODB_FORCE_VALUE (3).
  71. * Used in GetUpdateSql and GetInsertSql functions. Thx to Niko, nuko#mbnet.fi
  72. * @link https://adodb.org/dokuwiki/doku.php?id=v5:reference:adodb_force_type
  73. *
  74. * 0 = ignore empty fields. All empty fields in array are ignored.
  75. * 1 = force null. All empty, php null and string 'null' fields are
  76. * changed to sql NULL values.
  77. * 2 = force empty. All empty, php null and string 'null' fields are
  78. * changed to sql empty '' or 0 values.
  79. * 3 = force value. Value is left as it is. Php null and string 'null'
  80. * are set to sql NULL values and empty fields '' are set to empty '' sql values.
  81. * 4 = force value. Like 1 but numeric empty fields are set to zero.
  82. */
  83. define('ADODB_FORCE_IGNORE',0);
  84. define('ADODB_FORCE_NULL',1);
  85. define('ADODB_FORCE_EMPTY',2);
  86. define('ADODB_FORCE_VALUE',3);
  87. define('ADODB_FORCE_NULL_AND_ZERO',4);
  88. // ********************************************************
  89. /**
  90. * Constants for returned values from the charMax and textMax methods.
  91. * If not specifically defined in the driver, methods return the NOTSET value.
  92. */
  93. define ('ADODB_STRINGMAX_NOTSET', -1);
  94. define ('ADODB_STRINGMAX_NOLIMIT',-2);
  95. /*
  96. * Defines the the default meta type returned
  97. * when ADOdb encounters a type that it is not
  98. * defined in the metaTypes.
  99. */
  100. if (!defined('ADODB_DEFAULT_METATYPE'))
  101. define ('ADODB_DEFAULT_METATYPE','N');
  102. define('ADODB_BAD_RS','<p>Bad $rs in %s. Connection or SQL invalid. Try using $connection->debug=true;</p>');
  103. // allow [ ] @ ` " and . in table names
  104. define('ADODB_TABLE_REGEX','([]0-9a-z_\:\"\`\.\@\[-]*)');
  105. // prefetching used by oracle
  106. if (!defined('ADODB_PREFETCH_ROWS')) {
  107. define('ADODB_PREFETCH_ROWS',10);
  108. }
  109. /**
  110. * Fetch mode
  111. *
  112. * Set global variable $ADODB_FETCH_MODE to one of these constants or use
  113. * the SetFetchMode() method to control how recordset fields are returned
  114. * when fetching data.
  115. *
  116. * - NUM: array()
  117. * - ASSOC: array('id' => 456, 'name' => 'john')
  118. * - BOTH: array(0 => 456, 'id' => 456, 1 => 'john', 'name' => 'john')
  119. * - DEFAULT: driver-dependent
  120. */
  121. define('ADODB_FETCH_DEFAULT', 0);
  122. define('ADODB_FETCH_NUM', 1);
  123. define('ADODB_FETCH_ASSOC', 2);
  124. define('ADODB_FETCH_BOTH', 3);
  125. /**
  126. * Associative array case constants
  127. *
  128. * By defining the ADODB_ASSOC_CASE constant to one of these values, it is
  129. * possible to control the case of field names (associative array's keys)
  130. * when operating in ADODB_FETCH_ASSOC fetch mode.
  131. * - LOWER: $rs->fields['orderid']
  132. * - UPPER: $rs->fields['ORDERID']
  133. * - NATIVE: $rs->fields['OrderID'] (or whatever the RDBMS will return)
  134. *
  135. * The default is to use native case-names.
  136. *
  137. * NOTE: This functionality is not implemented everywhere, it currently
  138. * works only with: mssql, odbc, oci8 and ibase derived drivers
  139. */
  140. define('ADODB_ASSOC_CASE_LOWER', 0);
  141. define('ADODB_ASSOC_CASE_UPPER', 1);
  142. define('ADODB_ASSOC_CASE_NATIVE', 2);
  143. if (!defined('TIMESTAMP_FIRST_YEAR')) {
  144. define('TIMESTAMP_FIRST_YEAR',100);
  145. }
  146. /**
  147. * AutoExecute constants
  148. * (moved from adodb-pear.inc.php since they are only used in here)
  149. */
  150. define('DB_AUTOQUERY_INSERT', 1);
  151. define('DB_AUTOQUERY_UPDATE', 2);
  152. function ADODB_Setup() {
  153. GLOBAL
  154. $ADODB_vers, // database version
  155. $ADODB_COUNTRECS, // count number of records returned - slows down query
  156. $ADODB_CACHE_DIR, // directory to cache recordsets
  157. $ADODB_FETCH_MODE,
  158. $ADODB_CACHE,
  159. $ADODB_CACHE_CLASS,
  160. $ADODB_FORCE_TYPE,
  161. $ADODB_GETONE_EOF,
  162. $ADODB_QUOTE_FIELDNAMES;
  163. if (empty($ADODB_CACHE_CLASS)) {
  164. $ADODB_CACHE_CLASS = 'ADODB_Cache_File' ;
  165. }
  166. $ADODB_FETCH_MODE = ADODB_FETCH_DEFAULT;
  167. $ADODB_FORCE_TYPE = ADODB_FORCE_VALUE;
  168. $ADODB_GETONE_EOF = null;
  169. if (!isset($ADODB_CACHE_DIR)) {
  170. $ADODB_CACHE_DIR = '/tmp'; //(isset($_ENV['TMP'])) ? $_ENV['TMP'] : '/tmp';
  171. } else {
  172. // do not accept url based paths, eg. http:/ or ftp:/
  173. if (strpos($ADODB_CACHE_DIR,'://') !== false) {
  174. die("Illegal path http:// or ftp://");
  175. }
  176. }
  177. /**
  178. * ADODB version as a string.
  179. */
  180. $ADODB_vers = 'v5.21.0 2021-02-27';
  181. /**
  182. * Determines whether recordset->RecordCount() is used.
  183. * Set to false for highest performance -- RecordCount() will always return -1 then
  184. * for databases that provide "virtual" recordcounts...
  185. */
  186. if (!isset($ADODB_COUNTRECS)) {
  187. $ADODB_COUNTRECS = true;
  188. }
  189. }
  190. //==============================================================================================
  191. // CHANGE NOTHING BELOW UNLESS YOU ARE DESIGNING ADODB
  192. //==============================================================================================
  193. ADODB_Setup();
  194. //==============================================================================================
  195. // CLASS ADOFieldObject
  196. //==============================================================================================
  197. /**
  198. * Helper class for FetchFields -- holds info on a column
  199. */
  200. class ADOFieldObject {
  201. var $name = '';
  202. var $max_length=0;
  203. var $type="";
  204. /*
  205. // additional fields by dannym... (danny_milo@yahoo.com)
  206. var $not_null = false;
  207. // actually, this has already been built-in in the postgres, fbsql AND mysql module? ^-^
  208. // so we can as well make not_null standard (leaving it at "false" does not harm anyways)
  209. var $has_default = false; // this one I have done only in mysql and postgres for now ...
  210. // others to come (dannym)
  211. var $default_value; // default, if any, and supported. Check has_default first.
  212. */
  213. }
  214. function _adodb_safedate($s) {
  215. return str_replace(array("'", '\\'), '', $s);
  216. }
  217. // parse date string to prevent injection attack
  218. // date string will have one quote at beginning e.g. '3434343'
  219. function _adodb_safedateq($s) {
  220. $len = strlen($s);
  221. if ($s[0] !== "'") {
  222. $s2 = "'".$s[0];
  223. } else {
  224. $s2 = "'";
  225. }
  226. for($i=1; $i<$len; $i++) {
  227. $ch = $s[$i];
  228. if ($ch === '\\') {
  229. $s2 .= "'";
  230. break;
  231. } elseif ($ch === "'") {
  232. $s2 .= $ch;
  233. break;
  234. }
  235. $s2 .= $ch;
  236. }
  237. return strlen($s2) == 0 ? 'null' : $s2;
  238. }
  239. // for transaction handling
  240. function ADODB_TransMonitor($dbms, $fn, $errno, $errmsg, $p1, $p2, &$thisConnection) {
  241. //print "Errorno ($fn errno=$errno m=$errmsg) ";
  242. $thisConnection->_transOK = false;
  243. if ($thisConnection->_oldRaiseFn) {
  244. $errfn = $thisConnection->_oldRaiseFn;
  245. $errfn($dbms, $fn, $errno, $errmsg, $p1, $p2,$thisConnection);
  246. }
  247. }
  248. //------------------
  249. // class for caching
  250. class ADODB_Cache_File {
  251. var $createdir = true; // requires creation of temp dirs
  252. function __construct() {
  253. global $ADODB_INCLUDED_CSV;
  254. if (empty($ADODB_INCLUDED_CSV)) {
  255. include_once(ADODB_DIR.'/adodb-csvlib.inc.php');
  256. }
  257. }
  258. // write serialised recordset to cache item/file
  259. function writecache($filename, $contents, $debug, $secs2cache) {
  260. return adodb_write_file($filename, $contents,$debug);
  261. }
  262. // load serialised recordset and unserialise it
  263. function &readcache($filename, &$err, $secs2cache, $rsClass) {
  264. $rs = csv2rs($filename,$err,$secs2cache,$rsClass);
  265. return $rs;
  266. }
  267. // flush all items in cache
  268. function flushall($debug=false) {
  269. global $ADODB_CACHE_DIR;
  270. $rez = false;
  271. if (strlen($ADODB_CACHE_DIR) > 1) {
  272. $rez = $this->_dirFlush($ADODB_CACHE_DIR);
  273. if ($debug) {
  274. ADOConnection::outp( "flushall: $ADODB_CACHE_DIR<br><pre>\n". $rez."</pre>");
  275. }
  276. }
  277. return $rez;
  278. }
  279. // flush one file in cache
  280. function flushcache($f, $debug=false) {
  281. if (!@unlink($f)) {
  282. if ($debug) {
  283. ADOConnection::outp( "flushcache: failed for $f");
  284. }
  285. }
  286. }
  287. function getdirname($hash) {
  288. global $ADODB_CACHE_DIR;
  289. if (!isset($this->notSafeMode)) {
  290. $this->notSafeMode = !ini_get('safe_mode');
  291. }
  292. return ($this->notSafeMode) ? $ADODB_CACHE_DIR.'/'.substr($hash,0,2) : $ADODB_CACHE_DIR;
  293. }
  294. // create temp directories
  295. function createdir($hash, $debug) {
  296. global $ADODB_CACHE_PERMS;
  297. $dir = $this->getdirname($hash);
  298. if ($this->notSafeMode && !file_exists($dir)) {
  299. $oldu = umask(0);
  300. if (!@mkdir($dir, empty($ADODB_CACHE_PERMS) ? 0771 : $ADODB_CACHE_PERMS)) {
  301. if(!is_dir($dir) && $debug) {
  302. ADOConnection::outp("Cannot create $dir");
  303. }
  304. }
  305. umask($oldu);
  306. }
  307. return $dir;
  308. }
  309. /**
  310. * Private function to erase all of the files and subdirectories in a directory.
  311. *
  312. * Just specify the directory, and tell it if you want to delete the directory or just clear it out.
  313. * Note: $kill_top_level is used internally in the function to flush subdirectories.
  314. */
  315. function _dirFlush($dir, $kill_top_level = false) {
  316. if(!$dh = @opendir($dir)) return;
  317. while (($obj = readdir($dh))) {
  318. if($obj=='.' || $obj=='..') continue;
  319. $f = $dir.'/'.$obj;
  320. if (strpos($obj,'.cache')) {
  321. @unlink($f);
  322. }
  323. if (is_dir($f)) {
  324. $this->_dirFlush($f, true);
  325. }
  326. }
  327. if ($kill_top_level === true) {
  328. @rmdir($dir);
  329. }
  330. return true;
  331. }
  332. }
  333. //==============================================================================================
  334. // CLASS ADOConnection
  335. //==============================================================================================
  336. /**
  337. * Connection object. For connecting to databases, and executing queries.
  338. */
  339. abstract class ADOConnection {
  340. //
  341. // PUBLIC VARS
  342. //
  343. var $dataProvider = 'native';
  344. var $databaseType = ''; /// RDBMS currently in use, eg. odbc, mysql, mssql
  345. var $database = ''; /// Name of database to be used.
  346. var $host = ''; /// The hostname of the database server
  347. var $port = ''; /// The port of the database server
  348. var $user = ''; /// The username which is used to connect to the database server.
  349. var $password = ''; /// Password for the username. For security, we no longer store it.
  350. var $debug = false; /// if set to true will output sql statements
  351. var $maxblobsize = 262144; /// maximum size of blobs or large text fields (262144 = 256K)-- some db's die otherwise like foxpro
  352. var $concat_operator = '+'; /// default concat operator -- change to || for Oracle/Interbase
  353. var $substr = 'substr'; /// substring operator
  354. var $length = 'length'; /// string length ofperator
  355. var $random = 'rand()'; /// random function
  356. var $upperCase = 'upper'; /// uppercase function
  357. var $fmtDate = "'Y-m-d'"; /// used by DBDate() as the default date format used by the database
  358. var $fmtTimeStamp = "'Y-m-d, h:i:s A'"; /// used by DBTimeStamp as the default timestamp fmt.
  359. var $true = '1'; /// string that represents TRUE for a database
  360. var $false = '0'; /// string that represents FALSE for a database
  361. var $replaceQuote = "\\'"; /// string to use to replace quotes
  362. var $nameQuote = '"'; /// string to use to quote identifiers and names
  363. var $leftBracket = '['; /// left square bracked for t-sql styled column names
  364. var $rightBracket = ']'; /// right square bracked for t-sql styled column names
  365. var $charSet=false; /// character set to use - only for interbase, postgres and oci8
  366. var $metaDatabasesSQL = '';
  367. var $metaTablesSQL = '';
  368. var $uniqueOrderBy = false; /// All order by columns have to be unique
  369. var $emptyDate = '&nbsp;';
  370. var $emptyTimeStamp = '&nbsp;';
  371. var $lastInsID = false;
  372. //--
  373. var $hasInsertID = false; /// supports autoincrement ID?
  374. var $hasAffectedRows = false; /// supports affected rows for update/delete?
  375. var $hasTop = false; /// support mssql/access SELECT TOP 10 * FROM TABLE
  376. var $hasLimit = false; /// support pgsql/mysql SELECT * FROM TABLE LIMIT 10
  377. var $readOnly = false; /// this is a readonly database - used by phpLens
  378. var $hasMoveFirst = false; /// has ability to run MoveFirst(), scrolling backwards
  379. var $hasGenID = false; /// can generate sequences using GenID();
  380. var $hasTransactions = true; /// has transactions
  381. //--
  382. var $genID = 0; /// sequence id used by GenID();
  383. /** @var bool|callable Error function to call */
  384. var $raiseErrorFn = false;
  385. var $isoDates = false; /// accepts dates in ISO format
  386. var $cacheSecs = 3600; /// cache for 1 hour
  387. // memcache
  388. var $memCache = false; /// should we use memCache instead of caching in files
  389. var $memCacheHost; /// memCache host
  390. var $memCachePort = 11211; /// memCache port
  391. var $memCacheCompress = false; /// Use 'true' to store the item compressed (uses zlib, not supported w/memcached library)
  392. var $sysDate = false; /// name of function that returns the current date
  393. var $sysTimeStamp = false; /// name of function that returns the current timestamp
  394. var $sysUTimeStamp = false; // name of function that returns the current timestamp accurate to the microsecond or nearest fraction
  395. var $arrayClass = 'ADORecordSet_array'; /// name of class used to generate array recordsets, which are pre-downloaded recordsets
  396. var $noNullStrings = false; /// oracle specific stuff - if true ensures that '' is converted to ' '
  397. var $numCacheHits = 0;
  398. var $numCacheMisses = 0;
  399. var $pageExecuteCountRows = true;
  400. var $uniqueSort = false; /// indicates that all fields in order by must be unique
  401. var $leftOuter = false; /// operator to use for left outer join in WHERE clause
  402. var $rightOuter = false; /// operator to use for right outer join in WHERE clause
  403. var $ansiOuter = false; /// whether ansi outer join syntax supported
  404. var $autoRollback = false; // autoRollback on PConnect().
  405. var $poorAffectedRows = false; // affectedRows not working or unreliable
  406. /** @var bool|callable Execute function to call */
  407. var $fnExecute = false;
  408. /** @var bool|callable Cache execution function to call */
  409. var $fnCacheExecute = false;
  410. var $blobEncodeType = false; // false=not required, 'I'=encode to integer, 'C'=encode to char
  411. var $rsPrefix = "ADORecordSet_";
  412. var $autoCommit = true; /// do not modify this yourself - actually private
  413. var $transOff = 0; /// temporarily disable transactions
  414. var $transCnt = 0; /// count of nested transactions
  415. var $fetchMode=false;
  416. var $null2null = 'null'; // in autoexecute/getinsertsql/getupdatesql, this value will be converted to a null
  417. var $bulkBind = false; // enable 2D Execute array
  418. //
  419. // PRIVATE VARS
  420. //
  421. var $_oldRaiseFn = false;
  422. var $_transOK = null;
  423. var $_connectionID = false; /// The returned link identifier whenever a successful database connection is made.
  424. var $_errorMsg = false; /// A variable which was used to keep the returned last error message. The value will
  425. /// then returned by the errorMsg() function
  426. var $_errorCode = false; /// Last error code, not guaranteed to be used - only by oci8
  427. var $_queryID = false; /// This variable keeps the last created result link identifier
  428. var $_isPersistentConnection = false; /// A boolean variable to state whether its a persistent connection or normal connection. */
  429. var $_bindInputArray = false; /// set to true if ADOConnection.Execute() permits binding of array parameters.
  430. var $_evalAll = false;
  431. var $_affected = false;
  432. var $_logsql = false;
  433. var $_transmode = ''; // transaction mode
  434. /**
  435. * Default Constructor.
  436. * We define it even though it does not actually do anything. This avoids
  437. * getting a PHP Fatal error: Cannot call constructor if a subclass tries
  438. * to call its parent constructor.
  439. */
  440. public function __construct()
  441. {
  442. }
  443. /*
  444. * Additional parameters that may be passed to drivers in the connect string
  445. * Driver must be coded to accept the parameters
  446. */
  447. protected $connectionParameters = array();
  448. /**
  449. * Adds a parameter to the connection string.
  450. *
  451. * These parameters are added to the connection string when connecting,
  452. * if the driver is coded to use it.
  453. *
  454. * @param string $parameter The name of the parameter to set
  455. * @param string $value The value of the parameter
  456. *
  457. * @return null
  458. *
  459. * @example, for mssqlnative driver ('CharacterSet','UTF-8')
  460. */
  461. final public function setConnectionParameter($parameter,$value) {
  462. $this->connectionParameters[] = array($parameter=>$value);
  463. }
  464. /**
  465. * ADOdb version.
  466. *
  467. * @return string
  468. */
  469. static function Version() {
  470. global $ADODB_vers;
  471. // Semantic Version number matching regex
  472. $regex = '^[vV]?(\d+\.\d+\.\d+' // Version number (X.Y.Z) with optional 'V'
  473. . '(?:-(?:' // Optional preprod version: a '-'
  474. . 'dev|' // followed by 'dev'
  475. . '(?:(?:alpha|beta|rc)(?:\.\d+))' // or a preprod suffix and version number
  476. . '))?)(?:\s|$)'; // Whitespace or end of string
  477. if (!preg_match("/$regex/", $ADODB_vers, $matches)) {
  478. // This should normally not happen... Return whatever is between the start
  479. // of the string and the first whitespace (or the end of the string).
  480. self::outp("Invalid version number: '$ADODB_vers'", 'Version');
  481. $regex = '^[vV]?(.*?)(?:\s|$)';
  482. preg_match("/$regex/", $ADODB_vers, $matches);
  483. }
  484. return $matches[1];
  485. }
  486. /**
  487. * Get server version info.
  488. *
  489. * @return string[] An array with 2 elements: $arr['string'] is the description string,
  490. * and $arr[version] is the version (also a string).
  491. */
  492. function ServerInfo() {
  493. return array('description' => '', 'version' => '');
  494. }
  495. /**
  496. * Return true if connected to the database.
  497. *
  498. * @return bool
  499. */
  500. function IsConnected() {
  501. return !empty($this->_connectionID);
  502. }
  503. function _findvers($str) {
  504. if (preg_match('/([0-9]+\.([0-9\.])+)/',$str, $arr)) {
  505. return $arr[1];
  506. } else {
  507. return '';
  508. }
  509. }
  510. /**
  511. * All error messages go through this bottleneck function.
  512. *
  513. * You can define your own handler by defining the function name in ADODB_OUTP.
  514. *
  515. * @param string $msg Message to print
  516. * @param bool $newline True to add a newline after printing $msg
  517. */
  518. static function outp($msg,$newline=true) {
  519. global $ADODB_FLUSH,$ADODB_OUTP;
  520. if (defined('ADODB_OUTP')) {
  521. $fn = ADODB_OUTP;
  522. $fn($msg,$newline);
  523. return;
  524. } else if (isset($ADODB_OUTP)) {
  525. call_user_func($ADODB_OUTP,$msg,$newline);
  526. return;
  527. }
  528. if ($newline) {
  529. $msg .= "<br>\n";
  530. }
  531. if (isset($_SERVER['HTTP_USER_AGENT']) || !$newline) {
  532. echo $msg;
  533. } else {
  534. echo strip_tags($msg);
  535. }
  536. if (!empty($ADODB_FLUSH) && ob_get_length() !== false) {
  537. flush(); // do not flush if output buffering enabled - useless - thx to Jesse Mullan
  538. }
  539. }
  540. /**
  541. * Return the database server's current date and time.
  542. * @return int|false
  543. */
  544. function Time() {
  545. $rs = $this->_Execute("select $this->sysTimeStamp");
  546. if ($rs && !$rs->EOF) {
  547. return $this->UnixTimeStamp(reset($rs->fields));
  548. }
  549. return false;
  550. }
  551. /**
  552. * Parses the hostname to extract the port.
  553. * Overwrites $this->host and $this->port, only if a port is specified.
  554. * The Hostname can be fully or partially qualified,
  555. * ie: "db.mydomain.com:5432" or "ldaps://ldap.mydomain.com:636"
  556. * Any specified scheme such as ldap:// or ldaps:// is maintained.
  557. */
  558. protected function parseHostNameAndPort() {
  559. $parsed_url = parse_url($this->host);
  560. if (is_array($parsed_url) && isset($parsed_url['host']) && isset($parsed_url['port'])) {
  561. if ( isset($parsed_url['scheme']) ) {
  562. // If scheme is specified (ie: ldap:// or ldaps://, make sure we retain that.
  563. $this->host = $parsed_url['scheme'] . "://" . $parsed_url['host'];
  564. } else {
  565. $this->host = $parsed_url['host'];
  566. }
  567. $this->port = $parsed_url['port'];
  568. }
  569. }
  570. /**
  571. * Connect to database.
  572. *
  573. * @param string $argHostname Host to connect to
  574. * @param string $argUsername Userid to login
  575. * @param string $argPassword Associated password
  576. * @param string $argDatabaseName Database name
  577. * @param bool $forceNew Force new connection
  578. *
  579. * @return bool
  580. */
  581. function Connect($argHostname = "", $argUsername = "", $argPassword = "", $argDatabaseName = "", $forceNew = false) {
  582. if ($argHostname != "") {
  583. $this->host = $argHostname;
  584. }
  585. // Overwrites $this->host and $this->port if a port is specified.
  586. $this->parseHostNameAndPort();
  587. if ($argUsername != "") {
  588. $this->user = $argUsername;
  589. }
  590. if ($argPassword != "") {
  591. $this->password = 'not stored'; // not stored for security reasons
  592. }
  593. if ($argDatabaseName != "") {
  594. $this->database = $argDatabaseName;
  595. }
  596. $this->_isPersistentConnection = false;
  597. if ($forceNew) {
  598. if ($rez=$this->_nconnect($this->host, $this->user, $argPassword, $this->database)) {
  599. return true;
  600. }
  601. } else {
  602. if ($rez=$this->_connect($this->host, $this->user, $argPassword, $this->database)) {
  603. return true;
  604. }
  605. }
  606. if (isset($rez)) {
  607. $err = $this->ErrorMsg();
  608. $errno = $this->ErrorNo();
  609. if (empty($err)) {
  610. $err = "Connection error to server '$argHostname' with user '$argUsername'";
  611. }
  612. } else {
  613. $err = "Missing extension for ".$this->dataProvider;
  614. $errno = 0;
  615. }
  616. if ($fn = $this->raiseErrorFn) {
  617. $fn($this->databaseType, 'CONNECT', $errno, $err, $this->host, $this->database, $this);
  618. }
  619. $this->_connectionID = false;
  620. if ($this->debug) {
  621. ADOConnection::outp( $this->host.': '.$err);
  622. }
  623. return false;
  624. }
  625. function _nconnect($argHostname, $argUsername, $argPassword, $argDatabaseName) {
  626. return $this->_connect($argHostname, $argUsername, $argPassword, $argDatabaseName);
  627. }
  628. /**
  629. * Always force a new connection to database.
  630. *
  631. * Currently this only works with Oracle.
  632. *
  633. * @param string $argHostname Host to connect to
  634. * @param string $argUsername Userid to login
  635. * @param string $argPassword Associated password
  636. * @param string $argDatabaseName Database name
  637. *
  638. * @return bool
  639. */
  640. function NConnect($argHostname = "", $argUsername = "", $argPassword = "", $argDatabaseName = "") {
  641. return $this->Connect($argHostname, $argUsername, $argPassword, $argDatabaseName, true);
  642. }
  643. /**
  644. * Establish persistent connection to database.
  645. *
  646. * @param string $argHostname Host to connect to
  647. * @param string $argUsername Userid to login
  648. * @param string $argPassword Associated password
  649. * @param string $argDatabaseName Database name
  650. *
  651. * @return bool
  652. */
  653. function PConnect($argHostname = "", $argUsername = "", $argPassword = "", $argDatabaseName = "") {
  654. if (defined('ADODB_NEVER_PERSIST')) {
  655. return $this->Connect($argHostname,$argUsername,$argPassword,$argDatabaseName);
  656. }
  657. if ($argHostname != "") {
  658. $this->host = $argHostname;
  659. }
  660. // Overwrites $this->host and $this->port if a port is specified.
  661. $this->parseHostNameAndPort();
  662. if ($argUsername != "") {
  663. $this->user = $argUsername;
  664. }
  665. if ($argPassword != "") {
  666. $this->password = 'not stored';
  667. }
  668. if ($argDatabaseName != "") {
  669. $this->database = $argDatabaseName;
  670. }
  671. $this->_isPersistentConnection = true;
  672. if ($rez = $this->_pconnect($this->host, $this->user, $argPassword, $this->database)) {
  673. return true;
  674. }
  675. if (isset($rez)) {
  676. $err = $this->ErrorMsg();
  677. if (empty($err)) {
  678. $err = "Connection error to server '$argHostname' with user '$argUsername'";
  679. }
  680. $ret = false;
  681. } else {
  682. $err = "Missing extension for ".$this->dataProvider;
  683. $ret = false;
  684. }
  685. if ($fn = $this->raiseErrorFn) {
  686. $fn($this->databaseType,'PCONNECT',$this->ErrorNo(),$err,$this->host,$this->database,$this);
  687. }
  688. $this->_connectionID = false;
  689. if ($this->debug) {
  690. ADOConnection::outp( $this->host.': '.$err);
  691. }
  692. return $ret;
  693. }
  694. function outp_throw($msg,$src='WARN',$sql='') {
  695. if (defined('ADODB_ERROR_HANDLER') && ADODB_ERROR_HANDLER == 'adodb_throw') {
  696. adodb_throw($this->databaseType,$src,-9999,$msg,$sql,false,$this);
  697. return;
  698. }
  699. ADOConnection::outp($msg);
  700. }
  701. /**
  702. * Create cache class.
  703. *
  704. * Code is backwards-compatible with old memcache implementation.
  705. */
  706. function _CreateCache() {
  707. global $ADODB_CACHE, $ADODB_CACHE_CLASS;
  708. if ($this->memCache) {
  709. global $ADODB_INCLUDED_MEMCACHE;
  710. if (empty($ADODB_INCLUDED_MEMCACHE)) {
  711. include_once(ADODB_DIR.'/adodb-memcache.lib.inc.php');
  712. }
  713. $ADODB_CACHE = new ADODB_Cache_MemCache($this);
  714. } else {
  715. $ADODB_CACHE = new $ADODB_CACHE_CLASS($this);
  716. }
  717. }
  718. /**
  719. * Format date column in sql string.
  720. *
  721. * See https://adodb.org/dokuwiki/doku.php?id=v5:reference:connection:sqldate
  722. * for documentation on supported formats.
  723. *
  724. * @param string $fmt Format string
  725. * @param string $col Date column; use system date if not specified.
  726. */
  727. function SQLDate($fmt, $col = '') {
  728. if (!$col) {
  729. $col = $this->sysDate;
  730. }
  731. return $col; // child class implement
  732. }
  733. /**
  734. * Prepare an sql statement and return the statement resource.
  735. *
  736. * For databases that do not support this, we return the $sql. To ensure
  737. * compatibility with databases that do not support prepare:
  738. *
  739. * $stmt = $db->Prepare("insert into table (id, name) values (?,?)");
  740. * $db->Execute($stmt,array(1,'Jill')) or die('insert failed');
  741. * $db->Execute($stmt,array(2,'Joe')) or die('insert failed');
  742. *
  743. * @param string $sql SQL to send to database
  744. *
  745. * @return mixed|false The prepared statement, or the original sql if the
  746. * database does not support prepare.
  747. */
  748. function Prepare($sql) {
  749. return $sql;
  750. }
  751. /**
  752. * Prepare a Stored Procedure and return the statement resource.
  753. *
  754. * Some databases, eg. mssql require a different function for preparing
  755. * stored procedures. So we cannot use Prepare().
  756. *
  757. * For databases that do not support this, we return the $sql.
  758. *
  759. * @param string $sql SQL to send to database
  760. * @param bool $param
  761. *
  762. * @return mixed|false The prepared statement, or the original sql if the
  763. * database does not support prepare.
  764. */
  765. function PrepareSP($sql,$param=true) {
  766. return $this->Prepare($sql,$param);
  767. }
  768. /**
  769. * PEAR DB Compat - alias for qStr.
  770. * @param $s
  771. * @return string
  772. */
  773. function Quote($s) {
  774. return $this->qstr($s);
  775. }
  776. function q(&$s) {
  777. //if (!empty($this->qNull && $s == 'null') {
  778. // return $s;
  779. //}
  780. $s = $this->qstr($s);
  781. }
  782. /**
  783. * PEAR DB Compat - do not use internally.
  784. */
  785. function ErrorNative() {
  786. return $this->ErrorNo();
  787. }
  788. /**
  789. * PEAR DB Compat - do not use internally.
  790. */
  791. function nextId($seq_name) {
  792. return $this->GenID($seq_name);
  793. }
  794. /**
  795. * Lock a row, will escalate and lock the table if row locking not supported
  796. * will normally free the lock at the end of the transaction
  797. *
  798. * @param string $table name of table to lock
  799. * @param string $where where clause to use, eg: "WHERE row=12". If left empty, will escalate to table lock
  800. * @param string $col
  801. */
  802. function RowLock($table,$where,$col='1 as adodbignore') {
  803. return false;
  804. }
  805. /**
  806. * @param string $table
  807. * @return true
  808. */
  809. function CommitLock($table) {
  810. return $this->CommitTrans();
  811. }
  812. /**
  813. * @param string $table
  814. * @return true
  815. */
  816. function RollbackLock($table) {
  817. return $this->RollbackTrans();
  818. }
  819. /**
  820. * PEAR DB Compat - do not use internally.
  821. *
  822. * The fetch modes for NUMERIC and ASSOC for PEAR DB and ADODB are identical
  823. * for easy porting :-)
  824. *
  825. * @param int $mode The fetchmode ADODB_FETCH_ASSOC or ADODB_FETCH_NUM
  826. *
  827. * @return int Previous fetch mode
  828. */
  829. function SetFetchMode($mode) {
  830. $old = $this->fetchMode;
  831. $this->fetchMode = $mode;
  832. if ($old === false) {
  833. global $ADODB_FETCH_MODE;
  834. return $ADODB_FETCH_MODE;
  835. }
  836. return $old;
  837. }
  838. /**
  839. * PEAR DB Compat - do not use internally.
  840. *
  841. * @param string $sql
  842. * @param array|bool $inputarr
  843. *
  844. * @return ADORecordSet|bool
  845. */
  846. function Query($sql, $inputarr=false) {
  847. $rs = $this->Execute($sql, $inputarr);
  848. if (!$rs && defined('ADODB_PEAR')) {
  849. return ADODB_PEAR_Error();
  850. }
  851. return $rs;
  852. }
  853. /**
  854. * PEAR DB Compat - do not use internally
  855. */
  856. function LimitQuery($sql, $offset, $count, $params=false) {
  857. $rs = $this->SelectLimit($sql, $count, $offset, $params);
  858. if (!$rs && defined('ADODB_PEAR')) {
  859. return ADODB_PEAR_Error();
  860. }
  861. return $rs;
  862. }
  863. /**
  864. * PEAR DB Compat - do not use internally
  865. */
  866. function Disconnect() {
  867. return $this->Close();
  868. }
  869. /**
  870. * Returns a placeholder for query parameters.
  871. *
  872. * e.g. $DB->Param('a') will return
  873. * - '?' for most databases
  874. * - ':a' for Oracle
  875. * - '$1', '$2', etc. for PostgreSQL
  876. *
  877. * @param mixed $name parameter's name.
  878. * For databases that require positioned params (e.g. PostgreSQL),
  879. * a "falsy" value can be used to force resetting the placeholder
  880. * count; using boolean 'false' will reset it without actually
  881. * returning a placeholder. ADOdb will also automatically reset
  882. * the count when executing a query.
  883. * @param string $type (unused)
  884. * @return string query parameter placeholder
  885. */
  886. function Param($name,$type='C') {
  887. return '?';
  888. }
  889. /*
  890. InParameter and OutParameter are self-documenting versions of Parameter().
  891. */
  892. function InParameter(&$stmt,&$var,$name,$maxLen=4000,$type=false) {
  893. return $this->Parameter($stmt,$var,$name,false,$maxLen,$type);
  894. }
  895. /*
  896. */
  897. function OutParameter(&$stmt,&$var,$name,$maxLen=4000,$type=false) {
  898. return $this->Parameter($stmt,$var,$name,true,$maxLen,$type);
  899. }
  900. /*
  901. Usage in oracle
  902. $stmt = $db->Prepare('select * from table where id =:myid and group=:group');
  903. $db->Parameter($stmt,$id,'myid');
  904. $db->Parameter($stmt,$group,'group',64);
  905. $db->Execute();
  906. @param $stmt Statement returned by Prepare() or PrepareSP().
  907. @param $var PHP variable to bind to
  908. @param $name Name of stored procedure variable name to bind to.
  909. @param [$isOutput] Indicates direction of parameter 0/false=IN 1=OUT 2= IN/OUT. This is ignored in oci8.
  910. @param [$maxLen] Holds an maximum length of the variable.
  911. @param [$type] The data type of $var. Legal values depend on driver.
  912. */
  913. function Parameter(&$stmt,&$var,$name,$isOutput=false,$maxLen=4000,$type=false) {
  914. return false;
  915. }
  916. function IgnoreErrors($saveErrs=false) {
  917. if (!$saveErrs) {
  918. $saveErrs = array($this->raiseErrorFn,$this->_transOK);
  919. $this->raiseErrorFn = false;
  920. return $saveErrs;
  921. } else {
  922. $this->raiseErrorFn = $saveErrs[0];
  923. $this->_transOK = $saveErrs[1];
  924. }
  925. }
  926. /**
  927. * Improved method of initiating a transaction. Used together with CompleteTrans().
  928. * Advantages include:
  929. *
  930. * a. StartTrans/CompleteTrans is nestable, unlike BeginTrans/CommitTrans/RollbackTrans.
  931. * Only the outermost block is treated as a transaction.<br>
  932. * b. CompleteTrans auto-detects SQL errors, and will rollback on errors, commit otherwise.<br>
  933. * c. All BeginTrans/CommitTrans/RollbackTrans inside a StartTrans/CompleteTrans block
  934. * are disabled, making it backward compatible.
  935. */
  936. function StartTrans($errfn = 'ADODB_TransMonitor') {
  937. if ($this->transOff > 0) {
  938. $this->transOff += 1;
  939. return true;
  940. }
  941. $this->_oldRaiseFn = $this->raiseErrorFn;
  942. $this->raiseErrorFn = $errfn;
  943. $this->_transOK = true;
  944. if ($this->debug && $this->transCnt > 0) {
  945. ADOConnection::outp("Bad Transaction: StartTrans called within BeginTrans");
  946. }
  947. $ok = $this->BeginTrans();
  948. $this->transOff = 1;
  949. return $ok;
  950. }
  951. /**
  952. Used together with StartTrans() to end a transaction. Monitors connection
  953. for sql errors, and will commit or rollback as appropriate.
  954. @autoComplete if true, monitor sql errors and commit and rollback as appropriate,
  955. and if set to false force rollback even if no SQL error detected.
  956. @returns true on commit, false on rollback.
  957. */
  958. function CompleteTrans($autoComplete = true) {
  959. if ($this->transOff > 1) {
  960. $this->transOff -= 1;
  961. return true;
  962. }
  963. $this->raiseErrorFn = $this->_oldRaiseFn;
  964. $this->transOff = 0;
  965. if ($this->_transOK && $autoComplete) {
  966. if (!$this->CommitTrans()) {
  967. $this->_transOK = false;
  968. if ($this->debug) {
  969. ADOConnection::outp("Smart Commit failed");
  970. }
  971. } else {
  972. if ($this->debug) {
  973. ADOConnection::outp("Smart Commit occurred");
  974. }
  975. }
  976. } else {
  977. $this->_transOK = false;
  978. $this->RollbackTrans();
  979. if ($this->debug) {
  980. ADOCOnnection::outp("Smart Rollback occurred");
  981. }
  982. }
  983. return $this->_transOK;
  984. }
  985. /*
  986. At the end of a StartTrans/CompleteTrans block, perform a rollback.
  987. */
  988. function FailTrans() {
  989. if ($this->debug)
  990. if ($this->transOff == 0) {
  991. ADOConnection::outp("FailTrans outside StartTrans/CompleteTrans");
  992. } else {
  993. ADOConnection::outp("FailTrans was called");
  994. adodb_backtrace();
  995. }
  996. $this->_transOK = false;
  997. }
  998. /**
  999. Check if transaction has failed, only for Smart Transactions.
  1000. */
  1001. function HasFailedTrans() {
  1002. if ($this->transOff > 0) {
  1003. return $this->_transOK == false;
  1004. }
  1005. return false;
  1006. }
  1007. /**
  1008. * Execute SQL
  1009. *
  1010. * @param string $sql SQL statement to execute, or possibly an array
  1011. * holding prepared statement ($sql[0] will hold sql text)
  1012. * @param array|bool $inputarr holds the input data to bind to.
  1013. * Null elements will be set to null.
  1014. *
  1015. * @return ADORecordSet|bool
  1016. */
  1017. public function Execute($sql, $inputarr = false) {
  1018. if ($this->fnExecute) {
  1019. $fn = $this->fnExecute;
  1020. $ret = $fn($this,$sql,$inputarr);
  1021. if (isset($ret)) {
  1022. return $ret;
  1023. }
  1024. }
  1025. if ($inputarr !== false) {
  1026. if (!is_array($inputarr)) {
  1027. $inputarr = array($inputarr);
  1028. }
  1029. $element0 = reset($inputarr);
  1030. # is_object check because oci8 descriptors can be passed in
  1031. $array_2d = $this->bulkBind && is_array($element0) && !is_object(reset($element0));
  1032. //remove extra memory copy of input -mikefedyk
  1033. unset($element0);
  1034. if (!is_array($sql) && !$this->_bindInputArray) {
  1035. // @TODO this would consider a '?' within a string as a parameter...
  1036. $sqlarr = explode('?',$sql);
  1037. $nparams = sizeof($sqlarr)-1;
  1038. if (!$array_2d) {
  1039. // When not Bind Bulk - convert to array of arguments list
  1040. $inputarr = array($inputarr);
  1041. } else {
  1042. // Bulk bind - Make sure all list of params have the same number of elements
  1043. $countElements = array_map('count', $inputarr);
  1044. if (1 != count(array_unique($countElements))) {
  1045. $this->outp_throw(
  1046. "[bulk execute] Input array has different number of params [" . print_r($countElements, true) . "].",
  1047. 'Execute'
  1048. );
  1049. return false;
  1050. }
  1051. unset($countElements);
  1052. }
  1053. // Make sure the number of parameters provided in the input
  1054. // array matches what the query expects
  1055. $element0 = reset($inputarr);
  1056. if ($nparams != count($element0)) {
  1057. $this->outp_throw(
  1058. "Input array has " . count($element0) .
  1059. " params, does not match query: '" . htmlspecialchars($sql) . "'",
  1060. 'Execute'
  1061. );
  1062. return false;
  1063. }
  1064. // clean memory
  1065. unset($element0);
  1066. foreach($inputarr as $arr) {
  1067. $sql = ''; $i = 0;
  1068. foreach ($arr as $v) {
  1069. $sql .= $sqlarr[$i];
  1070. // from Ron Baldwin <ron.baldwin#sourceprose.com>
  1071. // Only quote string types
  1072. $typ = gettype($v);
  1073. if ($typ == 'string') {
  1074. //New memory copy of input created here -mikefedyk
  1075. $sql .= $this->qstr($v);
  1076. } else if ($typ == 'double') {
  1077. $sql .= str_replace(',','.',$v); // locales fix so 1.1 does not get converted to 1,1
  1078. } else if ($typ == 'boolean') {
  1079. $sql .= $v ? $this->true : $this->false;
  1080. } else if ($typ == 'object') {
  1081. if (method_exists($v, '__toString')) {
  1082. $sql .= $this->qstr($v->__toString());
  1083. } else {
  1084. $sql .= $this->qstr((string) $v);
  1085. }
  1086. } else if ($v === null) {
  1087. $sql .= 'NULL';
  1088. } else {
  1089. $sql .= $v;
  1090. }
  1091. $i += 1;
  1092. if ($i == $nparams) {
  1093. break;
  1094. }
  1095. } // while
  1096. if (isset($sqlarr[$i])) {
  1097. $sql .= $sqlarr[$i];
  1098. if ($i+1 != sizeof($sqlarr)) {
  1099. $this->outp_throw( "Input Array does not match ?: ".htmlspecialchars($sql),'Execute');
  1100. }
  1101. } else if ($i != sizeof($sqlarr)) {
  1102. $this->outp_throw( "Input array does not match ?: ".htmlspecialchars($sql),'Execute');
  1103. }
  1104. $ret = $this->_Execute($sql);
  1105. if (!$ret) {
  1106. return $ret;
  1107. }
  1108. }
  1109. } else {
  1110. if ($array_2d) {
  1111. if (is_string($sql)) {
  1112. $stmt = $this->Prepare($sql);
  1113. } else {
  1114. $stmt = $sql;
  1115. }
  1116. foreach($inputarr as $arr) {
  1117. $ret = $this->_Execute($stmt,$arr);
  1118. if (!$ret) {
  1119. return $ret;
  1120. }
  1121. }
  1122. } else {
  1123. $ret = $this->_Execute($sql,$inputarr);
  1124. }
  1125. }
  1126. } else {
  1127. $ret = $this->_Execute($sql,false);
  1128. }
  1129. return $ret;
  1130. }
  1131. function _Execute($sql,$inputarr=false) {
  1132. // ExecuteCursor() may send non-string queries (such as arrays),
  1133. // so we need to ignore those.
  1134. if( is_string($sql) ) {
  1135. // Strips keyword used to help generate SELECT COUNT(*) queries
  1136. // from SQL if it exists.
  1137. $sql = str_replace( '_ADODB_COUNT', '', $sql );
  1138. }
  1139. if ($this->debug) {
  1140. global $ADODB_INCLUDED_LIB;
  1141. if (empty($ADODB_INCLUDED_LIB)) {
  1142. include_once(ADODB_DIR.'/adodb-lib.inc.php');
  1143. }
  1144. $this->_queryID = _adodb_debug_execute($this, $sql,$inputarr);
  1145. } else {
  1146. $this->_queryID = @$this->_query($sql,$inputarr);
  1147. }
  1148. // ************************
  1149. // OK, query executed
  1150. // ************************
  1151. // error handling if query fails
  1152. if ($this->_queryID === false) {
  1153. if ($this->debug == 99) {
  1154. adodb_backtrace(true,5);
  1155. }
  1156. $fn = $this->raiseErrorFn;
  1157. if ($fn) {
  1158. $fn($this->databaseType,'EXECUTE',$this->ErrorNo(),$this->ErrorMsg(),$sql,$inputarr,$this);
  1159. }
  1160. return false;
  1161. }
  1162. // return simplified recordset for inserts/updates/deletes with lower overhead
  1163. if ($this->_queryID === true) {
  1164. $rsclass = $this->rsPrefix.'empty';
  1165. $rs = (class_exists($rsclass)) ? new $rsclass(): new ADORecordSet_empty();
  1166. return $rs;
  1167. }
  1168. if ($this->dataProvider == 'pdo' && $this->databaseType != 'pdo') {
  1169. // PDO uses a slightly different naming convention for the
  1170. // recordset class if the database type is changed, so we must
  1171. // treat it specifically. The mysql driver leaves the
  1172. // databaseType as pdo
  1173. $rsclass = $this->rsPrefix . 'pdo_' . $this->databaseType;
  1174. } else {
  1175. $rsclass = $this->rsPrefix . $this->databaseType;
  1176. }
  1177. // return real recordset from select statement
  1178. $rs = new $rsclass($this->_queryID,$this->fetchMode);
  1179. $rs->connection = $this; // Pablo suggestion
  1180. $rs->Init();
  1181. if (is_array($sql)) {
  1182. $rs->sql = $sql[0];
  1183. } else {
  1184. $rs->sql = $sql;
  1185. }
  1186. if ($rs->_numOfRows <= 0) {
  1187. global $ADODB_COUNTRECS;
  1188. if ($ADODB_COUNTRECS) {
  1189. if (!$rs->EOF) {
  1190. $rs = $this->_rs2rs($rs,-1,-1,!is_array($sql));
  1191. $rs->_queryID = $this->_queryID;
  1192. } else
  1193. $rs->_numOfRows = 0;
  1194. }
  1195. }
  1196. return $rs;
  1197. }
  1198. function CreateSequence($seqname='adodbseq',$startID=1) {
  1199. if (empty($this->_genSeqSQL)) {
  1200. return false;
  1201. }
  1202. return $this->Execute(sprintf($this->_genSeqSQL,$seqname,$startID));
  1203. }
  1204. function DropSequence($seqname='adodbseq') {
  1205. if (empty($this->_dropSeqSQL)) {
  1206. return false;
  1207. }
  1208. return $this->Execute(sprintf($this->_dropSeqSQL,$seqname));
  1209. }
  1210. /**
  1211. * Generates a sequence id and stores it in $this->genID.
  1212. *
  1213. * GenID is only available if $this->hasGenID = true;
  1214. *
  1215. * @param string $seqname Name of sequence to use
  1216. * @param int $startID If sequence does not exist, start at this ID
  1217. *
  1218. * @return int Sequence id, 0 if not supported
  1219. */
  1220. function GenID($seqname='adodbseq',$startID=1) {
  1221. if (!$this->hasGenID) {
  1222. return 0; // formerly returns false pre 1.60
  1223. }
  1224. $getnext = sprintf($this->_genIDSQL,$seqname);
  1225. $holdtransOK = $this->_transOK;
  1226. $save_handler = $this->raiseErrorFn;
  1227. $this->raiseErrorFn = '';
  1228. @($rs = $this->Execute($getnext));
  1229. $this->raiseErrorFn = $save_handler;
  1230. if (!$rs) {
  1231. $this->_transOK = $holdtransOK; //if the status was ok before reset
  1232. $createseq = $this->Execute(sprintf($this->_genSeqSQL,$seqname,$startID));
  1233. $rs = $this->Execute($getnext);
  1234. }
  1235. if ($rs && !$rs->EOF) {
  1236. $this->genID = reset($rs->fields);
  1237. } else {
  1238. $this->genID = 0; // false
  1239. }
  1240. if ($rs) {
  1241. $rs->Close();
  1242. }
  1243. return $this->genID;
  1244. }
  1245. /**
  1246. * Returns the last inserted ID.
  1247. *
  1248. * Not all databases support this feature. Some do not require to specify
  1249. * table or column name (e.g. MySQL).
  1250. *
  1251. * @param string $table Table name, default ''
  1252. * @param string $column Column name, default ''
  1253. *
  1254. * @return int The last inserted ID.
  1255. */
  1256. function Insert_ID($table='',$column='') {
  1257. if ($this->_logsql && $this->lastInsID) {
  1258. return $this->lastInsID;
  1259. }
  1260. if ($this->hasInsertID) {
  1261. return $this->_insertid($table,$column);
  1262. }
  1263. if ($this->debug) {
  1264. ADOConnection::outp( '<p>Insert_ID error</p>');
  1265. adodb_backtrace();
  1266. }
  1267. return false;
  1268. }
  1269. /**
  1270. * Portable Insert ID. Pablo Roca <pabloroca#mvps.org>
  1271. *
  1272. * @param string $table
  1273. * @param string $id
  1274. * @return mixed The last inserted ID. All databases support this, but be
  1275. * aware of possible problems in multiuser environments.
  1276. * Heavily test this before deploying.
  1277. */
  1278. function PO_Insert_ID($table="", $id="") {
  1279. if ($this->hasInsertID){
  1280. return $this->Insert_ID($table,$id);
  1281. } else {
  1282. return $this->GetOne("SELECT MAX($id) FROM $table");
  1283. }
  1284. }
  1285. /**
  1286. * @return # rows affected by UPDATE/DELETE
  1287. */
  1288. function Affected_Rows() {
  1289. if ($this->hasAffectedRows) {
  1290. if ($this->fnExecute === 'adodb_log_sql') {
  1291. if ($this->_logsql && $this->_affected !== false) {
  1292. return $this->_affected;
  1293. }
  1294. }
  1295. $val = $this->_affectedrows();
  1296. return ($val < 0) ? false : $val;
  1297. }
  1298. if ($this->debug) {
  1299. ADOConnection::outp( '<p>Affected_Rows error</p>',false);
  1300. }
  1301. return false;
  1302. }
  1303. /**
  1304. * @return string the last error message
  1305. */
  1306. function ErrorMsg() {
  1307. if ($this->_errorMsg) {
  1308. return '!! '.strtoupper($this->dataProvider.' '.$this->databaseType).': '.$this->_errorMsg;
  1309. } else {
  1310. return '';
  1311. }
  1312. }
  1313. /**
  1314. * @return int the last error number. Normally 0 means no error.
  1315. */
  1316. function ErrorNo() {
  1317. return ($this->_errorMsg) ? -1 : 0;
  1318. }
  1319. function MetaError($err=false) {
  1320. include_once(ADODB_DIR."/adodb-error.inc.php");
  1321. if ($err === false) {
  1322. $err = $this->ErrorNo();
  1323. }
  1324. return adodb_error($this->dataProvider,$this->databaseType,$err);
  1325. }
  1326. function MetaErrorMsg($errno) {
  1327. include_once(ADODB_DIR."/adodb-error.inc.php");
  1328. return adodb_errormsg($errno);
  1329. }
  1330. /**
  1331. * @returns an array with the primary key columns in it.
  1332. */
  1333. function MetaPrimaryKeys($table, $owner=false) {
  1334. // owner not used in base class - see oci8
  1335. $p = array();
  1336. $objs = $this->MetaColumns($table);
  1337. if ($objs) {
  1338. foreach($objs as $v) {
  1339. if (!empty($v->primary_key)) {
  1340. $p[] = $v->name;
  1341. }
  1342. }
  1343. }
  1344. if (sizeof($p)) {
  1345. return $p;
  1346. }
  1347. if (function_exists('ADODB_VIEW_PRIMARYKEYS')) {
  1348. return ADODB_VIEW_PRIMARYKEYS($this->databaseType, $this->database, $table, $owner);
  1349. }
  1350. return false;
  1351. }
  1352. /**
  1353. * @returns assoc array where keys are tables, and values are foreign keys
  1354. */
  1355. function MetaForeignKeys($table, $owner=false, $upper=false) {
  1356. return false;
  1357. }
  1358. /**
  1359. * Choose a database to connect to. Many databases do not support this.
  1360. *
  1361. * @param string $dbName the name of the database to select
  1362. * @return bool
  1363. */
  1364. function SelectDB($dbName) {return false;}
  1365. /**
  1366. * Select a limited number of rows.
  1367. *
  1368. * Will select, getting rows from $offset (1-based), for $nrows.
  1369. * This simulates the MySQL "select * from table limit $offset,$nrows" , and
  1370. * the PostgreSQL "select * from table limit $nrows offset $offset". Note that
  1371. * MySQL and PostgreSQL parameter ordering is the opposite of the other.
  1372. * eg.
  1373. * SelectLimit('select * from table',3); will return rows 1 to 3 (1-based)
  1374. * SelectLimit('select * from table',3,2); will return rows 3 to 5 (1-based)
  1375. *
  1376. * Uses SELECT TOP for Microsoft databases (when $this->hasTop is set)
  1377. * BUG: Currently SelectLimit fails with $sql with LIMIT or TOP clause already set
  1378. *
  1379. * @param string $sql
  1380. * @param int $offset Row to start calculations from (1-based)
  1381. * @param int $nrows Number of rows to get
  1382. * @param array|bool $inputarr Array of bind variables
  1383. * @param int $secs2cache Private parameter only used by jlim
  1384. *
  1385. * @return ADORecordSet The recordset ($rs->databaseType == 'array')
  1386. */
  1387. function SelectLimit($sql,$nrows=-1,$offset=-1, $inputarr=false,$secs2cache=0) {
  1388. $nrows = (int)$nrows;
  1389. $offset = (int)$offset;
  1390. if ($this->hasTop && $nrows > 0) {
  1391. // suggested by Reinhard Balling. Access requires top after distinct
  1392. // Informix requires first before distinct - F Riosa
  1393. $ismssql = (strpos($this->databaseType,'mssql') !== false);
  1394. if ($ismssql) {
  1395. $isaccess = false;
  1396. } else {
  1397. $isaccess = (strpos($this->databaseType,'access') !== false);
  1398. }
  1399. if ($offset <= 0) {
  1400. // access includes ties in result
  1401. if ($isaccess) {
  1402. $sql = preg_replace(
  1403. '/(^\s*select\s+(distinctrow|distinct)?)/i',
  1404. '\\1 '.$this->hasTop.' '.$nrows.' ',
  1405. $sql
  1406. );
  1407. if ($secs2cache != 0) {
  1408. $ret = $this->CacheExecute($secs2cache, $sql,$inputarr);
  1409. } else {
  1410. $ret = $this->Execute($sql,$inputarr);
  1411. }
  1412. return $ret; // PHP5 fix
  1413. } else if ($ismssql){
  1414. $sql = preg_replace(
  1415. '/(^\s*select\s+(distinctrow|distinct)?)/i',
  1416. '\\1 '.$this->hasTop.' '.$nrows.' ',
  1417. $sql
  1418. );
  1419. } else {
  1420. $sql = preg_replace(
  1421. '/(^\s*select\s)/i',
  1422. '\\1 '.$this->hasTop.' '.$nrows.' ',
  1423. $sql
  1424. );
  1425. }
  1426. } else {
  1427. $nn = $nrows + $offset;
  1428. if ($isaccess || $ismssql) {
  1429. $sql = preg_replace(
  1430. '/(^\s*select\s+(distinctrow|distinct)?)/i',
  1431. '\\1 '.$this->hasTop.' '.$nn.' ',
  1432. $sql
  1433. );
  1434. } else {
  1435. $sql = preg_replace(
  1436. '/(^\s*select\s)/i',
  1437. '\\1 '.$this->hasTop.' '.$nn.' ',
  1438. $sql
  1439. );
  1440. }
  1441. }
  1442. }
  1443. // if $offset>0, we want to skip rows, and $ADODB_COUNTRECS is set, we buffer rows
  1444. // 0 to offset-1 which will be discarded anyway. So we disable $ADODB_COUNTRECS.
  1445. global $ADODB_COUNTRECS;
  1446. $savec = $ADODB_COUNTRECS;
  1447. $ADODB_COUNTRECS = false;
  1448. if ($secs2cache != 0) {
  1449. $rs = $this->CacheExecute($secs2cache,$sql,$inputarr);
  1450. } else {
  1451. $rs = $this->Execute($sql,$inputarr);
  1452. }
  1453. $ADODB_COUNTRECS = $savec;
  1454. if ($rs && !$rs->EOF) {
  1455. $rs = $this->_rs2rs($rs,$nrows,$offset);
  1456. }
  1457. //print_r($rs);
  1458. return $rs;
  1459. }
  1460. /**
  1461. * Create serializable recordset. Breaks rs link to connection.
  1462. *
  1463. * @param ADORecordSet $rs the recordset to serialize
  1464. *
  1465. * @return ADORecordSet_array|bool the new recordset
  1466. */
  1467. function SerializableRS(&$rs) {
  1468. $rs2 = $this->_rs2rs($rs);
  1469. $ignore = false;
  1470. $rs2->connection = $ignore;
  1471. return $rs2;
  1472. }
  1473. /**
  1474. * Convert a database recordset to an array recordset.
  1475. *
  1476. * Input recordset's cursor should be at beginning, and old $rs will be closed.

Large files files are truncated, but you can click here to view the full file