Proyectos de Subversion Moodle

Rev

| Ultima modificación | Ver Log |

Rev Autor Línea Nro. Línea
1 efrain 1
<?php
2
/**
3
 * Sybase driver
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
 * @author Toni Tunkkari <toni.tunkkari@finebyte.com>
21
 */
22
 
23
 // security - hide paths
24
if (!defined('ADODB_DIR')) die();
25
 
26
class ADODB_sybase extends ADOConnection {
27
	var $databaseType = "sybase";
28
	var $dataProvider = 'sybase';
29
	var $replaceQuote = "''"; // string to use to replace quotes
30
	var $fmtDate = "'Y-m-d'";
31
	var $fmtTimeStamp = "'Y-m-d H:i:s'";
32
	var $hasInsertID = true;
33
	var $hasAffectedRows = true;
34
  	var $metaTablesSQL="select name from sysobjects where type='U' or type='V'";
35
	// see http://sybooks.sybase.com/onlinebooks/group-aw/awg0800e/dbrfen8/@ebt-link;pt=5981;uf=0?target=0;window=new;showtoc=true;book=dbrfen8
36
	var $metaColumnsSQL = "SELECT c.column_name, c.column_type, c.width FROM syscolumn c, systable t WHERE t.table_name='%s' AND c.table_id=t.table_id AND t.table_type='BASE'";
37
	/*
38
	"select c.name,t.name,c.length from
39
	syscolumns c join systypes t on t.xusertype=c.xusertype join sysobjects o on o.id=c.id
40
	where o.name='%s'";
41
	*/
42
	var $concat_operator = '+';
43
	var $arrayClass = 'ADORecordSet_array_sybase';
44
	var $sysDate = 'GetDate()';
45
	var $leftOuter = '*=';
46
	var $rightOuter = '=*';
47
 
48
	var $port;
49
 
50
	/**
51
	 * might require begintrans -- committrans
52
	 * @inheritDoc
53
	 */
54
	protected function _insertID($table = '', $column = '')
55
	{
56
		return $this->GetOne('select @@identity');
57
	}
58
 
59
	  // might require begintrans -- committrans
60
	function _affectedrows()
61
	{
62
		return $this->GetOne('select @@rowcount');
63
	}
64
 
65
 
66
	function BeginTrans()
67
	{
68
 
69
		if ($this->transOff) return true;
70
		$this->transCnt += 1;
71
 
72
		$this->Execute('BEGIN TRAN');
73
		return true;
74
	}
75
 
76
	function CommitTrans($ok=true)
77
	{
78
		if ($this->transOff) return true;
79
 
80
		if (!$ok) return $this->RollbackTrans();
81
 
82
		$this->transCnt -= 1;
83
		$this->Execute('COMMIT TRAN');
84
		return true;
85
	}
86
 
87
	function RollbackTrans()
88
	{
89
		if ($this->transOff) return true;
90
		$this->transCnt -= 1;
91
		$this->Execute('ROLLBACK TRAN');
92
		return true;
93
	}
94
 
95
	// http://www.isug.com/Sybase_FAQ/ASE/section6.1.html#6.1.4
96
	function RowLock($tables,$where,$col='top 1 null as ignore')
97
	{
98
		if (!$this->hasTransactions) {
99
			$this->BeginTrans();
100
		}
101
		$tables = str_replace(',',' HOLDLOCK,',$tables);
102
		return $this->GetOne("select $col from $tables HOLDLOCK where $where");
103
 
104
	}
105
 
106
	function SelectDB($dbName)
107
	{
108
		$this->database = $dbName;
109
		if ($this->_connectionID) {
110
			return @sybase_select_db($dbName);
111
		}
112
		else return false;
113
	}
114
 
115
	/*	Returns: the last error message from previous database operation
116
		Note: This function is NOT available for Microsoft SQL Server.	*/
117
 
118
 
119
	function ErrorMsg()
120
	{
121
		if ($this->_logsql) return $this->_errorMsg;
122
		if (function_exists('sybase_get_last_message'))
123
			$this->_errorMsg = sybase_get_last_message();
124
		else {
125
			$this->_errorMsg = 'SYBASE error messages not supported on this platform';
126
		}
127
 
128
		return $this->_errorMsg;
129
	}
130
 
131
	// returns true or false
132
	function _connect($argHostname, $argUsername, $argPassword, $argDatabasename)
133
	{
134
		if (!function_exists('sybase_connect')) return null;
135
 
136
		// Sybase connection on custom port
137
		if ($this->port) {
138
			$argHostname .= ':' . $this->port;
139
		}
140
 
141
		if ($this->charSet) {
142
			$this->_connectionID = @sybase_connect($argHostname,$argUsername,$argPassword, $this->charSet);
143
		} else {
144
			$this->_connectionID = @sybase_connect($argHostname,$argUsername,$argPassword);
145
		}
146
 
147
		if ($this->_connectionID === false) return false;
148
		if ($argDatabasename) return $this->SelectDB($argDatabasename);
149
		return true;
150
	}
151
 
152
	// returns true or false
153
	function _pconnect($argHostname, $argUsername, $argPassword, $argDatabasename)
154
	{
155
		if (!function_exists('sybase_connect')) return null;
156
 
157
		// Sybase connection on custom port
158
		if ($this->port) {
159
			$argHostname .= ':' . $this->port;
160
		}
161
 
162
		if ($this->charSet) {
163
			$this->_connectionID = @sybase_pconnect($argHostname,$argUsername,$argPassword, $this->charSet);
164
		} else {
165
			$this->_connectionID = @sybase_pconnect($argHostname,$argUsername,$argPassword);
166
		}
167
 
168
		if ($this->_connectionID === false) return false;
169
		if ($argDatabasename) return $this->SelectDB($argDatabasename);
170
		return true;
171
	}
172
 
173
	function _query($sql,$inputarr=false)
174
	{
175
	global $ADODB_COUNTRECS;
176
 
177
		if ($ADODB_COUNTRECS == false)
178
			return sybase_unbuffered_query($sql,$this->_connectionID);
179
		else
180
			return sybase_query($sql,$this->_connectionID);
181
	}
182
 
183
	// See http://www.isug.com/Sybase_FAQ/ASE/section6.2.html#6.2.12
184
	function SelectLimit($sql,$nrows=-1,$offset=-1,$inputarr=false,$secs2cache=0)
185
	{
186
		if ($secs2cache > 0) {// we do not cache rowcount, so we have to load entire recordset
187
			$rs = ADOConnection::SelectLimit($sql,$nrows,$offset,$inputarr,$secs2cache);
188
			return $rs;
189
		}
190
 
191
		$nrows = (integer) $nrows;
192
		$offset = (integer) $offset;
193
 
194
		$cnt = ($nrows >= 0) ? $nrows : 999999999;
195
		if ($offset > 0 && $cnt) $cnt += $offset;
196
 
197
		$this->Execute("set rowcount $cnt");
198
		$rs = ADOConnection::SelectLimit($sql,$nrows,$offset,$inputarr,0);
199
		$this->Execute("set rowcount 0");
200
 
201
		return $rs;
202
	}
203
 
204
	// returns true or false
205
	function _close()
206
	{
207
		return @sybase_close($this->_connectionID);
208
	}
209
 
210
	static function UnixDate($v)
211
	{
212
		return ADORecordSet_array_sybase::UnixDate($v);
213
	}
214
 
215
	static function UnixTimeStamp($v)
216
	{
217
		return ADORecordSet_array_sybase::UnixTimeStamp($v);
218
	}
219
 
220
 
221
 
222
	# Added 2003-10-05 by Chris Phillipson
223
	# Used ASA SQL Reference Manual -- http://sybooks.sybase.com/onlinebooks/group-aw/awg0800e/dbrfen8/@ebt-link;pt=16756?target=%25N%15_12018_START_RESTART_N%25
224
	# to convert similar Microsoft SQL*Server (mssql) API into Sybase compatible version
225
	// Format date column in sql string given an input format that understands Y M D
226
	function SQLDate($fmt, $col=false)
227
	{
228
		if (!$col) $col = $this->sysTimeStamp;
229
		$s = '';
230
 
231
		$len = strlen($fmt);
232
		for ($i=0; $i < $len; $i++) {
233
			if ($s) $s .= '+';
234
			$ch = $fmt[$i];
235
			switch($ch) {
236
			case 'Y':
237
			case 'y':
238
				$s .= "datename(yy,$col)";
239
				break;
240
			case 'M':
241
				$s .= "convert(char(3),$col,0)";
242
				break;
243
			case 'm':
244
				$s .= "str_replace(str(month($col),2),' ','0')";
245
				break;
246
			case 'Q':
247
			case 'q':
248
				$s .= "datename(qq,$col)";
249
				break;
250
			case 'D':
251
			case 'd':
252
				$s .= "str_replace(str(datepart(dd,$col),2),' ','0')";
253
				break;
254
			case 'h':
255
				$s .= "substring(convert(char(14),$col,0),13,2)";
256
				break;
257
 
258
			case 'H':
259
				$s .= "str_replace(str(datepart(hh,$col),2),' ','0')";
260
				break;
261
 
262
			case 'i':
263
				$s .= "str_replace(str(datepart(mi,$col),2),' ','0')";
264
				break;
265
			case 's':
266
				$s .= "str_replace(str(datepart(ss,$col),2),' ','0')";
267
				break;
268
			case 'a':
269
			case 'A':
270
				$s .= "substring(convert(char(19),$col,0),18,2)";
271
				break;
272
 
273
			default:
274
				if ($ch == '\\') {
275
					$i++;
276
					$ch = substr($fmt,$i,1);
277
				}
278
				$s .= $this->qstr($ch);
279
				break;
280
			}
281
		}
282
		return $s;
283
	}
284
 
285
	# Added 2003-10-07 by Chris Phillipson
286
	# Used ASA SQL Reference Manual -- http://sybooks.sybase.com/onlinebooks/group-aw/awg0800e/dbrfen8/@ebt-link;pt=5981;uf=0?target=0;window=new;showtoc=true;book=dbrfen8
287
	# to convert similar Microsoft SQL*Server (mssql) API into Sybase compatible version
288
	function MetaPrimaryKeys($table, $owner = false)
289
	{
290
		$sql = "SELECT c.column_name " .
291
			   "FROM syscolumn c, systable t " .
292
			   "WHERE t.table_name='$table' AND c.table_id=t.table_id " .
293
			   "AND t.table_type='BASE' " .
294
			   "AND c.pkey = 'Y' " .
295
			   "ORDER BY c.column_id";
296
 
297
		$a = $this->GetCol($sql);
298
		if ($a && sizeof($a)>0) return $a;
299
		return false;
300
	}
301
}
302
 
