249 if ($source instanceof $this)
251 $this->entity = Entity::getInstanceByQuery($source);
255 $this->entity = clone $source;
257 elseif (is_string($source))
264 'Unknown source type "%s" for new %s', gettype($source), __CLASS__
268 $this->filterHandler = static::filter();
269 $this->whereHandler = static::filter();
270 $this->havingHandler = static::filter();
283 if (str_starts_with(
$method,
'having'))
288 if (str_starts_with(
$method,
'where'))
290 if (method_exists($this->filterHandler,
$method))
292 call_user_func_array(
293 [$this->filterHandler,
$method],
301 if (str_starts_with(
$method,
'with'))
303 $dataClass = $this->entity->getDataClass();
305 if (method_exists($dataClass,
$method))
308 array_unshift($arguments, $this);
310 call_user_func_array(
355 $this->
select[$alias] = $definition;
359 $this->
select[] = $definition;
396 if (is_null(
$key) && is_array($value))
413 return $this->filterHandler;
476 $this->order =
array();
527 $order = $helper->getAscendingOrder();
531 $order = $helper->getDescendingOrder();
534 $this->order[$definition] =
$order;
568 return $this->offset;
587 return $this->countTotal;
604 public function union()
606 foreach (func_get_args() as $arg)
624 foreach (func_get_args() as $arg)
701 $this->data_doubling_off =
false;
714 if (
count($this->entity->getPrimaryArray()) !== 1)
718 trigger_error(sprintf(
719 'Disabling data doubling available for Entities with 1 primary field only. Number of primaries of your entity `%s` is %d.',
720 $this->entity->getFullName(),
count($this->entity->getPrimaryArray())
725 $this->data_doubling_off =
true;
738 $this->private_fields_on =
true;
750 $this->private_fields_on =
false;
760 return $this->private_fields_on;
766 foreach ($this->filter_chains as $chain)
768 if (static::isFieldPrivate($chain->getLastElement()->getValue()))
770 $columnField = $chain->getLastElement()->getValue();
773 'Private field %s.%s is restricted in filter',
774 $columnField->getEntity()->getDataClass(),
775 $columnField->getName()
781 if ($this->private_fields_on !==
true)
783 foreach ($this->global_chains as $chain)
785 if (static::isFieldPrivate($chain->getLastElement()->getValue()))
787 $columnField = $chain->getLastElement()->getValue();
790 'Private field %s.%s is restricted in query, use Query::enablePrivateFields() to allow it',
791 $columnField->getEntity()->getDataClass(),
792 $columnField->getName()
810 return $field->isPrivate();
814 foreach ($field->getBuildFromChains() as $chain)
816 if (static::isFieldPrivate($chain->getLastElement()->getValue()))
838 if (
$name instanceof
Field && $fieldInfo ===
null)
842 $name = $fieldInfo->getName();
846 $name = $fieldInfo->getName();
851 if ($fieldInfo instanceof
Field)
853 $fieldInfo = clone $fieldInfo;
857 $this->entity->addField($fieldInfo,
$name);
865 $this->collectExprChains($chain,
array(
'hidden'));
873 $this->table_alias_postfix = $postfix;
879 return $this->table_alias_postfix;
891 $this->custom_base_table_alias = $alias;
919 public static function expr($alias =
null)
921 if (static::$expressionHelper ===
null)
926 static::$expressionHelper->alias = $alias;
928 return static::$expressionHelper;
940 $this->is_executing =
true;
948 if($this->cacheTtl > 0 && (empty($this->join_map) || $this->
cacheJoins))
950 $ttl = $this->entity->getCacheTtl($this->cacheTtl);
959 if (!is_null($this->limit) && empty($this->limit))
980 $this->is_executing =
false;
984 if (!empty($this->forcedObjectPrimaryFields))
986 $queryResult->setHiddenObjectFields($this->forcedObjectPrimaryFields);
1003 return $this->
exec()->fetch($converter);
1017 return $this->
exec()->fetchAll($converter);
1030 if (empty($this->
select))
1035 return $this->
exec()->fetchObject();
1047 if (empty($this->
select))
1052 return $this->
exec()->fetchCollection();
1055 protected function ensurePrimarySelect()
1059 if ($this->hasAggregation() || $this->hasDistinct())
1066 foreach ($this->join_map as $join)
1068 $entities[] = [$join[
'entity'], $join];
1072 foreach ($entities as list(
$entity, $join))
1075 foreach (
$entity->getPrimaryArray() as $primary)
1077 if (!empty(
$entity->getField($primary)->hasParameter(
'auto_generated')))
1082 $needDefinition = !empty($join[
'definition']) ? $join[
'definition'].
'.'.$primary : $primary;
1084 $chain = $this->getRegisteredChain($needDefinition,
true);
1086 if (empty($this->select_chains[$chain->getAlias()]))
1089 $alias = $this->getUniqueAlias();
1090 $chain->setCustomAlias($alias);
1092 $this->registerChain(
'select', $chain);
1095 $this->forcedObjectPrimaryFields[] = $alias;
1099 ? $chain->getLastElement()->setParameter(
'talias', $join[
'alias'])
1100 : $chain->getLastElement()->setParameter(
'talias', $this->getInitAlias());
1114 protected function addToSelectChain($definition, $alias =
null)
1116 if ($definition instanceof ExpressionField)
1120 $alias = $definition->getName();
1130 if ($chain->getLastElement()->getValue() instanceof ExpressionField)
1132 $this->collectExprChains($chain,
array(
'hidden',
'select_expr'));
1135 elseif (is_array($definition))
1139 throw new Main\ArgumentException(
1140 'Expression as an array in `select` section is no more supported due to security reason.'
1141 .
' Please use `runtime` parameter, or Query->registerRuntimeField method, or pass ExpressionField object instead of array.'
1147 $localDefinitionPos = strrpos($definition,
'.');
1149 if ($localDefinitionPos !==
false)
1151 $localDefinition = substr($definition, $localDefinitionPos + 1);
1152 $localEntityDef = substr($definition, 0, $localDefinitionPos);
1153 $localChain = Chain::getChainByDefinition($this->entity, $localEntityDef.
'.*');
1154 $lastElemValue = $localChain->getLastElement()->getValue();
1156 if ($lastElemValue instanceof Reference)
1158 $localEntity = $lastElemValue->getRefEntity();
1160 elseif (is_array($lastElemValue))
1162 list($localEntity, ) = $lastElemValue;
1166 $localEntity = $lastElemValue;
1171 $localDefinition = $definition;
1172 $localEntityDef =
"";
1173 $dataClass = $this->entity->getDataClass();
1174 $localEntity = $dataClass::getEntity();
1178 if ((strlen($localDefinition) > 1 && str_contains($localDefinition,
'*'))
1179 || str_contains($localDefinition,
'?')
1183 foreach ($localEntity->getFields() as $field)
1186 ($field instanceof ScalarField || $field instanceof ExpressionField)
1187 && fnmatch($localDefinition, $field->getName())
1191 if ($field instanceof ScalarField && $field->isPrivate())
1198 str_starts_with($field->getName(),
'UF_') && str_ends_with($field->getName(),
'_SINGLE')
1199 && $localEntity->hasField(substr($field->getName(), 0, -7))
1207 $customAlias =
null;
1209 if ($alias !==
null)
1212 $customAlias = $alias.$field->getName();
1216 $fieldDefinition = $field->getName();
1218 if (!empty($localEntityDef))
1220 $fieldDefinition = $localEntityDef.
'.'.$fieldDefinition;
1223 $this->addToSelectChain($fieldDefinition, $customAlias);
1233 if ($alias !==
null)
1236 $chain = clone $chain;
1237 $chain->setCustomAlias($alias);
1240 $last_elem = $chain->getLastElement();
1244 $expand_entity =
null;
1246 if ($last_elem->getValue() instanceof Reference)
1248 $expand_entity = $last_elem->getValue()->getRefEntity();
1250 elseif (is_array($last_elem->getValue()))
1252 list($expand_entity, ) = $last_elem->getValue();
1254 elseif ($last_elem->getValue() instanceof Entity)
1256 $expand_entity = $last_elem->getValue();
1258 elseif ($last_elem->getValue() instanceof OneToMany)
1260 $expand_entity = $last_elem->getValue()->getRefEntity();
1262 elseif ($last_elem->getValue() instanceof ManyToMany)
1264 $expand_entity = $last_elem->getValue()->getRefEntity();
1267 if (!$expand_entity && $alias !==
null)
1271 $this->entity->hasField($alias)
1274 $this->entity->getFullName() !== $last_elem->getValue()->getEntity()->getFullName()
1276 $last_elem->getValue()->getName() !== $alias
1281 throw new Main\ArgumentException(sprintf(
1282 'Alias "%s" matches already existing field "%s" of initial entity "%s". '.
1283 'Please choose another name for alias.',
1284 $alias, $alias, $this->entity->getFullName()
1292 foreach ($expand_entity->getFields() as $exp_field)
1295 if ($exp_field instanceof ScalarField)
1298 if ($exp_field->isPrivate())
1303 $exp_chain = clone $chain;
1304 $exp_chain->addElement(
new ChainElement(
1309 if ($alias !==
null)
1311 $fieldAlias = $alias . $exp_field->getName();
1314 if ($this->entity->hasField($fieldAlias))
1316 throw new Main\ArgumentException(sprintf(
1317 'Alias "%s" + field "%s" match already existing field "%s" of initial entity "%s". '.
1318 'Please choose another name for alias.',
1319 $alias, $exp_field->getName(), $fieldAlias, $this->entity->getFullName()
1323 $exp_chain->setCustomAlias($fieldAlias);
1341 if ($chain->getLastElement()->getValue() instanceof ExpressionField)
1343 $this->collectExprChains($chain,
array(
'hidden',
'select_expr'));
1360 foreach (
$filter as $filter_def => &$filter_match)
1362 if ($filter_def ===
'LOGIC')
1367 if (!is_numeric($filter_def))
1369 $sqlWhere = new \CSQLWhere();
1370 $csw_result = $sqlWhere->makeOperation($filter_def);
1371 list($definition, ) = array_values($csw_result);
1381 $chain = $this->filter_chains[$definition] ?? Chain::getChainByDefinition($this->entity, $definition);
1385 $dstField = $chain->getLastElement()->getValue();
1386 $dstEntity = $dstField->getEntity();
1391 $dstBuildFromChains = $dstField->getBuildFromChains();
1393 $firstChain = $dstBuildFromChains[0];
1394 $dstField = $firstChain->getLastElement()->getValue();
1399 && $dstEntity->hasField($dstField->getName().
'_SINGLE'))
1401 $utmLinkField = $dstEntity->getField($dstField->getName().
'_SINGLE');
1405 $buildFromChains = $utmLinkField->getBuildFromChains();
1410 $endField = $buildFromChains[0]->getLastElement()->getValue();
1413 if(strpos($endField->getEntity()->getName(),
'Utm'))
1415 $expressionChain = clone $chain;
1416 $expressionChain->removeLastElement();
1417 $expressionChain->addElement(
new ChainElement(clone $utmLinkField));
1418 $expressionChain->forceDataDoublingOff();
1420 $chain = $expressionChain;
1424 $filter[$filter_def.
'_SINGLE'] = $filter_match;
1425 $definition .=
'_SINGLE';
1432 $registerChain =
true;
1435 if ($chain->forcesDataDoublingOff() || ($this->data_doubling_off && $chain->hasBackReference()))
1437 $registerChain =
false;
1447 $this->collectExprChains($chain);
1454 $this->filter_chains[$chain->getAlias()] = $chain;
1455 $this->filter_chains[$definition] = $chain;
1461 elseif (is_array($filter_match))
1477 foreach (
$where->getConditions() as $condition)
1479 if ($condition instanceof
Filter)
1486 $definition = $condition->getDefinition();
1489 if ($definition instanceof
Field)
1495 $definition = $definition->getName();
1496 $condition->setDefinition($definition);
1500 if ($definition !==
null)
1509 $chain = $this->filter_chains[$definition] ?? Chain::getChainByDefinition($this->entity, $definition);
1513 $dstField = $chain->getLastElement()->getValue();
1514 $dstEntity = $dstField->getEntity();
1519 $dstBuildFromChains = $dstField->getBuildFromChains();
1521 $firstChain = $dstBuildFromChains[0];
1522 $dstField = $firstChain->getLastElement()->getValue();
1527 && $dstEntity->hasField($dstField->getName().
'_SINGLE'))
1529 $utmLinkField = $dstEntity->getField($dstField->getName().
'_SINGLE');
1533 $buildFromChains = $utmLinkField->getBuildFromChains();
1538 $endField = $buildFromChains[0]->getLastElement()->getValue();
1541 if(strpos($endField->getEntity()->getName(),
'Utm'))
1543 $expressionChain = clone $chain;
1544 $expressionChain->removeLastElement();
1545 $expressionChain->addElement(
new ChainElement(clone $utmLinkField));
1546 $expressionChain->forceDataDoublingOff();
1548 $chain = $expressionChain;
1551 $definition .=
'_SINGLE';
1552 $condition->setDefinition($definition);
1559 $registerChain =
true;
1562 if ($chain->forcesDataDoublingOff() || ($this->data_doubling_off && $chain->hasBackReference()))
1564 $registerChain =
false;
1574 $this->collectExprChains($chain);
1581 $this->filter_chains[$chain->getAlias()] = $chain;
1582 $this->filter_chains[$definition] = $chain;
1590 foreach ($condition->getAtomicValues() as $value)
1594 $valueDefinition = $value->getDefinition();
1596 $chain = $this->filter_chains[$valueDefinition] ?? Chain::getChainByDefinition($this->entity, $valueDefinition);
1604 $value->setConnection($this->entity->getConnection());
1619 $logic = $this->
filter[
'LOGIC'] ??
'AND';
1626 $this->where =
array();
1627 $this->where_chains =
array();
1630 $this->having_chains = $this->filter_chains;
1635 $this->where_chains = $this->filter_chains;
1637 $this->having =
array();
1638 $this->having_chains =
array();
1644 foreach ($this->
filter as
$k => $sub_filter)
1648 $this->where[
$k] = $sub_filter;
1649 $this->having[
$k] = $sub_filter;
1654 $tmp_filter =
array(
$k => $sub_filter);
1658 $this->having[
$k] = $sub_filter;
1663 $this->where[
$k] = $sub_filter;
1670 foreach ($this->having_chains as $chain)
1674 $this->collectExprChains($chain,
array(
'hidden',
'having_expr'));
1685 $logic = $this->filterHandler->logic();
1692 $this->havingHandler = $this->filterHandler;
1693 $this->having_chains = $this->filter_chains;
1697 $this->whereHandler = $this->filterHandler;
1698 $this->where_chains = $this->filter_chains;
1704 foreach ($this->filterHandler->getConditions() as $condition)
1706 $tmpFilter = static::filter()->addCondition($condition);
1710 $this->havingHandler->addCondition($tmpFilter);
1715 $this->whereHandler->addCondition($condition);
1722 foreach ($this->having_chains as $chain)
1726 $this->collectExprChains($chain,
array(
'hidden',
'having_expr'));
1739 foreach (
$filter as $filter_def => $filter_match)
1741 if ($filter_def ===
'LOGIC')
1747 if (!is_numeric($filter_def))
1749 $sqlWhere = new \CSQLWhere();
1750 $csw_result = $sqlWhere->makeOperation($filter_def);
1751 list($definition, ) = array_values($csw_result);
1753 $chain = $this->filter_chains[$definition];
1754 $last = $chain->getLastElement();
1758 elseif (is_array($filter_match))
1780 foreach (
$filter->getConditions() as $condition)
1784 if ($condition instanceof
Filter)
1792 if ($condition->getDefinition() !==
null)
1795 $chain = $this->filter_chains[$condition->getDefinition()];
1796 $last = $chain->getLastElement();
1803 $chain = $this->filter_chains[$condition->getValue()->getDefinition()];
1804 $last = $chain->getLastElement();
1831 foreach (
$filter->getConditions() as $condition)
1833 if ($condition instanceof
Filter)
1838 elseif ($condition->getDefinition() !==
null)
1841 $chain = $this->filter_chains[$condition->getDefinition()];
1843 if ($chain->forcesDataDoublingOff() || ($this->data_doubling_off && $chain->hasBackReference()))
1845 $primaryName = $this->entity->getPrimary();
1846 $uniquePostfix =
'_TMP'.rand();
1849 $dataClass = $this->entity->getDataClass();
1851 $subQuery = $dataClass::query()
1852 ->addSelect($primaryName)
1853 ->where(clone $condition)
1854 ->setTableAliasPostfix(strtolower($uniquePostfix));
1857 $condition->setColumn($primaryName);
1858 $condition->setOperator(
'in');
1859 $condition->setValue($subQuery);
1881 $this->collectExprChains($chain);
1897 $this->collectExprChains($chain);
1900 if ($this->is_distinct)
1903 $this->addToSelectChain($definition);
1913 protected function buildJoinMap($chains =
null)
1918 $aliasLength = $helper->getAliasLength();
1922 $chains = $this->global_chains;
1925 foreach ($chains as $chain)
1927 if ($chain->getLastElement()->getParameter(
'talias'))
1934 if ($chain->forcesDataDoublingOff() || ($this->data_doubling_off && $chain->hasBackReference()))
1936 $alias = $chain->getAlias();
1938 if (isset($this->filter_chains[$alias])
1939 && !isset($this->select_chains[$alias]) && !isset($this->select_expr_chains[$alias])
1940 && !isset($this->group_chains[$alias]) && !isset($this->order_chains[$alias])
1947 $prev_alias = $this->getInitAlias(
false);
1955 $elements = array_slice($chain->getAllElements(), 1);
1957 $currentDefinition =
array();
1959 foreach ($elements as $element)
1961 $table_alias =
null;
1968 if ($element->getValue() instanceof Reference)
1971 $ref_field = $element->getValue();
1972 $dst_entity = $ref_field->getRefEntity();
1973 $joinType = $ref_field->getJoinType();
1975 elseif (is_array($element->getValue()))
1978 list($dst_entity, $ref_field) = $element->getValue();
1979 $joinType = $ref_field->getJoinType();
1981 elseif ($element->getValue() instanceof OneToMany)
1984 $dst_entity = $element->getValue()->getRefEntity();
1985 $ref_field = $element->getValue()->getRefField();
1986 $joinType = $element->getValue()->getJoinType() ?: $ref_field->getJoinType();
1988 elseif ($element->getValue() instanceof ManyToMany)
1990 $mtm = $element->getValue();
1994 $tmpChain = clone $chain;
1995 $mtmDefinition = join(
'.', $currentDefinition);
1997 while ($tmpChain->getDefinition() != $mtmDefinition)
1999 $tmpChain->removeLastElement();
2003 $tmpChain->addElement(
new ChainElement([
2004 $mtm->getMediatorEntity(), $mtm->getLocalReference()
2008 $tmpChain->addElement(
new ChainElement($mtm->getRemoteReference()));
2012 $this->buildJoinMap([$tmpChain]);
2015 $prev_alias = $tmpChain->getLastElement()->getParameter(
'talias');
2016 $element->setParameter(
'talias', $prev_alias);
2019 $ref_field = $element->getValue();
2020 $dst_entity = $element->getValue()->getRefEntity();
2028 $element->setParameter(
'talias', $this->
getInitAlias());
2032 $element->setParameter(
'talias', $prev_alias.$this->table_alias_postfix);
2039 if (empty($map_key))
2041 $map_key = join(
'.', $currentDefinition);
2044 $map_key .=
'/' . $ref_field->getName() .
'/' . $dst_entity->getName();
2046 $currentDefinition[] = $element->getDefinitionFragment();
2049 if ($element->getValue() instanceof ManyToMany)
2052 $lastKey = array_key_last($this->join_map);
2053 $this->join_map[$lastKey][
'definition'] = join(
'.', $currentDefinition);
2058 if (isset($this->join_registry[$map_key]))
2061 $table_alias = $this->join_registry[$map_key];
2066 $reference = $ref_field->getReference();
2068 if ($element->getValue() instanceof Reference)
2071 if (is_null($table_alias))
2073 $table_alias = $prev_alias.
'_'.strtolower($ref_field->getName());
2075 if (strlen($table_alias.$this->table_alias_postfix) > $aliasLength)
2077 $old_table_alias = $table_alias;
2078 $table_alias =
'TALIAS_' . (
count($this->replaced_taliases) + 1);
2079 $this->replaced_taliases[$table_alias] = $old_table_alias;
2083 $alias_this = $prev_alias;
2084 $alias_ref = $table_alias;
2086 $isBackReference =
false;
2088 $definition_this = join(
'.', array_slice($currentDefinition, 0, -1));
2089 $definition_ref = join(
'.', $currentDefinition);
2090 $definition_join = $definition_ref;
2092 elseif (is_array($element->getValue()) || $element->getValue() instanceof OneToMany)
2094 if (is_null($table_alias))
2096 $table_alias = StringHelper::camel2snake($dst_entity->getName()).
'_'.strtolower($ref_field->getName());
2097 $table_alias = $prev_alias.
'_'.$table_alias;
2099 if (strlen($table_alias.$this->table_alias_postfix) > $aliasLength)
2101 $old_table_alias = $table_alias;
2102 $table_alias =
'TALIAS_' . (
count($this->replaced_taliases) + 1);
2103 $this->replaced_taliases[$table_alias] = $old_table_alias;
2107 $alias_this = $table_alias;
2108 $alias_ref = $prev_alias;
2110 $isBackReference =
true;
2112 $definition_this = join(
'.', $currentDefinition);
2113 $definition_ref = join(
'.', array_slice($currentDefinition, 0, -1));
2114 $definition_join = $definition_this;
2118 throw new Main\SystemException(sprintf(
'Unknown reference element `%s`', $element->getValue()));
2122 if ($reference instanceof Filter)
2126 $alias_this.$this->table_alias_postfix,
2127 $alias_ref.$this->table_alias_postfix,
2137 $alias_this.$this->table_alias_postfix,
2138 $alias_ref.$this->table_alias_postfix,
2146 if (!isset($this->join_registry[$map_key]))
2149 'type' => $joinType,
2150 'entity' => $dst_entity,
2151 'definition' => $definition_join,
2152 'table' => $dst_entity->getDBTableName(),
2153 'alias' => $table_alias.$this->table_alias_postfix,
2154 'reference' => $csw_reference,
2155 'map_key' => $map_key
2158 $this->join_map[] = $join;
2159 $this->join_registry[$map_key] = $table_alias;
2164 $element->setParameter(
'talias', $table_alias.$this->table_alias_postfix);
2166 $prev_alias = $table_alias;
2175 $helper = $this->entity->getConnection()->getSqlHelper();
2176 $aliasLength = (int) $helper->getAliasLength();
2178 foreach ($this->select_chains as $chain)
2180 $definition = $chain->getSqlDefinition();
2181 $alias = $chain->getAlias();
2183 if (strlen($alias) > $aliasLength)
2186 $newAlias =
'FALIAS_'.count($this->replaced_aliases);
2187 $this->replaced_aliases[$newAlias] = $alias;
2192 $sql[] = $definition .
' AS ' . $helper->quote($alias);
2197 (!empty($this->forcedObjectPrimaryFields) &&
count($sql) ==
count($this->forcedObjectPrimaryFields))
2203 $strSql = join(
",\n\t", $sql);
2208 $strSql =
'DISTINCT '.$strSql;
2211 return "\n\t".$strSql;
2221 $csw = new \CSQLWhere;
2226 foreach ($this->join_map as $join)
2230 $csw->setFields($csw_fields);
2232 if ($join[
'reference'] instanceof
Filter)
2234 $joinConditionSql = $join[
'reference']->getSql($this->global_chains);
2238 $joinConditionSql = trim($csw->getQuery($join[
'reference']));
2242 $sql[] = sprintf(
'%s JOIN %s %s ON %s',
2245 $helper->quote($join[
'alias']),
2250 return "\n".join(
"\n", $sql);
2263 if (!empty($this->where))
2265 $csw = new \CSQLWhere;
2267 $csw_fields = $this->getFilterCswFields($this->where);
2268 $csw->setFields($csw_fields);
2270 $sql[] = trim($csw->getQuery($this->where));
2274 if ($this->whereHandler && $this->whereHandler->hasConditions())
2279 $sql[] = $this->whereHandler->getSql($this->where_chains);
2282 return join(
' AND ', array_filter($sql));
2296 foreach ($this->global_chains as $chain)
2298 $alias = $chain->getAlias();
2301 if ($chain->isConstant())
2306 if (isset($this->select_chains[$alias]) || isset($this->order_chains[$alias]) || isset($this->having_chains[$alias]))
2308 if (isset($this->group_chains[$alias]))
2313 elseif (!$chain->hasAggregation() && !$chain->hasSubquery())
2318 elseif (!$chain->hasAggregation() && $chain->hasSubquery() && $chain->getLastElement()->getValue() instanceof
ExpressionField)
2321 $sub_chains = $chain->getLastElement()->getValue()->getBuildFromChains();
2323 foreach ($sub_chains as $sub_chain)
2326 $real_sub_chain = clone $chain;
2328 foreach (array_slice($sub_chain->getAllElements(), 1) as $sub_chain_elem)
2330 $real_sub_chain->addElement($sub_chain_elem);
2334 $this->
registerChain(
'group', $this->global_chains[$real_sub_chain->getAlias()]);
2338 elseif (isset($this->having_expr_chains[$alias]))
2340 if (!$chain->hasAggregation() && $chain->hasSubquery())
2348 foreach ($this->group_chains as $chain)
2351 $sqlDefinition = $chain->getSqlDefinition();
2352 $valueField = $chain->getLastElement()->getValue();
2356 $valueField = $valueField->getValueField();
2363 $sqlDefinition =
$connection->getSqlHelper()->softCastTextToChar($sqlDefinition);
2366 $sql[] = $sqlDefinition;
2369 return join(
', ', $sql);
2382 if (!empty($this->having))
2384 $csw = new \CSQLWhere;
2386 $csw_fields = $this->getFilterCswFields($this->having);
2387 $csw->setFields($csw_fields);
2389 $sql[] = trim($csw->getQuery($this->having));
2393 if ($this->havingHandler && $this->havingHandler->hasConditions())
2398 $sql[] = $this->havingHandler->getSql($this->having_chains);
2401 return join(
' AND ', array_filter($sql));
2412 foreach ($this->order_chains as $chain)
2414 $sort = isset($this->order[$chain->getDefinition()])
2415 ? $this->order[$chain->getDefinition()]
2416 : ($this->order[$chain->getAlias()] ??
'');
2421 $valueField = $chain->getLastElement()->getValue();
2424 $valueField = $valueField->getValueField();
2428 if (isset($this->select_chains[$chain->getAlias()]))
2431 $alias = $chain->getAlias();
2433 if (
$key = array_search($alias, $this->replaced_aliases))
2439 $sqlDefinition =
$connection->getSqlHelper()->quote($alias);
2443 $sqlDefinition = $chain->getSqlDefinition();
2450 $sqlDefinition =
$connection->getSqlHelper()->softCastTextToChar($sqlDefinition);
2453 $sql[] = $sqlDefinition.
' ' . $sort;
2456 return join(
', ', $sql);
2471 if ($this->query_build_parts ===
null)
2476 $this->addToSelectChain($value, is_numeric(
$key) ?
null :
$key);
2483 $this->entity->setDefaultScope($this);
2488 foreach ($this->group as $value)
2493 foreach ($this->order as
$key => $value)
2498 $this->buildJoinMap();
2500 if ($forceObjectPrimary && empty($this->unionHandler))
2502 $this->ensurePrimarySelect();
2516 $sqlFrom .=
' '.$sqlJoin;
2518 $this->query_build_parts = array_filter(
array(
2519 'SELECT' => $sqlSelect,
2521 'WHERE' => $sqlWhere,
2522 'GROUP BY' => $sqlGroup,
2523 'HAVING' => $sqlHaving,
2524 'ORDER BY' => $sqlOrder
2531 $build_parts = $this->query_build_parts;
2533 foreach ($build_parts as
$k => &$v)
2538 $query = join(
"\n", $build_parts);
2540 if ($this->limit > 0)
2542 $query = $helper->getTopSql(
$query, $this->limit, $this->offset);
2546 if (!empty($this->unionHandler))
2548 if ($this->order || $this->limit)
2553 foreach ($this->unionHandler->getQueries() as $union)
2555 $query .=
" ".$union->getSql();
2559 if ($this->unionHandler->getOrder())
2561 $sqlUnionOrder =
array();
2562 foreach ($this->unionHandler->getOrder() as $definition => $sort)
2564 $sqlDefinition =
$connection->getSqlHelper()->quote(
2565 $this->global_chains[$definition]->getAlias()
2568 $sqlUnionOrder[] = $sqlDefinition .
' ' . $sort;
2571 $query .=
' ORDER BY ' . join(
', ', $sqlUnionOrder);
2575 if ($this->unionHandler->getLimit())
2577 $query = $helper->getTopSql(
$query, $this->unionHandler->getLimit(), $this->unionHandler->getOffset());
2591 protected function getFilterCswFields(&
$filter)
2595 foreach (
$filter as $filter_def => &$filter_match)
2597 if ($filter_def ===
'LOGIC')
2602 if (!is_numeric($filter_def))
2604 $sqlWhere = new \CSQLWhere();
2605 $csw_result = $sqlWhere->makeOperation($filter_def);
2606 list($definition, $operation) = array_values($csw_result);
2608 $chain = $this->filter_chains[$definition];
2609 $last = $chain->getLastElement();
2612 $field_type = $last->getValue()->getDataType();
2616 if (in_array($operation,
array(
'SE',
'SN'),
true)
2617 && in_array($filter_match,
array(
null,
true,
false),
true)
2620 $field_type =
'callback';
2622 if ($filter_match ===
null)
2624 $callback =
array($this,
'nullEqualityCallback');
2630 $callback =
array($this,
'booleanStrongEqualityCallback');
2633 elseif ($field_type ==
'integer')
2635 $field_type =
'int';
2637 elseif ($field_type ==
'boolean')
2639 $field_type =
'string';
2642 $field = $last->getValue();
2643 $values = $field->getValues();
2645 if (is_numeric($values[0]) && is_numeric($values[1]))
2647 $field_type =
'int';
2650 if (is_scalar($filter_match))
2652 $filter_match = $field->normalizeValue($filter_match);
2655 elseif ($field_type ==
'float' || $field_type ==
'decimal')
2657 $field_type =
'double';
2659 elseif ($field_type ==
'enum' || $field_type ==
'text')
2661 $field_type =
'string';
2664 $sqlDefinition = $chain->getSqlDefinition();
2668 if ($chain->forcesDataDoublingOff() || ($this->data_doubling_off && $chain->hasBackReference()))
2670 $primaryName = $this->entity->getPrimary();
2671 $uniquePostfix =
'_TMP'.rand();
2674 $subQuery =
new Query($this->entity);
2675 $subQuery->addSelect($primaryName);
2676 $subQuery->addFilter($filter_def, $filter_match);
2677 $subQuery->setTableAliasPostfix(strtolower($uniquePostfix));
2678 $subQuerySql = $subQuery->getQuery();
2681 $filter_match = $subQuerySql;
2682 $callback =
array($this,
'dataDoublingCallback');
2684 $field_type =
'callback';
2688 $sqlDefinition = $idChain->getSqlDefinition();
2692 if ($filter_match instanceof Main\DB\SqlExpression)
2694 $filter_match->setConnection($this->entity->getConnection());
2735 'TABLE_ALIAS' =>
'table',
2736 'FIELD_NAME' => $sqlDefinition,
2737 'FIELD_TYPE' => $field_type,
2740 'CALLBACK' => $callback
2743 elseif (is_array($filter_match))
2745 $fields = array_merge(
$fields, $this->getFilterCswFields($filter_match));
2764 protected function prepareJoinReference($reference, $alias_this, $alias_ref, $baseDefinition, $refDefinition, $isBackReference)
2768 foreach ($reference as
$k => $v)
2784 $sqlWhere = new \CSQLWhere();
2785 $csw_result = $sqlWhere->makeOperation(
$k);
2786 list($field, $operation) = array_values($csw_result);
2788 if (str_starts_with($field,
'this.'))
2792 $absDefinition = $baseDefinition <>
''? $baseDefinition.
'.'.$definition : $definition;
2796 if (!$isBackReference)
2799 $this->buildJoinMap(
array($chain));
2803 $chain->getLastElement()->setParameter(
'talias', $alias_this);
2809 $this->collectExprChains($chain);
2810 $buildFrom = $chain->getLastElement()->getValue()->getBuildFromChains();
2812 foreach ($buildFrom as $bf)
2815 $baseChain = clone $chain;
2818 $baseChain->removeLastElement();
2821 $bf->removeFirstElement();
2824 $bf->prepend($baseChain);
2827 $this->buildJoinMap($buildFrom);
2832 elseif (str_starts_with($field,
'ref.'))
2836 if (str_contains($definition,
'.'))
2839 'Reference chain `%s` is not allowed here. First-level definitions only.', $field
2843 $absDefinition = $refDefinition <>
''? $refDefinition.
'.'.$definition : $definition;
2846 if ($isBackReference)
2849 $this->buildJoinMap(
array($chain));
2853 $chain->getLastElement()->setParameter(
'talias', $alias_ref);
2859 $this->collectExprChains($chain);
2860 $this->buildJoinMap($chain->getLastElement()->getValue()->getBuildFromChains());
2867 throw new Main\SystemException(sprintf(
'Unknown reference key `%s`, it should start with "this." or "ref."',
$k));
2874 $v = new \CSQLWhereExpression($v[0], array_slice($v, 1));
2879 $v->setConnection($this->entity->getConnection());
2883 if (str_starts_with($v,
'this.'))
2885 $definition = str_replace(
'this.',
'', $v);
2886 $absDefinition = $baseDefinition <>
''? $baseDefinition.
'.'.$definition : $definition;
2890 if (!$isBackReference)
2893 $this->buildJoinMap(
array($chain));
2897 $chain->getLastElement()->setParameter(
'talias', $alias_this);
2903 $this->collectExprChains($chain);
2904 $buildFrom = $chain->getLastElement()->getValue()->getBuildFromChains();
2906 foreach ($buildFrom as $bf)
2909 $baseChain = clone $chain;
2912 $baseChain->removeLastElement();
2915 $bf->removeFirstElement();
2918 $bf->prepend($baseChain);
2921 $this->buildJoinMap($buildFrom);
2924 $field_def = $chain->getSqlDefinition();
2926 elseif (str_starts_with($v,
'ref.'))
2928 $definition = str_replace(
'ref.',
'', $v);
2930 if (str_contains($definition,
'.'))
2933 'Reference chain `%s` is not allowed here. First-level definitions only.', $v
2937 $absDefinition = $refDefinition <>
''? $refDefinition.
'.'.$definition : $definition;
2940 if ($isBackReference)
2943 $this->buildJoinMap(
array($chain));
2947 $chain->getLastElement()->setParameter(
'talias', $alias_ref);
2950 $this->buildJoinMap(
array($chain));
2956 $buildFromChains = $this->collectExprChains($chain);
2959 foreach ($buildFromChains as $buildFromChain)
2961 if (!$isBackReference && $buildFromChain->getSize() > $chain->getSize())
2964 'Reference chain `%s` is not allowed here. First-level definitions only.',
2965 $buildFromChain->getDefinition()
2969 if ($buildFromChain->getSize() === $chain->getSize())
2972 $buildFromChain->getLastElement()->setParameter(
'talias', $alias_ref);
2976 $this->buildJoinMap($buildFromChains);
2979 $field_def = $chain->getSqlDefinition();
2986 $v = new \CSQLWhereExpression($field_def);
2990 throw new Main\SystemException(sprintf(
'Unknown reference value `%s`, it should start with "this." or "ref."', $v));
3018 $reference = clone $reference;
3021 foreach ($reference->getConditions() as $condition)
3023 if ($condition instanceof
Filter)
3039 $field = $condition->getDefinition();
3041 if (str_starts_with($field,
'this.'))
3044 $definition = str_replace(
'this.',
'', $field);
3045 $absDefinition = $baseDefinition <>
''? $baseDefinition.
'.'.$definition : $definition;
3049 if (!$isBackReference)
3052 $this->buildJoinMap(
array($chain));
3056 $chain->getLastElement()->setParameter(
'talias', $alias_this);
3062 $this->collectExprChains($chain);
3063 $buildFrom = $chain->getLastElement()->getValue()->getBuildFromChains();
3065 foreach ($buildFrom as $bf)
3068 $baseChain = clone $chain;
3071 $baseChain->removeLastElement();
3074 $bf->removeFirstElement();
3077 $bf->prepend($baseChain);
3080 $this->buildJoinMap($buildFrom);
3083 $condition->setColumn($absDefinition);
3085 elseif (str_starts_with($field,
'ref.'))
3087 $definition = str_replace(
'ref.',
'', $field);
3089 if (str_contains($definition,
'.'))
3092 'Reference chain `%s` is not allowed here. First-level definitions only.', $field
3096 $absDefinition = $refDefinition <>
''? $refDefinition.
'.'.$definition : $definition;
3099 if ($isBackReference)
3102 $this->buildJoinMap(
array($chain));
3106 $chain->getLastElement()->setParameter(
'talias', $alias_ref);
3112 $this->collectExprChains($chain);
3113 $this->buildJoinMap($chain->getLastElement()->getValue()->getBuildFromChains());
3116 $condition->setColumn($absDefinition);
3120 throw new Main\SystemException(sprintf(
'Unknown reference key `%s`, it should start with "this." or "ref."', $field));
3124 $v = $condition->getValue();
3129 $v->setConnection($this->entity->getConnection());
3133 if (str_starts_with($v->getDefinition(),
'this.'))
3135 $definition = str_replace(
'this.',
'', $v->getDefinition());
3136 $absDefinition = $baseDefinition <>
''? $baseDefinition.
'.'.$definition : $definition;
3140 if (!$isBackReference)
3143 $this->buildJoinMap(
array($chain));
3147 $chain->getLastElement()->setParameter(
'talias', $alias_this);
3153 $this->collectExprChains($chain);
3154 $buildFrom = $chain->getLastElement()->getValue()->getBuildFromChains();
3156 foreach ($buildFrom as $bf)
3159 $baseChain = clone $chain;
3162 $baseChain->removeLastElement();
3165 $bf->removeFirstElement();
3168 $bf->prepend($baseChain);
3171 $this->buildJoinMap($buildFrom);
3174 $v->setDefinition($absDefinition);
3176 elseif (str_starts_with($v->getDefinition(),
'ref.'))
3178 $definition = str_replace(
'ref.',
'', $v->getDefinition());
3180 if (str_contains($definition,
'.'))
3183 'Reference chain `%s` is not allowed here. First-level definitions only.', $v->getDefinition()
3187 $absDefinition = $refDefinition <>
''? $refDefinition.
'.'.$definition : $definition;
3190 if ($isBackReference)
3193 $this->buildJoinMap(
array($chain));
3197 $chain->getLastElement()->setParameter(
'talias', $alias_ref);
3200 $this->buildJoinMap(
array($chain));
3206 $buildFromChains = $this->collectExprChains($chain);
3209 foreach ($buildFromChains as $buildFromChain)
3211 if (!$isBackReference && $buildFromChain->getSize() > $chain->getSize())
3214 'Reference chain `%s` is not allowed here. First-level definitions only.',
3215 $buildFromChain->getDefinition()
3219 if ($buildFromChain->getSize() === $chain->getSize())
3222 $buildFromChain->getLastElement()->setParameter(
'talias', $alias_ref);
3226 $this->buildJoinMap($buildFromChains);
3229 $v->setDefinition($absDefinition);
3242 foreach ($reference as
$k => $v)
3256 $sqlWhere = new \CSQLWhere();
3257 $csw_result = $sqlWhere->makeOperation(
$k);
3258 list($field, ) = array_values($csw_result);
3261 'TABLE_ALIAS' =>
'alias',
3262 'FIELD_NAME' => $field,
3263 'FIELD_TYPE' =>
'string',
3281 protected function checkChainsAggregation($chain)
3284 $chains = is_array($chain) ? $chain :
array($chain);
3286 foreach ($chains as $chain)
3288 $last = $chain->getLastElement();
3300 protected function checkChainsDistinct($chain)
3303 $chains = is_array($chain) ? $chain :
array($chain);
3305 foreach ($chains as $chain)
3307 $field = $chain->getLastElement()->getValue();
3309 if ($field instanceof ExpressionField)
3311 $expression = $field->getFullExpression();
3312 $expression = ExpressionField::removeSubqueries($expression);
3314 preg_match_all(
'/(?:^|[^a-z0-9_])(DISTINCT)[\s(]+/i', $expression,
$matches);
3328 return !empty($this->group_chains) || !empty($this->having_chains)
3329 || $this->checkChainsAggregation($this->select_chains)
3330 || $this->checkChainsAggregation($this->order_chains);
3335 $this->is_distinct = (bool) $distinct;
3342 $distinctInSelect = $this->checkChainsDistinct($this->select_chains);
3344 if ($distinctInSelect && $this->is_distinct)
3347 $this->is_distinct =
false;
3350 return ($distinctInSelect || $this->is_distinct);
3362 protected function collectExprChains(
Chain $chain, $storages =
array(
'hidden'))
3365 $bf_chains = $last_elem->getValue()->getBuildFromChains();
3367 $pre_chain = clone $chain;
3369 $scopedBuildFrom = [];
3371 foreach ($bf_chains as $bf_chain)
3374 $tmp_chain = clone $pre_chain;
3378 $bf_elements = array_slice($bf_chain->getAllElements(), 1);
3381 foreach ($bf_elements as $bf_element)
3383 $tmp_chain->addElement($bf_element);
3390 $reg_chain = $this->registerChain(
$storage, $tmp_chain);
3395 $bf_chain->removeLastElement();
3396 $bf_chain->addElement($reg_chain->getLastElement());
3399 $scoped_bf_chain = clone $pre_chain;
3400 $scoped_bf_chain->removeLastElement();
3403 $tail = array_slice($reg_chain->getAllElements(), $pre_chain->getSize());
3405 foreach ($tail as $tailElement)
3407 $scoped_bf_chain->addElement($tailElement);
3410 $scopedBuildFrom[] = $scoped_bf_chain;
3414 foreach ($bf_elements as $bf_element)
3416 if ($bf_element->getValue() instanceof ExpressionField)
3418 $this->collectExprChains($tmp_chain);
3423 return $scopedBuildFrom;
3432 if ($this->unionHandler ===
null)
3434 $this->unionHandler =
new Union($this->entity->getConnection());
3437 return $this->unionHandler;
3444 if (isset($this->global_chains[$alias]))
3446 if ($this->global_chains[$alias]->getDefinition() == $chain->
getDefinition())
3448 $reg_chain = $this->global_chains[$alias];
3456 $reg_chain = $chain;
3458 $this->global_chains[$reg_chain->getDefinition()] = $chain;
3463 $this->global_chains[$alias] = $chain;
3468 $reg_chain = $chain;
3469 $def = $reg_chain->getDefinition();
3471 $this->global_chains[$alias] = $chain;
3472 $this->global_chains[
$def] = $chain;
3475 $storage_name = $section .
'_chains';
3478 if (!isset($this->{$storage_name}[$alias]))
3480 $this->{$storage_name}[$alias] = $reg_chain;
3484 if (!is_null($opt_key))
3486 $this->{$storage_name}[$opt_key] = $reg_chain;
3502 if (isset($this->global_chains[
$key]))
3504 return $this->global_chains[
$key];
3509 $chain = Chain::getChainByDefinition($this->entity,
$key);
3520 return 'UALIAS_'.($this->uniqueAliasCounter++);
3525 $value = ($operation ==
'SE') ? $value : !$value;
3526 return ($value ?
'' :
'NOT ') . $field;
3531 return $field.
' IS '.($operation ==
'SE' ?
'' :
'NOT ') .
'NULL';
3536 return $field.
' IN ('.$value.
')';
3547 protected function query(
$query)
3556 if (isset($configuration[
'handlersocket'][
'read']))
3559 $nosqlConnectionName = $configuration[
'handlersocket'][
'read'];
3564 if ($isNosqlCapable)
3570 if (!empty($nosqlResult))
3575 foreach ($this->getSelectChains() as $selectChain)
3577 $field = $selectChain->getLastElement()->getValue();
3581 $converter =
$connection->getSqlHelper()->getConverter($field);
3583 if (is_callable($converter))
3585 $converter[$selectChain->getAlias()] = $converter;
3590 if (!empty($converters))
3592 $result->setConverters($converters);
3602 $result->setReplacedAliases($this->replaced_aliases);
3606 if ($this->limit && (
$result->getSelectedRowsCount() < $this->limit))
3609 $result->setCount((
int) $this->offset +
$result->getSelectedRowsCount());
3611 elseif (empty($this->limit))
3623 static::$last_query =
$query;
3628 $result->addFetchDataModifier(
array($this,
'fetchDataModificationCallback'));
3636 if ($this->query_build_parts ===
null)
3641 $buildParts = $this->query_build_parts;
3644 unset($buildParts[
'ORDER BY']);
3647 $buildParts[
'SELECT'] =
"1 cntholder";
3649 foreach ($buildParts as
$k => &$v)
3654 $cntQuery = join(
"\n", $buildParts);
3658 "SELECT COUNT(cntholder) AS TMP_ROWS_CNT FROM ({$cntQuery}) xxx";
3660 return $this->entity->getConnection()->queryScalar($cntQuery);
3670 foreach ($this->selectFetchModifiers as $alias => $modifiers)
3672 foreach ($modifiers as $modifier)
3686 $this->selectFetchModifiers =
array();
3688 foreach ($this->select_chains as $chain)
3690 if ($chain->getLastElement()->getValue()->getFetchDataModifiers())
3692 $this->selectFetchModifiers[$chain->getAlias()] = $chain->getLastElement()->getValue()->getFetchDataModifiers();
3696 return !empty($this->selectFetchModifiers) || !empty($this->files);
3711 $length = (int) $helper->getAliasLength();
3712 $leftQuote = $helper->getLeftQuote();
3713 $rightQuote = $helper->getRightQuote();
3715 $replaced =
array();
3718 '/ AS '.preg_quote($leftQuote).
'([a-z0-9_]{'.($length+1).
',})'.preg_quote($rightQuote).
'/i',
3726 $newAlias =
'FALIAS_'.count($replaced);
3727 $replaced[$newAlias] = $alias;
3730 ' AS ' . $helper->quote($alias),
3731 ' AS ' . $helper->quote($newAlias) .
'/* '.$alias.
' */',
3749 if (!preg_match(
'/\s*\(\s*SELECT.*\)\s*/is', $source))
3751 $source = $this->entity->getConnection()->getSqlHelper()->quote($source);
3761 $this->filterHandler = clone $this->filterHandler;
3762 $this->whereHandler = clone $this->whereHandler;
3763 $this->havingHandler = clone $this->havingHandler;
3765 foreach ($this->
select as
$k => $v)
3780 if (empty($this->global_chains))
3785 foreach ($this->global_chains as $chain)
3787 if ($chain->hasBackReference())
3801 return $this->global_chains;
3809 return $this->group_chains;
3817 return $this->hidden_chains;
3825 return $this->having_chains;
3833 return $this->filter_chains;
3841 return $this->order_chains;
3849 return $this->select_chains;
3857 return $this->where_chains;
3865 return $this->runtime_chains;
3870 return $this->join_map;
3884 return $this->
buildQuery($forceObjectPrimary);
3894 return static::$last_query;
3928 $query->setCustomBaseTableAlias(
$entity->getDBTableName())->buildQuery();
3930 return $query->query_build_parts[
'WHERE'];
3941 if ($this->custom_base_table_alias !==
null)
3943 return $this->custom_base_table_alias;
3946 $init_alias = strtolower($this->entity->getCode());
3951 $init_alias .= $this->table_alias_postfix;
3956 $aliasLength =
$connection->getSqlHelper()->getAliasLength();
3958 if (strlen($init_alias) > $aliasLength)
3960 $init_alias =
'base';
3965 $init_alias .= $this->table_alias_postfix;
3974 return $this->replaced_aliases;
3984 $this->cacheTtl = (int)$ttl;
4003 echo
'last query: ';
4004 var_dump(static::$last_query);
4007 echo
'size of select_chains: '.count($this->select_chains);
4009 foreach ($this->select_chains as $num => $chain)
4011 echo
' chain ['.$num.
'] has '.$chain->getSize().
' elements: '.PHP_EOL;
4016 echo PHP_EOL.PHP_EOL;
4018 echo
'size of where_chains: '.count($this->where_chains);
4020 foreach ($this->where_chains as $num => $chain)
4022 echo
' chain ['.$num.
'] has '.$chain->getSize().
' elements: '.PHP_EOL;
4027 echo PHP_EOL.PHP_EOL;
4029 echo
'size of group_chains: '.count($this->group_chains);
4031 foreach ($this->group_chains as $num => $chain)
4033 echo
' chain ['.$num.
'] has '.$chain->getSize().
' elements: '.PHP_EOL;
4038 echo PHP_EOL.PHP_EOL;
4040 echo
'size of having_chains: '.count($this->having_chains);
4042 foreach ($this->having_chains as $num => $chain)
4044 echo
' chain ['.$num.
'] has '.$chain->getSize().
' elements: '.PHP_EOL;
4049 echo PHP_EOL.PHP_EOL;
4051 echo
'size of filter_chains: '.count($this->filter_chains);
4053 foreach ($this->filter_chains as $num => $chain)
4055 echo
' chain ['.$num.
'] has '.$chain->getSize().
' elements: '.PHP_EOL;
4060 echo PHP_EOL.PHP_EOL;
4062 echo
'size of select_expr_chains: '.count($this->select_expr_chains);
4064 foreach ($this->select_expr_chains as $num => $chain)
4066 echo
' chain ['.$num.
'] has '.$chain->getSize().
' elements: '.PHP_EOL;
4071 echo PHP_EOL.PHP_EOL;
4073 echo
'size of hidden_chains: '.count($this->hidden_chains);
4075 foreach ($this->hidden_chains as $num => $chain)
4077 echo
' chain ['.$num.
'] has '.$chain->getSize().
' elements: '.PHP_EOL;
4082 echo PHP_EOL.PHP_EOL;
4084 echo
'size of global_chains: '.count($this->global_chains);
4086 foreach ($this->global_chains as $num => $chain)
4088 echo
' chain ['.$num.
'] has '.$chain->getSize().
' elements: '.PHP_EOL;
4093 echo PHP_EOL.PHP_EOL;
4095 var_dump($this->join_map);