summaryrefslogtreecommitdiffstats
path: root/modules/database
diff options
context:
space:
mode:
Diffstat (limited to 'modules/database')
-rw-r--r--modules/database/classes/database/query.php49
-rw-r--r--modules/database/classes/driver/pdo/query.php80
2 files changed, 115 insertions, 14 deletions
diff --git a/modules/database/classes/database/query.php b/modules/database/classes/database/query.php
index 981a33c..c48407c 100644
--- a/modules/database/classes/database/query.php
+++ b/modules/database/classes/database/query.php
@@ -5,8 +5,6 @@
* Database drivers extend this class so that they can generate database specific queries.
* The idea is to provide a database agnostic interface to query writing.
*
- * @method mixed table(string $table = null) Set table to query.
- * Without arguments returns current table, returns self otherwise.
*
* @method mixed data(array $data = null) Set data for insert or update queries.
* Without arguments returns current data, returns self otherwise.
@@ -125,8 +123,15 @@ abstract class Query_Database {
* @var array
* @access protected
*/
- protected $methods = array('table' => 'string','data' => 'array','limit' => array('integer','NULL'),'offset' => array('integer','NULL'),'group_by' => array('string','NULL'),'type' => 'string');
+ protected $methods = array('data' => 'array','limit' => array('integer','NULL'),'offset' => array('integer','NULL'),'group_by' => array('string','NULL'),'type' => 'string');
+ /**
+ * UNION queries
+ * @var array
+ * @access protected
+ */
+ protected $_union = array();
+
/**
* Generates a query in format that can be executed on current database implementation
*
@@ -169,7 +174,26 @@ abstract class Query_Database {
}
return $this;
}
-
+
+ /**
+ * Sets the table to perform operations on, also supports subqueries
+ *
+ * @param string|Query_database|Expression_database $table table to select from
+ * @param string $alias Alias for this table
+ * @return mixed Returns self if a table is passed, otherwise returns the table
+ * @access public
+ */
+ public function table($table=null,$alias=null) {
+ if ($table == null)
+ return is_array($this->_table)?$this->_table[1]:$this->_table;
+
+ if (!is_string($table) && $alias==null)
+ $alias = $this->add_alias();
+ $this->_table = $alias == null?$table:array($table, $alias);
+
+ return $this;
+ }
+
/**
* Magic methods to create methods for all generic query parts
*
@@ -352,7 +376,20 @@ abstract class Query_Database {
throw new Exception('Incorrect conditional statement passed');
}
-
+
+ /**
+ * Adds a UNION to the query
+ *
+ * @param Query_Database|Expression_Database $query Query for the UNION
+ * @param string $all whether to do a UNION ALL, e.g. keep duplicate rows
+ * @return Query_Database Returns self
+ * @access public
+ */
+ public function union($query,$all=true) {
+ $this->_union[] = array($query,$all);
+ return $this;
+ }
+
/**
* Gets last generated alias
*
@@ -361,7 +398,7 @@ abstract class Query_Database {
*/
public function last_alias() {
if ($this->_alias === null)
- return $this->_table;
+ return $this->table();
return 'a'.$this->_alias;
}
diff --git a/modules/database/classes/driver/pdo/query.php b/modules/database/classes/driver/pdo/query.php
index f23e28b..8d3148d 100644
--- a/modules/database/classes/driver/pdo/query.php
+++ b/modules/database/classes/driver/pdo/query.php
@@ -78,12 +78,63 @@ class Query_PDO_Driver extends Query_Database {
* @access public
*/
public function escape_value($val,&$params) {
- if (is_object($val) && get_class($val) == 'Expression_Database')
+ if ($val instanceof Expression_Database)
return $val->value;
+ if ($val instanceof Query_Database)
+ return $this->subquery($val,$params);
$params[] = $val;
return '?';
}
+ /**
+ * Gets the SQL for a subquery and appends its parameters to current ones
+ *
+ * @param Query_Database $query Query builder for the subquery
+ * @param array &$params Reference to parameters array
+ * @return string Subquery SQL
+ * @access public
+ */
+ protected function subquery($query, &$params) {
+ $query = $query->query();
+ $params = array_merge($params, $query[1]);
+ return "({$query[0]}) ";
+ }
+
+ /**
+ * Gets the SQL for a table to select from
+ *
+ * @param string|Expression_Database|Query_Database|array $table Table representation
+ * @param array &$params Reference to parameters array
+ * @param string &alias Alias for this table
+ * @return string Table SQL
+ * @access public
+ */
+ public function escape_table($table, &$params) {
+ $alias=null;
+ if (is_array($table)) {
+ $alias = $table[1];
+ $table = $table[0];
+ }
+
+ if (is_string($table)){
+ $table = $this->quote($table);
+ if ($alias != null)
+ $table.= " AS {$alias}";
+ return $table;
+ }
+
+ if ($alias == null)
+ $alias = $this->last_alias();
+
+ if($table instanceof Query_Database)
+ return "{$this->subquery($table,$params)} AS {$alias}";
+
+ if($table instanceof Expression_Database)
+ return "({$table->value}) AS {$alias}";
+
+ throw new Exception("Parameter type {get_class($table)} cannot be used as a table");
+ }
+
/**
* Builds a query and fills the $params array with parameter values
*
@@ -94,6 +145,7 @@ class Query_PDO_Driver extends Query_Database {
$query = '';
$params = array();
+
if ($this->_type == 'insert') {
$query.= "INSERT INTO {$this->quote($this->_table)} ";
if (empty($this->_data) && $this->_db_type == 'pgsql'){
@@ -134,11 +186,12 @@ class Query_PDO_Driver extends Query_Database {
}
}
}
- $query.= "FROM {$this->quote($this->_table)} ";
+ $query.="FROM {$this->escape_table($this->_table,$params)} ";
}
if ($this->_type == 'count') {
- $query.= "SELECT COUNT(*) as {$this->quote('count')} FROM {$this->quote($this->_table)} ";
+ $query.= "SELECT COUNT(*) as {$this->quote('count')} FROM {$this->escape_table($this->_table,$params)} ";
}
+
if ($this->_type == 'delete') {
if($this->_db_type!='sqlite'){
$query.= "DELETE {$this->last_alias()}.* FROM {$this->quote($this->_table)} ";
@@ -164,11 +217,7 @@ class Query_PDO_Driver extends Query_Database {
foreach($this->_joins as $join) {
$table = $join[0];
- if (is_array($table)){
- $table = "{$this->quote($table[0])} as {$this->quote($table[1])}";
- }else {
- $table="{$this->quote($table)}";
- }
+ $table = $this->escape_table($table,$params);
$query.= strtoupper($join[1])." JOIN {$table} ON {$this->get_condition_query($join[2],$params,true,true)} ";
}
@@ -198,6 +247,21 @@ class Query_PDO_Driver extends Query_Database {
}
}
}
+
+ if (count($this->_union) > 0 && ($this->_type == 'select')) {
+ $query="({$query}) ";
+ foreach($this->_union as $union) {
+ $query.= $union[1]?"UNION ALL ":"UNION ";
+ if (is_subclass_of($union[0], 'Query_Database')) {
+ $query.=$this->subquery($union[0],$params);
+ }elseif(is_subclass_of($union[0], 'Expression_Database')) {
+ $query.="({$union[0]->value}) ";
+ }else {
+ throw new Exception("You can only use query builder instances or DB::expr for unions");
+ }
+ }
+ }
+
if($this->_type != 'count'){
if ($this->_limit != null)
$query.= "LIMIT {$this->_limit} ";