1<?php
2/*
3V4.65 22 July 2005  (c) 2000-2005 John Lim (jlim#natsoft.com.my). All rights reserved.
4  Released under both BSD license and Lesser GPL library license.
5  Whenever there is any discrepancy between the two licenses,
6  the BSD license will take precedence.
7Set tabs to 4 for best viewing.
8
9  Latest version is available at http://adodb.sourceforge.net
10
11  Requires ODBC. Works on Windows and Unix.
12
13	Problems:
14		Where is float/decimal type in pdo_param_type
15		LOB handling for CLOB/BLOB differs significantly
16*/
17// security - hide paths
18if (!defined('ADODB_DIR')) die();
19
20
21/*
22enum pdo_param_type {
23PDO_PARAM_NULL, 0
24
25/* int as in long (the php native int type).
26 * If you mark a column as an int, PDO expects get_col to return
27 * a pointer to a long
28PDO_PARAM_INT, 1
29
30/* get_col ptr should point to start of the string buffer
31PDO_PARAM_STR, 2
32
33/* get_col: when len is 0 ptr should point to a php_stream *,
34 * otherwise it should behave like a string. Indicate a NULL field
35 * value by setting the ptr to NULL
36PDO_PARAM_LOB, 3
37
38/* get_col: will expect the ptr to point to a new PDOStatement object handle,
39 * but this isn't wired up yet
40PDO_PARAM_STMT, 4 /* hierarchical result set
41
42/* get_col ptr should point to a zend_bool
43PDO_PARAM_BOOL, 5
44
45
46/* magic flag to denote a parameter as being input/output
47PDO_PARAM_INPUT_OUTPUT = 0x80000000
48};
49*/
50
51function adodb_pdo_type($t)
52{
53	switch($t) {
54	case 2: return 'VARCHAR';
55	case 3: return 'BLOB';
56	default: return 'NUMERIC';
57	}
58}
59
60/*--------------------------------------------------------------------------------------
61--------------------------------------------------------------------------------------*/
62
63////////////////////////////////////////////////
64
65
66
67class ADODB_pdo_base extends ADODB_pdo {
68
69	function _init($parentDriver)
70	{
71		$parentDriver->_bindInputArray = false;
72		#$parentDriver->_connectionID->setAttribute(PDO_MYSQL_ATTR_USE_BUFFERED_QUERY,true);
73	}
74
75	function ServerInfo()
76	{
77		return ADOConnection::ServerInfo();
78	}
79
80	function &SelectLimit($sql,$nrows=-1,$offset=-1,$inputarr=false,$secs2cache=0)
81	{
82		$ret = ADOConnection::SelectLimit($sql,$nrows,$offset,$inputarr,$secs2cache);
83		return $ret;
84	}
85
86	function MetaTables()
87	{
88		return false;
89	}
90
91	function MetaColumns()
92	{
93		return false;
94	}
95}
96
97
98class ADODB_pdo extends ADOConnection {
99	var $databaseType = "pdo";
100	var $dataProvider = "pdo";
101	var $fmtDate = "'Y-m-d'";
102	var $fmtTimeStamp = "'Y-m-d, h:i:sA'";
103	var $replaceQuote = "''"; // string to use to replace quotes
104	var $hasAffectedRows = true;
105	var $_bindInputArray = true;
106	var $_genSeqSQL = "create table %s (id integer)";
107	var $_autocommit = true;
108	var $_haserrorfunctions = true;
109	var $_lastAffectedRows = 0;
110
111	var $_errormsg = false;
112	var $_errorno = false;
113
114	var $dsnType = '';
115	var $stmt = false;
116
117	function ADODB_pdo()
118	{
119	}
120
121	function _UpdatePDO()
122	{
123		$d = &$this->_driver;
124		$this->fmtDate = $d->fmtDate;
125		$this->fmtTimeStamp = $d->fmtTimeStamp;
126		$this->replaceQuote = $d->replaceQuote;
127		$this->sysDate = $d->sysDate;
128		$this->sysTimeStamp = $d->sysTimeStamp;
129		$this->random = $d->random;
130		$this->concat_operator = $d->concat_operator;
131
132		$d->_init($this);
133	}
134
135	function Time()
136	{
137		return false;
138	}
139
140	// returns true or false
141	function _connect($argDSN, $argUsername, $argPassword, $argDatabasename, $persist=false)
142	{
143		$at = strpos($argDSN,':');
144		$this->dsnType = substr($argDSN,0,$at);
145
146		try {
147			$this->_connectionID = new PDO($argDSN, $argUsername, $argPassword);
148		} catch (Exception $e) {
149			$this->_connectionID = false;
150			$this->_errorno = -1;
151			//var_dump($e);
152			$this->_errormsg = 'Connection attempt failed: '.$e->getMessage();
153			return false;
154		}
155
156		if ($this->_connectionID) {
157			switch(ADODB_ASSOC_CASE){
158			case 0: $m = PDO_CASE_LOWER; break;
159			case 1: $m = PDO_CASE_UPPER; break;
160			default:
161			case 2: $m = PDO_CASE_NATURAL; break;
162			}
163
164			//$this->_connectionID->setAttribute(PDO_ATTR_ERRMODE,PDO_ERRMODE_SILENT );
165			$this->_connectionID->setAttribute(PDO_ATTR_CASE,$m);
166
167			$class = 'ADODB_pdo_'.$this->dsnType;
168			//$this->_connectionID->setAttribute(PDO_ATTR_AUTOCOMMIT,true);
169			switch($this->dsnType) {
170			case 'oci':
171			case 'mysql':
172			case 'pgsql':
173				include_once(ADODB_DIR.'/drivers/adodb-pdo_'.$this->dsnType.'.inc.php');
174				break;
175			}
176			if (class_exists($class))
177				$this->_driver = new $class();
178			else
179				$this->_driver = new ADODB_pdo_base();
180
181			$this->_driver->_connectionID = $this->_connectionID;
182			$this->_UpdatePDO();
183			return true;
184		}
185		$this->_driver = new ADODB_pdo_base();
186		return false;
187	}
188
189	// returns true or false
190	function _pconnect($argDSN, $argUsername, $argPassword, $argDatabasename)
191	{
192		return $this->_connect($argDSN, $argUsername, $argPassword, $argDatabasename, true);
193	}
194
195	/*------------------------------------------------------------------------------*/
196
197
198	function &SelectLimit($sql,$nrows=-1,$offset=-1,$inputarr=false,$secs2cache=0)
199	{
200		$save = $this->_driver->fetchMode;
201		$this->_driver->fetchMode = $this->fetchMode;
202		$ret = $this->_driver->SelectLimit($sql,$nrows,$offset,$inputarr,$secs2cache);
203		$this->_driver->fetchMode = $save;
204		return $ret;
205	}
206
207
208	function ServerInfo()
209	{
210		return $this->_driver->ServerInfo();
211	}
212
213	function MetaTables($ttype=false,$showSchema=false,$mask=false)
214	{
215		return $this->_driver->MetaTables($ttype,$showSchema,$mask);
216	}
217
218	function MetaColumns($table,$normalize=true)
219	{
220		return $this->_driver->MetaColumns($table,$normalize);
221	}
222
223	function InParameter(&$stmt,&$var,$name,$maxLen=4000,$type=false)
224	{
225		$obj = $stmt[1];
226		if ($type) $obj->bindParam($name,$var,$type,$maxLen);
227		else $obj->bindParam($name, $var);
228	}
229
230
231	function ErrorMsg()
232	{
233		if ($this->_errormsg !== false) return $this->_errormsg;
234		if (!empty($this->_stmt)) $arr = $this->_stmt->errorInfo();
235		else if (!empty($this->_connectionID)) $arr = $this->_connectionID->errorInfo();
236		else return 'No Connection Established';
237
238
239		if ($arr) {
240		 	if (sizeof($arr)<2) return '';
241			if ((integer)$arr[1]) return $arr[2];
242			else return '';
243		} else return '-1';
244	}
245
246
247	function ErrorNo()
248	{
249		if ($this->_errorno !== false) return $this->_errorno;
250		if (!empty($this->_stmt)) $err = $this->_stmt->errorCode();
251		else if (!empty($this->_connectionID)) {
252			$arr = $this->_connectionID->errorInfo();
253			if (isset($arr[0])) $err = $arr[0];
254			else $err = -1;
255		} else
256			return 0;
257
258		if ($err == '00000') return 0; // allows empty check
259		return $err;
260	}
261
262	function BeginTrans()
263	{
264		if (!$this->hasTransactions) return false;
265		if ($this->transOff) return true;
266		$this->transCnt += 1;
267		$this->_autocommit = false;
268		$this->_connectionID->setAttribute(PDO_ATTR_AUTOCOMMIT,false);
269		return $this->_connectionID->beginTransaction();
270	}
271
272	function CommitTrans($ok=true)
273	{
274		if (!$this->hasTransactions) return false;
275		if ($this->transOff) return true;
276		if (!$ok) return $this->RollbackTrans();
277		if ($this->transCnt) $this->transCnt -= 1;
278		$this->_autocommit = true;
279
280		$ret = $this->_connectionID->commit();
281		$this->_connectionID->setAttribute(PDO_ATTR_AUTOCOMMIT,true);
282		return $ret;
283	}
284
285	function RollbackTrans()
286	{
287		if (!$this->hasTransactions) return false;
288		if ($this->transOff) return true;
289		if ($this->transCnt) $this->transCnt -= 1;
290		$this->_autocommit = true;
291
292		$ret = $this->_connectionID->rollback();
293		$this->_connectionID->setAttribute(PDO_ATTR_AUTOCOMMIT,true);
294		return $ret;
295	}
296
297	function Prepare($sql)
298	{
299		$this->_stmt = $this->_connectionID->prepare($sql);
300		if ($this->_stmt) return array($sql,$this->_stmt);
301
302		return false;
303	}
304
305	function PrepareStmt($sql)
306	{
307		$stmt = $this->_connectionID->prepare($sql);
308		if (!$stmt) return false;
309		$obj = new ADOPDOStatement($stmt,$this);
310		return $obj;
311	}
312
313	/* returns queryID or false */
314	function _query($sql,$inputarr=false)
315	{
316		if (is_array($sql)) {
317			$stmt = $sql[1];
318		} else {
319			$stmt = $this->_connectionID->prepare($sql);
320		}
321
322		if ($stmt) {
323			if ($inputarr) $ok = $stmt->execute($inputarr);
324			else $ok = $stmt->execute();
325		}
326
327
328		$this->_errormsg = false;
329		$this->_errorno = false;
330
331		if ($ok) {
332			$this->_stmt = $stmt;
333			return $stmt;
334		}
335
336		if ($stmt) {
337
338			$arr = $stmt->errorinfo();
339			if ((integer)$arr[1]) {
340				$this->_errormsg = $arr[2];
341				$this->_errorno = $arr[1];
342			}
343
344		} else {
345			$this->_errormsg = false;
346			$this->_errorno = false;
347		}
348		return false;
349	}
350
351	// returns true or false
352	function _close()
353	{
354		$this->_stmt = false;
355		return true;
356	}
357
358	function _affectedrows()
359	{
360		return ($this->_stmt) ? $this->_stmt->rowCount() : 0;
361	}
362
363	function _insertid()
364	{
365		return ($this->_connectionID) ? $this->_connectionID->lastInsertId() : 0;
366	}
367}
368
369class ADOPDOStatement {
370
371	var $databaseType = "pdo";
372	var $dataProvider = "pdo";
373	var $_stmt;
374	var $_connectionID;
375
376	function ADOPDOStatement($stmt,$connection)
377	{
378		$this->_stmt = $stmt;
379		$this->_connectionID = $connection;
380	}
381
382	function Execute($inputArr=false)
383	{
384		$savestmt = $this->_connectionID->_stmt;
385		$rs = $this->_connectionID->Execute(array(false,$this->_stmt),$inputArr);
386		$this->_connectionID->_stmt = $savestmt;
387		return $rs;
388	}
389
390	function InParameter(&$var,$name,$maxLen=4000,$type=false)
391	{
392
393		if ($type) $this->_stmt->bindParam($name,$var,$type,$maxLen);
394		else $this->_stmt->bindParam($name, $var);
395	}
396
397	function Affected_Rows()
398	{
399		return ($this->_stmt) ? $this->_stmt->rowCount() : 0;
400	}
401
402	function ErrorMsg()
403	{
404		if ($this->_stmt) $arr = $this->_stmt->errorInfo();
405		else $arr = $this->_connectionID->errorInfo();
406
407		if (is_array($arr)) {
408			if ((integer) $arr[0] && isset($arr[2])) return $arr[2];
409			else return '';
410		} else return '-1';
411	}
412
413	function NumCols()
414	{
415		return ($this->_stmt) ? $this->_stmt->columnCount() : 0;
416	}
417
418	function ErrorNo()
419	{
420		if ($this->_stmt) return $this->_stmt->errorCode();
421		else return $this->_connectionID->errorInfo();
422	}
423}
424
425/*--------------------------------------------------------------------------------------
426	 Class Name: Recordset
427--------------------------------------------------------------------------------------*/
428
429class ADORecordSet_pdo extends ADORecordSet {
430
431	var $bind = false;
432	var $databaseType = "pdo";
433	var $dataProvider = "pdo";
434
435	function ADORecordSet_pdo($id,$mode=false)
436	{
437		if ($mode === false) {
438			global $ADODB_FETCH_MODE;
439			$mode = $ADODB_FETCH_MODE;
440		}
441		$this->adodbFetchMode = $mode;
442		switch($mode) {
443		case ADODB_FETCH_NUM: $mode = PDO_FETCH_NUM; break;
444		case ADODB_FETCH_ASSOC:  $mode = PDO_FETCH_ASSOC; break;
445
446		case ADODB_FETCH_BOTH:
447		default: $mode = PDO_FETCH_BOTH; break;
448		}
449		$this->fetchMode = $mode;
450
451		$this->_queryID = $id;
452		$this->ADORecordSet($id);
453	}
454
455
456	function Init()
457	{
458		if ($this->_inited) return;
459		$this->_inited = true;
460		if ($this->_queryID) @$this->_initrs();
461		else {
462			$this->_numOfRows = 0;
463			$this->_numOfFields = 0;
464		}
465		if ($this->_numOfRows != 0 && $this->_currentRow == -1) {
466			$this->_currentRow = 0;
467			if ($this->EOF = ($this->_fetch() === false)) {
468				$this->_numOfRows = 0; // _numOfRows could be -1
469			}
470		} else {
471			$this->EOF = true;
472		}
473	}
474
475	function _initrs()
476	{
477	global $ADODB_COUNTRECS;
478
479		$this->_numOfRows = ($ADODB_COUNTRECS) ? @$this->_queryID->rowCount() : -1;
480		if (!$this->_numOfRows) $this->_numOfRows = -1;
481		$this->_numOfFields = $this->_queryID->columnCount();
482	}
483
484	// returns the field object
485	function &FetchField($fieldOffset = -1)
486	{
487		$off=$fieldOffset+1; // offsets begin at 1
488
489		$o= new ADOFieldObject();
490		$arr = @$this->_queryID->getColumnMeta($fieldOffset);
491		if (!$arr) {
492			$o->name = 'bad getColumnMeta()';
493			$o->max_length = -1;
494			$o->type = 'VARCHAR';
495			$o->precision = 0;
496	#		$false = false;
497			return $o;
498		}
499		//adodb_pr($arr);
500		$o->name = $arr['name'];
501		if (isset($arr['native_type'])) $o->type = $arr['native_type'];
502		else $o->type = adodb_pdo_type($arr['pdo_type']);
503		$o->max_length = $arr['len'];
504		$o->precision = $arr['precision'];
505
506		if (ADODB_ASSOC_CASE == 0) $o->name = strtolower($o->name);
507		else if (ADODB_ASSOC_CASE == 1) $o->name = strtoupper($o->name);
508		return $o;
509	}
510
511	function _seek($row)
512	{
513		return false;
514	}
515
516	function _fetch()
517	{
518		if (!$this->_queryID) return false;
519
520		$this->fields = $this->_queryID->fetch($this->fetchMode);
521		return !empty($this->fields);
522	}
523
524	function _close()
525	{
526		$this->_queryID = false;
527	}
528
529	function Fields($colname)
530	{
531		if ($this->adodbFetchMode != ADODB_FETCH_NUM) return @$this->fields[$colname];
532
533		if (!$this->bind) {
534			$this->bind = array();
535			for ($i=0; $i < $this->_numOfFields; $i++) {
536				$o = $this->FetchField($i);
537				$this->bind[strtoupper($o->name)] = $i;
538			}
539		}
540		 return $this->fields[$this->bind[strtoupper($colname)]];
541	}
542
543}
544
545?>