303
/*--------------------------------------------------------------------------------------
304
	 Class Name: Recordset
305
--------------------------------------------------------------------------------------*/
306
global $ADODB_sybase_mths;
307
$ADODB_sybase_mths = array(
308
	'JAN'=>1,'FEB'=>2,'MAR'=>3,'APR'=>4,'MAY'=>5,'JUN'=>6,
309
	'JUL'=>7,'AUG'=>8,'SEP'=>9,'OCT'=>10,'NOV'=>11,'DEC'=>12);
310
 
311
class ADORecordset_sybase extends ADORecordSet {
312
 
313
	var $databaseType = "sybase";
314
	var $canSeek = true;
315
	// _mths works only in non-localised system
316
	var  $_mths = array('JAN'=>1,'FEB'=>2,'MAR'=>3,'APR'=>4,'MAY'=>5,'JUN'=>6,'JUL'=>7,'AUG'=>8,'SEP'=>9,'OCT'=>10,'NOV'=>11,'DEC'=>12);
317
 
318
	function __construct($id,$mode=false)
319
	{
320
		if ($mode === false) {
321
			global $ADODB_FETCH_MODE;
322
			$mode = $ADODB_FETCH_MODE;
323
		}
324
		if (!$mode) $this->fetchMode = ADODB_FETCH_ASSOC;
325
		else $this->fetchMode = $mode;
326
		parent::__construct($id);
327
	}
328
 
329
	/*	Returns: an object containing field information.
330
		Get column information in the Recordset object. fetchField() can be used in order to obtain information about
331
		fields in a certain query result. If the field offset isn't specified, the next field that wasn't yet retrieved by
332
		fetchField() is retrieved.	*/
333
	function FetchField($fieldOffset = -1)
334
	{
335
		if ($fieldOffset != -1) {
336
			$o = @sybase_fetch_field($this->_queryID, $fieldOffset);
337
		}
338
		else if ($fieldOffset == -1) {	/*	The $fieldOffset argument is not provided thus its -1 	*/
339
			$o = @sybase_fetch_field($this->_queryID);
340
		}
341
		// older versions of PHP did not support type, only numeric
342
		if ($o && !isset($o->type)) $o->type = ($o->numeric) ? 'float' : 'varchar';
343
		return $o;
344
	}
345
 
346
	function _initrs()
347
	{
348
	global $ADODB_COUNTRECS;
349
		$this->_numOfRows = ($ADODB_COUNTRECS)? @sybase_num_rows($this->_queryID):-1;
350
		$this->_numOfFields = @sybase_num_fields($this->_queryID);
351
	}
352
 
353
	function _seek($row)
354
	{
355
		return @sybase_data_seek($this->_queryID, $row);
356
	}
357
 
358
	function _fetch($ignore_fields=false)
359
	{
360
		if ($this->fetchMode == ADODB_FETCH_NUM) {
361
			$this->fields = @sybase_fetch_row($this->_queryID);
362
		} else if ($this->fetchMode == ADODB_FETCH_ASSOC) {
363
			$this->fields = @sybase_fetch_assoc($this->_queryID);
364
 
365
			if (is_array($this->fields)) {
366
				$this->fields = $this->GetRowAssoc();
367
				return true;
368
			}
369
			return false;
370
		}  else {
371
			$this->fields = @sybase_fetch_array($this->_queryID);
372
		}
373
		if ( is_array($this->fields)) {
374
			return true;
375
		}
376
 
377
		return false;
378
	}
379
 
380
	/*	close() only needs to be called if you are worried about using too much memory while your script
381
		is running. All associated result memory for the specified result identifier will automatically be freed.	*/
382
	function _close() {
383
		return @sybase_free_result($this->_queryID);
384
	}
385
 
386
	// sybase/mssql uses a default date like Dec 30 2000 12:00AM
387
	static function UnixDate($v)
388
	{
389
		return ADORecordSet_array_sybase::UnixDate($v);
390
	}
391
 
392
	static function UnixTimeStamp($v)
393
	{
394
		return ADORecordSet_array_sybase::UnixTimeStamp($v);
395
	}
396
}
397
 
