1<?php
2/**
3 * ADOdb PDO dblib driver.
4 *
5 * Released under both BSD license and Lesser GPL library license.
6 * Whenever there is any discrepancy between the two licenses, the BSD license
7 * will take precedence.
8 *
9 * @version   v5.21.0  2021-02-27
10 * @copyright (c) 2000-2013 John Lim (jlim#natsoft.com). All rights reserved.
11 * @copyright (c) 2019      Damien Regad, Mark Newnham and the ADOdb community
12 */
13
14class ADODB_pdo_dblib extends ADODB_pdo
15{
16	var $hasTop = 'top';
17	var $sysDate = 'convert(datetime,convert(char,GetDate(),102),102)';
18	var $sysTimeStamp = 'GetDate()';
19	var $metaDatabasesSQL = "select name from sysdatabases where name <> 'master'";
20	var $metaTablesSQL="select name,case when type='U' then 'T' else 'V' end from sysobjects where (type='U' or type='V') and (name not in ('sysallocations','syscolumns','syscomments','sysdepends','sysfilegroups','sysfiles','sysfiles1','sysforeignkeys','sysfulltextcatalogs','sysindexes','sysindexkeys','sysmembers','sysobjects','syspermissions','sysprotects','sysreferences','systypes','sysusers','sysalternates','sysconstraints','syssegments','REFERENTIAL_CONSTRAINTS','CHECK_CONSTRAINTS','CONSTRAINT_TABLE_USAGE','CONSTRAINT_COLUMN_USAGE','VIEWS','VIEW_TABLE_USAGE','VIEW_COLUMN_USAGE','SCHEMATA','TABLES','TABLE_CONSTRAINTS','TABLE_PRIVILEGES','COLUMNS','COLUMN_DOMAIN_USAGE','COLUMN_PRIVILEGES','DOMAINS','DOMAIN_CONSTRAINTS','KEY_COLUMN_USAGE','dtproperties'))";
21
22	var $metaColumnsSQL = "SELECT c.NAME, OBJECT_NAME(c.id) as tbl_name, c.length, c.isnullable, c.status, ( CASE WHEN c.xusertype=61 THEN 0 ELSE c.xprec END), ( CASE WHEN c.xusertype=61 THEN 0 ELSE c.xscale END), ISNULL(i.is_primary_key, 0) as primary_key FROM   syscolumns c INNER JOIN systypes t ON t.xusertype=c.xusertype INNER JOIN sysobjects o ON o.id=c.id LEFT JOIN sys.index_columns ic ON ic.object_id = c.id AND c.colid = ic.column_id LEFT JOIN sys.indexes i ON i.object_id = ic.object_id AND i.index_id = ic.index_id WHERE c.id = OBJECT_ID('%s') ORDER by c.colid";
23
24	function _init(ADODB_pdo $parentDriver)
25	{
26		$parentDriver->hasTransactions = true;
27		$parentDriver->_bindInputArray = true;
28		$parentDriver->hasInsertID = true;
29		$parentDriver->fmtTimeStamp = "'Y-m-d H:i:s'";
30		$parentDriver->fmtDate = "'Y-m-d'";
31	}
32
33	function BeginTrans()
34	{
35		$returnval = parent::BeginTrans();
36		return $returnval;
37	}
38
39	function MetaColumns($table, $normalize=true)
40	{
41		$this->_findschema($table,$schema);
42		if ($schema) {
43			$dbName = $this->database;
44			$this->SelectDB($schema);
45		}
46		global $ADODB_FETCH_MODE;
47		$save = $ADODB_FETCH_MODE;
48		$ADODB_FETCH_MODE = ADODB_FETCH_NUM;
49
50		if ($this->fetchMode !== false) $savem = $this->SetFetchMode(false);
51		$rs = $this->Execute(sprintf($this->metaColumnsSQL,$table));
52
53		if ($schema) {
54			$this->SelectDB($dbName);
55		}
56
57		if (isset($savem)) $this->SetFetchMode($savem);
58		$ADODB_FETCH_MODE = $save;
59		if (!is_object($rs)) {
60			$false = false;
61			return $false;
62		}
63
64		$retarr = array();
65		while (!$rs->EOF) {
66			$fld = new ADOFieldObject();
67			$fld->name = $rs->fields[0];
68			$fld->type = $rs->fields[1];
69			$fld->primary_key = $rs->fields[7];
70
71			$fld->not_null = (!$rs->fields[3]);
72			$fld->auto_increment = ($rs->fields[4] == 128);		// sys.syscolumns status field. 0x80 = 128 ref: http://msdn.microsoft.com/en-us/library/ms186816.aspx
73
74			if (isset($rs->fields[5]) && $rs->fields[5]) {
75				if ($rs->fields[5]>0) $fld->max_length = $rs->fields[5];
76				$fld->scale = $rs->fields[6];
77				if ($fld->scale>0) $fld->max_length += 1;
78			} else
79				$fld->max_length = $rs->fields[2];
80
81			if ($save == ADODB_FETCH_NUM) {
82				$retarr[] = $fld;
83			} else {
84				$retarr[strtoupper($fld->name)] = $fld;
85			}
86			$rs->MoveNext();
87		}
88
89		$rs->Close();
90		return $retarr;
91	}
92
93	function MetaTables($ttype=false,$showSchema=false,$mask=false)
94	{
95		if ($mask) {
96			$save = $this->metaTablesSQL;
97			$mask = $this->qstr(($mask));
98			$this->metaTablesSQL .= " AND name like $mask";
99		}
100		$ret = ADOConnection::MetaTables($ttype,$showSchema);
101
102		if ($mask) {
103			$this->metaTablesSQL = $save;
104		}
105		return $ret;
106	}
107
108	function SelectLimit($sql,$nrows=-1,$offset=-1, $inputarr=false,$secs2cache=0)
109	{
110		if ($nrows > 0 && $offset <= 0) {
111			$sql = preg_replace(
112				'/(^\s*select\s+(distinctrow|distinct)?)/i','\\1 '.$this->hasTop." $nrows ",$sql);
113
114			if ($secs2cache)
115				$rs = $this->CacheExecute($secs2cache, $sql, $inputarr);
116			else
117				$rs = $this->Execute($sql,$inputarr);
118		} else
119			$rs = ADOConnection::SelectLimit($sql,$nrows,$offset,$inputarr,$secs2cache);
120
121		return $rs;
122	}
123
124	function _query($sql,$inputarr=false)
125	{
126		$this->_connectionID->setAttribute(\PDO::ATTR_EMULATE_PREPARES , true);
127		if (is_array($sql)) {
128			$stmt = $sql[1];
129		} else {
130			$stmt = $this->_connectionID->prepare($sql);
131		}
132
133		if ($stmt) {
134			$this->_driver->debug = $this->debug;
135			if ($inputarr) {
136				foreach ($inputarr as $key => $value) {
137					if(gettype($key) == 'integer') {
138						$key += 1;
139					}
140					$stmt->bindValue($key, $value, $this->GetPDODataType($value));
141				}
142			}
143		}
144
145		$ok = $stmt->execute();
146
147		$this->_errormsg = false;
148		$this->_errorno = false;
149
150		if ($ok) {
151			$this->_stmt = $stmt;
152			return $stmt;
153		}
154
155		if ($stmt) {
156
157			$arr = $stmt->errorinfo();
158			if ((integer)$arr[1]) {
159				$this->_errormsg = $arr[2];
160				$this->_errorno = $arr[1];
161			}
162
163		} else {
164			$this->_errormsg = false;
165			$this->_errorno = false;
166		}
167		return false;
168	}
169
170	private function GetPDODataType($var)
171	{
172		if(gettype($var) == 'integer') {
173			return PDO::PARAM_INT ;
174		}
175		return PDO::PARAM_STR;
176	}
177
178	function ServerInfo()
179	{
180		return ADOConnection::ServerInfo();
181	}
182}
183