Proyectos de Subversion Moodle

Rev

| Ultima modificación | Ver Log |

Rev Autor Línea Nro. Línea
1 efrain 1
<?php
2
/**
3
 * ODBTP driver
4
 *
5
 * @deprecated will be removed in ADOdb version 6
6
 *
7
 * This file is part of ADOdb, a Database Abstraction Layer library for PHP.
8
 *
9
 * @package ADOdb
10
 * @link https://adodb.org Project's web site and documentation
11
 * @link https://github.com/ADOdb/ADOdb Source code and issue tracker
12
 *
13
 * The ADOdb Library is dual-licensed, released under both the BSD 3-Clause
14
 * and the GNU Lesser General Public Licence (LGPL) v2.1 or, at your option,
15
 * any later version. This means you can use it in proprietary products.
16
 * See the LICENSE.md file distributed with this source code for details.
17
 * @license BSD-3-Clause
18
 * @license LGPL-2.1-or-later
19
 *
20
 * @copyright 2000-2013 John Lim
21
 * @copyright 2014 Damien Regad, Mark Newnham and the ADOdb community
22
 * @author stefan bogdan <sbogdan@rsb.ro>
23
 */
24
 
25
// security - hide paths
26
if (!defined('ADODB_DIR')) die();
27
 
28
define("_ADODB_ODBTP_LAYER", 2 );
29
 
