ILIAS  release_4-3 Revision
 All Data Structures Namespaces Files Functions Variables Groups Pages
oci8.php
Go to the documentation of this file.
1 <?php
2 // +----------------------------------------------------------------------+
3 // | PHP versions 4 and 5 |
4 // +----------------------------------------------------------------------+
5 // | Copyright (c) 1998-2006 Manuel Lemos, Tomas V.V.Cox, |
6 // | Stig. S. Bakken, Lukas Smith, Frank M. Kromann |
7 // | All rights reserved. |
8 // +----------------------------------------------------------------------+
9 // | MDB2 is a merge of PEAR DB and Metabases that provides a unified DB |
10 // | API as well as database abstraction for PHP applications. |
11 // | This LICENSE is in the BSD license style. |
12 // | |
13 // | Redistribution and use in source and binary forms, with or without |
14 // | modification, are permitted provided that the following conditions |
15 // | are met: |
16 // | |
17 // | Redistributions of source code must retain the above copyright |
18 // | notice, this list of conditions and the following disclaimer. |
19 // | |
20 // | Redistributions in binary form must reproduce the above copyright |
21 // | notice, this list of conditions and the following disclaimer in the |
22 // | documentation and/or other materials provided with the distribution. |
23 // | |
24 // | Neither the name of Manuel Lemos, Tomas V.V.Cox, Stig. S. Bakken, |
25 // | Lukas Smith nor the names of his contributors may be used to endorse |
26 // | or promote products derived from this software without specific prior|
27 // | written permission. |
28 // | |
29 // | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
30 // | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
31 // | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS |
32 // | FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE |
33 // | REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, |
34 // | INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, |
35 // | BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS|
36 // | OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED |
37 // | AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
38 // | LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY|
39 // | WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
40 // | POSSIBILITY OF SUCH DAMAGE. |
41 // +----------------------------------------------------------------------+
42 // | Author: Lukas Smith <smith@pooteeweet.org> |
43 // +----------------------------------------------------------------------+
44 //
45 // $Id: oci8.php,v 1.62 2007/03/29 18:18:06 quipo Exp $
46 //
47 
48 require_once 'MDB2/Driver/Reverse/Common.php';
49 
58 {
59  // {{{ getTableFieldDefinition()
60 
69  function getTableFieldDefinition($table, $field_name)
70  {
71  $db =& $this->getDBInstance();
72  if (PEAR::isError($db)) {
73  return $db;
74  }
75 
76  $result = $db->loadModule('Datatype', null, true);
77  if (PEAR::isError($result)) {
78  return $result;
79  }
80 
81  $query = 'SELECT column_name name, data_type "type", nullable, data_default "default"';
82  $query.= ', COALESCE(data_precision, data_length) "length", data_scale "scale"';
83  $query.= ' FROM user_tab_columns';
84  $query.= ' WHERE (table_name='.$db->quote($table, 'text').' OR table_name='.$db->quote(strtoupper($table), 'text').')';
85  $query.= ' AND (column_name='.$db->quote($field_name, 'text').' OR column_name='.$db->quote(strtoupper($field_name), 'text').')';
86  $query.= ' ORDER BY column_id';
87  $column = $db->queryRow($query, null, MDB2_FETCHMODE_ASSOC);
88  if (PEAR::isError($column)) {
89  return $column;
90  }
91 
92  if (empty($column)) {
93  return $db->raiseError(MDB2_ERROR_NOT_FOUND, null, null,
94  'it was not specified an existing table column', __FUNCTION__);
95  }
96 
97  $column = array_change_key_case($column, CASE_LOWER);
98  if ($db->options['portability'] & MDB2_PORTABILITY_FIX_CASE) {
99  if ($db->options['field_case'] == CASE_LOWER) {
100  $column['name'] = strtolower($column['name']);
101  } else {
102  $column['name'] = strtoupper($column['name']);
103  }
104  }
105  $mapped_datatype = $db->datatype->mapNativeDatatype($column);
106  if (PEAR::IsError($mapped_datatype)) {
107  return $mapped_datatype;
108  }
109  list($types, $length, $unsigned, $fixed) = $mapped_datatype;
110  $notnull = false;
111  if (!empty($column['nullable']) && $column['nullable'] == 'N') {
112  $notnull = true;
113  }
114  $default = false;
115  if (array_key_exists('default', $column)) {
116  $default = $column['default'];
117  if ($default === 'NULL') {
118  $default = null;
119  }
120  if (is_null($default) && $notnull) {
121  $default = '';
122  }
123  }
124 
125  $definition[0] = array('notnull' => $notnull, 'nativetype' => $column['type']);
126  if (!is_null($length)) {
127  $definition[0]['length'] = $length;
128  }
129  if (!is_null($unsigned)) {
130  $definition[0]['unsigned'] = $unsigned;
131  }
132  if (!is_null($fixed)) {
133  $definition[0]['fixed'] = $fixed;
134  }
135  if ($default !== false) {
136  $definition[0]['default'] = $default;
137  }
138  foreach ($types as $key => $type) {
139  $definition[$key] = $definition[0];
140  if ($type == 'clob' || $type == 'blob') {
141  unset($definition[$key]['default']);
142  }
143  $definition[$key]['type'] = $type;
144  $definition[$key]['mdb2type'] = $type;
145  }
146  if ($type == 'integer') {
147  $query = "SELECT DISTINCT name
148  FROM all_source
149  WHERE type='TRIGGER'
150  AND UPPER(text) like '%ON ". strtoupper($db->escape($table, 'text')) ."%'";
151  $result = $db->query($query);
152  if (!PEAR::isError($result)) {
153  while ($row = $result->fetchRow(MDB2_FETCHMODE_ASSOC)) {
154  $row = array_change_key_case($row, CASE_LOWER);
155  $trquery = 'SELECT text
156  FROM all_source
157  WHERE name=' . $db->quote($row['name'],'text')
158  . ' ORDER BY line';
159  $triggersth = $db->query($trquery);
160  $triggerstr = '';
161  while ($triggerline = $triggersth->fetchRow(MDB2_FETCHMODE_ASSOC)) {
162  $triggerline = array_change_key_case($triggerline,CASE_LOWER);
163  $triggerstr .= $triggerline['text']. ' ';
164  }
165  $matches = array();
166  if (preg_match('/.*\W(.+)\.nextval into :NEW\.'.$field_name.' FROM dual/i', $triggerstr, $matches)) {
167  // we reckon it's an autoincrementing trigger on field_name
168  // there will be other pcre patterns needed here for other ways of mimicking auto_increment in ora.
169  $definition[0]['autoincrement'] = $matches[1];
170  }
171  }
172  }
173  }
174  return $definition;
175  }
176 
177  // }}}
178 
179  // {{{ getTableIndexDefinition()
180 
189  function getTableIndexDefinition($table, $index_name)
190  {
191  $db =& $this->getDBInstance();
192  if (PEAR::isError($db)) {
193  return $db;
194  }
195 
196  $query = "SELECT column_name,
197  column_position,
198  descend
199  FROM user_ind_columns
200  WHERE (table_name=".$db->quote($table, 'text').' OR table_name='.$db->quote(strtoupper($table), 'text').')
201  AND (index_name=%s OR index_name=%s)
202  AND index_name NOT IN (
203  SELECT constraint_name
204  FROM dba_constraints
205  WHERE (table_name = '.$db->quote($table, 'text').' OR table_name='.$db->quote(strtoupper($table), 'text').")
206  AND constraint_type in ('P','U')
207  )
208  ORDER BY column_position";
209  $index_name_mdb2 = $db->getIndexName($index_name);
210  $sql = sprintf($query,
211  $db->quote($index_name_mdb2, 'text'),
212  $db->quote(strtoupper($index_name_mdb2), 'text')
213  );
214  $result = $db->queryRow($sql);
215  if (!PEAR::isError($result) && !is_null($result)) {
216  // apply 'idxname_format' only if the query succeeded, otherwise
217  // fallback to the given $index_name, without transformation
218  $index_name = $index_name_mdb2;
219  }
220  $sql = sprintf($query,
221  $db->quote($index_name, 'text'),
222  $db->quote(strtoupper($index_name), 'text')
223  );
224  $result = $db->query($sql);
225  if (PEAR::isError($result)) {
226  return $result;
227  }
228 
229  $definition = array();
230  while ($row = $result->fetchRow(MDB2_FETCHMODE_ASSOC)) {
231  $row = array_change_key_case($row, CASE_LOWER);
232  $column_name = $row['column_name'];
233  if ($db->options['portability'] & MDB2_PORTABILITY_FIX_CASE) {
234  if ($db->options['field_case'] == CASE_LOWER) {
235  $column_name = strtolower($column_name);
236  } else {
237  $column_name = strtoupper($column_name);
238  }
239  }
240  $definition['fields'][$column_name] = array(
241  'position' => (int)$row['column_position'],
242  );
243  if (!empty($row['descend'])) {
244  $definition['fields'][$column_name]['sorting'] =
245  ($row['descend'] == 'ASC' ? 'ascending' : 'descending');
246  }
247  }
248  $result->free();
249  if (empty($definition['fields'])) {
250  return $db->raiseError(MDB2_ERROR_NOT_FOUND, null, null,
251  'it was not specified an existing table index', __FUNCTION__);
252  }
253  return $definition;
254  }
255 
256  // }}}
257  // {{{ getTableConstraintDefinition()
258 
267  function getTableConstraintDefinition($table, $constraint_name)
268  {
269  $db =& $this->getDBInstance();
270  if (PEAR::isError($db)) {
271  return $db;
272  }
273 
274  $query = 'SELECT alc.constraint_name,
275  alc.constraint_type,
276  alc.search_condition,
277  alc.r_constraint_name,
278  alc.search_condition,
279  cols.column_name,
280  cols.position
281  FROM all_constraints alc,
282  all_cons_columns cols
283  WHERE (alc.constraint_name=%s OR alc.constraint_name=%s)
284  AND alc.constraint_name = cols.constraint_name
285  AND alc.owner = '.$db->quote(strtoupper($db->dsn['username']), 'text');
286  if (!empty($table)) {
287  $query.= ' AND (alc.table_name='.$db->quote($table, 'text').' OR alc.table_name='.$db->quote(strtoupper($table), 'text').')';
288  }
289  if (strtolower($constraint_name) != 'primary') {
290  $constraint_name_mdb2 = $db->getIndexName($constraint_name);
291  $sql = sprintf($query,
292  $db->quote($constraint_name_mdb2, 'text'),
293  $db->quote(strtoupper($constraint_name_mdb2), 'text')
294  );
295  $result = $db->queryRow($sql);
296  if (!PEAR::isError($result) && !is_null($result)) {
297  // apply 'idxname_format' only if the query succeeded, otherwise
298  // fallback to the given $index_name, without transformation
299  $constraint_name = $constraint_name_mdb2;
300  }
301  }
302  $sql = sprintf($query,
303  $db->quote($constraint_name, 'text'),
304  $db->quote(strtoupper($constraint_name), 'text')
305  );
306  $result = $db->query($sql);
307  if (PEAR::isError($result)) {
308  return $result;
309  }
310  $definition = array();
311  while (is_array($row = $result->fetchRow(MDB2_FETCHMODE_ASSOC))) {
312  $row = array_change_key_case($row, CASE_LOWER);
313  $column_name = $row['column_name'];
314  if ($db->options['portability'] & MDB2_PORTABILITY_FIX_CASE) {
315  if ($db->options['field_case'] == CASE_LOWER) {
316  $column_name = strtolower($column_name);
317  } else {
318  $column_name = strtoupper($column_name);
319  }
320  }
321  $definition['fields'][$column_name] = array(
322  'position' => (int)$row['position']
323  );
324  $lastrow = $row;
325  // otherwise $row is no longer usable on exit from loop
326  }
327  $result->free();
328  if (empty($definition)) {
329  return $db->raiseError(MDB2_ERROR_NOT_FOUND, null, null,
330  $constraint_name . ' is not an existing table constraint', __FUNCTION__);
331  }
332  if ($lastrow['constraint_type'] === 'P') {
333  $definition['primary'] = true;
334  } elseif ($lastrow['constraint_type'] === 'U') {
335  $definition['unique'] = true;
336  } elseif ($lastrow['constraint_type'] === 'R') {
337  $definition['foreign'] = $lastrow['r_constraint_name'];
338  } elseif ($lastrow['constraint_type'] === 'C') {
339  $definition['check'] = true;
340  // pattern match constraint for check constraint values into enum-style output:
341  $enumregex = '/'.$lastrow['column_name'].' in \((.+?)\)/i';
342  if (preg_match($enumregex, $lastrow['search_condition'], $rangestr)) {
343  $definition['fields'][$column_name] = array();
344  $allowed = explode(',', $rangestr[1]);
345  foreach ($allowed as $val) {
346  $val = trim($val);
347  $val = preg_replace('/^\'/', '', $val);
348  $val = preg_replace('/\'$/', '', $val);
349  array_push($definition['fields'][$column_name], $val);
350  }
351  }
352  }
353  return $definition;
354  }
355 
356  // }}}
357  // {{{ getSequenceDefinition()
358 
366  function getSequenceDefinition($sequence)
367  {
368  $db =& $this->getDBInstance();
369  if (PEAR::isError($db)) {
370  return $db;
371  }
372 
373  $sequence_name = $db->getSequenceName($sequence);
374  $query = 'SELECT last_number FROM user_sequences';
375  $query.= ' WHERE sequence_name='.$db->quote($sequence_name, 'text');
376  $query.= ' OR sequence_name='.$db->quote(strtoupper($sequence_name), 'text');
377  $start = $db->queryOne($query, 'integer');
378  if (PEAR::isError($start)) {
379  return $start;
380  }
381  $definition = array();
382  if ($start != 1) {
383  $definition = array('start' => $start);
384  }
385  return $definition;
386  }
387 
388  // }}}
389  // {{{ getTriggerDefinition()
390 
403  function getTriggerDefinition($trigger)
404  {
405  $db =& $this->getDBInstance();
406  if (PEAR::isError($db)) {
407  return $db;
408  }
409 
410  $query = 'SELECT trigger_name,
411  table_name,
412  trigger_body,
413  trigger_type,
414  triggering_event trigger_event,
415  description trigger_comment,
416  1 trigger_enabled,
417  when_clause
418  FROM user_triggers
419  WHERE trigger_name = \''. strtoupper($trigger).'\'';
420  $types = array(
421  'trigger_name' => 'text',
422  'table_name' => 'text',
423  'trigger_body' => 'text',
424  'trigger_type' => 'text',
425  'trigger_event' => 'text',
426  'trigger_comment' => 'text',
427  'trigger_enabled' => 'boolean',
428  'when_clause' => 'text',
429  );
430  $result = $db->queryRow($query, $types, MDB2_FETCHMODE_ASSOC);
431  if (PEAR::isError($result)) {
432  return $result;
433  }
434  if (!empty($result['trigger_type'])) {
435  //$result['trigger_type'] = array_shift(explode(' ', $result['trigger_type']));
436  $result['trigger_type'] = preg_replace('/(\S+).*/', '\\1', $result['trigger_type']);
437  }
438  return $result;
439  }
440 
441  // }}}
442  // {{{ tableInfo()
443 
464  function tableInfo($result, $mode = null)
465  {
466  if (is_string($result)) {
467  return parent::tableInfo($result, $mode);
468  }
469 
470  $db =& $this->getDBInstance();
471  if (PEAR::isError($db)) {
472  return $db;
473  }
474 
475  $resource = MDB2::isResultCommon($result) ? $result->getResource() : $result;
476  if (!is_resource($resource)) {
477  return $db->raiseError(MDB2_ERROR_NEED_MORE_DATA, null, null,
478  'Could not generate result resource', __FUNCTION__);
479  }
480 
481  if ($db->options['portability'] & MDB2_PORTABILITY_FIX_CASE) {
482  if ($db->options['field_case'] == CASE_LOWER) {
483  $case_func = 'strtolower';
484  } else {
485  $case_func = 'strtoupper';
486  }
487  } else {
488  $case_func = 'strval';
489  }
490 
491  $count = @OCINumCols($resource);
492  $res = array();
493 
494  if ($mode) {
495  $res['num_fields'] = $count;
496  }
497 
498  $db->loadModule('Datatype', null, true);
499  for ($i = 0; $i < $count; $i++) {
500  $column = array(
501  'table' => '',
502  'name' => $case_func(@OCIColumnName($resource, $i+1)),
503  'type' => @OCIColumnType($resource, $i+1),
504  'length' => @OCIColumnSize($resource, $i+1),
505  'flags' => '',
506  );
507  $res[$i] = $column;
508  $res[$i]['mdb2type'] = $db->datatype->mapNativeDatatype($res[$i]);
509  if ($mode & MDB2_TABLEINFO_ORDER) {
510  $res['order'][$res[$i]['name']] = $i;
511  }
512  if ($mode & MDB2_TABLEINFO_ORDERTABLE) {
513  $res['ordertable'][$res[$i]['table']][$res[$i]['name']] = $i;
514  }
515  }
516  return $res;
517  }
518 }
519 ?>