Andrew's Web Libraries (AWL)
 All Classes Namespaces Functions Variables Pages
AwlDBDialect.php
1 <?php
18 if ( !defined('E_USER_ERROR') ) define('E_USER_ERROR',256);
19 
33 class AwlDBDialect {
41  protected $dialect;
42 
46  protected $db;
47 
51  private $version;
52 
59  const HttpDateFormat = "'Dy, DD Mon IYYY HH24:MI:SS \"GMT\"'";
60 
64  const SqlDateFormat = "'YYYYMMDD\"T\"HH24MISS'";
65 
70  const SqlUTCFormat = "'YYYYMMDD\"T\"HH24MISS\"Z\"'";
71 
76  const SqlDurationFormat = "'\"PT\"HH24\"H\"MI\"M\"'";
77 
90  function __construct( $connection_string, $dbuser=null, $dbpass=null, $options=null ) {
91  if ( preg_match( '/^(pgsql):/', $connection_string, $matches ) ) {
92  $this->dialect = $matches[1];
93  }
94  else {
95  error_log("Unable to connect to database: ". $e->getMessage() );
96  trigger_error("Unsupported database connection '".$connection_string."'",E_USER_ERROR);
97  }
98  try {
99  $this->db = new PDO( $connection_string, $dbuser, $dbpass, $options );
100  } catch (PDOException $e) {
101  error_log("Unable to connect to database: ". $e->getMessage() );
102  if ( function_exists('trigger_error') )
103  trigger_error("PDO connection error '".$connection_string."': ".$e->getMessage(),E_USER_ERROR);
104  throw $e;
105  }
106  }
107 
108 
109 
113  function SetSearchPath( $search_path = null ) {
114  if ( !isset($this->dialect) ) {
115  trigger_error("Unsupported database dialect",E_USER_ERROR);
116  }
117 
118  switch ( $this->dialect ) {
119  case 'pgsql':
120  if ( $search_path == null ) $search_path = 'public';
121  $sql = "SET search_path TO " . $this->Quote( $search_path, 'identifier' );
122  return $sql;
123  }
124  }
125 
126 
131  function GetVersion( ) {
132  if ( isset($this->version) ) return $this->version;
133  if ( !isset($this->dialect) ) {
134  trigger_error("Unsupported database dialect", E_USER_ERROR);
135  }
136 
137  $version = $this->dialect.':';
138 
139  switch ( $this->dialect ) {
140  case 'pgsql':
141  $sql = "SELECT version()";
142  if ( $sth = $this->db->query($sql) ) {
143  $row = $sth->fetch(PDO::FETCH_NUM);
144  $version .= preg_replace( '/^PostgreSQL (\d+\.\d+)\..*$/i', '$1', $row[0]);
145  }
146  break;
147  default:
148  return null;
149  }
150  $this->version = $version;
151  return $version;
152  }
153 
154 
160  function GetFields( $tablename_string ) {
161  if ( !isset($this->dialect) ) {
162  trigger_error("Unsupported database dialect", E_USER_ERROR);
163  }
164 
165  switch ( $this->dialect ) {
166  case 'pgsql':
167  list( $schema, $table ) = explode('.', $tablename_string, 2);
168  if ( empty($table) ) {
169  $table = $tablename_string;
170  $schema = null;
171  }
172 
173  $sql = 'SELECT f.attname AS fieldname, t.typname AS typename, f.atttypmod AS precision FROM pg_attribute f';
174  $sql .= ' JOIN pg_class c ON ( f.attrelid = c.oid )';
175  $sql .= ' JOIN pg_type t ON ( f.atttypid = t.oid )';
176  $sql .= ' JOIN pg_namespace ns ON ( c.relnamespace = ns.oid )';
177  $sql .= ' WHERE relname = '.$this->Quote($table,PDO::PARAM_STR).' AND attnum >= 0 ';
178  if ( isset($schema) ) $sql .= ' AND ns.nspname = '.$this->Quote($schema,PDO::PARAM_STR);
179  $sql .= ' ORDER BY f.attnum';
180  dbg_error_log($sql);
181  return $sql;
182  }
183  }
184 
185 
199  function TranslateSQL( $sql_string ) {
200  // Noop for the time being...
201  return $sql_string;
202  }
203 
204 
205 
213  function Quote( $value, $value_type = null ) {
214  if ( isset($value_type) && $value_type == 'identifier' ) {
215  if ( $this->dialect == 'mysql' ) {
217  $rv = '`' . str_replace('`', '\\`', $value ) . '`';
218  }
219  else {
220  $rv = '"' . str_replace('"', '\\"', $value ) . '"';
221  }
222  return $rv;
223  }
224 
225  if ( !isset($value_type) ) {
226  if ( !isset($value) ) $value_type = PDO::PARAM_NULL;
227  elseif ( is_bool($value) ) $value_type = PDO::PARAM_BOOL;
228  elseif ( is_float($value) ) $value_type = PDO::PARAM_INT;
229  elseif ( is_numeric($value)) {
230  if ( preg_match('{^(19|20)\d\d(0[1-9]|1[012])([012]\d|30|31)$}', $value) )
231  $value_type = PDO::PARAM_STR; // YYYYMMDD
232  elseif ( preg_match('{^0x}i', $value) )
233  $value_type = PDO::PARAM_STR; // Any hex numbers will need to be explicitly cast in SQL
234  elseif ( preg_match('{^[0-9+-]+e[0-9+-]+$}i', $value) )
235  $value_type = PDO::PARAM_STR; // 72e57650 could easily be a string and will need an explicit cast also
236  elseif ( preg_match('/^[01]{6,}$/i', $value) )
237  $value_type = PDO::PARAM_STR; // Binary numbers will need to be explicitly cast in SQL
238  else
239  $value_type = PDO::PARAM_INT;
240  }
241  else
242  $value_type = PDO::PARAM_STR;
243  }
244 
245  if ( is_string($value_type) ) {
246  switch( $value_type ) {
247  case 'null':
248  $value_type = PDO::PARAM_NULL;
249  break;
250  case 'integer':
251  case 'double' :
252  $value_type = PDO::PARAM_INT;
253  break;
254  case 'boolean':
255  $value_type = PDO::PARAM_BOOL;
256  break;
257  case 'string':
258  $value_type = PDO::PARAM_STR;
259  break;
260  }
261  }
262 
263  switch ( $value_type ) {
264  case PDO::PARAM_NULL:
265  $rv = 'NULL';
266  break;
267  case PDO::PARAM_INT:
268  $rv = $value;
269  break;
270  case PDO::PARAM_BOOL:
271  $rv = ($value ? 'TRUE' : 'FALSE');
272  break;
273  case PDO::PARAM_STR:
274  default:
281  $rv = "'".str_replace("'", "''", str_replace(':', '\\x3a', str_replace('\\', '\\x5c', $value)))."'";
282 
283  if ( $this->dialect == 'pgsql' && strpos( $rv, '\\' ) !== false ) {
288  $rv = 'E'.str_replace('?', '\\x3f', $rv);
289  }
290 
291  }
292 
293  return $rv;
294 
295  }
296 
297 
315  function ReplaceParameters() {
316  $argc = func_num_args();
317  $args = func_get_args();
318 
319  if ( is_array($args[0]) ) {
323  $args = $args[0];
324  $argc = count($args);
325  }
326  $qry = array_shift($args);
327 
328  if ( is_array($args[0]) ) {
329  $args = $args[0];
330  $argc = count($args);
331  }
332 
333  if ( ! isset($args[0]) ) return $this->ReplaceNamedParameters($qry,$args);
334 
339  $parts = explode( '?', $qry, $argc + 1 );
340  $querystring = $parts[0];
341  $z = count($parts);
342 
343  for( $i = 0; $i < $argc; $i++ ) {
344  $arg = $args[$i];
345  $querystring .= $this->Quote($arg); //parameter
346  $z = $i+1;
347  if ( isset($parts[$z]) ) $querystring .= $parts[$z];
348  }
349 
350  return $querystring;
351  }
352 
372  $argc = func_num_args();
373  $args = func_get_args();
374 
375  if ( is_array($args[0]) ) {
379  $args = $args[0];
380  $argc = count($args);
381  }
382  $querystring = array_shift($args);
383 
384  if ( is_array($args[0]) ) {
385  $args = $args[0];
386  $argc = count($args);
387  }
388 
389  foreach( $args AS $name => $value ) {
390  if ( substr($name, 0, 1) != ':' ) {
391  dbg_error_log( "ERROR", "AwlDBDialect: Named parameter '%s' does not begin with a colon.", $name);
392  }
393  $replacement = str_replace('$', '\\$', $this->Quote($value)); // No positional replacement in $replacement!
394  $querystring = preg_replace( '{\Q'.$name.'\E\b}s', $replacement, $querystring );
395  }
396 
397  return $querystring;
398  }
399 
400 }
TranslateSQL($sql_string)
const HttpDateFormat
__construct($connection_string, $dbuser=null, $dbpass=null, $options=null)
SetSearchPath($search_path=null)
const SqlDurationFormat
const SqlDateFormat
GetFields($tablename_string)
Quote($value, $value_type=null)
const SqlUTCFormat