30
class ADODB_odbtp extends ADOConnection{
31
	var $databaseType = "odbtp";
32
	var $dataProvider = "odbtp";
33
	var $fmtDate = "'Y-m-d'";
34
	var $fmtTimeStamp = "'Y-m-d, h:i:sA'";
35
	var $replaceQuote = "''"; // string to use to replace quotes
36
	var $odbc_driver = 0;
37
	var $hasAffectedRows = true;
38
	var $hasInsertID = false;
39
	var $hasGenID = true;
40
	var $hasMoveFirst = true;
41
 
42
	var $_genSeqSQL = "create table %s (seq_name char(30) not null unique , seq_value integer not null)";
43
	var $_dropSeqSQL = "delete from adodb_seq where seq_name = '%s'";
44
	var $_bindInputArray = false;
45
	var $_useUnicodeSQL = false;
46
	var $_canPrepareSP = false;
47
	var $_dontPoolDBC = true;
48
 
49
	/** @var string DBMS name. */
50
	var $odbc_name;
51
 
52
	/** @var bool */
53
	var $_canSelectDb = false;
54
 
55
	/** @var mixed */
56
	var $_lastAffectedRows;
57
 
58
	function ServerInfo()
59
	{
60
		return array('description' => @odbtp_get_attr( ODB_ATTR_DBMSNAME, $this->_connectionID),
61
		             'version' => @odbtp_get_attr( ODB_ATTR_DBMSVER, $this->_connectionID));
62
	}
63
 
64
	function ErrorMsg()
65
	{
66
		if ($this->_errorMsg !== false) return $this->_errorMsg;
67
		if (empty($this->_connectionID)) return @odbtp_last_error();
68
		return @odbtp_last_error($this->_connectionID);
69
	}
70
 
71
	function ErrorNo()
72
	{
73
		if ($this->_errorCode !== false) return $this->_errorCode;
74
		if (empty($this->_connectionID)) return @odbtp_last_error_state();
75
			return @odbtp_last_error_state($this->_connectionID);
76
	}
77
/*
78
	function DBDate($d,$isfld=false)
79
	{
80
		if (empty($d) && $d !== 0) return 'null';
81
		if ($isfld) return "convert(date, $d, 120)";
82
 
83
		if (is_string($d)) $d = ADORecordSet::UnixDate($d);
84
		$d = adodb_date($this->fmtDate,$d);
85
		return "convert(date, $d, 120)";
86
	}
87
 
88
	function DBTimeStamp($d,$isfld=false)
89
	{
90
		if (empty($d) && $d !== 0) return 'null';
91
		if ($isfld) return "convert(datetime, $d, 120)";
92
 
93
		if (is_string($d)) $d = ADORecordSet::UnixDate($d);
94
		$d = adodb_date($this->fmtDate,$d);
95
		return "convert(datetime, $d, 120)";
96
	}
97
*/
98
 
99
	protected function _insertID($table = '', $column = '')
100
	{
101
	// SCOPE_IDENTITY()
102
	// Returns the last IDENTITY value inserted into an IDENTITY column in
103
	// the same scope. A scope is a module -- a stored procedure, trigger,
104
	// function, or batch. Thus, two statements are in the same scope if
105
	// they are in the same stored procedure, function, or batch.
106
			return $this->GetOne($this->identitySQL);
107
	}
108
 
109
	function _affectedrows()
110
	{
111
		if ($this->_queryID) {
112
			return @odbtp_affected_rows ($this->_queryID);
113
	   } else
114
		return 0;
115
	}
116
 
117
	function CreateSequence($seqname='adodbseq',$start=1)
118
	{
119
		//verify existence
120
		$num = $this->GetOne("select seq_value from adodb_seq");
121
		$seqtab='adodb_seq';
122
		if( $this->odbc_driver == ODB_DRIVER_FOXPRO ) {
123
			$path = @odbtp_get_attr( ODB_ATTR_DATABASENAME, $this->_connectionID );
124
			//if using vfp dbc file
125
			if( !strcasecmp(strrchr($path, '.'), '.dbc') )
126
                $path = substr($path,0,strrpos($path,'\/'));
127
           	$seqtab = $path . '/' . $seqtab;
128
        }
129
		if($num == false) {
130
			if (empty($this->_genSeqSQL)) return false;
131
			$ok = $this->Execute(sprintf($this->_genSeqSQL ,$seqtab));
132
		}
133
		$num = $this->GetOne("select seq_value from adodb_seq where seq_name='$seqname'");
134
		if ($num) {
135
			return false;
136
		}
137
		$start -= 1;
138
		return $this->Execute("insert into adodb_seq values('$seqname',$start)");
139
	}
140
 
141
	function DropSequence($seqname = 'adodbseq')
142
	{
143
		if (empty($this->_dropSeqSQL)) return false;
144
		return $this->Execute(sprintf($this->_dropSeqSQL,$seqname));
145
	}
146
 
147
	function GenID($seq='adodbseq',$start=1)
148
	{
149
		$seqtab='adodb_seq';
150
		if( $this->odbc_driver == ODB_DRIVER_FOXPRO) {
151
			$path = @odbtp_get_attr( ODB_ATTR_DATABASENAME, $this->_connectionID );
152
			//if using vfp dbc file
153
			if( !strcasecmp(strrchr($path, '.'), '.dbc') )
154
                $path = substr($path,0,strrpos($path,'\/'));
155
           	$seqtab = $path . '/' . $seqtab;
156
        }
157
		$MAXLOOPS = 100;
158
		while (--$MAXLOOPS>=0) {
159
			$num = $this->GetOne("select seq_value from adodb_seq where seq_name='$seq'");
160
			if ($num === false) {
161
				//verify if abodb_seq table exist
162
				$ok = $this->GetOne("select seq_value from adodb_seq ");
163
				if(!$ok) {
164
					//creating the sequence table adodb_seq
165
					$this->Execute(sprintf($this->_genSeqSQL ,$seqtab));
166
				}
167
				$start -= 1;
168
				$num = '0';
169
				$ok = $this->Execute("insert into adodb_seq values('$seq',$start)");
170
				if (!$ok) return false;
171
			}
172
			$ok = $this->Execute("update adodb_seq set seq_value=seq_value+1 where seq_name='$seq'");
173
			if($ok) {
174
				$num += 1;
175
				$this->genID = $num;
176
				return $num;
177
			}
178
		}
179
	if ($fn = $this->raiseErrorFn) {
180
		$fn($this->databaseType,'GENID',-32000,"Unable to generate unique id after $MAXLOOPS attempts",$seq,$num);
181
	}
182
		return false;
183
	}
184
 
185
	//example for $UserOrDSN
186
	//for visual fox : DRIVER={Microsoft Visual FoxPro Driver};SOURCETYPE=DBF;SOURCEDB=c:\YourDbfFileDir;EXCLUSIVE=NO;
187
	//for visual fox dbc: DRIVER={Microsoft Visual FoxPro Driver};SOURCETYPE=DBC;SOURCEDB=c:\YourDbcFileDir\mydb.dbc;EXCLUSIVE=NO;
188
	//for access : DRIVER={Microsoft Access Driver (*.mdb)};DBQ=c:\path_to_access_db\base_test.mdb;UID=root;PWD=;
189
	//for mssql : DRIVER={SQL Server};SERVER=myserver;UID=myuid;PWD=mypwd;DATABASE=OdbtpTest;
190
	//if uid & pwd can be separate
191
    function _connect($HostOrInterface, $UserOrDSN='', $argPassword='', $argDatabase='')
192
	{
193
		if ($argPassword && stripos($UserOrDSN,'DRIVER=') !== false) {
194
			$this->_connectionID = odbtp_connect($HostOrInterface,$UserOrDSN.';PWD='.$argPassword);
195
		} else
196
			$this->_connectionID = odbtp_connect($HostOrInterface,$UserOrDSN,$argPassword,$argDatabase);
197
		if ($this->_connectionID === false) {
198
			$this->_errorMsg = $this->ErrorMsg() ;
199
			return false;
200
		}
201
 
202
		odbtp_convert_datetime($this->_connectionID,true);
203
 
204
		if ($this->_dontPoolDBC) {
205
			if (function_exists('odbtp_dont_pool_dbc'))
206
				@odbtp_dont_pool_dbc($this->_connectionID);
207
		}
208
		else {
209
			$this->_dontPoolDBC = true;
210
		}
211
		$this->odbc_driver = @odbtp_get_attr(ODB_ATTR_DRIVER, $this->_connectionID);
212
		$dbms = strtolower(@odbtp_get_attr(ODB_ATTR_DBMSNAME, $this->_connectionID));
213
		$this->odbc_name = $dbms;
214
 
215
		// Account for inconsistent DBMS names
216
		if( $this->odbc_driver == ODB_DRIVER_ORACLE )
217
			$dbms = 'oracle';
218
		else if( $this->odbc_driver == ODB_DRIVER_SYBASE )
219
			$dbms = 'sybase';
220
 
221
		// Set DBMS specific attributes
222
		switch( $dbms ) {
223
			case 'microsoft sql server':
224
				$this->databaseType = 'odbtp_mssql';
225
				$this->fmtDate = "'Y-m-d'";
226
				$this->fmtTimeStamp = "'Y-m-d h:i:sA'";
227
				$this->sysDate = 'convert(datetime,convert(char,GetDate(),102),102)';
228
				$this->sysTimeStamp = 'GetDate()';
229
				$this->ansiOuter = true;
230
				$this->leftOuter = '*=';
231
				$this->rightOuter = '=*';
232
                $this->hasTop = 'top';
233
				$this->hasInsertID = true;
234
				$this->hasTransactions = true;
235
				$this->_bindInputArray = true;
236
				$this->_canSelectDb = true;
237
				$this->substr = "substring";
238
				$this->length = 'len';
239
				$this->identitySQL = 'select SCOPE_IDENTITY()';
240
				$this->metaDatabasesSQL = "select name from master..sysdatabases where name <> 'master'";
241
				$this->_canPrepareSP = true;
242
				break;
243
			case 'access':
244
				$this->databaseType = 'odbtp_access';
245
				$this->fmtDate = "#Y-m-d#";
246
				$this->fmtTimeStamp = "#Y-m-d h:i:sA#";
247
				$this->sysDate = "FORMAT(NOW,'yyyy-mm-dd')";
248
				$this->sysTimeStamp = 'NOW';
249
                $this->hasTop = 'top';
250
				$this->hasTransactions = false;
251
				$this->_canPrepareSP = true;  // For MS Access only.
252
				break;
253
			case 'visual foxpro':
254
				$this->databaseType = 'odbtp_vfp';
255
				$this->fmtDate = "{^Y-m-d}";
256
				$this->fmtTimeStamp = "{^Y-m-d, h:i:sA}";
257
				$this->sysDate = 'date()';
258
				$this->sysTimeStamp = 'datetime()';
259
				$this->ansiOuter = true;
260
                $this->hasTop = 'top';
261
				$this->hasTransactions = false;
262
				$this->replaceQuote = "'+chr(39)+'";
263
				$this->true = '.T.';
264
				$this->false = '.F.';
265
 
266
				break;
267
			case 'oracle':
268
				$this->databaseType = 'odbtp_oci8';
269
				$this->fmtDate = "'Y-m-d 00:00:00'";
270
				$this->fmtTimeStamp = "'Y-m-d h:i:sA'";
271
				$this->sysDate = 'TRUNC(SYSDATE)';
272
				$this->sysTimeStamp = 'SYSDATE';
273
				$this->hasTransactions = true;
274
				$this->_bindInputArray = true;
275
				$this->concat_operator = '||';
276
				break;
277
			case 'sybase':
278
				$this->databaseType = 'odbtp_sybase';
279
				$this->fmtDate = "'Y-m-d'";
280
				$this->fmtTimeStamp = "'Y-m-d H:i:s'";
281
				$this->sysDate = 'GetDate()';
282
				$this->sysTimeStamp = 'GetDate()';
283
				$this->leftOuter = '*=';
284
				$this->rightOuter = '=*';
285
				$this->hasInsertID = true;
286
				$this->hasTransactions = true;
287
				$this->identitySQL = 'select SCOPE_IDENTITY()';
288
				break;
289
			default:
290
				$this->databaseType = 'odbtp';
291
				if( @odbtp_get_attr(ODB_ATTR_TXNCAPABLE, $this->_connectionID) )
292
					$this->hasTransactions = true;
293
				else
294
					$this->hasTransactions = false;
295
		}
296
        @odbtp_set_attr(ODB_ATTR_FULLCOLINFO, TRUE, $this->_connectionID );
297
 
298
		if ($this->_useUnicodeSQL )
299
			@odbtp_set_attr(ODB_ATTR_UNICODESQL, TRUE, $this->_connectionID);
300
 
301
        return true;
302
	}
303
 
304
	function _pconnect($HostOrInterface, $UserOrDSN='', $argPassword='', $argDatabase='')
305
	{
306
		$this->_dontPoolDBC = false;
307
  		return $this->_connect($HostOrInterface, $UserOrDSN, $argPassword, $argDatabase);
308
	}
309
 
310
	function SelectDB($dbName)
311
	{
312
		if (!@odbtp_select_db($dbName, $this->_connectionID)) {
313
			return false;
314
		}
315
		$this->database = $dbName;
316
		return true;
317
	}
318
 
319
	function MetaTables($ttype='',$showSchema=false,$mask=false)
320
	{
321
	global $ADODB_FETCH_MODE;
322
 
323
		$savem = $ADODB_FETCH_MODE;
324
		$ADODB_FETCH_MODE = ADODB_FETCH_NUM;
325
		if ($this->fetchMode !== false) $savefm = $this->SetFetchMode(false);
326
 
327
		$arr = $this->GetArray("||SQLTables||||$ttype");
328
 
329
		if (isset($savefm)) $this->SetFetchMode($savefm);
330
		$ADODB_FETCH_MODE = $savem;
331
 
332
		$arr2 = array();
333
		for ($i=0; $i < sizeof($arr); $i++) {
334
			if ($arr[$i][3] == 'SYSTEM TABLE' )	continue;
335
			if ($arr[$i][2])
336
				$arr2[] = $showSchema && $arr[$i][1]? $arr[$i][1].'.'.$arr[$i][2] : $arr[$i][2];
337
		}
338
		return $arr2;
339
	}
340
 
341
	function MetaColumns($table,$upper=true)
342
	{
343
	global $ADODB_FETCH_MODE;
344
 
345
		$schema = false;
346
		$this->_findschema($table,$schema);
347
		if ($upper) $table = strtoupper($table);
348
 
349
		$savem = $ADODB_FETCH_MODE;
350
		$ADODB_FETCH_MODE = ADODB_FETCH_NUM;
351
		if ($this->fetchMode !== false) $savefm = $this->SetFetchMode(false);
352
 
353
		$rs = $this->Execute( "||SQLColumns||$schema|$table" );
354
 
355
		if (isset($savefm)) $this->SetFetchMode($savefm);
356
		$ADODB_FETCH_MODE = $savem;
357
 
358
		if (!$rs || $rs->EOF) {
359
			$false = false;
360
			return $false;
361
		}
362
		$retarr = array();
363
		while (!$rs->EOF) {
364
			//print_r($rs->fields);
365
			if (strtoupper($rs->fields[2]) == $table) {
366
				$fld = new ADOFieldObject();
367
				$fld->name = $rs->fields[3];
368
				$fld->type = $rs->fields[5];
369
				$fld->max_length = $rs->fields[6];
370
    			$fld->not_null = !empty($rs->fields[9]);
371
 				$fld->scale = $rs->fields[7];
372
				if (isset($rs->fields[12])) // vfp does not have field 12
373
	 				if (!is_null($rs->fields[12])) {
374
	 					$fld->has_default = true;
375
	 					$fld->default_value = $rs->fields[12];
376
					}
377
				$retarr[strtoupper($fld->name)] = $fld;
378
			} else if (!empty($retarr))
379
				break;
380
			$rs->MoveNext();
381
		}
382
		$rs->Close();
383
 
384
		return $retarr;
385
	}
386
 
387
	function MetaPrimaryKeys($table, $owner='')
388
	{
389
	global $ADODB_FETCH_MODE;
390
 
391
		$savem = $ADODB_FETCH_MODE;
392
		$ADODB_FETCH_MODE = ADODB_FETCH_NUM;
393
		$arr = $this->GetArray("||SQLPrimaryKeys||$owner|$table");
394
		$ADODB_FETCH_MODE = $savem;
395
 
396
		//print_r($arr);
397
		$arr2 = array();
398
		for ($i=0; $i < sizeof($arr); $i++) {
399
			if ($arr[$i][3]) $arr2[] = $arr[$i][3];
400
		}
401
		return $arr2;
402
	}
403
 
404
	public function metaForeignKeys($table, $owner = '', $upper = false, $associative = false)
405
	{
406
	global $ADODB_FETCH_MODE;
407
 
408
		$savem = $ADODB_FETCH_MODE;
409
		$ADODB_FETCH_MODE = ADODB_FETCH_NUM;
410
		$constraints = $this->GetArray("||SQLForeignKeys|||||$owner|$table");
411
		$ADODB_FETCH_MODE = $savem;
412
 
413
		$arr = false;
414
		foreach($constraints as $constr) {
415
			//print_r($constr);
416
			$arr[$constr[11]][$constr[2]][] = $constr[7].'='.$constr[3];
417
		}
418
		if (!$arr) {
419
			$false = false;
420
			return $false;
421
		}
422
 
423
		$arr2 = array();
424
 
425
		foreach($arr as $k => $v) {
426
			foreach($v as $a => $b) {
427
				if ($upper) $a = strtoupper($a);
428
				$arr2[$a] = $b;
429
			}
430
		}
431
		return $arr2;
432
	}
433
 
434
	function BeginTrans()
435
	{
436
		if (!$this->hasTransactions) return false;
437
		if ($this->transOff) return true;
438
		$this->transCnt += 1;
439
		$this->autoCommit = false;
440
		if (defined('ODB_TXN_DEFAULT'))
441
			$txn = ODB_TXN_DEFAULT;
442
		else
443
			$txn = ODB_TXN_READUNCOMMITTED;
444
		$rs = @odbtp_set_attr(ODB_ATTR_TRANSACTIONS,$txn,$this->_connectionID);
445
		if(!$rs) return false;
446
		return true;
447
	}
448
 
449
	function CommitTrans($ok=true)
450
	{
451
		if ($this->transOff) return true;
452
		if (!$ok) return $this->RollbackTrans();
453
		if ($this->transCnt) $this->transCnt -= 1;
454
		$this->autoCommit = true;
455
		if( ($ret = @odbtp_commit($this->_connectionID)) )
456
			$ret = @odbtp_set_attr(ODB_ATTR_TRANSACTIONS, ODB_TXN_NONE, $this->_connectionID);//set transaction off
457
		return $ret;
458
	}
459
 
460
	function RollbackTrans()
461
	{
462
		if ($this->transOff) return true;
463
		if ($this->transCnt) $this->transCnt -= 1;
464
		$this->autoCommit = true;
465
		if( ($ret = @odbtp_rollback($this->_connectionID)) )
466
			$ret = @odbtp_set_attr(ODB_ATTR_TRANSACTIONS, ODB_TXN_NONE, $this->_connectionID);//set transaction off
467
		return $ret;
468
	}
469
 
470
	function SelectLimit($sql,$nrows=-1,$offset=-1, $inputarr=false,$secs2cache=0)
471
	{
472
		// TOP requires ORDER BY for Visual FoxPro
473
		if( $this->odbc_driver == ODB_DRIVER_FOXPRO ) {
474
			if (!preg_match('/ORDER[ \t\r\n]+BY/is',$sql)) $sql .= ' ORDER BY 1';
475
		}
476
		$ret = ADOConnection::SelectLimit($sql,$nrows,$offset,$inputarr,$secs2cache);
477
		return $ret;
478
	}
479
 
480
	function Prepare($sql)
481
	{
482
		if (! $this->_bindInputArray) return $sql; // no binding
483
 
484
        $this->_errorMsg = false;
485
		$this->_errorCode = false;
486
 
487
		$stmt = @odbtp_prepare($sql,$this->_connectionID);
488
		if (!$stmt) {
489
		//	print "Prepare Error for ($sql) ".$this->ErrorMsg()."<br>";
490
			return $sql;
491
		}
492
		return array($sql,$stmt,false);
493
	}
494
 
495
	function PrepareSP($sql, $param = true)
496
	{
497
		if (!$this->_canPrepareSP) return $sql; // Can't prepare procedures
498
 
499
        $this->_errorMsg = false;
500
		$this->_errorCode = false;
501
 
502
		$stmt = @odbtp_prepare_proc($sql,$this->_connectionID);
503
		if (!$stmt) return false;
504
		return array($sql,$stmt);
505
	}
506
 
507
	/*
508
	Usage:
509
		$stmt = $db->PrepareSP('SP_RUNSOMETHING'); -- takes 2 params, @myid and @group
510
 
511
		# note that the parameter does not have @ in front!
512
		$db->Parameter($stmt,$id,'myid');
513
		$db->Parameter($stmt,$group,'group',false,64);
514
		$db->Parameter($stmt,$group,'photo',false,100000,ODB_BINARY);
515
		$db->Execute($stmt);
516
 
517
		@param $stmt Statement returned by Prepare() or PrepareSP().
518
		@param $var PHP variable to bind to. Can set to null (for isNull support).
519
		@param $name Name of stored procedure variable name to bind to.
520
		@param [$isOutput] Indicates direction of parameter 0/false=IN  1=OUT  2= IN/OUT. This is ignored in odbtp.
521
		@param [$maxLen] Holds an maximum length of the variable.
522
		@param [$type] The data type of $var. Legal values depend on driver.
523
 
524
		See odbtp_attach_param documentation at http://odbtp.sourceforge.net.
525
	*/
526
	function Parameter(&$stmt, &$var, $name, $isOutput=false, $maxLen=0, $type=0)
527
	{
528
		if ( $this->odbc_driver == ODB_DRIVER_JET ) {
529
			$name = '['.$name.']';
530
			if( !$type && $this->_useUnicodeSQL
531
				&& @odbtp_param_bindtype($stmt[1], $name) == ODB_CHAR )
532
			{
533
				$type = ODB_WCHAR;
534
			}
535
		}
536
		else {
537
			$name = '@'.$name;
538
		}
539
		return @odbtp_attach_param($stmt[1], $name, $var, $type, $maxLen);
540
	}
541
 
542
	/*
543
		Insert a null into the blob field of the table first.
544
		Then use UpdateBlob to store the blob.
545
 
546
		Usage:
547
 
548
		$conn->Execute('INSERT INTO blobtable (id, blobcol) VALUES (1, null)');
549
		$conn->UpdateBlob('blobtable','blobcol',$blob,'id=1');
550
	*/
551
 
552
	function UpdateBlob($table,$column,$val,$where,$blobtype='image')
553
	{
554
		$sql = "UPDATE $table SET $column = ? WHERE $where";
555
		if( !($stmt = @odbtp_prepare($sql, $this->_connectionID)) )
556
			return false;
557
		if( !@odbtp_input( $stmt, 1, ODB_BINARY, 1000000, $blobtype ) )
558
			return false;
559
		if( !@odbtp_set( $stmt, 1, $val ) )
560
			return false;
561
		return @odbtp_execute( $stmt ) != false;
562
	}
563
 
564
	function MetaIndexes($table,$primary=false, $owner=false)
565
	{
566
		switch ( $this->odbc_driver) {
567
			case ODB_DRIVER_MSSQL:
568
				return $this->MetaIndexes_mssql($table, $primary);
569
			default:
570
				return array();
571
		}
572
	}
573
 
574
	function MetaIndexes_mssql($table,$primary=false, $owner = false)
575
	{
576
		$table = strtolower($this->qstr($table));
577
 
578
		$sql = "SELECT i.name AS ind_name, C.name AS col_name, USER_NAME(O.uid) AS Owner, c.colid, k.Keyno,
579
			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,
580
			CASE WHEN I.status & 2 = 2 THEN 1 ELSE 0 END AS IsUnique
581
			FROM dbo.sysobjects o INNER JOIN dbo.sysindexes I ON o.id = i.id
582
			INNER JOIN dbo.sysindexkeys K ON I.id = K.id AND I.Indid = K.Indid
583
			INNER JOIN dbo.syscolumns c ON K.id = C.id AND K.colid = C.Colid
584
			WHERE LEFT(i.name, 8) <> '_WA_Sys_' AND o.status >= 0 AND lower(O.Name) = $table
585
			ORDER BY O.name, I.Name, K.keyno";
586
 
587
		global $ADODB_FETCH_MODE;
588
		$save = $ADODB_FETCH_MODE;
589
        $ADODB_FETCH_MODE = ADODB_FETCH_NUM;
590
        if ($this->fetchMode !== FALSE) {
591
        	$savem = $this->SetFetchMode(FALSE);
592
        }
593
 
594
        $rs = $this->Execute($sql);
595
        if (isset($savem)) {
596
        	$this->SetFetchMode($savem);
597
        }
598
        $ADODB_FETCH_MODE = $save;
599
 
600
        if (!is_object($rs)) {
601
        	return FALSE;
602
        }
603
 
604
		$indexes = array();
605
		while ($row = $rs->FetchRow()) {
606
			if ($primary && !$row[5]) continue;
607
 
608
            $indexes[$row[0]]['unique'] = $row[6];
609
            $indexes[$row[0]]['columns'][] = $row[1];
610
    	}
611
        return $indexes;
612
	}
613
 
614
	function IfNull( $field, $ifNull )
615
	{
616
		switch( $this->odbc_driver ) {
617
			case ODB_DRIVER_MSSQL:
618
				return " ISNULL($field, $ifNull) ";
619
			case ODB_DRIVER_JET:
620
				return " IIF(IsNull($field), $ifNull, $field) ";
621
		}
622
		return " CASE WHEN $field is null THEN $ifNull ELSE $field END ";
623
	}
624
 
625
	function _query($sql,$inputarr=false)
626
	{
627
		$last_php_error = $this->resetLastError();
628
		$this->_errorMsg = false;
629
		$this->_errorCode = false;
630
 
631
 		if ($inputarr) {
632
			if (is_array($sql)) {
633
				$stmtid = $sql[1];
634
			} else {
635
				$stmtid = @odbtp_prepare($sql,$this->_connectionID);
636
				if ($stmtid == false) {
637
					$this->_errorMsg = $this->getChangedErrorMsg($last_php_error);
638
					return false;
639
				}
640
			}
641
			$num_params = @odbtp_num_params( $stmtid );
642
			/*
643
			for( $param = 1; $param <= $num_params; $param++ ) {
644
				@odbtp_input( $stmtid, $param );
645
				@odbtp_set( $stmtid, $param, $inputarr[$param-1] );
646
			}*/
647
 
648
			$param = 1;
649
			foreach($inputarr as $v) {
650
				@odbtp_input( $stmtid, $param );
651
				@odbtp_set( $stmtid, $param, $v );
652
				$param += 1;
653
				if ($param > $num_params) break;
654
			}
655
 
656
			if (!@odbtp_execute($stmtid) ) {
657
				return false;
658
			}
659
		} else if (is_array($sql)) {
660
			$stmtid = $sql[1];
661
			if (!@odbtp_execute($stmtid)) {
662
				return false;
663
			}
664
		} else {
665
			$stmtid = odbtp_query($sql,$this->_connectionID);
666
   		}
667
		$this->_lastAffectedRows = 0;
668
		if ($stmtid) {
669
				$this->_lastAffectedRows = @odbtp_affected_rows($stmtid);
670
		}
671
        return $stmtid;
672
	}
673
 
674
	function _close()
675
	{
676
		$ret = @odbtp_close($this->_connectionID);
677
		$this->_connectionID = false;
678
		return $ret;
679
	}
680
}
681
 
