/** * * Returns the SQL query that can be used to obtain the related records of this * relationship. Note that the value returned from this method cannot be passed * directly to xf_db_query(). It may still have unresolved wildcards and must * be passed through Dataface_Record::parseString() to replace all wildcards. * * @param getBlobs If true then Blob columns will also be returned. Default is false. * @type boolean * * @returns SQL Query * @type string */ function getSQL($getBlobs = false, $where = 0, $sort = 0, $preview = 1) { $start = microtime_float(); import('SQL/Compiler.php'); import('SQL/Parser/wrapper.php'); $loadParserTime = microtime_float() - $start; if (isset($this->_sql_generated[$where][$sort][$preview]) and $this->_sql_generated[$where][$sort][$preview]) { /* * The SQL has already been generated and stored. We can just return it. */ if ($getBlobs) { // We will be returning blob columns as well return $this->_schema['sql_with_blobs'][$where][$sort][$preview]; } else { // We will NOT be returning BLOB columns return $this->_schema['sql_without_blobs'][$where][$sort][$preview]; } } else { /* * The SQL has not been generated yet. We will generate it. */ $this->_sql_generated[$where][$sort][$preview] = true; if (!isset($this->_schema['sql_without_blobs'])) { $this->_schema['sql_without_blobs'] = array(); } if (!isset($this->_schema['sql_with_blobs'])) { $this->_schema['sql_with_blobs'] = array(); } if (defined('DATAFACE_USE_CACHE') and DATAFACE_USE_CACHE) { $cache_key_blobs = 'tables/' . $this->_sourceTable->tablename . '/relationships/' . $this->_name . '/sql/withblobs'; $cache_key_noblobs = 'tables/' . $this->_sourceTable->tablename . '/relationships/' . $this->_name . '/sql/withoutblobs'; // we are using the APC cache import('Dataface/Cache.php'); $cache =& Dataface_Cache::getInstance(); $this->_schema['sql_with_blobs'] = $cache->get($cache_key_blobs); $this->_schema['sql_without_blobs'] = $cache->get($cache_key_noblobs); } if (!isset($this->_schema['sql_without_blobs'][$where][$sort][$preview]) or !isset($this->_schema['sql_with_blobs'][$where][$sort][$preview])) { //if ( !$this->_schema['sql_without_blobs'][$where][$sort] ) $this->_schema['sql_without_blobs'] = array(); //if ( !$this->_schema['sql_with_blobs'] ) $this->_schema['sql_with_blobs'] = array(); $parsed = unserialize(serialize($this->_schema['parsed_sql'])); $parsed['column_names'] = array(); $parsed['column_aliases'] = array(); $parsed['columns'] = array(); $wrapper = new SQL_Parser_wrapper($parsed, 'MySQL'); $blobCols = array(); $tableAliases = array(); // For tables that have custom SQL defined we sub in its SQL // here. foreach (array_keys($parsed['tables']) as $tkey) { if ($parsed['tables'][$tkey]['type'] == 'ident') { $table =& Dataface_Table::loadTable($parsed['tables'][$tkey]['value']); $proxyView = $table->getProxyView(); $tsql = $table->sql(); if (isset($tsql) and !$proxyView) { $parsed['tables'][$tkey]['type'] = 'compiled_subselect'; $parsed['tables'][$tkey]['value'] = $tsql; if (!$parsed['tables'][$tkey]['alias']) { $parsed['tables'][$tkey]['alias'] = $table->tablename; } } else { if ($proxyView) { $parsed['tables'][$tkey]['value'] = $proxyView; if (!$parsed['tables'][$tkey]['alias']) { $parsed['tables'][$tkey]['alias'] = $table->tablename; } } } $tableAliases[$table->tablename] = $parsed['tables'][$tkey]['alias']; unset($table); unset($tsql); } } $done = array(); $dups = array(); foreach ($this->fields(true) as $colname) { // We go through each column in the query and add meta columns for length. //$table =& Dataface_Table::getTableTableForField($colname); list($tablename, $col) = explode('.', $colname); if ($tablename != $this->getDomainTable() and Dataface_Table::loadTable($this->getDomainTable())->hasField($col)) { // If this is a duplicate field we take the domain table value. $dups[$col] = $this->getDomainTable(); continue; } if (isset($done[$col])) { $dups[$col] = $tablename; } $done[$col] = true; $table =& Dataface_Table::loadTable($tablename); $alias = $wrapper->getTableAlias($tablename); if (!$alias) { $alias = $tablename; } $colname = $alias . '.' . $col; if (isset($field)) { unset($field); } $field =& $table->getField($col); if (PEAR::isError($field)) { $field = array(); } if ($table->isPassword($col)) { unset($table); continue; } if ($table->isBlob($col)) { $blobCols[] = $colname; } if (@$tableAliases[$tablename]) { $tableAlias = $tableAliases[$tablename]; } else { $tableAlias = $tablename; } if ($tableAlias) { $colFull = '`' . $tableAlias . '`.`' . $col . '`'; //echo "Full"; } else { $colFull = '`' . $col . '`'; } $rfieldProps = array(); if (isset($this->_schema['field']) and isset($this->_schema['field'][$col])) { $rfieldProps = $this->_schema['field'][$col]; } $maxlen = 255; if (@$rfieldProps['max_length']) { $maxlen = intval($rfieldProps['max_length']); } if (in_array(strtolower($table->getType($col)), array('timestamp', 'datetime'))) { $parsed['columns'][] = array('type' => 'compiled_func', 'table' => null, 'value' => "ifnull(convert_tz(" . $colFull . ",'SYSTEM','" . addslashes(df_tz_or_offset()) . "'), " . $colFull . ")", 'alias' => $col); } else { if ($preview and $table->isText($col) and !@$field['struct'] and !$table->isXML($col)) { $parsed['columns'][] = array('type' => 'compiled_func', 'table' => null, 'value' => "SUBSTRING({$colFull}, 1, {$maxlen})", 'alias' => $col); } else { $parsed['columns'][] = array('type' => 'ident', 'table' => $tableAlias, 'value' => $col, 'alias' => null); } } //$wrapper->addMetaDataColumn($colname); // Note: Removed *length* metadata columns for now.. not hard to add // back. Will wait to see if anyone screams! // Steve Hannah 071229 unset($table); } if ($where !== 0) { $whereClause = $where; // Avoid ambiguous column error. Any duplicate columns need to be specified. foreach ($dups as $dcolname => $dtablename) { $whereClause = preg_replace('/([^.]|^) *`' . preg_quote($dcolname) . '`/', '$1 `' . $dtablename . '`.`' . $dcolname . '`', $whereClause); } $wrapper->addWhereClause($whereClause); } if ($sort !== 0) { $sortClause = $sort; foreach ($dups as $dcolname => $dtablename) { $sortClause = preg_replace('/([^.]|^) *`' . preg_quote($dcolname) . '`/', '$1 `' . $dtablename . '`.`' . $dcolname . '`', $sortClause); } $wrapper->setSortClause($sortClause); } //$compiler = new SQL_Compiler(null, 'mysql'); $compiler =& SQL_Compiler::newInstance('mysql'); $compiler->version = 2; $this->_schema['sql_with_blobs'][$where][$sort][$preview] = $compiler->compile($parsed); foreach ($blobCols as $blobCol) { $wrapper->removeColumn($blobCol); } $this->_schema['sql_without_blobs'][$where][$sort][$preview] = $compiler->compile($parsed); if (defined('DATAFACE_USE_CACHE') and DATAFACE_USE_CACHE) { $cache->set($cache_key_blobs, $this->_schema['sql_with_blobs']); $cache->set($cache_key_noblobs, $this->_schema['sql_without_blobs']); } } /* * Now that the SQL is generated we can call ourselves and the first * case will now be initiated (ie: the generated sql will be returned). */ $timeToGenerate = microtime_float() - $start; if (DATAFACE_DEBUG) { $this->app->addDebugInfo("Time to generate sql for relationship {$this->name} : {$timeToGenerate}"); } return $this->getSQL($getBlobs, $where, $sort); } }
/** * Returns the select portion of the sql query. * eg: SELECT foo, bar * @param columns An option list of columns to select. */ function _select($columns = '', $query = array(), $preview = false, $previewLen = null) { if (!isset($previewLen) and defined('XATAFACE_DEFAULT_PREVIEW_LENGTH') and is_int(XATAFACE_DEFAULT_PREVIEW_LENGTH)) { $previewLen = XATAFACE_DEFAULT_PREVIEW_LENGTH; } if (!is_int($previewLen)) { $previewLen = 255; } $app =& Dataface_Application::getInstance(); $query = array_merge($this->_query, $query); foreach ($query as $key => $value) { if ($value === null) { unset($query[$key]); } } $select = "SELECT "; $colcount = 0; foreach ($this->_fields as $key => $field) { if ($this->selectMetaData) { $select .= "length(`{$this->_tablename}`.`" . $key . "`) as `__" . $key . "_length`,"; } if (is_array($columns) and !in_array($key, $columns)) { continue; } // if the columns array is set then we only return the columns listed in that array. if ($this->_omitBlobs and $this->_table->isBlob($field['name'])) { continue; } // if the omitBlobs flag is set then we don't select blob columns if ($this->_omitPasswords and $this->_table->isPassword($field['name'])) { continue; } // if the omitPasswords flag is set then we don't select password columns if ($preview and $this->_table->isText($field['name']) and !@$field['struct'] and !$this->_table->isXML($field['name'])) { $select .= "SUBSTRING(`{$this->_tablename}`.`{$key}`, 1, " . $previewLen . ") as `{$key}`,"; } else { if (in_array(strtolower($this->_table->getType($key)), array('datetime', 'timestamp'))) { $select .= "ifnull(convert_tz(`" . $this->_tablename . "`.`" . $key . "`, 'SYSTEM', '" . df_tz_or_offset() . "'), `" . $this->_tablename . "`.`" . $key . "`) as `{$key}`,"; } else { $select .= "`{$this->_tablename}`.`{$key}`,"; } } $colcount++; } if ($this->metadata) { $clauses = array(); foreach ($this->_table->getMetadataColumns() as $mdc) { $clauses[] = "`{$this->_tablename}__metadata`.`{$mdc}`"; } $select .= implode(',', $clauses) . ','; } if ($colcount == 0) { return PEAR::raiseError(QUERYBUILDER_ERROR_EMPTY_SELECT, null, null, null, "No columns were selected in select statement. Make sure that _omitBlobs property is disabled in QueryBuilder object if you are only wanting to return Blob columns."); } $select = substr($select, 0, strlen($select) - 1); return $select; }