Proyectos de Subversion Moodle

Rev

| Ultima modificación | Ver Log |

Rev Autor Línea Nro. Línea
1 efrain 1
<?php
2
/**
3
 * ADOdb base PDO driver
4
 *
5
 * This file is part of ADOdb, a Database Abstraction Layer library for PHP.
6
 *
7
 * @package ADOdb
8
 * @link https://adodb.org Project's web site and documentation
9
 * @link https://github.com/ADOdb/ADOdb Source code and issue tracker
10
 *
11
 * The ADOdb Library is dual-licensed, released under both the BSD 3-Clause
12
 * and the GNU Lesser General Public Licence (LGPL) v2.1 or, at your option,
13
 * any later version. This means you can use it in proprietary products.
14
 * See the LICENSE.md file distributed with this source code for details.
15
 * @license BSD-3-Clause
16
 * @license LGPL-2.1-or-later
17
 *
18
 * @copyright 2000-2013 John Lim
19
 * @copyright 2014 Damien Regad, Mark Newnham and the ADOdb community
20
 */
21
 
22
// security - hide paths
23
if (!defined('ADODB_DIR')) die();
24
 
25
 
26
/*
27
enum pdo_param_type {
28
PDO::PARAM_NULL, 0
29
 
30
/* int as in long (the php native int type).
31
 * If you mark a column as an int, PDO expects get_col to return
32
 * a pointer to a long
33
PDO::PARAM_INT, 1
34
 
35
/* get_col ptr should point to start of the string buffer
36
PDO::PARAM_STR, 2
37
 
38
/* get_col: when len is 0 ptr should point to a php_stream *,
39
 * otherwise it should behave like a string. Indicate a NULL field
40
 * value by setting the ptr to NULL
41
PDO::PARAM_LOB, 3
42
 
43
/* get_col: will expect the ptr to point to a new PDOStatement object handle,
44
 * but this isn't wired up yet
45
PDO::PARAM_STMT, 4 /* hierarchical result set
46
 
47
/* get_col ptr should point to a zend_bool
48
PDO::PARAM_BOOL, 5
49
 
50
 
51
/* magic flag to denote a parameter as being input/output
52
PDO::PARAM_INPUT_OUTPUT = 0x80000000
53
};
54
*/
55
 
56
function adodb_pdo_type($t)
57
{
58
	switch($t) {
59
	case 2: return 'VARCHAR';
60
	case 3: return 'BLOB';
61
	default: return 'NUMERIC';
62
	}
63
}
64
 
65
/*----------------------------------------------------------------------------*/
66
 
67
 
