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