398
class ADORecordSet_array_sybase extends ADORecordSet_array {
399
 
400
	// sybase/mssql uses a default date like Dec 30 2000 12:00AM
401
	static function UnixDate($v)
402
	{
403
	global $ADODB_sybase_mths;
404
 
405
		//Dec 30 2000 12:00AM
406
		if (!preg_match( "/([A-Za-z]{3})[-/\. ]+([0-9]{1,2})[-/\. ]+([0-9]{4})/"
407
			,$v, $rr)) return parent::UnixDate($v);
408
 
409
		if ($rr[3] <= TIMESTAMP_FIRST_YEAR) return 0;
410
 
411
		$themth = substr(strtoupper($rr[1]),0,3);
412
		$themth = $ADODB_sybase_mths[$themth];
413
		if ($themth <= 0) return false;
414
		// h-m-s-MM-DD-YY
415
		return  adodb_mktime(0,0,0,$themth,$rr[2],$rr[3]);
416
	}
417
 
418
	static function UnixTimeStamp($v)
419
	{
420
	global $ADODB_sybase_mths;
421
		//11.02.2001 Toni Tunkkari toni.tunkkari@finebyte.com
422
		//Changed [0-9] to [0-9 ] in day conversion
423
		if (!preg_match( "/([A-Za-z]{3})[-/\. ]([0-9 ]{1,2})[-/\. ]([0-9]{4}) +([0-9]{1,2}):([0-9]{1,2}) *([apAP]{0,1})/"
424
			,$v, $rr)) return parent::UnixTimeStamp($v);
425
		if ($rr[3] <= TIMESTAMP_FIRST_YEAR) return 0;
426
 
427
		$themth = substr(strtoupper($rr[1]),0,3);
428
		$themth = $ADODB_sybase_mths[$themth];
429
		if ($themth <= 0) return false;
430
 
431
		switch (strtoupper($rr[6])) {
432
		case 'P':
433
			if ($rr[4]<12) $rr[4] += 12;
434
			break;
435
		case 'A':
436
			if ($rr[4]==12) $rr[4] = 0;
437
			break;
438
		default:
439
			break;
440
		}
441
		// h-m-s-MM-DD-YY
442
		return  adodb_mktime($rr[4],$rr[5],0,$themth,$rr[2],$rr[3]);
443
	}
444
}