Squiz Matrix  4.12.2
 All Data Structures Namespaces Functions Variables Pages
Query.inc
1 <?php
13 require_once dirname(__FILE__).'/DAL.inc';
14 
22 class Query
23 {
24 
25 
37  public $_lobStack = Array();
38 
39 
46  private $_queryid = '';
47 
54  private $_totalBindings = 0;
55 
63  private $_arrayRepresentation = array();
64 
74  private $_sqlString = '';
75 
82  private $_bindings = array();
83 
92  private $_keywords = array();
93 
102  private $_execMethod = NULL;
103 
110  private $_bindMap = array();
111 
112 
124  public function __construct($queryid='', array $arrayRepresentation=array(), $sqlString='')
125  {
126  $this->_queryid = $queryid;
127 
128  if (isset($arrayRepresentation['query']) === FALSE) {
129  throw new DALException('Invalid array representation');
130  }
131 
132  $this->_arrayRepresentation = $arrayRepresentation;
133  $this->_sqlString = $sqlString;
134 
135  }//end __construct()
136 
137 
144  public function getQueryType()
145  {
146  return $this->_arrayRepresentation['query_type'];
147 
148  }//end getQueryType()
149 
150 
157  public function getArrayRepresentation()
158  {
159  return $this->_arrayRepresentation;
160 
161  }//end getArrayRepresentation()
162 
163 
173  public function merge($bindName, Query $query)
174  {
175  $subQuery = clone $query;
176  $subQueryArray = $subQuery->getQueryArray();
177 
178  // Merge the passed query into the appropriate part of ours.
179  // We need to determine if the merging these two queries is simple or complex.
180  if ($subQuery->getQueryType() === 'with') {
181  $afterPart = $subQueryArray['WITH']['AFTER'];
182 
183  // Add this query to after WITH clause.
184  $subQueryArray['WITH']['AFTER'] = $this->getQueryArray();
185 
186 
187  $this->_arrayRepresentation['query'] = $subQueryArray;
188  $this->_findAndReplacePlaceHolder($bindName, $afterPart);
189  $this->_arrayRepresentation['query_type'] = 'with';
190  $this->_addBindingsFromQuery($subQuery);
191  } else {
192  $this->_addBindingsFromQuery($subQuery);
193  $this->_findAndReplacePlaceHolder($bindName, $subQueryArray);
194  }
195 
196  return TRUE;
197 
198  }//end merge()
199 
200 
209  private function _addBindingsFromQuery(Query $subQuery)
210  {
211  $bindings = $subQuery->getBindings();
212  foreach ($bindings as $binding) {
213  $newName = $this->_getNextValidBindName();
214  $subQuery->_findAndReplacePlaceHolder($binding['name'], $newName);
215  $this->_addBindVar($newName, $binding['value'], $binding['type'], $binding['name']);
216  }
217 
218  }//end _addBindingsFromQuery()
219 
220 
227  private function _getNextValidBindName()
228  {
229  $this->_totalBindings++;
230  $bindName = ':bind_'.$this->_totalBindings;
231  return $bindName;
232 
233  }//end _getNextValidBindName()
234 
235 
247  private function _addBindVar($name, $value, $type, $realName)
248  {
249  $this->_bindings[] = array(
250  'name' => $name,
251  'value' => $value,
252  'type' => $type,
253  );
254 
255  $this->_bindMap[] = array(
256  $realName => $name,
257  );
258 
259  }//end _addBindVar()
260 
261 
270  private function _removeLastBindVar($count=1)
271  {
272  for ($i = 0; $i < $count; $i++) {
273  array_pop($this->_bindings);
274  array_pop($this->_bindMap);
275  $this->_totalBindings--;
276  }
277 
278  }//end _removeLastBindVar()
279 
280 
290  public function replaceBindVarName($oldName, $newName)
291  {
292  $this->_sqlString = str_replace($oldName, $newName, $this->_sqlString);
293 
294  }//end replaceBindVarName()
295 
296 
303  public function getQueryid()
304  {
305  return $this->_queryid;
306 
307  }//end getQueryid()
308 
309 
316  public function getBindings()
317  {
318  return $this->_bindings;
319 
320  }//end getBindings()
321 
322 
329  public function getQueryArray()
330  {
331  return $this->_arrayRepresentation['query'];
332 
333  }//end getQueryArray()
334 
335 
346  public function getSql($convert=FALSE)
347  {
348  if ($convert === TRUE || $this->_sqlString === '') {
349  // TODO: Should not include DALBaker here.
350  require_once SQ_LIB_PATH.'/DAL/DALBaker.inc';
351  $converter = DALBaker::getConverter();
352  $this->_sqlString = $converter->convertToSql($this->_arrayRepresentation['query']);
353  }
354 
355  return $this->_sqlString;
356 
357  }//end getSql()
358 
359 
366  public function prepare()
367  {
368  $sql = $this->getSql(TRUE);
369 
370  // Replace keywords.
371  foreach ($this->_keywords as $keyword => $value) {
372  $sql = str_replace('['.$keyword.']', $value, $sql);
373  }
374 
375  // Update sqlString..
376  $this->_sqlString = $sql;
377 
378  // Prepare PDO statement.
379  $dbh = DAL::getDb();
380 
381  if (DAL::getDbType() === 'oci') {
382 
383  $query = oci_parse($dbh, $sql);
384  // Add bindings
385  foreach ($this->_bindings as $binding) {
386  // TODO: Handle insert/update of CLOB fields - this needs to be determined at bake time
387  if ($binding['type'] === PDO::PARAM_LOB) {
388  oci_bind_by_name($query, $binding['name'], $binding['value'], -1, SQLT_CLOB);
389 
390  // Add to LOB stack so we can release it later
391  $this->_lobStack[] = $binding['value'];
392  } else {
393  oci_bind_by_name($query, $binding['name'], $binding['value'], -1);
394  }
395  }
396 
397  } else {
398 
399  $query = $dbh->prepare($sql);
400  // Add bindings to PDO.
401  foreach ($this->_bindings as $binding) {
402  // $query->bindValue($binding['name'], $binding['value'], $binding['type']);
403  $query->bindValue($binding['name'], $binding['value']);
404  }
405 
406  }
407 
408  return $query;
409 
410  }//end prepare()
411 
412 
423  public function setExecMethod($method)
424  {
425  $this->_execMethod = $method;
426 
427  }//end setExecMethod()
428 
429 
438  public function getExecMethod()
439  {
440  return $this->_execMethod;
441 
442  }//end getExecMethod()
443 
444 
458  public function bind($name, $value, $dataType=NULL)
459  {
460  // Depending on the data type replace, merge, split etc.
461  if (($value instanceof Query) === TRUE) {
462  $this->merge($name, $value);
463  } else if (is_array($value) === TRUE) {
464  $bindNames = array();
465  foreach ($value as $val) {
466  $newBindName = $this->_getNextValidBindName();
467  $this->_addBindVar($newBindName, $val, $dataType, $name);
468  $bindNames[] = $newBindName;
469  }
470 
471  if ($this->_findAndReplacePlaceHolder($name, implode(',', $bindNames)) === FALSE) {
472  $this->_removeLastBindVar(count($bindNames));
473  }
474  } else {
475  $newBindName = $this->_getNextValidBindName();
476  $this->_addBindVar($newBindName, $value, $dataType, $name);
477 
478  // Find the bind place holder in the query array and replace it.
479  if ($this->_findAndReplacePlaceHolder($name, $newBindName) === FALSE) {
480  $this->_removeLastBindVar();
481  }
482 
483  }//end if
484 
485  }//end bind()
486 
487 
499  private function _findAndReplacePlaceHolder($placeHolder, $value)
500  {
501  $arrays = Array();
502  $arrays[] =& $this->_arrayRepresentation['query'];
503  $found = FALSE;
504 
505  for ($i = 0; $i < count($arrays); $i++) {
506  $this_array =& $arrays[$i];
507 
508  foreach(array_keys($this_array) as $key) {
509  if ($this_array[$key] === $placeHolder) {
510  $this_array[$key] = $value;
511 
512  // Set found, then break out of both loops
513  $found = TRUE;
514  break 2;
515  }
516 
517  if (is_array($this_array[$key])) {
518  $arrays[] =& $this_array[$key];
519  }
520  }
521  }
522 
523  return $found;
524 
525  }//end _findAndReplacePlaceHolder()
526 
527 
539  private function _findAndReplaceCallBack(&$item, $key, array $data)
540  {
541  if ($item === $data[0]) {
542  $item = $data[1];
543  // We are done exit array_walk_recursive.
544  throw new Exception('done');
545  }
546 
547  }//end _findAndReplaceCallBack()
548 
549 
559  public function subQueries($subQueryid, array $queries)
560  {
561  foreach ($queries as $query) {
562  if (($query instanceof Query) === TRUE) {
563  $query->getSql();
564  $this->merge('HOOKID:'.$subQueryid, $query);
565  } else {
566  $this->bind('HOOKID:'.$subQueryid, $query, PDO::PARAM_STR);
567  }
568  }
569 
570  }//end subQueries()
571 
572 
583  public function keywords(array $keywords)
584  {
585  $this->_keywords = array_merge($this->_keywords, $keywords);
586 
587  }//end keywords()
588 
589 
596  public function releaseLobs()
597  {
598  // OCI8:
599  if (DAL::getDBType() === 'oci') {
600  foreach($this->_lobStack as $key => $lob) {
601  $lob->close();
602  oci_free_descriptor($lob);
603  unset($this->_lobStack[$key]);
604  }
605  }
606 
607  }//end releaseLobs()
608 
609 
610 
611 }//end class
612 
613 
614 ?>