Differences Between: [Versions 310 and 400] [Versions 311 and 400] [Versions 39 and 400] [Versions 400 and 401] [Versions 400 and 402] [Versions 400 and 403]
1 <?php 2 /** 3 * MSSQL driver via ODBC 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 if (!defined('_ADODB_ODBC_LAYER')) { 26 include_once(ADODB_DIR."/drivers/adodb-odbc.inc.php"); 27 } 28 29 30 class ADODB_odbc_mssql extends ADODB_odbc { 31 var $databaseType = 'odbc_mssql'; 32 var $fmtDate = "'Y-m-d'"; 33 var $fmtTimeStamp = "'Y-m-d\TH:i:s'"; 34 var $_bindInputArray = true; 35 var $metaDatabasesSQL = "select name from sysdatabases where name <> 'master'"; 36 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'))"; 37 var $metaColumnsSQL = # xtype==61 is datetime 38 "select c.name,t.name,c.length,c.isnullable, c.status, 39 (case when c.xusertype=61 then 0 else c.xprec end), 40 (case when c.xusertype=61 then 0 else c.xscale end) 41 from syscolumns c join systypes t on t.xusertype=c.xusertype join sysobjects o on o.id=c.id where o.name='%s'"; 42 var $hasTop = 'top'; // support mssql/interbase SELECT TOP 10 * FROM TABLE 43 var $sysDate = 'GetDate()'; 44 var $sysTimeStamp = 'GetDate()'; 45 var $leftOuter = '*='; 46 var $rightOuter = '=*'; 47 var $substr = 'substring'; 48 var $length = 'len'; 49 var $ansiOuter = true; // for mssql7 or later 50 var $identitySQL = 'select SCOPE_IDENTITY()'; // 'select SCOPE_IDENTITY'; # for mssql 2000 51 var $hasInsertID = true; 52 var $connectStmt = 'SET CONCAT_NULL_YIELDS_NULL OFF'; # When SET CONCAT_NULL_YIELDS_NULL is ON, 53 # concatenating a null value with a string yields a NULL result 54 55 // crashes php... 56 function ServerInfo() 57 { 58 global $ADODB_FETCH_MODE; 59 $save = $ADODB_FETCH_MODE; 60 $ADODB_FETCH_MODE = ADODB_FETCH_NUM; 61 $row = $this->GetRow("execute sp_server_info 2"); 62 $ADODB_FETCH_MODE = $save; 63 if (!is_array($row)) return false; 64 $arr['description'] = $row[2]; 65 $arr['version'] = ADOConnection::_findvers($arr['description']); 66 return $arr; 67 } 68 69 function IfNull( $field, $ifNull ) 70 { 71 return " ISNULL($field, $ifNull) "; // if MS SQL Server 72 } 73 74 protected function _insertID($table = '', $column = '') 75 { 76 // SCOPE_IDENTITY() 77 // Returns the last IDENTITY value inserted into an IDENTITY column in 78 // the same scope. A scope is a module -- a stored procedure, trigger, 79 // function, or batch. Thus, two statements are in the same scope if 80 // they are in the same stored procedure, function, or batch. 81 return $this->GetOne($this->identitySQL); 82 } 83 84 85 function MetaForeignKeys($table, $owner=false, $upper=false) 86 { 87 global $ADODB_FETCH_MODE; 88 89 $save = $ADODB_FETCH_MODE; 90 $ADODB_FETCH_MODE = ADODB_FETCH_NUM; 91 $table = $this->qstr(strtoupper($table)); 92 93 $sql = 94 "select object_name(constid) as constraint_name, 95 col_name(fkeyid, fkey) as column_name, 96 object_name(rkeyid) as referenced_table_name, 97 col_name(rkeyid, rkey) as referenced_column_name 98 from sysforeignkeys 99 where upper(object_name(fkeyid)) = $table 100 order by constraint_name, referenced_table_name, keyno"; 101 102 $constraints = $this->GetArray($sql); 103 104 $ADODB_FETCH_MODE = $save; 105 106 $arr = false; 107 foreach($constraints as $constr) { 108 //print_r($constr); 109 $arr[$constr[0]][$constr[2]][] = $constr[1].'='.$constr[3]; 110 } 111 if (!$arr) return false; 112 113 $arr2 = false; 114 115 foreach($arr as $k => $v) { 116 foreach($v as $a => $b) { 117 if ($upper) $a = strtoupper($a); 118 $arr2[$a] = $b; 119 } 120 } 121 return $arr2; 122 } 123 124 function MetaTables($ttype=false,$showSchema=false,$mask=false) 125 { 126 if ($mask) {//$this->debug=1; 127 $save = $this->metaTablesSQL; 128 $mask = $this->qstr($mask); 129 $this->metaTablesSQL .= " AND name like $mask"; 130 } 131 $ret = ADOConnection::MetaTables($ttype,$showSchema); 132 133 if ($mask) { 134 $this->metaTablesSQL = $save; 135 } 136 return $ret; 137 } 138 139 function MetaColumns($table, $normalize=true) 140 { 141 142 $this->_findschema($table,$schema); 143 if ($schema) { 144 $dbName = $this->database; 145 $this->SelectDB($schema); 146 } 147 global $ADODB_FETCH_MODE; 148 $save = $ADODB_FETCH_MODE; 149 $ADODB_FETCH_MODE = ADODB_FETCH_NUM; 150 151 if ($this->fetchMode !== false) $savem = $this->SetFetchMode(false); 152 $rs = $this->Execute(sprintf($this->metaColumnsSQL,$table)); 153 154 if ($schema) { 155 $this->SelectDB($dbName); 156 } 157 158 if (isset($savem)) $this->SetFetchMode($savem); 159 $ADODB_FETCH_MODE = $save; 160 if (!is_object($rs)) { 161 $false = false; 162 return $false; 163 } 164 165 $retarr = array(); 166 while (!$rs->EOF){ 167 $fld = new ADOFieldObject(); 168 $fld->name = $rs->fields[0]; 169 $fld->type = $rs->fields[1]; 170 171 $fld->not_null = (!$rs->fields[3]); 172 $fld->auto_increment = ($rs->fields[4] == 128); // sys.syscolumns status field. 0x80 = 128 ref: http://msdn.microsoft.com/en-us/library/ms186816.aspx 173 174 175 if (isset($rs->fields[5]) && $rs->fields[5]) { 176 if ($rs->fields[5]>0) $fld->max_length = $rs->fields[5]; 177 $fld->scale = $rs->fields[6]; 178 if ($fld->scale>0) $fld->max_length += 1; 179 } else 180 $fld->max_length = $rs->fields[2]; 181 182 183 if ($save == ADODB_FETCH_NUM) { 184 $retarr[] = $fld; 185 } else { 186 $retarr[strtoupper($fld->name)] = $fld; 187 } 188 $rs->MoveNext(); 189 } 190 191 $rs->Close(); 192 return $retarr; 193 194 } 195 196 197 function MetaIndexes($table,$primary=false, $owner=false) 198 { 199 $table = $this->qstr($table); 200 201 $sql = "SELECT i.name AS ind_name, C.name AS col_name, USER_NAME(O.uid) AS Owner, c.colid, k.Keyno, 202 CASE WHEN I.indid BETWEEN 1 AND 254 AND (I.status & 2048 = 2048 OR I.Status = 16402 AND O.XType = 'V') THEN 1 ELSE 0 END AS IsPK, 203 CASE WHEN I.status & 2 = 2 THEN 1 ELSE 0 END AS IsUnique 204 FROM dbo.sysobjects o INNER JOIN dbo.sysindexes I ON o.id = i.id 205 INNER JOIN dbo.sysindexkeys K ON I.id = K.id AND I.Indid = K.Indid 206 INNER JOIN dbo.syscolumns c ON K.id = C.id AND K.colid = C.Colid 207 WHERE LEFT(i.name, 8) <> '_WA_Sys_' AND o.status >= 0 AND O.Name LIKE $table 208 ORDER BY O.name, I.Name, K.keyno"; 209 210 global $ADODB_FETCH_MODE; 211 $save = $ADODB_FETCH_MODE; 212 $ADODB_FETCH_MODE = ADODB_FETCH_NUM; 213 if ($this->fetchMode !== FALSE) { 214 $savem = $this->SetFetchMode(FALSE); 215 } 216 217 $rs = $this->Execute($sql); 218 if (isset($savem)) { 219 $this->SetFetchMode($savem); 220 } 221 $ADODB_FETCH_MODE = $save; 222 223 if (!is_object($rs)) { 224 return FALSE; 225 } 226 227 $indexes = array(); 228 while ($row = $rs->FetchRow()) { 229 if (!$primary && $row[5]) continue; 230 231 $indexes[$row[0]]['unique'] = $row[6]; 232 $indexes[$row[0]]['columns'][] = $row[1]; 233 } 234 return $indexes; 235 } 236 237 function _query($sql,$inputarr=false) 238 { 239 if (is_string($sql)) $sql = str_replace('||','+',$sql); 240 return ADODB_odbc::_query($sql,$inputarr); 241 } 242 243 function SetTransactionMode( $transaction_mode ) 244 { 245 $this->_transmode = $transaction_mode; 246 if (empty($transaction_mode)) { 247 $this->Execute('SET TRANSACTION ISOLATION LEVEL READ COMMITTED'); 248 return; 249 } 250 if (!stristr($transaction_mode,'isolation')) $transaction_mode = 'ISOLATION LEVEL '.$transaction_mode; 251 $this->Execute("SET TRANSACTION ".$transaction_mode); 252 } 253 254 // "Stein-Aksel Basma" <basma@accelero.no> 255 // tested with MSSQL 2000 256 function MetaPrimaryKeys($table, $owner = false) 257 { 258 global $ADODB_FETCH_MODE; 259 260 $schema = ''; 261 $this->_findschema($table,$schema); 262 //if (!$schema) $schema = $this->database; 263 if ($schema) $schema = "and k.table_catalog like '$schema%'"; 264 265 $sql = "select distinct k.column_name,ordinal_position from information_schema.key_column_usage k, 266 information_schema.table_constraints tc 267 where tc.constraint_name = k.constraint_name and tc.constraint_type = 268 'PRIMARY KEY' and k.table_name = '$table' $schema order by ordinal_position "; 269 270 $savem = $ADODB_FETCH_MODE; 271 $ADODB_FETCH_MODE = ADODB_FETCH_ASSOC; 272 $a = $this->GetCol($sql); 273 $ADODB_FETCH_MODE = $savem; 274 275 if ($a && sizeof($a)>0) return $a; 276 $false = false; 277 return $false; 278 } 279 280 function SelectLimit($sql,$nrows=-1,$offset=-1, $inputarr=false,$secs2cache=0) 281 { 282 $nrows = (int) $nrows; 283 $offset = (int) $offset; 284 if ($nrows > 0 && $offset <= 0) { 285 $sql = preg_replace( 286 '/(^\s*select\s+(distinctrow|distinct)?)/i','\\1 '.$this->hasTop." $nrows ",$sql); 287 $rs = $this->Execute($sql,$inputarr); 288 } else 289 $rs = ADOConnection::SelectLimit($sql,$nrows,$offset,$inputarr,$secs2cache); 290 291 return $rs; 292 } 293 294 // Format date column in sql string given an input format that understands Y M D 295 function SQLDate($fmt, $col=false) 296 { 297 if (!$col) $col = $this->sysTimeStamp; 298 $s = ''; 299 300 $len = strlen($fmt); 301 for ($i=0; $i < $len; $i++) { 302 if ($s) $s .= '+'; 303 $ch = $fmt[$i]; 304 switch($ch) { 305 case 'Y': 306 case 'y': 307 $s .= "datename(yyyy,$col)"; 308 break; 309 case 'M': 310 $s .= "convert(char(3),$col,0)"; 311 break; 312 case 'm': 313 $s .= "replace(str(month($col),2),' ','0')"; 314 break; 315 case 'Q': 316 case 'q': 317 $s .= "datename(quarter,$col)"; 318 break; 319 case 'D': 320 case 'd': 321 $s .= "replace(str(day($col),2),' ','0')"; 322 break; 323 case 'h': 324 $s .= "substring(convert(char(14),$col,0),13,2)"; 325 break; 326 327 case 'H': 328 $s .= "replace(str(datepart(hh,$col),2),' ','0')"; 329 break; 330 331 case 'i': 332 $s .= "replace(str(datepart(mi,$col),2),' ','0')"; 333 break; 334 case 's': 335 $s .= "replace(str(datepart(ss,$col),2),' ','0')"; 336 break; 337 case 'a': 338 case 'A': 339 $s .= "substring(convert(char(19),$col,0),18,2)"; 340 break; 341 342 default: 343 if ($ch == '\\') { 344 $i++; 345 $ch = substr($fmt,$i,1); 346 } 347 $s .= $this->qstr($ch); 348 break; 349 } 350 } 351 return $s; 352 } 353 354 /** 355 * Returns a substring of a varchar type field 356 * 357 * The SQL server version varies because the length is mandatory, so 358 * we append a reasonable string length 359 * 360 * @param string $fld The field to sub-string 361 * @param int $start The start point 362 * @param int $length An optional length 363 * 364 * @return The SQL text 365 */ 366 function substr($fld,$start,$length=0) 367 { 368 if ($length == 0) 369 /* 370 * The length available to varchar is 2GB, but that makes no 371 * sense in a substring, so I'm going to arbitrarily limit 372 * the length to 1K, but you could change it if you want 373 */ 374 $length = 1024; 375 376 $text = "SUBSTRING($fld,$start,$length)"; 377 return $text; 378 } 379 380 /** 381 * Returns the maximum size of a MetaType C field. Because of the 382 * database design, SQL Server places no limits on the size of data inserted 383 * Although the actual limit is 2^31-1 bytes. 384 * 385 * @return int 386 */ 387 function charMax() 388 { 389 return ADODB_STRINGMAX_NOLIMIT; 390 } 391 392 /** 393 * Returns the maximum size of a MetaType X field. Because of the 394 * database design, SQL Server places no limits on the size of data inserted 395 * Although the actual limit is 2^31-1 bytes. 396 * 397 * @return int 398 */ 399 function textMax() 400 { 401 return ADODB_STRINGMAX_NOLIMIT; 402 } 403 404 // returns concatenated string 405 // MSSQL requires integers to be cast as strings 406 // automatically cast every datatype to VARCHAR(255) 407 // @author David Rogers (introspectshun) 408 function Concat() 409 { 410 $s = ""; 411 $arr = func_get_args(); 412 413 // Split single record on commas, if possible 414 if (sizeof($arr) == 1) { 415 foreach ($arr as $arg) { 416 $args = explode(',', $arg); 417 } 418 $arr = $args; 419 } 420 421 array_walk( 422 $arr, 423 function(&$value, $key) { 424 $value = "CAST(" . $value . " AS VARCHAR(255))"; 425 } 426 ); 427 $s = implode('+',$arr); 428 if (sizeof($arr) > 0) return "$s"; 429 430 return ''; 431 } 432 433 } 434 435 class ADORecordSet_odbc_mssql extends ADORecordSet_odbc { 436 437 var $databaseType = 'odbc_mssql'; 438 439 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body