68
class ADODB_pdo extends ADOConnection {
69
	var $databaseType = "pdo";
70
	var $dataProvider = "pdo";
71
	var $fmtDate = "'Y-m-d'";
72
	var $fmtTimeStamp = "'Y-m-d, h:i:sA'";
73
	var $replaceQuote = "''"; // string to use to replace quotes
74
	var $hasAffectedRows = true;
75
	var $_bindInputArray = true;
76
	var $_genIDSQL;
77
	var $_genSeqSQL = "create table %s (id integer)";
78
	var $_dropSeqSQL;
79
	var $_autocommit = true;
80
	var $_lastAffectedRows = 0;
81
 
82
	var $_errormsg = false;
83
	var $_errorno = false;
84
 
85
	var $_stmt = false;
86
 
87
	/** @var ADODB_pdo_base */
88
	var $_driver;
89
 
90
	/** @var PDO */
91
	var $_connectionID;
92
 
93
	/** @var PDOStatement */
94
	var $_queryID;
95
 
96
	/*
97
	* Describe parameters passed directly to the PDO driver
98
	*
99
	* @example $db->pdoOptions = [\PDO::ATTR_ERRMODE => \PDO::ERRMODE_EXCEPTION];
100
	*/
101
	public $pdoParameters = array();
102
 
103
	function _UpdatePDO()
104
	{
105
		$d = $this->_driver;
106
		$this->fmtDate = $d->fmtDate;
107
		$this->fmtTimeStamp = $d->fmtTimeStamp;
108
		$this->replaceQuote = $d->replaceQuote;
109
		$this->sysDate = $d->sysDate;
110
		$this->sysTimeStamp = $d->sysTimeStamp;
111
		$this->random = $d->random;
112
		$this->concat_operator = $d->concat_operator;
113
		$this->nameQuote = $d->nameQuote;
114
		$this->arrayClass = $d->arrayClass;
115
 
116
		$this->hasGenID = $d->hasGenID;
117
		$this->_genIDSQL = $d->_genIDSQL;
118
		$this->_genSeqSQL = $d->_genSeqSQL;
119
		$this->_dropSeqSQL = $d->_dropSeqSQL;
120
 
121
		$d->_init($this);
122
	}
123
 
124
	function Time()
125
	{
126
		if (!empty($this->_driver->_hasdual)) {
127
			$sql = "select $this->sysTimeStamp from dual";
128
		}
129
		else {
130
			$sql = "select $this->sysTimeStamp";
131
		}
132
 
133
		$rs = $this->_Execute($sql);
134
		if ($rs && !$rs->EOF) {
135
			return $this->UnixTimeStamp(reset($rs->fields));
136
		}
137
 
138
		return false;
139
	}
140
 
141
	// returns true or false
142
	function _connect($argDSN, $argUsername, $argPassword, $argDatabasename, $persist=false)
143
	{
144
		$at = strpos($argDSN,':');
145
		$this->dsnType = substr($argDSN,0,$at);
146
 
147
		if ($argDatabasename) {
148
			switch($this->dsnType){
149
				case 'sqlsrv':
150
					$argDSN .= ';database='.$argDatabasename;
151
					break;
152
				case 'mssql':
153
				case 'mysql':
154
				case 'oci':
155
				case 'pgsql':
156
				case 'sqlite':
157
				case 'firebird':
158
				default:
159
					$argDSN .= ';dbname='.$argDatabasename;
160
			}
161
		}
162
		/*
163
		* Configure for persistent connection if required,
164
		* by adding the the pdo parameter into any provided
165
		* ones
166
		*/
167
		if ($persist) {
168
			$this->pdoParameters[\PDO::ATTR_PERSISTENT] = true;
169
		}
170
 
171
		try {
172
			$this->_connectionID = new \PDO($argDSN, $argUsername, $argPassword, $this->pdoParameters);
173
		} catch (Exception $e) {
174
			$this->_connectionID = false;
175
			$this->_errorno = -1;
176
			//var_dump($e);
177
			$this->_errormsg = 'Connection attempt failed: '.$e->getMessage();
178
			return false;
179
		}
180
 
181
		if ($this->_connectionID) {
182
			switch(ADODB_ASSOC_CASE){
183
				case ADODB_ASSOC_CASE_LOWER:
184
					$m = PDO::CASE_LOWER;
185
					break;
186
				case ADODB_ASSOC_CASE_UPPER:
187
					$m = PDO::CASE_UPPER;
188
					break;
189
				default:
190
				case ADODB_ASSOC_CASE_NATIVE:
191
					$m = PDO::CASE_NATURAL;
192
					break;
193
			}
194
 
195
			//$this->_connectionID->setAttribute(PDO::ATTR_ERRMODE,PDO::ERRMODE_SILENT );
196
			$this->_connectionID->setAttribute(PDO::ATTR_CASE,$m);
197
 
198
			// Now merge in any provided attributes for PDO
199
			foreach ($this->connectionParameters as $options) {
200
				foreach($options as $k=>$v) {
201
					if ($this->debug) {
202
						ADOconnection::outp('Setting attribute: ' . $k . ' to ' . $v);
203
					}
204
					$this->_connectionID->setAttribute($k,$v);
205
				}
206
			}
207
 
208
			$class = 'ADODB_pdo_'.$this->dsnType;
209
			//$this->_connectionID->setAttribute(PDO::ATTR_AUTOCOMMIT,true);
210
			switch($this->dsnType) {
211
				case 'mssql':
212
				case 'mysql':
213
				case 'oci':
214
				case 'pgsql':
215
				case 'sqlite':
216
				case 'sqlsrv':
217
				case 'firebird':
218
				case 'dblib':
219
					include_once(ADODB_DIR.'/drivers/adodb-pdo_'.$this->dsnType.'.inc.php');
220
					break;
221
			}
222
			if (class_exists($class)) {
223
				$this->_driver = new $class();
224
			}
225
			else {
226
				$this->_driver = new ADODB_pdo_base();
227
			}
228
 
229
			$this->_driver->_connectionID = $this->_connectionID;
230
			$this->_UpdatePDO();
231
			$this->_driver->database = $this->database;
232
			return true;
233
		}
234
		$this->_driver = new ADODB_pdo_base();
235
		return false;
236
	}
237
 
238
	function Concat()
239
	{
240
		$args = func_get_args();
241
		if($this->_driver instanceof ADODB_pdo && method_exists($this->_driver, 'Concat')) {
242
			return call_user_func_array(array($this->_driver, 'Concat'), $args);
243
		}
244
 
245
		return call_user_func_array(parent::class . '::Concat', $args);
246
	}
247
 
248
	/**
249
	 * Triggers a driver-specific request for a bind parameter
250
	 *
251
	 * @param string $name
252
	 * @param string $type
253
	 *
254
	 * @return string
255
	 */
256
	public function param($name,$type='C') {
257
 
258
		$args = func_get_args();
259
		if($this->_driver instanceof ADODB_pdo && method_exists($this->_driver, 'param')) {
260
			// Return the driver specific entry, that mimics the native driver
261
			return call_user_func_array(array($this->_driver, 'param'), $args);
262
		}
263
 
264
		// No driver specific method defined, use mysql format '?'
265
		return call_user_func_array(parent::class . '::param', $args);
266
	}
267
 
268
	// returns true or false
269
	function _pconnect($argDSN, $argUsername, $argPassword, $argDatabasename)
270
	{
271
		return $this->_connect($argDSN, $argUsername, $argPassword, $argDatabasename, true);
272
	}
273
 
274
	/*------------------------------------------------------------------------------*/
275
 
276
 
277
	function SelectLimit($sql,$nrows=-1,$offset=-1,$inputarr=false,$secs2cache=0)
278
	{
279
		$save = $this->_driver->fetchMode;
280
		$this->_driver->fetchMode = $this->fetchMode;
281
		$this->_driver->debug = $this->debug;
282
		$ret = $this->_driver->SelectLimit($sql,$nrows,$offset,$inputarr,$secs2cache);
283
		$this->_driver->fetchMode = $save;
284
		return $ret;
285
	}
286
 
287
 
288
	function ServerInfo()
289
	{
290
		return $this->_driver->ServerInfo();
291
	}
292
 
293
	function MetaTables($ttype=false,$showSchema=false,$mask=false)
294
	{
295
		return $this->_driver->MetaTables($ttype,$showSchema,$mask);
296
	}
297
 
298
	function MetaColumns($table,$normalize=true)
299
	{
300
		return $this->_driver->MetaColumns($table,$normalize);
301
	}
302
 
303
	public function metaIndexes($table,$normalize=true,$owner=false)
304
	{
305
		if (method_exists($this->_driver,'metaIndexes'))
306
			return $this->_driver->metaIndexes($table,$normalize,$owner);
307
	}
308
 
309
	/**
310
	 * Return a list of Primary Keys for a specified table.
311
	 *
312
	 * @param string   $table
313
	 * @param bool     $owner      (optional) not used in this driver
314
	 *
315
	 * @return string[]    Array of indexes
316
	 */
317
	public function metaPrimaryKeys($table,$owner=false)
318
	{
319
		if (method_exists($this->_driver,'metaPrimaryKeys'))
320
			return $this->_driver->metaPrimaryKeys($table,$owner);
321
	}
322
 
323
	/**
324
	 * Returns a list of Foreign Keys associated with a specific table.
325
	 *
326
	 * @param string   $table
327
	 * @param string   $owner      (optional) not used in this driver
328
	 * @param bool     $upper
329
	 * @param bool     $associative
330
	 *
331
	 * @return string[]|false An array where keys are tables, and values are foreign keys;
332
	 *                        false if no foreign keys could be found.
333
	 */
334
	public function metaForeignKeys($table, $owner = '', $upper = false, $associative = false) {
335
		if (method_exists($this->_driver,'metaForeignKeys'))
336
			return $this->_driver->metaForeignKeys($table, $owner, $upper, $associative);
337
	}
338
 
339
	/**
340
	 * List procedures or functions in an array.
341
	 *
342
	 * @param $procedureNamePattern A procedure name pattern; must match the procedure name as it is stored in the database.
343
	 * @param $catalog              A catalog name; must match the catalog name as it is stored in the database.
344
	 * @param $schemaPattern        A schema name pattern.
345
	 *
346
	 * @return false|array false if not supported, or array of procedures on current database with structure below
347
	 *         Array(
348
	 *           [name_of_procedure] => Array(
349
	 *             [type] => PROCEDURE or FUNCTION
350
	 *             [catalog] => Catalog_name
351
	 *             [schema] => Schema_name
352
	 *             [remarks] => explanatory comment on the procedure
353
	 *           )
354
	 *         )
355
	 */
356
	public function metaProcedures($procedureNamePattern = null, $catalog  = null, $schemaPattern  = null) {
357
		if (method_exists($this->_driver,'metaProcedures'))
358
			return $this->_driver->metaProcedures($procedureNamePattern,$catalog,$schemaPattern);
359
		return false;
360
	}
361
 
362
	function InParameter(&$stmt,&$var,$name,$maxLen=4000,$type=false)
363
	{
364
		$obj = $stmt[1];
365
		if ($type) {
366
			$obj->bindParam($name, $var, $type, $maxLen);
367
		}
368
		else {
369
			$obj->bindParam($name, $var);
370
		}
371
	}
372
 
373
	function OffsetDate($dayFraction,$date=false)
374
	{
375
		return $this->_driver->OffsetDate($dayFraction,$date);
376
	}
377
 
378
	function SelectDB($dbName)
379
	{
380
		return $this->_driver->SelectDB($dbName);
381
	}
382
 
383
	function SQLDate($fmt, $col=false)
384
	{
385
		return $this->_driver->SQLDate($fmt, $col);
386
	}
387
 
388
	function ErrorMsg()
389
	{
390
		if ($this->_errormsg !== false) {
391
			return $this->_errormsg;
392
		}
393
		if (!empty($this->_stmt)) {
394
			$arr = $this->_stmt->errorInfo();
395
		}
396
		else if (!empty($this->_connectionID)) {
397
			$arr = $this->_connectionID->errorInfo();
398
		}
399
		else {
400
			return 'No Connection Established';
401
		}
402
 
403
		if ($arr) {
404
			if (sizeof($arr)<2) {
405
				return '';
406
			}
407
			if ((integer)$arr[0]) {
408
				return $arr[2];
409
			}
410
			else {
411
				return '';
412
			}
413
		}
414
		else {
415
			return '-1';
416
		}
417
	}
418
 
419
 
420
	function ErrorNo()
421
	{
422
		if ($this->_errorno !== false) {
423
			return $this->_errorno;
424
		}
425
		if (!empty($this->_stmt)) {
426
			$err = $this->_stmt->errorCode();
427
		}
428
		else if (!empty($this->_connectionID)) {
429
			$arr = $this->_connectionID->errorInfo();
430
			if (isset($arr[0])) {
431
				$err = $arr[0];
432
			}
433
			else {
434
				$err = -1;
435
			}
436
		} else {
437
			return 0;
438
		}
439
 
440
		if ($err == '00000') {
441
			return 0; // allows empty check
442
		}
443
		return $err;
444
	}
445
 
446
	/**
447
	 * @param bool $auto_commit
448
	 * @return void
449
	 */
450
	function SetAutoCommit($auto_commit)
451
	{
452
		if($this->_driver instanceof ADODB_pdo && method_exists($this->_driver, 'SetAutoCommit')) {
453
			$this->_driver->SetAutoCommit($auto_commit);
454
		}
455
	}
456
 
457
	function SetTransactionMode($transaction_mode)
458
	{
459
		if($this->_driver instanceof ADODB_pdo && method_exists($this->_driver, 'SetTransactionMode')) {
460
			return $this->_driver->SetTransactionMode($transaction_mode);
461
		}
462
 
463
		return parent::SetTransactionMode($transaction_mode);
464
	}
465
 
466
	function beginTrans()
467
	{
468
		if($this->_driver instanceof ADODB_pdo && method_exists($this->_driver, 'beginTrans')) {
469
			return $this->_driver->beginTrans();
470
		}
471
 
472
		if (!$this->hasTransactions) {
473
			return false;
474
		}
475
		if ($this->transOff) {
476
			return true;
477
		}
478
		$this->transCnt += 1;
479
		$this->_autocommit = false;
480
		$this->SetAutoCommit(false);
481
 
482
		return $this->_connectionID->beginTransaction();
483
	}
484
 
485
	function commitTrans($ok=true)
486
	{
487
 
488
		if($this->_driver instanceof ADODB_pdo && method_exists($this->_driver, 'commitTrans')) {
489
			return $this->_driver->commitTrans($ok);
490
		}
491
 
492
		if (!$this->hasTransactions) {
493
			return false;
494
		}
495
		if ($this->transOff) {
496
			return true;
497
		}
498
		if (!$ok) {
499
			return $this->rollbackTrans();
500
		}
501
		if ($this->transCnt) {
502
			$this->transCnt -= 1;
503
		}
504
		$this->_autocommit = true;
505
 
506
		$ret = $this->_connectionID->commit();
507
		$this->SetAutoCommit(true);
508
		return $ret;
509
	}
510
 
511
	function RollbackTrans()
512
	{
513
		if($this->_driver instanceof ADODB_pdo && method_exists($this->_driver, 'RollbackTrans')) {
514
			return $this->_driver->RollbackTrans();
515
		}
516
 
517
		if (!$this->hasTransactions) {
518
			return false;
519
		}
520
		if ($this->transOff) {
521
			return true;
522
		}
523
		if ($this->transCnt) {
524
			$this->transCnt -= 1;
525
		}
526
		$this->_autocommit = true;
527
 
528
		$ret = $this->_connectionID->rollback();
529
		$this->SetAutoCommit(true);
530
		return $ret;
531
	}
532
 
533
	function Prepare($sql)
534
	{
535
		$this->_stmt = $this->_connectionID->prepare($sql);
536
		if ($this->_stmt) {
537
			return array($sql,$this->_stmt);
538
		}
539
 
540
		return false;
541
	}
542
 
543
	function PrepareStmt($sql)
544
	{
545
		$stmt = $this->_connectionID->prepare($sql);
546
		if (!$stmt) {
547
			return false;
548
		}
549
		$obj = new ADOPDOStatement($stmt,$this);
550
		return $obj;
551
	}
552
 
553
	public function createSequence($seqname='adodbseq',$startID=1)
554
	{
555
		if($this->_driver instanceof ADODB_pdo && method_exists($this->_driver, 'createSequence')) {
556
			return $this->_driver->createSequence($seqname, $startID);
557
		}
558
 
559
		return parent::CreateSequence($seqname, $startID);
560
	}
561
 
562
	function DropSequence($seqname='adodbseq')
563
	{
564
		if($this->_driver instanceof ADODB_pdo && method_exists($this->_driver, 'DropSequence')) {
565
			return $this->_driver->DropSequence($seqname);
566
		}
567
 
568
		return parent::DropSequence($seqname);
569
	}
570
 
571
	function GenID($seqname='adodbseq',$startID=1)
572
	{
573
		if($this->_driver instanceof ADODB_pdo && method_exists($this->_driver, 'GenID')) {
574
			return $this->_driver->GenID($seqname, $startID);
575
		}
576
 
577
		return parent::GenID($seqname, $startID);
578
	}
579
 
580
 
581
	function _query($sql,$inputarr=false)
582
	{
583
		$ok = false;
584
		if (is_array($sql)) {
585
			$stmt = $sql[1];
586
		} else {
587
			$stmt = $this->_connectionID->prepare($sql);
588
		}
589
 
590
		if ($stmt) {
591
			if ($this->_driver instanceof ADODB_pdo) {
592
				$this->_driver->debug = $this->debug;
593
			}
594
			if ($inputarr) {
595
 
596
				/*
597
				* inputarr must be numeric
598
				*/
599
				$inputarr = array_values($inputarr);
600
				$ok = $stmt->execute($inputarr);
601
			}
602
			else {
603
				$ok = $stmt->execute();
604
			}
605
		}
606
 
607
 
608
		$this->_errormsg = false;
609
		$this->_errorno = false;
610
 
611
		if ($ok) {
612
			$this->_stmt = $stmt;
613
			return $stmt;
614
		}
615
 
616
		if ($stmt) {
617
 
618
			$arr = $stmt->errorinfo();
619
			if ((integer)$arr[1]) {
620
				$this->_errormsg = $arr[2];
621
				$this->_errorno = $arr[1];
622
			}
623
 
624
		} else {
625
			$this->_errormsg = false;
626
			$this->_errorno = false;
627
		}
628
		return false;
629
	}
630
 
631
	// returns true or false
632
	function _close()
633
	{
634
		$this->_stmt = false;
635
		return true;
636
	}
637
 
638
	function _affectedrows()
639
	{
640
		return ($this->_stmt) ? $this->_stmt->rowCount() : 0;
641
	}
642
 
643
	protected function _insertID($table = '', $column = '')
644
	{
645
		return ($this->_connectionID) ? $this->_connectionID->lastInsertId() : 0;
646
	}
647
 
648
	/**
649
	 * Quotes a string to be sent to the database.
650
	 *
651
	 * If we have an active connection, delegates quoting to the underlying
652
	 * PDO object PDO::quote(). Otherwise, replace "'" by the value of
653
	 * $replaceQuote (same behavior as mysqli driver).
654
	 *
655
	 * @param string  $s           The string to quote
656
	 * @param bool   $magic_quotes This param is not used since 5.21.0.
657
	 *                             It remains for backwards compatibility.
658
	 *
659
	 * @return string Quoted string
660
	 */
661
	function qStr($s, $magic_quotes = false)
662
	{
663
		if ($this->_connectionID) {
664
			return $this->_connectionID->quote($s);
665
		}
666
		return "'" . str_replace("'", $this->replaceQuote, $s) . "'";
667
	}
668
 
669
}
670
 
