Proyectos de Subversion Moodle

Rev

| Ultima modificación | Ver Log |

Rev Autor Línea Nro. Línea
1 efrain 1
<?php
2
/**
3
 * Microsoft ADO driver.
4
 *
5
 * Requires ADO. Works only on MS Windows.
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
 */
23
 
24
// security - hide paths
25
if (!defined('ADODB_DIR')) die();
26
 
27
define("_ADODB_ADO_LAYER", 1 );
28
/*--------------------------------------------------------------------------------------
29
--------------------------------------------------------------------------------------*/
30
 
31
 
32
class ADODB_ado extends ADOConnection {
33
	var $databaseType = "ado";
34
	var $_bindInputArray = false;
35
	var $fmtDate = "'Y-m-d'";
36
	var $fmtTimeStamp = "'Y-m-d, h:i:sA'";
37
	var $replaceQuote = "''"; // string to use to replace quotes
38
	var $dataProvider = "ado";
39
	var $hasAffectedRows = true;
40
	var $adoParameterType = 201; // 201 = long varchar, 203=long wide varchar, 205 = long varbinary
41
	var $_affectedRows = false;
42
	var $_thisTransactions;
43
	var $_cursor_type = 3; // 3=adOpenStatic,0=adOpenForwardOnly,1=adOpenKeyset,2=adOpenDynamic
44
	var $_cursor_location = 3; // 2=adUseServer, 3 = adUseClient;
45
	var $_lock_type = -1;
46
	var $_execute_option = -1;
47
	var $poorAffectedRows = true;
48
	var $charPage;
49
 
50
	function __construct()
51
	{
52
		$this->_affectedRows = new VARIANT;
53
	}
54
 
55
	function ServerInfo()
56
	{
57
		if (!empty($this->_connectionID)) $desc = $this->_connectionID->provider;
58
		return array('description' => $desc, 'version' => '');
59
	}
60
 
61
	function _affectedrows()
62
	{
63
		return $this->_affectedRows;
64
	}
65
 
66
	// you can also pass a connection string like this:
67
	//
68
	// $DB->Connect('USER ID=sa;PASSWORD=pwd;SERVER=mangrove;DATABASE=ai',false,false,'SQLOLEDB');
69
	function _connect($argHostname, $argUsername, $argPassword, $argProvider= 'MSDASQL')
70
	{
71
		$u = 'UID';
72
		$p = 'PWD';
73
 
74
		if (!empty($this->charPage))
75
			$dbc = new COM('ADODB.Connection',null,$this->charPage);
76
		else
77
			$dbc = new COM('ADODB.Connection');
78
 
79
		if (! $dbc) return false;
80
 
81
		/* special support if provider is mssql or access */
82
		if ($argProvider=='mssql') {
83
			$u = 'User Id';  //User parameter name for OLEDB
84
			$p = 'Password';
85
			$argProvider = "SQLOLEDB"; // SQL Server Provider
86
 
87
			// not yet
88
			//if ($argDatabasename) $argHostname .= ";Initial Catalog=$argDatabasename";
89
 
90
			//use trusted connection for SQL if username not specified
91
			if (!$argUsername) $argHostname .= ";Trusted_Connection=Yes";
92
		} else if ($argProvider=='access')
93
			$argProvider = "Microsoft.Jet.OLEDB.4.0"; // Microsoft Jet Provider
94
 
95
		if ($argProvider) $dbc->Provider = $argProvider;
96
 
97
		if ($argUsername) $argHostname .= ";$u=$argUsername";
98
		if ($argPassword)$argHostname .= ";$p=$argPassword";
99
 
100
		if ($this->debug) ADOConnection::outp( "Host=".$argHostname."<BR>\n version=$dbc->version");
101
		// @ added below for php 4.0.1 and earlier
102
		@$dbc->Open((string) $argHostname);
103
 
104
		$this->_connectionID = $dbc;
105
 
106
		$dbc->CursorLocation = $this->_cursor_location;
107
		return  $dbc->State > 0;
108
	}
109
 
110
	// returns true or false
111
	function _pconnect($argHostname, $argUsername, $argPassword, $argProvider='MSDASQL')
112
	{
113
		return $this->_connect($argHostname,$argUsername,$argPassword,$argProvider);
114
	}
115
 
116
/*
117
	adSchemaCatalogs	= 1,
118
	adSchemaCharacterSets	= 2,
119
	adSchemaCollations	= 3,
120
	adSchemaColumns	= 4,
121
	adSchemaCheckConstraints	= 5,
122
	adSchemaConstraintColumnUsage	= 6,
123
	adSchemaConstraintTableUsage	= 7,
124
	adSchemaKeyColumnUsage	= 8,
125
	adSchemaReferentialContraints	= 9,
126
	adSchemaTableConstraints	= 10,
127
	adSchemaColumnsDomainUsage	= 11,
128
	adSchemaIndexes	= 12,
129
	adSchemaColumnPrivileges	= 13,
130
	adSchemaTablePrivileges	= 14,
131
	adSchemaUsagePrivileges	= 15,
132
	adSchemaProcedures	= 16,
133
	adSchemaSchemata	= 17,
134
	adSchemaSQLLanguages	= 18,
135
	adSchemaStatistics	= 19,
136
	adSchemaTables	= 20,
137
	adSchemaTranslations	= 21,
138
	adSchemaProviderTypes	= 22,
139
	adSchemaViews	= 23,
140
	adSchemaViewColumnUsage	= 24,
141
	adSchemaViewTableUsage	= 25,
142
	adSchemaProcedureParameters	= 26,
143
	adSchemaForeignKeys	= 27,
144
	adSchemaPrimaryKeys	= 28,
145
	adSchemaProcedureColumns	= 29,
146
	adSchemaDBInfoKeywords	= 30,
147
	adSchemaDBInfoLiterals	= 31,
148
	adSchemaCubes	= 32,
149
	adSchemaDimensions	= 33,
150
	adSchemaHierarchies	= 34,
151
	adSchemaLevels	= 35,
152
	adSchemaMeasures	= 36,
153
	adSchemaProperties	= 37,
154
	adSchemaMembers	= 38
155
 
156
*/
157
 
158
	function MetaTables($ttype = false, $showSchema = false, $mask = false)
159
	{
160
		$arr= array();
161
		$dbc = $this->_connectionID;
162
 
163
		$adors=@$dbc->OpenSchema(20);//tables
164
		if ($adors){
165
			$f = $adors->Fields(2);//table/view name
166
			$t = $adors->Fields(3);//table type
167
			while (!$adors->EOF){
168
				$tt=substr($t->value,0,6);
169
				if ($tt!='SYSTEM' && $tt !='ACCESS')
170
					$arr[]=$f->value;
171
				//print $f->value . ' ' . $t->value.'<br>';
172
				$adors->MoveNext();
173
			}
174
			$adors->Close();
175
		}
176
 
177
		return $arr;
178
	}
179
 
180
	function MetaColumns($table, $normalize=true)
181
	{
182
		$table = strtoupper($table);
183
		$arr = array();
184
		$dbc = $this->_connectionID;
185
 
186
		$adors=@$dbc->OpenSchema(4);//tables
187
 
188
		if ($adors){
189
			$t = $adors->Fields(2);//table/view name
190
			while (!$adors->EOF){
191
 
192
 
193
				if (strtoupper($t->Value) == $table) {
194
 
195
					$fld = new ADOFieldObject();
196
					$c = $adors->Fields(3);
197
					$fld->name = $c->Value;
198
					$fld->type = 'CHAR'; // cannot discover type in ADO!
199
					$fld->max_length = -1;
200
					$arr[strtoupper($fld->name)]=$fld;
201
				}
202
 
203
				$adors->MoveNext();
204
			}
205
			$adors->Close();
206
		}
207
		$false = false;
208
		return empty($arr) ? $false : $arr;
209
	}
210
 
211
	function _query($sql,$inputarr=false)
212
	{
213
 
214
		$dbc = $this->_connectionID;
215
		$false = false;
216
 
217
	//	return rs
218
		if ($inputarr) {
219
 
220
			if (!empty($this->charPage))
221
				$oCmd = new COM('ADODB.Command',null,$this->charPage);
222
			else
223
				$oCmd = new COM('ADODB.Command');
224
			$oCmd->ActiveConnection = $dbc;
225
			$oCmd->CommandText = $sql;
226
			$oCmd->CommandType = 1;
227
 
228
      // Map by http://msdn.microsoft.com/library/default.asp?url=/library/en-us/ado270/htm/mdmthcreateparam.asp
229
      // Check issue http://bugs.php.net/bug.php?id=40664 !!!
230
			foreach ($inputarr as $val) {
231
				$type = gettype($val);
232
				$len=strlen($val);
233
				if ($type == 'boolean')
234
					$this->adoParameterType = 11;
235
				else if ($type == 'integer')
236
					$this->adoParameterType = 3;
237
				else if ($type == 'double')
238
					$this->adoParameterType = 5;
239
				elseif ($type == 'string')
240
					$this->adoParameterType = 202;
241
				else if (($val === null) || (!defined($val)))
242
					$len=1;
243
				else
244
					$this->adoParameterType = 130;
245
 
246
				// name, type, direction 1 = input, len,
247
        		$p = $oCmd->CreateParameter('name',$this->adoParameterType,1,$len,$val);
248
 
249
				$oCmd->Parameters->Append($p);
250
			}
251
			$p = false;
252
			$rs = $oCmd->Execute();
253
			$e = $dbc->Errors;
254
			if ($dbc->Errors->Count > 0) return $false;
255
			return $rs;
256
		}
257
 
258
		$rs = @$dbc->Execute($sql,$this->_affectedRows, $this->_execute_option);
259
 
260
		if ($dbc->Errors->Count > 0) return $false;
261
		if (! $rs) return $false;
262
 
263
		if ($rs->State == 0) {
264
			$true = true;
265
			return $true; // 0 = adStateClosed means no records returned
266
		}
267
		return $rs;
268
	}
269
 
270
 
271
	function BeginTrans()
272
	{
273
		if ($this->transOff) return true;
274
 
275
		if (isset($this->_thisTransactions))
276
			if (!$this->_thisTransactions) return false;
277
		else {
278
			$o = $this->_connectionID->Properties("Transaction DDL");
279
			$this->_thisTransactions = $o ? true : false;
280
			if (!$o) return false;
281
		}
282
		@$this->_connectionID->BeginTrans();
283
		$this->transCnt += 1;
284
		return true;
285
	}
286
 
287
	function CommitTrans($ok=true)
288
	{
289
		if (!$ok) return $this->RollbackTrans();
290
		if ($this->transOff) return true;
291
 
292
		@$this->_connectionID->CommitTrans();
293
		if ($this->transCnt) @$this->transCnt -= 1;
294
		return true;
295
	}
296
	function RollbackTrans() {
297
		if ($this->transOff) return true;
298
		@$this->_connectionID->RollbackTrans();
299
		if ($this->transCnt) @$this->transCnt -= 1;
300
		return true;
301
	}
302
 
303
	/*	Returns: the last error message from previous database operation	*/
304
 
305
	function ErrorMsg()
306
	{
307
		if (!$this->_connectionID) return "No connection established";
308
		$errc = $this->_connectionID->Errors;
309
		if (!$errc) return "No Errors object found";
310
		if ($errc->Count == 0) return '';
311
		$err = $errc->Item($errc->Count-1);
312
		return $err->Description;
313
	}
314
 
315
	function ErrorNo()
316
	{
317
		$errc = $this->_connectionID->Errors;
318
		if ($errc->Count == 0) return 0;
319
		$err = $errc->Item($errc->Count-1);
320
		return $err->NativeError;
321
	}
322
 
323
	// returns true or false
324
	function _close()
325
	{
326
		if ($this->_connectionID) $this->_connectionID->Close();
327
		$this->_connectionID = false;
328
		return true;
329
	}
330
 
331
 
332
}
333
 
