ILIAS  Release_4_2_x_branch Revision 61807
 All Data Structures Namespaces Files Functions Variables Groups Pages
class.ilDBOracle.php
Go to the documentation of this file.
1 <?php
2 /* Copyright (c) 1998-2009 ILIAS open source, Extended GPL, see docs/LICENSE */
3 
4 
5 include_once ("./Services/Database/classes/class.ilDB.php");
6 
18 class ilDBOracle extends ilDB
19 {
20  const CLOB_BUFFER_SIZE = 2000;
22 
23 
27  function getDSN()
28  {
29  // TODO: check if there is another solution.
30  // This works with 11g
31  if(!isset($GLOBALS['_MDB2_dsninfo_default']['charset']) or
32  $GLOBALS['_MDB2_dsninfo_default']['charset'] != 'utf8')
33  {
34  $GLOBALS['_MDB2_dsninfo_default']['charset'] = 'utf8';
35  }
36 
37  return array('phptype' => 'oci8',
38  'hostspec' => $this->getDBHost(),
39  'username' => $this->getDBUser(),
40  'password' => $this->getDBPassword(),
41  'port' => $this->getDBPort(),
42  'service' => $this->getDBName()
43  );
44 
45  //return "oci8://".$this->getDBUser().":".$this->getDBPassword()."@".
46  // $this->getDBHost()."/?service=".$this->getDBName();
47  }
48 
52  function getDBType()
53  {
54  return "oracle";
55  }
56 
57  public function getDBVersion()
58  {
59  $query = 'SELECT * FROM v$version';
60  $res = $this->db->query($query);
61 
62  if(MDB2::isError($res))
63  {
64  return parent::getDBVersion();
65  }
66  $row = $res->fetchRow(DB_FETCHMODE_ASSOC);
67  return isset($row['banner']) ? $row['banner'] : parent::getDBVersion();
68  }
69 
73  static function getReservedWords()
74  {
75  // version: 10g
76  // url: http://download-west.oracle.com/docs/cd/B14117_01/server.101/b10759/ap_keywd.htm#g691972
77  return array(
78  "ACCESS", "ADD", "ALL", "ALTER", "AND", "ANY", "AS", "ASC",
79  "AUDIT", "BETWEEN", "BY", "CHAR", "CHECK", "CLUSTER", "COLUMN",
80  "COMMENT", "COMPRESS", "CONNECT", "CREATE", "CURRENT", "DATE",
81  "DECIMAL", "DEFAULT", "DELETE", "DESC", "DISTINCT", "DROP", "ELSE",
82  "EXCLUSIVE", "EXISTS", "FILE", "FLOAT", "FOR", "FROM", "GRANT", "GROUP",
83  "HAVING", "IDENTIFIED", "IMMEDIATE", "IN", "INCREMENT", "INDEX", "INITIAL",
84  "INSERT", "INTEGER", "INTERSECT", "INTO", "IS", "LEVEL", "LIKE", "LOCK", "LONG",
85  "MAXEXTENTS", "MINUS", "MLSLABEL", "MODE", "MODIFY", "NOAUDIT", "NOCOMPRESS", "NOT",
86  "NOWAIT", "NULL", "NUMBER", "OF", "OFFLINE", "ON", "ONLINE","OPTION",
87  "OR", "ORDER", "PCTFREE", "PRIOR", "PRIVILEGES", "PUBLIC", "RAW", "RENAME",
88  "RESOURCE", "REVOKE", "ROW", "ROWID", "ROWNUM", "ROWS", "SELECT", "SESSION", "SET",
89  "SHARE", "SIZE", "SMALLINT", "START", "SUCCESSFUL", "SYNONYM", "SYSDATE","TABLE",
90  "THEN", "TO", "TRIGGER", "UID", "UNION", "UNIQUE", "UPDATE", "USER","VALIDATE",
91  "VALUES", "VARCHAR", "VARCHAR2", "VIEW", "WHENEVER", "WHERE", "WITH"
92  );
93  }
94 
98  function doConnect()
99  {
100  $this->db = MDB2::connect($this->getDSN(),
101  array("use_transactions" => true));
102  }
103 
107  function initConnection()
108  {
109  $GLOBALS['_MDB2_dsninfo_default']['charset'] = 'utf8';
110  $this->query("ALTER SESSION SET nls_length_semantics='CHAR'");
111  $this->query("ALTER SESSION SET NLS_SORT = binary_ci");
112  }
113 
114 /* function manipulate($sql)
115  {
116 //echo "1";
117 //if (!is_int(strpos($sql, "frm_thread_access")))
118 //{
119 //echo "2";
120  return parent::manipulate($sql);
121 //}
122 //echo "3";
123  }*/
124 
129  function now()
130  {
131  return "LOCALTIMESTAMP";
132  }
133 
137  function fromUnixtime($a_expr, $a_to_text = true)
138  {
139  if (!$a_to_text)
140  {
141  return "TO_DATE('19700101000000','YYYYMMDDHH24MISS') ".
142  "+ NUMTODSINTERVAL(".$a_expr.", 'SECOND')";
143  }
144  else
145  {
146  return "to_char(TO_DATE('19700101000000','YYYYMMDDHH24MISS') ".
147  "+ NUMTODSINTERVAL(".$a_expr.", 'SECOND'), 'yyyy-mm-dd hh24:mi:ss')";
148  }
149  }
150 
154  function unixTimestamp()
155  {
156  // sysdate should respect database time zone
157  // current_date would respect session time zone
158  return "ROUND((sysdate - to_date('01-JAN-1970','DD-MON-YYYY')) * (86400))";
159  }
160 
164  function constraintName($a_table, $a_constraint)
165  {
166  return $a_table."_".$a_constraint;
167  }
168 
173  {
174  return "pk";
175  }
176 
180  function supportsFulltext()
181  {
182  return false;
183  }
184 
192  function replace($a_table, $a_pk_columns, $a_other_columns)
193  {
194  $a_columns = array_merge($a_pk_columns, $a_other_columns);
195  $fields = array();
196  $field_values = array();
197  $placeholders = array();
198  $types = array();
199  $values = array();
200  $lobs = false;
201  $lob = array();
202  $val_field = array();
203  $a = array();
204  $b = array();
205  foreach ($a_columns as $k => $col)
206  {
207  if($col[0] == 'clob' or $col[0] == 'blob')
208  {
209  $val_field[] = $this->quote($col[1], 'text')." ".$k;
210  }
211  else
212  {
213  $val_field[] = $this->quote($col[1], $col[0])." ".$k;
214  }
215  $fields[] = $k;
216  $placeholders[] = "%s";
217  $placeholders2[] = ":$k";
218  $types[] = $col[0];
219  $values[] = $col[1];
220  $field_values[$k] = $col[1];
221  if ($col[0] == "blob" || $col[0] == "clob")
222  {
223  $lobs = true;
224  $lob[$k] = $k;
225  }
226  $a[] = "a.".$k;
227  $b[] = "b.".$k;
228  }
229  $abpk = array();
230  $aboc = array();
231  $delwhere = array();
232  foreach ($a_pk_columns as $k => $col)
233  {
234  $abpk[] = "a.".$k." = b.".$k;
235  $delwhere[] = $k." = ".$this->quote($col[1], $col[0]);
236  }
237  foreach ($a_other_columns as $k => $col)
238  {
239  $aboc[] = "a.".$k." = b.".$k;
240  }
241  if ($lobs) // lobs -> use prepare execute (autoexecute broken in PEAR 2.4.1)
242  {
243  $this->manipulate("DELETE FROM ".$a_table." WHERE ".
244  implode ($delwhere, " AND ")
245  );
246  $this->insert($a_table, $a_columns);
247 
248  //$r = $this->db->extended->autoExecute($a_table, $field_values, MDB2_AUTOQUERY_INSERT, null, $types);
249  $this->handleError($r, "replace, delete/insert(".$a_table.")");
250  }
251  else // if no lobs are used, use manipulate
252  {
253  $q = "MERGE INTO ".$a_table." a ".
254  "USING (SELECT ".implode($val_field, ", ")." ".
255  "FROM DUAL) b ON (".implode($abpk, " AND ").") ".
256  "WHEN MATCHED THEN UPDATE SET ".implode($aboc, ", ")." ".
257  "WHEN NOT MATCHED THEN INSERT (".implode($a, ",").") VALUES (".implode($b, ",").")";
258  $r = $this->manipulate($q);
259  }
260  return $r;
261  }
262 
270  public function locate($a_needle,$a_string,$a_start_pos = 1)
271  {
272  $locate = ' INSTR( ';
273  $locate .= ('SUBSTR('.$a_string.',0,'.self::CLOB_BUFFER_SIZE.')');
274  $locate .= ',';
275  $locate .= $a_needle;
276  $locate .= ',';
277  $locate .= $a_start_pos;
278  $locate .= ') ';
279  return $locate;
280  }
281 
293  public function like($a_col, $a_type, $a_value = "?", $case_insensitive = true)
294  {
295  if($a_type == 'text')
296  {
297  return parent::like($a_col,$a_type,$a_value,$case_insensitive);
298  }
299 
300  if (!in_array($a_type, array("text", "clob", "blob")))
301  {
302  $this->raisePearError("Like: Invalid column type '".$a_type."'.", $this->error_class->FATAL);
303  }
304  if ($a_value == "?")
305  {
306  if ($case_insensitive)
307  {
308  return "UPPER(SUBSTR(".$a_col.",0,".self::CLOB_BUFFER_SIZE.")) LIKE(UPPER(?))";
309  }
310  else
311  {
312  return "SUBSTR(".$a_col .",0,".self::CLOB_BUFFER_SIZE.") LIKE(?)";
313  }
314  }
315  else
316  {
317  if ($case_insensitive)
318  {
319  return " UPPER(SUBSTR(".$a_col.",0,".self::CLOB_BUFFER_SIZE.")) LIKE(UPPER(".$this->quote($a_value, 'text')."))";
320  }
321  else
322  {
323  return " SUBSTR(".$a_col.",0,".self::CLOB_BUFFER_SIZE.") LIKE(".$this->quote($a_value, 'text').")";
324  }
325  }
326  }
327 
334  public function concat($a_values, $a_allow_null = true)
335  {
336  if(count($a_values) <= 2)
337  {
338  return parent::concat($a_values,false);
339  }
340 
341  $first = true;
342  foreach($a_values as $field_info)
343  {
344  if(!$first)
345  {
346  $concat_value = parent::concat(
347  array(
348  array($concat_value,$concat_type),
349  array($field_info[0],$field_info[1])),
350  false
351  );
352  }
353  else
354  {
355  $first = false;
356  $concat_value = $field_info[0];
357  $concat_type = $field_info[1];
358  }
359  }
360  return $concat_value;
361  }
362 
377  function in($a_field, $a_values, $negate = false, $a_type = "")
378  {
379  if(count($a_values) <= self::LIMIT_EXPRESSIONS_IN_LIST)
380  {
381  return parent::in($a_field,$a_values,$negate,$a_type);
382  }
383 
384  $first = true;
385  $concat = $negate ? ' AND ' : ' OR ';
386  $in = '(';
387  do
388  {
389  if(!$first)
390  {
391  $in .= $concat;
392 
393  }
394  $first = false;
395 
396  $spliced = array_splice($a_values, 0, self::LIMIT_EXPRESSIONS_IN_LIST);
397  $in .= parent::in($a_field, $spliced, $negate, $a_type);
398 
399  }
400  while($a_values);
401 
402  return $in." ) ";
403  }
404 
405 
415  public function lockTables($a_tables)
416  {
417  global $ilLog;
418 
419  $locks = array();
420 
421  $counter = 0;
422  foreach($a_tables as $table)
423  {
424  $lock = 'LOCK TABLE ';
425 
426  $lock .= ($table['name'].' ');
427 
428  switch($table['type'])
429  {
430  case ilDB::LOCK_READ:
431  $lock .= ' IN SHARE MODE ';
432  break;
433 
434  case ilDB::LOCK_WRITE:
435  $lock .= ' IN EXCLUSIVE MODE ';
436  break;
437  }
438 
439  $locks[] = $lock;
440  }
441 
442  // @TODO use and store a unique identifier to allow nested lock/unlocks
443  $this->db->beginTransaction();
444  foreach($locks as $lock)
445  {
446  $this->db->query($lock);
447  $ilLog->write(__METHOD__.': '.$lock);
448  }
449  return true;
450  }
451 
456  public function unlockTables()
457  {
458  $this->db->commit();
459  }
460 
466  function dropPrimaryKey($a_table)
467  {
468  // oracle 10: dropping constraint may not drop attached index
469  // http://www.orafaq.com/forum/t/59807/0/
470 
471  $query = "ALTER TABLE ".$a_table." DROP PRIMARY KEY DROP INDEX";
472  $res = $this->db->query($query);
473 
474  return $this->handleError($res, "dropPrimaryKey(".$a_table.")");
475  }
476 }
477 ?>