PageRenderTime 63ms CodeModel.GetById 32ms RepoModel.GetById 1ms app.codeStats 0ms

/lib/adodb/drivers/adodb-mysql.inc.php

https://bitbucket.org/moodle/moodle
PHP | 925 lines | 691 code | 129 blank | 105 comment | 134 complexity | 16634cde390c56555dc5d81f2ee32fe6 MD5 | raw file
Possible License(s): Apache-2.0, LGPL-2.1, BSD-3-Clause, MIT, GPL-3.0
  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. Set tabs to 8.
  10. This driver only supports the original non-transactional MySQL driver. It
  11. is deprecated in PHP version 5.5 and removed in PHP version 7. It is deprecated
  12. as of ADOdb version 5.20.0. Use the mysqli driver instead, which supports both
  13. transactional and non-transactional updates
  14. Requires mysql client. Works on Windows and Unix.
  15. 28 Feb 2001: MetaColumns bug fix - suggested by Freek Dijkstra (phpeverywhere@macfreek.com)
  16. */
  17. // security - hide paths
  18. if (!defined('ADODB_DIR')) die();
  19. if (! defined("_ADODB_MYSQL_LAYER")) {
  20. define("_ADODB_MYSQL_LAYER", 1 );
  21. class ADODB_mysql extends ADOConnection {
  22. var $databaseType = 'mysql';
  23. var $dataProvider = 'mysql';
  24. var $hasInsertID = true;
  25. var $hasAffectedRows = true;
  26. var $metaTablesSQL = "SELECT
  27. TABLE_NAME,
  28. CASE WHEN TABLE_TYPE = 'VIEW' THEN 'V' ELSE 'T' END
  29. FROM INFORMATION_SCHEMA.TABLES
  30. WHERE TABLE_SCHEMA=";
  31. var $metaColumnsSQL = "SHOW COLUMNS FROM `%s`";
  32. var $fmtTimeStamp = "'Y-m-d H:i:s'";
  33. var $hasLimit = true;
  34. var $hasMoveFirst = true;
  35. var $hasGenID = true;
  36. var $isoDates = true; // accepts dates in ISO format
  37. var $sysDate = 'CURDATE()';
  38. var $sysTimeStamp = 'NOW()';
  39. var $hasTransactions = false;
  40. var $forceNewConnect = false;
  41. var $poorAffectedRows = true;
  42. var $clientFlags = 0;
  43. var $charSet = '';
  44. var $substr = "substring";
  45. var $nameQuote = '`'; /// string to use to quote identifiers and names
  46. var $compat323 = false; // true if compat with mysql 3.23
  47. /**
  48. * ADODB_mysql constructor.
  49. */
  50. public function __construct() {
  51. if(version_compare(PHP_VERSION, '7.0.0', '>=')) {
  52. $this->outp_throw(
  53. 'mysql extension is not supported since PHP 7.0.0, use mysqli instead',
  54. __METHOD__
  55. );
  56. die(1); // Stop execution even if not using Exceptions
  57. } elseif(version_compare(PHP_VERSION, '5.5.0', '>=')) {
  58. // If mysql extension is available just print a warning,
  59. // otherwise die with an error message
  60. if(function_exists('mysql_connect')) {
  61. $this->outp('mysql extension is deprecated since PHP 5.5.0, consider using mysqli');
  62. } else {
  63. $this->outp_throw(
  64. 'mysql extension is not available, use mysqli instead',
  65. __METHOD__
  66. );
  67. die(1); // Stop execution even if not using Exceptions
  68. }
  69. }
  70. }
  71. // SetCharSet - switch the client encoding
  72. function setCharSet($charset_name)
  73. {
  74. if (!function_exists('mysql_set_charset')) {
  75. return false;
  76. }
  77. if ($this->charSet !== $charset_name) {
  78. $ok = @mysql_set_charset($charset_name,$this->_connectionID);
  79. if ($ok) {
  80. $this->charSet = $charset_name;
  81. return true;
  82. }
  83. return false;
  84. }
  85. return true;
  86. }
  87. function serverInfo()
  88. {
  89. $arr['description'] = ADOConnection::GetOne("select version()");
  90. $arr['version'] = ADOConnection::_findvers($arr['description']);
  91. return $arr;
  92. }
  93. function ifNull( $field, $ifNull )
  94. {
  95. return " IFNULL($field, $ifNull) "; // if MySQL
  96. }
  97. function metaProcedures($NamePattern = false, $catalog = null, $schemaPattern = null)
  98. {
  99. // save old fetch mode
  100. global $ADODB_FETCH_MODE;
  101. $false = false;
  102. $save = $ADODB_FETCH_MODE;
  103. $ADODB_FETCH_MODE = ADODB_FETCH_NUM;
  104. if ($this->fetchMode !== FALSE) {
  105. $savem = $this->SetFetchMode(FALSE);
  106. }
  107. $procedures = array ();
  108. // get index details
  109. $likepattern = '';
  110. if ($NamePattern) {
  111. $likepattern = " LIKE '".$NamePattern."'";
  112. }
  113. $rs = $this->Execute('SHOW PROCEDURE STATUS'.$likepattern);
  114. if (is_object($rs)) {
  115. // parse index data into array
  116. while ($row = $rs->FetchRow()) {
  117. $procedures[$row[1]] = array(
  118. 'type' => 'PROCEDURE',
  119. 'catalog' => '',
  120. 'schema' => '',
  121. 'remarks' => $row[7],
  122. );
  123. }
  124. }
  125. $rs = $this->Execute('SHOW FUNCTION STATUS'.$likepattern);
  126. if (is_object($rs)) {
  127. // parse index data into array
  128. while ($row = $rs->FetchRow()) {
  129. $procedures[$row[1]] = array(
  130. 'type' => 'FUNCTION',
  131. 'catalog' => '',
  132. 'schema' => '',
  133. 'remarks' => $row[7]
  134. );
  135. }
  136. }
  137. // restore fetchmode
  138. if (isset($savem)) {
  139. $this->SetFetchMode($savem);
  140. }
  141. $ADODB_FETCH_MODE = $save;
  142. return $procedures;
  143. }
  144. /**
  145. * Retrieves a list of tables based on given criteria
  146. *
  147. * @param string $ttype Table type = 'TABLE', 'VIEW' or false=both (default)
  148. * @param string $showSchema schema name, false = current schema (default)
  149. * @param string $mask filters the table by name
  150. *
  151. * @return array list of tables
  152. */
  153. function metaTables($ttype=false,$showSchema=false,$mask=false)
  154. {
  155. $save = $this->metaTablesSQL;
  156. if ($showSchema && is_string($showSchema)) {
  157. $this->metaTablesSQL .= $this->qstr($showSchema);
  158. } else {
  159. $this->metaTablesSQL .= "schema()";
  160. }
  161. if ($mask) {
  162. $mask = $this->qstr($mask);
  163. $this->metaTablesSQL .= " AND table_name LIKE $mask";
  164. }
  165. $ret = ADOConnection::MetaTables($ttype,$showSchema);
  166. $this->metaTablesSQL = $save;
  167. return $ret;
  168. }
  169. function metaIndexes ($table, $primary = FALSE, $owner=false)
  170. {
  171. // save old fetch mode
  172. global $ADODB_FETCH_MODE;
  173. $false = false;
  174. $save = $ADODB_FETCH_MODE;
  175. $ADODB_FETCH_MODE = ADODB_FETCH_NUM;
  176. if ($this->fetchMode !== FALSE) {
  177. $savem = $this->SetFetchMode(FALSE);
  178. }
  179. // get index details
  180. $rs = $this->Execute(sprintf('SHOW INDEX FROM %s',$table));
  181. // restore fetchmode
  182. if (isset($savem)) {
  183. $this->SetFetchMode($savem);
  184. }
  185. $ADODB_FETCH_MODE = $save;
  186. if (!is_object($rs)) {
  187. return $false;
  188. }
  189. $indexes = array ();
  190. // parse index data into array
  191. while ($row = $rs->FetchRow()) {
  192. if ($primary == FALSE AND $row[2] == 'PRIMARY') {
  193. continue;
  194. }
  195. if (!isset($indexes[$row[2]])) {
  196. $indexes[$row[2]] = array(
  197. 'unique' => ($row[1] == 0),
  198. 'columns' => array()
  199. );
  200. }
  201. $indexes[$row[2]]['columns'][$row[3] - 1] = $row[4];
  202. }
  203. // sort columns by order in the index
  204. foreach ( array_keys ($indexes) as $index )
  205. {
  206. ksort ($indexes[$index]['columns']);
  207. }
  208. return $indexes;
  209. }
  210. /**
  211. * Appropriately quotes strings with ' characters for insertion into the database.
  212. *
  213. * Relies on mysql_real_escape_string()
  214. * @link https://adodb.org/dokuwiki/doku.php?id=v5:reference:connection:qstr
  215. *
  216. * @param string $s The string to quote
  217. * @param bool $magic_quotes This param is not used since 5.21.0.
  218. * It remains for backwards compatibility.
  219. *
  220. * @return string Quoted string
  221. */
  222. function qStr($s, $magic_quotes=false)
  223. {
  224. if (is_null($s)) {
  225. return 'NULL';
  226. }
  227. if (is_resource($this->_connectionID)) {
  228. return "'" . mysql_real_escape_string($s, $this->_connectionID) . "'";
  229. }
  230. if ($this->replaceQuote[0] == '\\') {
  231. $s = str_replace(array('\\', "\0"), array('\\\\', "\\\0"), $s);
  232. }
  233. return "'" . str_replace("'", $this->replaceQuote, $s) . "'";
  234. }
  235. function _insertid()
  236. {
  237. return ADOConnection::GetOne('SELECT LAST_INSERT_ID()');
  238. //return mysql_insert_id($this->_connectionID);
  239. }
  240. function getOne($sql,$inputarr=false)
  241. {
  242. global $ADODB_GETONE_EOF;
  243. if ($this->compat323 == false && strncasecmp($sql,'sele',4) == 0) {
  244. $rs = $this->SelectLimit($sql,1,-1,$inputarr);
  245. if ($rs) {
  246. $rs->Close();
  247. if ($rs->EOF) return $ADODB_GETONE_EOF;
  248. return reset($rs->fields);
  249. }
  250. } else {
  251. return ADOConnection::GetOne($sql,$inputarr);
  252. }
  253. return false;
  254. }
  255. function beginTrans()
  256. {
  257. if ($this->debug) ADOConnection::outp("Transactions not supported in 'mysql' driver. Use 'mysqlt' or 'mysqli' driver");
  258. }
  259. function _affectedrows()
  260. {
  261. return mysql_affected_rows($this->_connectionID);
  262. }
  263. // See http://www.mysql.com/doc/M/i/Miscellaneous_functions.html
  264. // Reference on Last_Insert_ID on the recommended way to simulate sequences
  265. var $_genIDSQL = "update %s set id=LAST_INSERT_ID(id+1);";
  266. var $_genSeqSQL = "create table if not exists %s (id int not null)";
  267. var $_genSeqCountSQL = "select count(*) from %s";
  268. var $_genSeq2SQL = "insert into %s values (%s)";
  269. var $_dropSeqSQL = "drop table if exists %s";
  270. function createSequence($seqname='adodbseq',$startID=1)
  271. {
  272. if (empty($this->_genSeqSQL)) return false;
  273. $u = strtoupper($seqname);
  274. $ok = $this->Execute(sprintf($this->_genSeqSQL,$seqname));
  275. if (!$ok) return false;
  276. return $this->Execute(sprintf($this->_genSeq2SQL,$seqname,$startID-1));
  277. }
  278. function genID($seqname='adodbseq',$startID=1)
  279. {
  280. // post-nuke sets hasGenID to false
  281. if (!$this->hasGenID) return false;
  282. $savelog = $this->_logsql;
  283. $this->_logsql = false;
  284. $getnext = sprintf($this->_genIDSQL,$seqname);
  285. $holdtransOK = $this->_transOK; // save the current status
  286. $rs = @$this->Execute($getnext);
  287. if (!$rs) {
  288. if ($holdtransOK) $this->_transOK = true; //if the status was ok before reset
  289. $u = strtoupper($seqname);
  290. $this->Execute(sprintf($this->_genSeqSQL,$seqname));
  291. $cnt = $this->GetOne(sprintf($this->_genSeqCountSQL,$seqname));
  292. if (!$cnt) $this->Execute(sprintf($this->_genSeq2SQL,$seqname,$startID-1));
  293. $rs = $this->Execute($getnext);
  294. }
  295. if ($rs) {
  296. $this->genID = mysql_insert_id($this->_connectionID);
  297. $rs->Close();
  298. } else
  299. $this->genID = 0;
  300. $this->_logsql = $savelog;
  301. return $this->genID;
  302. }
  303. function metaDatabases()
  304. {
  305. $qid = mysql_list_dbs($this->_connectionID);
  306. $arr = array();
  307. $i = 0;
  308. $max = mysql_num_rows($qid);
  309. while ($i < $max) {
  310. $db = mysql_tablename($qid,$i);
  311. if ($db != 'mysql') $arr[] = $db;
  312. $i += 1;
  313. }
  314. return $arr;
  315. }
  316. // Format date column in sql string given an input format that understands Y M D
  317. function sqlDate($fmt, $col=false)
  318. {
  319. if (!$col) $col = $this->sysTimeStamp;
  320. $s = 'DATE_FORMAT('.$col.",'";
  321. $concat = false;
  322. $len = strlen($fmt);
  323. for ($i=0; $i < $len; $i++) {
  324. $ch = $fmt[$i];
  325. switch($ch) {
  326. default:
  327. if ($ch == '\\') {
  328. $i++;
  329. $ch = substr($fmt,$i,1);
  330. }
  331. /** FALL THROUGH */
  332. case '-':
  333. case '/':
  334. $s .= $ch;
  335. break;
  336. case 'Y':
  337. case 'y':
  338. $s .= '%Y';
  339. break;
  340. case 'M':
  341. $s .= '%b';
  342. break;
  343. case 'm':
  344. $s .= '%m';
  345. break;
  346. case 'D':
  347. case 'd':
  348. $s .= '%d';
  349. break;
  350. case 'Q':
  351. case 'q':
  352. $s .= "'),Quarter($col)";
  353. if ($len > $i+1) $s .= ",DATE_FORMAT($col,'";
  354. else $s .= ",('";
  355. $concat = true;
  356. break;
  357. case 'H':
  358. $s .= '%H';
  359. break;
  360. case 'h':
  361. $s .= '%I';
  362. break;
  363. case 'i':
  364. $s .= '%i';
  365. break;
  366. case 's':
  367. $s .= '%s';
  368. break;
  369. case 'a':
  370. case 'A':
  371. $s .= '%p';
  372. break;
  373. case 'w':
  374. $s .= '%w';
  375. break;
  376. case 'W':
  377. $s .= '%U';
  378. break;
  379. case 'l':
  380. $s .= '%W';
  381. break;
  382. }
  383. }
  384. $s.="')";
  385. if ($concat) $s = "CONCAT($s)";
  386. return $s;
  387. }
  388. // returns concatenated string
  389. // much easier to run "mysqld --ansi" or "mysqld --sql-mode=PIPES_AS_CONCAT" and use || operator
  390. function concat()
  391. {
  392. $s = "";
  393. $arr = func_get_args();
  394. // suggestion by andrew005@mnogo.ru
  395. $s = implode(',',$arr);
  396. if (strlen($s) > 0) return "CONCAT($s)";
  397. else return '';
  398. }
  399. function offsetDate($dayFraction,$date=false)
  400. {
  401. if (!$date) $date = $this->sysDate;
  402. $fraction = $dayFraction * 24 * 3600;
  403. return '('. $date . ' + INTERVAL ' . $fraction.' SECOND)';
  404. // return "from_unixtime(unix_timestamp($date)+$fraction)";
  405. }
  406. // returns true or false
  407. function _connect($argHostname, $argUsername, $argPassword, $argDatabasename)
  408. {
  409. if (!empty($this->port))
  410. $argHostname .= ":".$this->port;
  411. $this->_connectionID =
  412. mysql_connect($argHostname,
  413. $argUsername,
  414. $argPassword,
  415. $this->forceNewConnect,
  416. $this->clientFlags
  417. );
  418. if ($this->_connectionID === false)
  419. return false;
  420. if ($argDatabasename)
  421. return $this->SelectDB($argDatabasename);
  422. return true;
  423. }
  424. // returns true or false
  425. function _pconnect($argHostname, $argUsername, $argPassword, $argDatabasename)
  426. {
  427. if (!empty($this->port)) $argHostname .= ":".$this->port;
  428. $this->_connectionID =
  429. mysql_pconnect($argHostname,
  430. $argUsername,
  431. $argPassword,
  432. $this->clientFlags);
  433. if ($this->_connectionID === false)
  434. return false;
  435. if ($this->autoRollback)
  436. $this->RollbackTrans();
  437. if ($argDatabasename)
  438. return $this->SelectDB($argDatabasename);
  439. return true;
  440. }
  441. function _nconnect($argHostname, $argUsername, $argPassword, $argDatabasename)
  442. {
  443. $this->forceNewConnect = true;
  444. return $this->_connect($argHostname, $argUsername, $argPassword, $argDatabasename);
  445. }
  446. function metaColumns($table, $normalize=true)
  447. {
  448. $this->_findschema($table,$schema);
  449. if ($schema) {
  450. $dbName = $this->database;
  451. $this->SelectDB($schema);
  452. }
  453. global $ADODB_FETCH_MODE;
  454. $save = $ADODB_FETCH_MODE;
  455. $ADODB_FETCH_MODE = ADODB_FETCH_NUM;
  456. if ($this->fetchMode !== false) $savem = $this->SetFetchMode(false);
  457. $rs = $this->Execute(sprintf($this->metaColumnsSQL,$table));
  458. if ($schema) {
  459. $this->SelectDB($dbName);
  460. }
  461. if (isset($savem)) $this->SetFetchMode($savem);
  462. $ADODB_FETCH_MODE = $save;
  463. if (!is_object($rs)) {
  464. $false = false;
  465. return $false;
  466. }
  467. $retarr = array();
  468. while (!$rs->EOF){
  469. $fld = new ADOFieldObject();
  470. $fld->name = $rs->fields[0];
  471. $type = $rs->fields[1];
  472. // split type into type(length):
  473. $fld->scale = null;
  474. if (preg_match("/^(.+)\((\d+),(\d+)/", $type, $query_array)) {
  475. $fld->type = $query_array[1];
  476. $fld->max_length = is_numeric($query_array[2]) ? $query_array[2] : -1;
  477. $fld->scale = is_numeric($query_array[3]) ? $query_array[3] : -1;
  478. } elseif (preg_match("/^(.+)\((\d+)/", $type, $query_array)) {
  479. $fld->type = $query_array[1];
  480. $fld->max_length = is_numeric($query_array[2]) ? $query_array[2] : -1;
  481. } elseif (preg_match("/^(enum)\((.*)\)$/i", $type, $query_array)) {
  482. $fld->type = $query_array[1];
  483. $arr = explode(",",$query_array[2]);
  484. $fld->enums = $arr;
  485. $zlen = max(array_map("strlen",$arr)) - 2; // PHP >= 4.0.6
  486. $fld->max_length = ($zlen > 0) ? $zlen : 1;
  487. } else {
  488. $fld->type = $type;
  489. $fld->max_length = -1;
  490. }
  491. $fld->not_null = ($rs->fields[2] != 'YES');
  492. $fld->primary_key = ($rs->fields[3] == 'PRI');
  493. $fld->auto_increment = (strpos($rs->fields[5], 'auto_increment') !== false);
  494. $fld->binary = (strpos($type,'blob') !== false || strpos($type,'binary') !== false);
  495. $fld->unsigned = (strpos($type,'unsigned') !== false);
  496. $fld->zerofill = (strpos($type,'zerofill') !== false);
  497. if (!$fld->binary) {
  498. $d = $rs->fields[4];
  499. if ($d != '' && $d != 'NULL') {
  500. $fld->has_default = true;
  501. $fld->default_value = $d;
  502. } else {
  503. $fld->has_default = false;
  504. }
  505. }
  506. if ($save == ADODB_FETCH_NUM) {
  507. $retarr[] = $fld;
  508. } else {
  509. $retarr[strtoupper($fld->name)] = $fld;
  510. }
  511. $rs->MoveNext();
  512. }
  513. $rs->Close();
  514. return $retarr;
  515. }
  516. // returns true or false
  517. function selectDB($dbName)
  518. {
  519. $this->database = $dbName;
  520. $this->databaseName = $dbName; # obsolete, retained for compat with older adodb versions
  521. if ($this->_connectionID) {
  522. return @mysql_select_db($dbName,$this->_connectionID);
  523. }
  524. else return false;
  525. }
  526. // parameters use PostgreSQL convention, not MySQL
  527. function selectLimit($sql,$nrows=-1,$offset=-1,$inputarr=false,$secs=0)
  528. {
  529. $nrows = (int) $nrows;
  530. $offset = (int) $offset;
  531. $offsetStr =($offset>=0) ? ((integer)$offset)."," : '';
  532. // jason judge, see PHPLens Issue No: 9220
  533. if ($nrows < 0) $nrows = '18446744073709551615';
  534. if ($secs)
  535. $rs = $this->CacheExecute($secs,$sql." LIMIT $offsetStr".((integer)$nrows),$inputarr);
  536. else
  537. $rs = $this->Execute($sql." LIMIT $offsetStr".((integer)$nrows),$inputarr);
  538. return $rs;
  539. }
  540. // returns queryID or false
  541. function _query($sql,$inputarr=false)
  542. {
  543. return mysql_query($sql,$this->_connectionID);
  544. /*
  545. global $ADODB_COUNTRECS;
  546. if($ADODB_COUNTRECS)
  547. return mysql_query($sql,$this->_connectionID);
  548. else
  549. return @mysql_unbuffered_query($sql,$this->_connectionID); // requires PHP >= 4.0.6
  550. */
  551. }
  552. /* Returns: the last error message from previous database operation */
  553. function errorMsg()
  554. {
  555. if ($this->_logsql) return $this->_errorMsg;
  556. if (empty($this->_connectionID)) $this->_errorMsg = @mysql_error();
  557. else $this->_errorMsg = @mysql_error($this->_connectionID);
  558. return $this->_errorMsg;
  559. }
  560. /* Returns: the last error number from previous database operation */
  561. function errorNo()
  562. {
  563. if ($this->_logsql) return $this->_errorCode;
  564. if (empty($this->_connectionID)) return @mysql_errno();
  565. else return @mysql_errno($this->_connectionID);
  566. }
  567. // returns true or false
  568. function _close()
  569. {
  570. @mysql_close($this->_connectionID);
  571. $this->charSet = '';
  572. $this->_connectionID = false;
  573. }
  574. /*
  575. * Maximum size of C field
  576. */
  577. function charMax()
  578. {
  579. return 255;
  580. }
  581. /*
  582. * Maximum size of X field
  583. */
  584. function textMax()
  585. {
  586. return 4294967295;
  587. }
  588. // "Innox - Juan Carlos Gonzalez" <jgonzalez#innox.com.mx>
  589. function metaForeignKeys( $table, $owner = FALSE, $upper = FALSE, $associative = FALSE )
  590. {
  591. global $ADODB_FETCH_MODE;
  592. if ($ADODB_FETCH_MODE == ADODB_FETCH_ASSOC || $this->fetchMode == ADODB_FETCH_ASSOC) $associative = true;
  593. if ( !empty($owner) ) {
  594. $table = "$owner.$table";
  595. }
  596. $a_create_table = $this->getRow(sprintf('SHOW CREATE TABLE %s', $table));
  597. if ($associative) {
  598. $create_sql = isset($a_create_table["Create Table"]) ? $a_create_table["Create Table"] : $a_create_table["Create View"];
  599. } else {
  600. $create_sql = $a_create_table[1];
  601. }
  602. $matches = array();
  603. if (!preg_match_all("/FOREIGN KEY \(`(.*?)`\) REFERENCES `(.*?)` \(`(.*?)`\)/", $create_sql, $matches)) return false;
  604. $foreign_keys = array();
  605. $num_keys = count($matches[0]);
  606. for ( $i = 0; $i < $num_keys; $i ++ ) {
  607. $my_field = explode('`, `', $matches[1][$i]);
  608. $ref_table = $matches[2][$i];
  609. $ref_field = explode('`, `', $matches[3][$i]);
  610. if ( $upper ) {
  611. $ref_table = strtoupper($ref_table);
  612. }
  613. // see https://sourceforge.net/p/adodb/bugs/100/
  614. if (!isset($foreign_keys[$ref_table])) {
  615. $foreign_keys[$ref_table] = array();
  616. }
  617. $num_fields = count($my_field);
  618. for ( $j = 0; $j < $num_fields; $j ++ ) {
  619. if ( $associative ) {
  620. $foreign_keys[$ref_table][$ref_field[$j]] = $my_field[$j];
  621. } else {
  622. $foreign_keys[$ref_table][] = "{$my_field[$j]}={$ref_field[$j]}";
  623. }
  624. }
  625. }
  626. return $foreign_keys;
  627. }
  628. }
  629. /*--------------------------------------------------------------------------------------
  630. Class Name: Recordset
  631. --------------------------------------------------------------------------------------*/
  632. class ADORecordSet_mysql extends ADORecordSet{
  633. var $databaseType = "mysql";
  634. var $canSeek = true;
  635. function __construct($queryID,$mode=false)
  636. {
  637. if ($mode === false) {
  638. global $ADODB_FETCH_MODE;
  639. $mode = $ADODB_FETCH_MODE;
  640. }
  641. switch ($mode)
  642. {
  643. case ADODB_FETCH_NUM: $this->fetchMode = MYSQL_NUM; break;
  644. case ADODB_FETCH_ASSOC:$this->fetchMode = MYSQL_ASSOC; break;
  645. case ADODB_FETCH_DEFAULT:
  646. case ADODB_FETCH_BOTH:
  647. default:
  648. $this->fetchMode = MYSQL_BOTH; break;
  649. }
  650. $this->adodbFetchMode = $mode;
  651. parent::__construct($queryID);
  652. }
  653. function _initrs()
  654. {
  655. //GLOBAL $ADODB_COUNTRECS;
  656. // $this->_numOfRows = ($ADODB_COUNTRECS) ? @mysql_num_rows($this->_queryID):-1;
  657. $this->_numOfRows = @mysql_num_rows($this->_queryID);
  658. $this->_numOfFields = @mysql_num_fields($this->_queryID);
  659. }
  660. function fetchField($fieldOffset = -1)
  661. {
  662. if ($fieldOffset != -1) {
  663. $o = @mysql_fetch_field($this->_queryID, $fieldOffset);
  664. $f = @mysql_field_flags($this->_queryID,$fieldOffset);
  665. if ($o) $o->max_length = @mysql_field_len($this->_queryID,$fieldOffset); // suggested by: Jim Nicholson (jnich#att.com)
  666. //$o->max_length = -1; // mysql returns the max length less spaces -- so it is unrealiable
  667. if ($o) $o->binary = (strpos($f,'binary')!== false);
  668. }
  669. else { /* The $fieldOffset argument is not provided thus its -1 */
  670. $o = @mysql_fetch_field($this->_queryID);
  671. //if ($o) $o->max_length = @mysql_field_len($this->_queryID); // suggested by: Jim Nicholson (jnich#att.com)
  672. $o->max_length = -1; // mysql returns the max length less spaces -- so it is unrealiable
  673. }
  674. return $o;
  675. }
  676. function getRowAssoc($upper = ADODB_ASSOC_CASE)
  677. {
  678. if ($this->fetchMode == MYSQL_ASSOC && $upper == ADODB_ASSOC_CASE_LOWER) {
  679. $row = $this->fields;
  680. }
  681. else {
  682. $row = ADORecordSet::GetRowAssoc($upper);
  683. }
  684. return $row;
  685. }
  686. /* Use associative array to get fields array */
  687. function fields($colname)
  688. {
  689. // added @ by "Michael William Miller" <mille562@pilot.msu.edu>
  690. if ($this->fetchMode != MYSQL_NUM) return @$this->fields[$colname];
  691. if (!$this->bind) {
  692. $this->bind = array();
  693. for ($i=0; $i < $this->_numOfFields; $i++) {
  694. $o = $this->FetchField($i);
  695. $this->bind[strtoupper($o->name)] = $i;
  696. }
  697. }
  698. return $this->fields[$this->bind[strtoupper($colname)]];
  699. }
  700. function _seek($row)
  701. {
  702. if ($this->_numOfRows == 0) return false;
  703. return @mysql_data_seek($this->_queryID,$row);
  704. }
  705. function moveNext()
  706. {
  707. if (@$this->fields = mysql_fetch_array($this->_queryID,$this->fetchMode)) {
  708. $this->_updatefields();
  709. $this->_currentRow += 1;
  710. return true;
  711. }
  712. if (!$this->EOF) {
  713. $this->_currentRow += 1;
  714. $this->EOF = true;
  715. }
  716. return false;
  717. }
  718. function _fetch()
  719. {
  720. $this->fields = @mysql_fetch_array($this->_queryID,$this->fetchMode);
  721. $this->_updatefields();
  722. return is_array($this->fields);
  723. }
  724. function _close() {
  725. @mysql_free_result($this->_queryID);
  726. $this->_queryID = false;
  727. }
  728. function metaType($t,$len=-1,$fieldobj=false)
  729. {
  730. if (is_object($t)) {
  731. $fieldobj = $t;
  732. $t = $fieldobj->type;
  733. $len = $fieldobj->max_length;
  734. }
  735. $len = -1; // mysql max_length is not accurate
  736. switch (strtoupper($t)) {
  737. case 'STRING':
  738. case 'CHAR':
  739. case 'VARCHAR':
  740. case 'TINYBLOB':
  741. case 'TINYTEXT':
  742. case 'ENUM':
  743. case 'SET':
  744. if ($len <= $this->blobSize) return 'C';
  745. case 'TEXT':
  746. case 'LONGTEXT':
  747. case 'MEDIUMTEXT':
  748. return 'X';
  749. // php_mysql extension always returns 'blob' even if 'text'
  750. // so we have to check whether binary...
  751. case 'IMAGE':
  752. case 'LONGBLOB':
  753. case 'BLOB':
  754. case 'MEDIUMBLOB':
  755. case 'BINARY':
  756. return !empty($fieldobj->binary) ? 'B' : 'X';
  757. case 'YEAR':
  758. case 'DATE': return 'D';
  759. case 'TIME':
  760. case 'DATETIME':
  761. case 'TIMESTAMP': return 'T';
  762. case 'INT':
  763. case 'INTEGER':
  764. case 'BIGINT':
  765. case 'TINYINT':
  766. case 'MEDIUMINT':
  767. case 'SMALLINT':
  768. if (!empty($fieldobj->primary_key)) return 'R';
  769. else return 'I';
  770. default: return ADODB_DEFAULT_METATYPE;
  771. }
  772. }
  773. }
  774. /**
  775. * Class ADORecordSet_ext_mysql
  776. */
  777. class ADORecordSet_ext_mysql extends ADORecordSet_mysql {
  778. function moveNext()
  779. {
  780. return @adodb_movenext($this);
  781. }
  782. }
  783. }