671
/**
672
 * Base class for Database-specific PDO drivers.
673
 */
674
class ADODB_pdo_base extends ADODB_pdo {
675
 
676
	var $sysDate = "'?'";
677
	var $sysTimeStamp = "'?'";
678
 
679
 
680
	function _init($parentDriver)
681
	{
682
		$parentDriver->_bindInputArray = true;
683
		#$parentDriver->_connectionID->setAttribute(PDO::MYSQL_ATTR_USE_BUFFERED_QUERY,true);
684
	}
685
 
686
	function ServerInfo()
687
	{
688
		return ADOConnection::ServerInfo();
689
	}
690
 
691
	function SelectLimit($sql,$nrows=-1,$offset=-1,$inputarr=false,$secs2cache=0)
692
	{
693
		$ret = ADOConnection::SelectLimit($sql,$nrows,$offset,$inputarr,$secs2cache);
694
		return $ret;
695
	}
696
 
697
	function MetaTables($ttype=false,$showSchema=false,$mask=false)
698
	{
699
		return false;
700
	}
701
 
702
	function MetaColumns($table,$normalize=true)
703
	{
704
		return false;
705
	}
706
}
707
 
708
class ADOPDOStatement {
709
 
710
	var $databaseType = "pdo";
711
	var $dataProvider = "pdo";
712
	var $_stmt;
713
	var $_connectionID;
714
 
715
	function __construct($stmt,$connection)
716
	{
717
		$this->_stmt = $stmt;
718
		$this->_connectionID = $connection;
719
	}
720
 
721
	function Execute($inputArr=false)
722
	{
723
		$savestmt = $this->_connectionID->_stmt;
724
		$rs = $this->_connectionID->Execute(array(false,$this->_stmt),$inputArr);
725
		$this->_connectionID->_stmt = $savestmt;
726
		return $rs;
727
	}
728
 
729
	function InParameter(&$var,$name,$maxLen=4000,$type=false)
730
	{
731
 
732
		if ($type) {
733
			$this->_stmt->bindParam($name,$var,$type,$maxLen);
734
		}
735
		else {
736
			$this->_stmt->bindParam($name, $var);
737
		}
738
	}
739
 
740
	function Affected_Rows()
741
	{
742
		return ($this->_stmt) ? $this->_stmt->rowCount() : 0;
743
	}
744
 
745
	function ErrorMsg()
746
	{
747
		if ($this->_stmt) {
748
			$arr = $this->_stmt->errorInfo();
749
		}
750
		else {
751
			$arr = $this->_connectionID->errorInfo();
752
		}
753
 
754
		if (is_array($arr)) {
755
			if ((integer) $arr[0] && isset($arr[2])) {
756
				return $arr[2];
757
			}
758
			else {
759
				return '';
760
			}
761
		} else {
762
			return '-1';
763
		}
764
	}
765
 
766
	function NumCols()
767
	{
768
		return ($this->_stmt) ? $this->_stmt->columnCount() : 0;
769
	}
770
 
771
	function ErrorNo()
772
	{
773
		if ($this->_stmt) {
774
			return $this->_stmt->errorCode();
775
		}
776
		else {
777
			return $this->_connectionID->errorInfo();
778
		}
779
	}
780
}
781
 