334
/*--------------------------------------------------------------------------------------
335
	 Class Name: Recordset
336
--------------------------------------------------------------------------------------*/
337
 
338
class ADORecordSet_ado extends ADORecordSet {
339
 
340
	var $bind = false;
341
	var $databaseType = "ado";
342
	var $dataProvider = "ado";
343
	var $_tarr = false; // caches the types
344
	var $_flds; // and field objects
345
	var $canSeek = true;
346
  	var $hideErrors = true;
347
 
348
	function __construct($id,$mode=false)
349
	{
350
		if ($mode === false) {
351
			global $ADODB_FETCH_MODE;
352
			$mode = $ADODB_FETCH_MODE;
353
		}
354
		$this->fetchMode = $mode;
355
		parent::__construct($id);
356
	}
357
 
358
 
359
	// returns the field object
360
	function FetchField($fieldOffset = -1) {
361
		$off=$fieldOffset+1; // offsets begin at 1
362
 
363
		$o= new ADOFieldObject();
364
		$rs = $this->_queryID;
365
		$f = $rs->Fields($fieldOffset);
366
		$o->name = $f->Name;
367
		$t = $f->Type;
368
		$o->type = $this->MetaType($t);
369
		$o->max_length = $f->DefinedSize;
370
		$o->ado_type = $t;
371
 
372
		//print "off=$off name=$o->name type=$o->type len=$o->max_length<br>";
373
		return $o;
374
	}
375
 
376
	/* Use associative array to get fields array */
377
	function Fields($colname)
378
	{
379
		if ($this->fetchMode & ADODB_FETCH_ASSOC) return $this->fields[$colname];
380
		if (!$this->bind) {
381
			$this->bind = array();
382
			for ($i=0; $i < $this->_numOfFields; $i++) {
383
				$o = $this->FetchField($i);
384
				$this->bind[strtoupper($o->name)] = $i;
385
			}
386
		}
387
 
388
		 return $this->fields[$this->bind[strtoupper($colname)]];
389
	}
390
 
391
 
392
	function _initrs()
393
	{
394
		$rs = $this->_queryID;
395
		$this->_numOfRows = $rs->RecordCount;
396
 
397
		$f = $rs->Fields;
398
		$this->_numOfFields = $f->Count;
399
	}
400
 
401
 
402
	 // should only be used to move forward as we normally use forward-only cursors
403
	function _seek($row)
404
	{
405
	   $rs = $this->_queryID;
406
		// absoluteposition doesn't work -- my maths is wrong ?
407
		//	$rs->AbsolutePosition->$row-2;
408
		//	return true;
409
		if ($this->_currentRow > $row) return false;
410
		@$rs->Move((integer)$row - $this->_currentRow-1); //adBookmarkFirst
411
		return true;
412
	}
413
 
414
/*
415
	OLEDB types
416
 
417
	 enum DBTYPEENUM
418
	{	DBTYPE_EMPTY	= 0,
419
	DBTYPE_NULL	= 1,
420
	DBTYPE_I2	= 2,
421
	DBTYPE_I4	= 3,
422
	DBTYPE_R4	= 4,
423
	DBTYPE_R8	= 5,
424
	DBTYPE_CY	= 6,
425
	DBTYPE_DATE	= 7,
426
	DBTYPE_BSTR	= 8,
427
	DBTYPE_IDISPATCH	= 9,
428
	DBTYPE_ERROR	= 10,
429
	DBTYPE_BOOL	= 11,
430
	DBTYPE_VARIANT	= 12,
431
	DBTYPE_IUNKNOWN	= 13,
432
	DBTYPE_DECIMAL	= 14,
433
	DBTYPE_UI1	= 17,
434
	DBTYPE_ARRAY	= 0x2000,
435
	DBTYPE_BYREF	= 0x4000,
436
	DBTYPE_I1	= 16,
437
	DBTYPE_UI2	= 18,
438
	DBTYPE_UI4	= 19,
439
	DBTYPE_I8	= 20,
440
	DBTYPE_UI8	= 21,
441
	DBTYPE_GUID	= 72,
442
	DBTYPE_VECTOR	= 0x1000,
443
	DBTYPE_RESERVED	= 0x8000,
444
	DBTYPE_BYTES	= 128,
445
	DBTYPE_STR	= 129,
446
	DBTYPE_WSTR	= 130,
447
	DBTYPE_NUMERIC	= 131,
448
	DBTYPE_UDT	= 132,
449
	DBTYPE_DBDATE	= 133,
450
	DBTYPE_DBTIME	= 134,
451
	DBTYPE_DBTIMESTAMP	= 135
452
 
453
	ADO Types
454
 
455
   	adEmpty	= 0,
456
	adTinyInt	= 16,
457
	adSmallInt	= 2,
458
	adInteger	= 3,
459
	adBigInt	= 20,
460
	adUnsignedTinyInt	= 17,
461
	adUnsignedSmallInt	= 18,
462
	adUnsignedInt	= 19,
463
	adUnsignedBigInt	= 21,
464
	adSingle	= 4,
465
	adDouble	= 5,
466
	adCurrency	= 6,
467
	adDecimal	= 14,
468
	adNumeric	= 131,
469
	adBoolean	= 11,
470
	adError	= 10,
471
	adUserDefined	= 132,
472
	adVariant	= 12,
473
	adIDispatch	= 9,
474
	adIUnknown	= 13,
475
	adGUID	= 72,
476
	adDate	= 7,
477
	adDBDate	= 133,
478
	adDBTime	= 134,
479
	adDBTimeStamp	= 135,
480
	adBSTR	= 8,
481
	adChar	= 129,
482
	adVarChar	= 200,
483
	adLongVarChar	= 201,
484
	adWChar	= 130,
485
	adVarWChar	= 202,
486
	adLongVarWChar	= 203,
487
	adBinary	= 128,
488
	adVarBinary	= 204,
489
	adLongVarBinary	= 205,
490
	adChapter	= 136,
491
	adFileTime	= 64,
492
	adDBFileTime	= 137,
493
	adPropVariant	= 138,
494
	adVarNumeric	= 139
495
*/
496
	function MetaType($t,$len=-1,$fieldobj=false)
497
	{
498
		if (is_object($t)) {
499
			$fieldobj = $t;
500
			$t = $fieldobj->type;
501
			$len = $fieldobj->max_length;
502
		}
503
 
504
		if (array_key_exists($t,$this->connection->customActualTypes))
505
			return  $this->connection->customActualTypes[$t];
506
 
507
		if (!is_numeric($t)) return $t;
508
 
509
		switch ($t) {
510
		case 0:
511
		case 12: // variant
512
		case 8: // bstr
513
		case 129: //char
514
		case 130: //wc
515
		case 200: // varc
516
		case 202:// varWC
517
		case 128: // bin
518
		case 204: // varBin
519
		case 72: // guid
520
			if ($len <= $this->blobSize) return 'C';
521
 
522
		case 201:
523
		case 203:
524
			return 'X';
525
		case 128:
526
		case 204:
527
		case 205:
528
			 return 'B';
529
		case 7:
530
		case 133: return 'D';
531
 
532
		case 134:
533
		case 135: return 'T';
534
 
535
		case 11: return 'L';
536
 
537
		case 16://	adTinyInt	= 16,
538
		case 2://adSmallInt	= 2,
539
		case 3://adInteger	= 3,
540
		case 4://adBigInt	= 20,
541
		case 17://adUnsignedTinyInt	= 17,
542
		case 18://adUnsignedSmallInt	= 18,
543
		case 19://adUnsignedInt	= 19,
544
		case 20://adUnsignedBigInt	= 21,
545
			return 'I';
546
		default: return ADODB_DEFAULT_METATYPE;
547
		}
548
	}
549
 
550
	// time stamp not supported yet
551
	function _fetch()
552
	{
553
		$rs = $this->_queryID;
554
		if (!$rs or $rs->EOF) {
555
			$this->fields = false;
556
			return false;
557
		}
558
		$this->fields = array();
559
 
560
		if (!$this->_tarr) {
561
			$tarr = array();
562
			$flds = array();
563
			for ($i=0,$max = $this->_numOfFields; $i < $max; $i++) {
564
				$f = $rs->Fields($i);
565
				$flds[] = $f;
566
				$tarr[] = $f->Type;
567
			}
568
			// bind types and flds only once
569
			$this->_tarr = $tarr;
570
			$this->_flds = $flds;
571
		}
572
		$t = reset($this->_tarr);
573
		$f = reset($this->_flds);
574
 
575
		if ($this->hideErrors)  $olde = error_reporting(E_ERROR|E_CORE_ERROR);// sometimes $f->value be null
576
		for ($i=0,$max = $this->_numOfFields; $i < $max; $i++) {
577
			//echo "<p>",$t,' ';var_dump($f->value); echo '</p>';
578
			switch($t) {
579
			case 135: // timestamp
580
				if (!strlen((string)$f->value)) $this->fields[] = false;
581
				else {
582
					if (!is_numeric($f->value)) # $val = variant_date_to_timestamp($f->value);
583
						// VT_DATE stores dates as (float) fractional days since 1899/12/30 00:00:00
584
						$val=(float) variant_cast($f->value,VT_R8)*3600*24-2209161600;
585
					else
586
						$val = $f->value;
587
					$this->fields[] = adodb_date('Y-m-d H:i:s',$val);
588
				}
589
				break;
590
			case 133:// A date value (yyyymmdd)
591
				if ($val = $f->value) {
592
					$this->fields[] = substr($val,0,4).'-'.substr($val,4,2).'-'.substr($val,6,2);
593
				} else
594
					$this->fields[] = false;
595
				break;
596
			case 7: // adDate
597
				if (!strlen((string)$f->value)) $this->fields[] = false;
598
				else {
599
					if (!is_numeric($f->value)) $val = variant_date_to_timestamp($f->value);
600
					else $val = $f->value;
601
 
602
					if (($val % 86400) == 0) $this->fields[] = adodb_date('Y-m-d',$val);
603
					else $this->fields[] = adodb_date('Y-m-d H:i:s',$val);
604
				}
605
				break;
606
			case 1: // null
607
				$this->fields[] = false;
608
				break;
609
			case 6: // currency is not supported properly;
610
				ADOConnection::outp( '<b>'.$f->Name.': currency type not supported by PHP</b>');
611
				$this->fields[] = (float) $f->value;
612
				break;
613
			case 11: //BIT;
614
				$val = "";
615
				if(is_bool($f->value))	{
616
					if($f->value==true) $val = 1;
617
					else $val = 0;
618
				}
619
				if(is_null($f->value)) $val = null;
620
 
621
				$this->fields[] = $val;
622
				break;
623
			default:
624
				$this->fields[] = $f->value;
625
				break;
626
			}
627
			//print " $f->value $t, ";
628
			$f = next($this->_flds);
629
			$t = next($this->_tarr);
630
		} // for
631
		if ($this->hideErrors) error_reporting($olde);
632
		@$rs->MoveNext(); // @ needed for some versions of PHP!
633
 
634
		if ($this->fetchMode & ADODB_FETCH_ASSOC) {
635
			$this->fields = $this->GetRowAssoc();
636
		}
637
		return true;
638
	}
639
 
640
		function NextRecordSet()
641
		{
642
			$rs = $this->_queryID;
643
			$this->_queryID = $rs->NextRecordSet();
644
			//$this->_queryID = $this->_QueryId->NextRecordSet();
645
			if ($this->_queryID == null) return false;
646
 
647
			$this->_currentRow = -1;
648
			$this->_currentPage = -1;
649
			$this->bind = false;
650
			$this->fields = false;
651
			$this->_flds = false;
652
			$this->_tarr = false;
653
 
654
			$this->_inited = false;
655
			$this->Init();
656
			return true;
657
		}
658
 
659
	function _close() {
660
		$this->_flds = false;
661
		@$this->_queryID->Close();// by Pete Dishman (peterd@telephonetics.co.uk)
662
		$this->_queryID = false;
663
	}
664
 
665
}