protected function registerRecordImpl(array &$records = NULL, $record) { parent::registerRecordImpl($records, $record); $recordKey = NULL; foreach ($this->keyColumnNames as $keyColumnName) { $recordKey[] = isset($record[$keyColumnName]) ? $record[$keyColumnName] : NULL; } $key = ArrayHelper::prepareCompositeKey($recordKey); if (isset($records[$key])) { if ($this->isColumnValueUnique) { throw new IllegalArgumentException(t( 'Found several records for the key: %key', array('%key' => ArrayHelper::serialize($recordKey, ', ', TRUE, TRUE)))); } $records[$key][] = $record; } else { if ($this->isColumnValueUnique) { $records[$key] = $record; } else { $records[$key][] = $record; } } return TRUE; }
public function replaceColumnNames(ParserCallback $callback, &$callerSession) { $columnName = $callback->marker; $column = $this->columnReferenceFactory->getColumn($columnName); $this->approveColumn4ParticipationInExpression($column); if ($column->persistence == FormulaMetaData::PERSISTENCE__CALCULATED) { // checking if the column is already in the stack if (in_array($column->name, $this->columnAssemblingStack)) { $columnPublicNames = NULL; // adding columns from stack foreach ($this->columnAssemblingStack as $stackColumnName) { $stackColumn = $this->dataset->getColumn($stackColumnName); $columnPublicNames[] = $stackColumn->publicName; } // adding current processed column $columnPublicNames[] = $column->publicName; throw new IllegalStateException(t( 'Circular reference in formula expression is not allowed: %stack', array('%stack' => ArrayHelper::serialize($columnPublicNames, ', ', TRUE, FALSE)))); } array_push($this->columnAssemblingStack, $column->name); $language = isset($column->expressionLanguage) ? $column->expressionLanguage : NULL; $parser = new FormulaExpressionParser($language); $expression = $parser->expressionLanguageHandler->clean($column->source); $callback->marker = $parser->parse($expression, array($this, 'replaceColumnNames')); array_pop($this->columnAssemblingStack); $callback->removeDelimiters = TRUE; } }
protected function loadColumnsProperties(SystemTableMetaModelLoaderCallContext $callcontext, DataSourceMetaData $datasource) { $tableNames = NULL; foreach ($callcontext->datasets as $dataset) { $tableNames[] = $dataset->sourse; } if (!isset($tableNames)) { return NULL; } $sql = 'SELECT c.relname AS ' . self::CN_TABLE_NAME . ",\n" . ' a.attname AS ' . self::CN_COLUMN_NAME . ",\n" . ' a.attnum AS ' . self::CN_COLUMN_INDEX . ",\n" . ' t.typname AS ' . self::CN_COLUMN_TYPE . " FROM pg_class c INNER JOIN pg_namespace ns ON ns.oid = c.relnamespace\n" . " INNER JOIN pg_attribute a ON a.attrelid = c.oid\n" . " INNER JOIN pg_type t ON t.oid = a.atttypid\n" . " WHERE c.relkind IN ('r','v')\n" . " AND ns.nspname = '$datasource->schema'\n" . " AND a.attnum > 0\n" . ' AND c.relname IN (' . ArrayHelper::serialize($tableNames) . ')'; return $this->executeQuery($datasource, 'table.column', $sql); }
protected function loadConstraintColumnsProperties(SystemTableMetaModelLoaderCallContext $callcontext, DataSourceMetaData $datasource, array $constraintTypes) { $eligibleOwners = $this->getEligibleOwners( $callcontext, (isset($datasource->schema) ? $datasource->schema : NULL)); $ineligibleOwners = $this->getIneligibleOwners($callcontext); $types = $this->convertConstraintTypes($constraintTypes); $sql = 'SELECT c.constraint_schema AS ' . self::CN_TABLE_OWNER . ",\n" . ' cu.constraint_name AS ' . self::CN_OBJECT_NAME . ",\n" . ' cu.table_name AS ' . self::CN_TABLE_NAME . ",\n" . ' cu.column_name AS ' . self::CN_COLUMN_NAME . ",\n" . ' (cu.ordinal_position - 1) AS ' . self::CN_COLUMN_INDEX . "\n" . " FROM information_schema.key_column_usage cu JOIN information_schema.table_constraints c ON cu.constraint_name = c.constraint_name AND cu.constraint_catalog = c.constraint_catalog\n" . " WHERE cu.table_catalog = '{$datasource->database}'\n" . " AND cu.constraint_catalog = cu.table_catalog\n" . ' AND c.constraint_type IN (' . ArrayHelper::serialize($types) . ')'; $this->appendOwnerStatementCondition($sql, TRUE, 'c.constraint_schema', $eligibleOwners, $ineligibleOwners); return $this->executeQuery($datasource, 'constraint.column', $sql); }
public function findNestedLinkByDatasetNameAndParentColumnNames($datasetName, $parentColumnNames) { $selectedNestedLink = NULL; if (isset($this->nestedLinks)) { $parentColumnCount = count($parentColumnNames); foreach ($this->nestedLinks as $nestedLink) { if ($nestedLink->dataset->name !== $datasetName) { continue; } $nestedLinkParentColumnCount = count($nestedLink->parentColumnNames); if ($nestedLinkParentColumnCount != $parentColumnCount) { continue; } foreach ($nestedLink->parentColumnNames as $parentColumnIndex => $nestedLinkParentColumnName) { if (!isset($parentColumnNames[$parentColumnIndex])) { continue 2; } if ($nestedLinkParentColumnName != $parentColumnNames[$parentColumnIndex]) { continue 2; } } if (isset($selectedNestedLink)) { throw new UnsupportedOperationException(t( 'Found several nested reference links for %datasetName dataset by the parent columns: %parentColumns', array( '%datasetName' => $datasetName, '%parentColumns' => ArrayHelper::serialize($parentColumnNames, ', ', TRUE, FALSE)))); } $selectedNestedLink = $nestedLink; } } return $selectedNestedLink; }
protected function loadConstraintColumnsProperties(SystemTableMetaModelLoaderCallContext $callcontext, DataSourceMetaData $datasource, array $constraintTypes) { $eligibleOwners = $this->getEligibleOwners($callcontext, $datasource->username); $ineligibleOwners = $this->getIneligibleOwners($callcontext); $types = $this->convertConstraintTypes($constraintTypes); $sql = 'SELECT c.owner AS ' . self::CN_TABLE_OWNER . ",\n" . ' cc.constraint_name AS ' . self::CN_OBJECT_NAME . ",\n" . ' cc.table_name AS ' . self::CN_TABLE_NAME . ",\n" . ' cc.column_name AS ' . self::CN_COLUMN_NAME . ",\n" . ' (cc.position - 1) AS ' . self::CN_COLUMN_INDEX . "\n" . " FROM all_cons_columns cc JOIN all_constraints c ON cc.constraint_name = c.constraint_name AND cc.owner = c.owner\n" . ' WHERE c.constraint_type IN (' . ArrayHelper::serialize($types) . ')'; $this->appendOwnerStatementCondition($sql, TRUE, 'c.owner', $eligibleOwners, $ineligibleOwners); return $this->executeQuery($datasource, 'constraint.column', $sql); }
protected function prepareCacheEntryName() { $entryName = NULL; $filters = $this->getMetaModelFilters(); if (isset($filters)) { $suffix = NULL; ksort($filters); foreach ($filters as $className => $properties) { if (isset($suffix)) { $suffix .= ','; } $suffix .= $className . '{'; $propertySuffix = NULL; ksort($properties); foreach ($properties as $propertyName => $filterValues) { sort($filterValues); if (isset($propertySuffix)) { $propertySuffix .= ','; } $propertySuffix .= $propertyName . '=' . ArrayHelper::serialize($filterValues, ',', TRUE, FALSE); } $suffix .= $propertySuffix . '}'; } $entryName = $suffix; } return $entryName; }
public function getValues(array $names, array $options = NULL) { $timeStart = microtime(TRUE); $values = parent::getValues($names, $options); $nameCount = count($names); $loadedValueCount = count($values); LogHelper::log_debug(t( '[@cacheType] Requested entries: @entryNames', array( '@cacheType' => $this->getCacheType(), '@entryNames' => ArrayHelper::serialize(array_values($names), ', ', TRUE, FALSE)))); LogHelper::log_debug( t('[@cacheType] Retrieved entries: @entryNames', array( '@cacheType' => $this->getCacheType(), '@entryNames' => (($nameCount == $loadedValueCount) ? 'ALL' : (isset($values) ? ArrayHelper::serialize(array_keys($values), ', ', TRUE, FALSE) : t('NONE')))))); LogHelper::log_info(t( '[@cacheType] Execution time for retrieving @entryCount entry(-ies) is !executionTime@successFlag', array( '@cacheType' => $this->getCacheType(), '@entryCount' => $nameCount, '!executionTime' => LogHelper::formatExecutionTime($timeStart), '@successFlag' => ( isset($values) ? (($nameCount == $loadedValueCount) ? '' : t(" (cache hit for ONLY @loadedValueCount entry(-ies) out of @nameCount)", array('@loadedValueCount' => $loadedValueCount, '@nameCount' => $nameCount))) : (' (' . t('cache was NOT hit') . ')'))))); return $values; }
protected function selectDataType(array $datatypes, $selectCompatible = TRUE) { // eliminating null records from the array if (isset($datatypes)) { foreach ($datatypes as $index => $datatype) { if (!isset($datatype)) { unset($datatypes[$index]); } } if (count($datatypes) == 0) { $datatypes = NULL; } } if (!isset($datatypes)) { return NULL; } // checking if all elements are equal $selectedDataType = NULL; foreach ($datatypes as $datatype) { if (isset($selectedDataType)) { if ($selectedDataType != $datatype) { $selectedDataType = NULL; break; } } else { $selectedDataType = $datatype; } } if (isset($selectedDataType)) { return $selectedDataType; } // checking if we need to return compatible type if (!$selectCompatible) { // if some types are not compatible we need to return the lowest compatible type if (!$this->areCompatible($datatypes)) { $selectCompatible = TRUE; } } $selectedDataTypes = $datatypes; if ($selectCompatible) { do { $initialDataTypeCount = count($selectedDataTypes); $selectedDataTypes = $this->selectCompatible($selectedDataTypes); $selectedDataTypeCount = count($selectedDataTypes); if (($initialDataTypeCount > 1) && ($initialDataTypeCount == $selectedDataTypeCount)) { throw new IncompatibleDataTypeException(t( 'Data types are inter-compatible. Single type could not be selected: %datatypes', array('%datatypes' => ArrayHelper::serialize($datatypes, ',', TRUE, FALSE)))); } } while ($selectedDataTypeCount > 1); } else { // it is expected that we have only 2 types here while (($datatypeCount = count($selectedDataTypes)) >= 2) { $datatypeA = $selectedDataTypes[0]; $datatypeB = $selectedDataTypes[1]; $selectedByDataTypeA = $this->getHandler($datatypeA)->selectCompatible($datatypeB); $selectedByDataTypeB = $this->getHandler($datatypeB)->selectCompatible($datatypeA); $selectedDataType = NULL; if (isset($selectedByDataTypeA)) { if (isset($selectedByDataTypeB)) { throw new IncompatibleDataTypeException(t( '%datatypeA and %datatypeB data types are inter-compatible. Single type could not be selected', array('%datatypeA' => $datatypeA, '%datatypeB' => $datatypeB))); } else { $selectedDataType = $selectedByDataTypeA; } } elseif (isset($selectedByDataTypeB)) { $selectedDataType = $selectedByDataTypeB; } else { throw new UnsupportedOperationException(); } $selectedDataTypes = array_slice($selectedDataTypes, 2); // selecting opposite data type. We do not need the lowest compatible type $selectedDataTypes[] = ($selectedDataType == $datatypeA) ? $datatypeB : $datatypeA; } } if (count($selectedDataTypes) == 1) { return $selectedDataTypes[0]; } else { throw new IncompatibleDataTypeException(t( 'Incompatible data types: %datatypes', array('%datatypes' => ArrayHelper::serialize($datatypes, ',', TRUE, FALSE)))); } }
protected function loadIdentifiers($lookupDatasetName, array $uniqueSetColumns, array &$lookupValues) { $dataQueryController = data_controller_get_instance(); $metamodel = data_controller_get_metamodel(); $lookupDataset = $metamodel->getDataset($lookupDatasetName); $identifierColumnName = $lookupDataset->getKeyColumn()->name; $lookupCacheKey = $this->prepareLookupCacheKey($lookupDataset->name); $isCompositeUniqueSet = count($uniqueSetColumns) > 1; // preparing parameters for the query $queryParameters = NULL; foreach ($lookupValues as $lookupKey => $lookupValue) { if (isset($lookupValue->identifier)) { continue; } if (isset($this->cachedIdentifiers[$lookupCacheKey][$lookupKey])) { $lookupValues[$lookupKey]->identifier = $this->cachedIdentifiers[$lookupCacheKey][$lookupKey]; continue; } if ($isCompositeUniqueSet) { $keyColumnValues = NULL; foreach ($uniqueSetColumns as $column) { $columnName = $column->name; $keyColumnValues[$columnName] = $lookupValue->$columnName; } $queryParameters[] = $keyColumnValues; } else { $columnName = $uniqueSetColumns[0]->name; $queryParameters[$columnName][] = $lookupValue->$columnName; } } if (!isset($queryParameters)) { return; } // preparing columns for the query $queryColumns = array($identifierColumnName); foreach ($uniqueSetColumns as $column) { ArrayHelper::addUniqueValue($queryColumns, $column->name); } // loading data from database for 'missing' records $loadedLookupProperties = $dataQueryController->queryDataset($lookupDataset->name, $queryColumns, $queryParameters); // processing found records if (isset($loadedLookupProperties)) { $foundUnmatchedIdentifiers = FALSE; foreach ($loadedLookupProperties as $lookupProperties) { $identifier = $lookupProperties[$identifierColumnName]; // preparing lookup key $keyItems = NULL; foreach ($uniqueSetColumns as $column) { $keyItems[] = $lookupProperties[$column->name]; } $lookupKey = self::prepareLookupKey($keyItems); if (!isset($lookupValues[$lookupKey])) { if (count($lookupValues) == 1) { // 04/23/2014 if only one record requested and one record received, but the received key does not match the request // it means that character encoding functionality is more sophisticated on server and we actually have a match // storing the value into cache for further usage $this->cachedIdentifiers[$lookupCacheKey][$lookupKey] = $identifier; reset($lookupValues); $alternativeLookupKey = key($lookupValues); $lookupKey = $alternativeLookupKey; } else { $foundUnmatchedIdentifiers = TRUE; continue; } } if (isset($lookupValues[$lookupKey]->identifier)) { $searchCriteria = array(); foreach ($uniqueSetColumns as $column) { $searchCriteria[$column->name] = $lookupProperties[$column->name]; } LogHelper::log_error(t( 'Key: @searchCriteria. Loaded identifiers: @identifiers', array( '@searchCriteria' => ArrayHelper::serialize($searchCriteria, ', ', TRUE, FALSE), '@identifiers' => ArrayHelper::serialize(array($lookupValues[$lookupKey]->identifier, $identifier), ', ', TRUE, FALSE)))); throw new IllegalArgumentException(t( 'Several records in %datasetName dataset match search criteria', array('%datasetName' => $lookupDataset->publicName))); } $lookupValues[$lookupKey]->identifier = $identifier; // storing the value into cache for further usage $this->cachedIdentifiers[$lookupCacheKey][$lookupKey] = $identifier; } // found unmatched values. Processing unprocessed lookups one by one if ($foundUnmatchedIdentifiers) { foreach ($lookupValues as $lookupKey => $lookupValue) { if (!isset($lookupValue->identifier)) { $singleLookupValue = array($lookupKey => $lookupValue); $this->loadIdentifiers($lookupDatasetName, $uniqueSetColumns, $singleLookupValue); } } } $this->freeSpaceInIdentifierCache($lookupDataset->name); } }
public function permitDatasetStorageTruncation(DataControllerCallContext $callcontext, DatasetMetaData $logicalDataset) { parent::permitDatasetStorageTruncation($callcontext, $logicalDataset); if (!self::isLookupDataset($logicalDataset)) { return; } $dataQueryController = data_controller_get_instance(); $metamodel = data_controller_get_metamodel(); // checking of the reference datasets have any NOT NULL data in reference columns $populatedReferenceDatasetPublicNames = NULL; foreach ($metamodel->datasets as $dataset) { foreach ($dataset->getColumns(FALSE, TRUE) as $column) { if ($column->persistence != ColumnMetaData::PERSISTENCE__STORAGE_CREATED) { continue; } if ($column->type->getReferencedDatasetName() == $logicalDataset->name) { $recordCount = $dataQueryController->countDatasetRecords( $dataset->name, array($column->name => OperatorFactory::getInstance()->initiateHandler(NotEmptyOperatorHandler::OPERATOR__NAME))); if ($recordCount > 0) { $populatedReferenceDatasetPublicNames[] = $dataset->publicName; break; } } } } // we should not allow to truncate the dataset if there is any data in any reference datasets if (isset($populatedReferenceDatasetPublicNames)) { throw new IllegalArgumentException(t( "%datasetName dataset is referenced by other datasets. The dataset truncation is not permitted unless records in %referenceDatasetNames datasets are deleted first", array( '%datasetName' => $logicalDataset->publicName, '%referenceDatasetNames' => ArrayHelper::serialize($populatedReferenceDatasetPublicNames)))); } }
public function getValues(array $names, array $options = NULL) { $this->checkAccessibility(TRUE); $cacheEntryNameMap = NULL; foreach ($names as $name) { $cacheEntryName = $this->assembleCacheEntryName($name); $cacheEntryNameMap[$cacheEntryName] = $name; } if (!isset($cacheEntryNameMap)) { return NULL; } $result = NULL; try { $cacheEntries = $this->loadValues(array_keys($cacheEntryNameMap), $options); foreach ($cacheEntryNameMap as $cacheEntryName => $name) { if (!isset($cacheEntries[$cacheEntryName])) { continue; } $value = $cacheEntries[$cacheEntryName]; $result[$name] = $value; unset($cacheEntries[$cacheEntryName]); } // checking for unknown returned entries which are still in the list (were not processed) if (isset($cacheEntries)) { $unrequestedCacheEntryNames = array_keys($cacheEntries); if (count($unrequestedCacheEntryNames) > 0) { throw new IllegalStateException(t( 'Received unrequested data for the cache entry names: %cacheEntryName', array('%cacheEntryName' => ArrayHelper::serialize($unrequestedCacheEntryNames, ', ', TRUE, FALSE)))); } } } catch (Exception $e) { LogHelper::log_error($e); } return $result; }