682
class ADORecordSet_odbtp extends ADORecordSet {
683
 
684
	var $databaseType = 'odbtp';
685
	var $canSeek = true;
686
 
687
	function __construct($queryID,$mode=false)
688
	{
689
		if ($mode === false) {
690
			global $ADODB_FETCH_MODE;
691
			$mode = $ADODB_FETCH_MODE;
692
		}
693
		$this->fetchMode = $mode;
694
		parent::__construct($queryID);
695
	}
696
 
697
	function _initrs()
698
	{
699
		$this->_numOfFields = @odbtp_num_fields($this->_queryID);
700
		if (!($this->_numOfRows = @odbtp_num_rows($this->_queryID)))
701
			$this->_numOfRows = -1;
702
 
703
		if (!$this->connection->_useUnicodeSQL) return;
704
 
705
		if ($this->connection->odbc_driver == ODB_DRIVER_JET) {
706
			if (!@odbtp_get_attr(ODB_ATTR_MAPCHARTOWCHAR,
707
			                     $this->connection->_connectionID))
708
			{
709
				for ($f = 0; $f < $this->_numOfFields; $f++) {
710
					if (@odbtp_field_bindtype($this->_queryID, $f) == ODB_CHAR)
711
						@odbtp_bind_field($this->_queryID, $f, ODB_WCHAR);
712
				}
713
			}
714
		}
715
	}
716
 
717
	function FetchField($fieldOffset = 0)
718
	{
719
		$off=$fieldOffset; // offsets begin at 0
720
		$o= new ADOFieldObject();
721
		$o->name = @odbtp_field_name($this->_queryID,$off);
722
		$o->type = @odbtp_field_type($this->_queryID,$off);
723
        $o->max_length = @odbtp_field_length($this->_queryID,$off);
724
		if (ADODB_ASSOC_CASE == 0) $o->name = strtolower($o->name);
725
		else if (ADODB_ASSOC_CASE == 1) $o->name = strtoupper($o->name);
726
		return $o;
727
	}
728
 
729
	function _seek($row)
730
	{
731
		return @odbtp_data_seek($this->_queryID, $row);
732
	}
733
 
734
	function fields($colname)
735
	{
736
		if ($this->fetchMode & ADODB_FETCH_ASSOC) return $this->fields[$colname];
737
 
738
		if (!$this->bind) {
739
			$this->bind = array();
740
			for ($i=0; $i < $this->_numOfFields; $i++) {
741
				$name = @odbtp_field_name( $this->_queryID, $i );
742
				$this->bind[strtoupper($name)] = $i;
743
			}
744
		}
745
		return $this->fields[$this->bind[strtoupper($colname)]];
746
	}
747
 
748
	function _fetch_odbtp($type=0)
749
	{
750
		switch ($this->fetchMode) {
751
			case ADODB_FETCH_NUM:
752
				$this->fields = @odbtp_fetch_row($this->_queryID, $type);
753
				break;
754
			case ADODB_FETCH_ASSOC:
755
				$this->fields = @odbtp_fetch_assoc($this->_queryID, $type);
756
				break;
757
            default:
758
				$this->fields = @odbtp_fetch_array($this->_queryID, $type);
759
		}
760
		if ($this->databaseType = 'odbtp_vfp') {
761
			if ($this->fields)
762
			foreach($this->fields as $k => $v) {
763
				if (strncmp($v,'1899-12-30',10) == 0) $this->fields[$k] = '';
764
			}
765
		}
766
		return is_array($this->fields);
767
	}
768
 
769
	function _fetch()
770
	{
771
		return $this->_fetch_odbtp();
772
	}
773
 
774
	function MoveFirst()
775
	{
776
		if (!$this->_fetch_odbtp(ODB_FETCH_FIRST)) return false;
777
		$this->EOF = false;
778
		$this->_currentRow = 0;
779
		return true;
780
    }
781
 
782
	function MoveLast()
783
	{
784
		if (!$this->_fetch_odbtp(ODB_FETCH_LAST)) return false;
785
		$this->EOF = false;
786
		$this->_currentRow = $this->_numOfRows - 1;
787
		return true;
788
	}
789
 
790
	function NextRecordSet()
791
	{
792
		if (!@odbtp_next_result($this->_queryID)) return false;
793
		$this->_inited = false;
794
		$this->bind = false;
795
		$this->_currentRow = -1;
796
		$this->Init();
797
		return true;
798
	}
799
 
800
	function _close()
801
	{
802
		return @odbtp_free_query($this->_queryID);
803
	}
804
}
805
 
806
class ADORecordSet_odbtp_mssql extends ADORecordSet_odbtp {
807
 
808
	var $databaseType = 'odbtp_mssql';
809
 
810
}
811
 
812
class ADORecordSet_odbtp_access extends ADORecordSet_odbtp {
813
 
814
	var $databaseType = 'odbtp_access';
815
 
816
}
817
 
818
class ADORecordSet_odbtp_vfp extends ADORecordSet_odbtp {
819
 
820
	var $databaseType = 'odbtp_vfp';
821
 
822
}
823
 
824
class ADORecordSet_odbtp_oci8 extends ADORecordSet_odbtp {
825
 
826
	var $databaseType = 'odbtp_oci8';
827
 
828
}
829
 
830
class ADORecordSet_odbtp_sybase extends ADORecordSet_odbtp {
831
 
832
	var $databaseType = 'odbtp_sybase';
833
 
834
}