782
/*--------------------------------------------------------------------------------------
783
	Class Name: Recordset
784
--------------------------------------------------------------------------------------*/
785
 
786
class ADORecordSet_pdo extends ADORecordSet {
787
 
788
	var $bind = false;
789
	var $databaseType = "pdo";
790
	var $dataProvider = "pdo";
791
 
792
	/** @var PDOStatement */
793
	var $_queryID;
794
 
795
	function __construct($id,$mode=false)
796
	{
797
		if ($mode === false) {
798
			global $ADODB_FETCH_MODE;
799
			$mode = $ADODB_FETCH_MODE;
800
		}
801
		$this->adodbFetchMode = $mode;
802
		switch($mode) {
803
		case ADODB_FETCH_NUM: $mode = PDO::FETCH_NUM; break;
804
		case ADODB_FETCH_ASSOC:  $mode = PDO::FETCH_ASSOC; break;
805
 
806
		case ADODB_FETCH_BOTH:
807
		default: $mode = PDO::FETCH_BOTH; break;
808
		}
809
		$this->fetchMode = $mode;
810
 
811
		$this->_queryID = $id;
812
		parent::__construct($id);
813
	}
814
 
815
 
816
	function Init()
817
	{
818
		if ($this->_inited) {
819
			return;
820
		}
821
		$this->_inited = true;
822
		if ($this->_queryID) {
823
			@$this->_initrs();
824
		}
825
		else {
826
			$this->_numOfRows = 0;
827
			$this->_numOfFields = 0;
828
		}
829
		if ($this->_numOfRows != 0 && $this->_currentRow == -1) {
830
			$this->_currentRow = 0;
831
			if ($this->EOF = ($this->_fetch() === false)) {
832
				$this->_numOfRows = 0; // _numOfRows could be -1
833
			}
834
		} else {
835
			$this->EOF = true;
836
		}
837
	}
838
 
839
	function _initrs()
840
	{
841
	global $ADODB_COUNTRECS;
842
 
843
		$this->_numOfRows = ($ADODB_COUNTRECS) ? @$this->_queryID->rowCount() : -1;
844
		if (!$this->_numOfRows) {
845
			$this->_numOfRows = -1;
846
		}
847
		$this->_numOfFields = $this->_queryID->columnCount();
848
	}
849
 
850
	// returns the field object
851
	function FetchField($fieldOffset = -1)
852
	{
853
		$off=$fieldOffset+1; // offsets begin at 1
854
 
855
		$o= new ADOFieldObject();
856
		$arr = @$this->_queryID->getColumnMeta($fieldOffset);
857
		if (!$arr) {
858
			$o->name = 'bad getColumnMeta()';
859
			$o->max_length = -1;
860
			$o->type = 'VARCHAR';
861
			$o->precision = 0;
862
	#		$false = false;
863
			return $o;
864
		}
865
		//adodb_pr($arr);
866
		$o->name = $arr['name'];
867
		if (isset($arr['sqlsrv:decl_type']) && $arr['sqlsrv:decl_type'] <> "null")
868
		{
869
		    /*
870
		    * If the database is SQL server, use the native built-ins
871
		    */
872
		    $o->type = $arr['sqlsrv:decl_type'];
873
		}
874
		elseif (isset($arr['native_type']) && $arr['native_type'] <> "null")
875
		{
876
		    $o->type = $arr['native_type'];
877
		}
878
		else
879
		{
880
		     $o->type = adodb_pdo_type($arr['pdo_type']);
881
		}
882
 
883
		$o->max_length = $arr['len'];
884
		$o->precision = $arr['precision'];
885
 
886
		switch(ADODB_ASSOC_CASE) {
887
			case ADODB_ASSOC_CASE_LOWER:
888
				$o->name = strtolower($o->name);
889
				break;
890
			case ADODB_ASSOC_CASE_UPPER:
891
				$o->name = strtoupper($o->name);
892
				break;
893
		}
894
		return $o;
895
	}
896
 
897
	function _seek($row)
898
	{
899
		return false;
900
	}
901
 
902
	function _fetch()
903
	{
904
		if (!$this->_queryID) {
905
			return false;
906
		}
907
 
908
		$this->fields = $this->_queryID->fetch($this->fetchMode);
909
		return !empty($this->fields);
910
	}
911
 
912
	function _close()
913
	{
914
		$this->_queryID = false;
915
	}
916
 
917
	function Fields($colname)
918
	{
919
		if ($this->adodbFetchMode != ADODB_FETCH_NUM) {
920
			return @$this->fields[$colname];
921
		}
922
 
923
		if (!$this->bind) {
924
			$this->bind = array();
925
			for ($i=0; $i < $this->_numOfFields; $i++) {
926
				$o = $this->FetchField($i);
927
				$this->bind[strtoupper($o->name)] = $i;
928
			}
929
		}
930
		return $this->fields[$this->bind[strtoupper($colname)]];
931
	}
932
 
933
}
934
 
935
class ADORecordSet_array_pdo extends ADORecordSet_array {
936
	/** @var PDOStatement */
937
	var $_queryID;
938
}