Example #1
0
        public override string HackExtractionSQL(string sql, IDataLoadEventListener listener)
        {
            SetServer();

            //call base hacks
            sql = base.HackExtractionSQL(sql, listener);

            if (_doNotMigrate)
            {
                listener.OnNotify(this, new NotifyEventArgs(ProgressEventType.Information, "Cohort and Data are on same server so no migration will occur"));
                return(sql);
            }

            listener.OnNotify(this, new NotifyEventArgs(ProgressEventType.Information, "Original (unhacked) SQL was " + sql, null));

            //now replace database with tempdb
            var extractableCohort       = Request.ExtractableCohort;
            var extractableCohortSource = extractableCohort.ExternalCohortTable;

            var syntaxHelperFactory = new QuerySyntaxHelperFactory();
            var sourceSyntax        = syntaxHelperFactory.Create(extractableCohortSource.DatabaseType);
            var destinationSyntax   = syntaxHelperFactory.Create(_server.DatabaseType);

            //To replace (in this order)
            //Cohort database.table.privateId
            //Cohort database.table.releaseId
            //Cohort database.table.cohortdefinitionId
            //Cohort database.table name
            Dictionary <string, string> replacementStrings = new Dictionary <string, string>();

            var sourceDb                 = sourceSyntax.GetRuntimeName(extractableCohortSource.Database);
            var sourceTable              = sourceSyntax.GetRuntimeName(extractableCohortSource.TableName);
            var sourcePrivateId          = sourceSyntax.GetRuntimeName(extractableCohort.GetPrivateIdentifier());
            var sourceReleaseId          = sourceSyntax.GetRuntimeName(extractableCohort.GetReleaseIdentifier());
            var sourceCohortDefinitionId = sourceSyntax.GetRuntimeName(extractableCohortSource.DefinitionTableForeignKeyField);

            //Swaps the given entity for the same entity but in _tempDb
            AddReplacement(replacementStrings, sourceDb, sourceTable, sourcePrivateId, sourceSyntax, destinationSyntax);
            AddReplacement(replacementStrings, sourceDb, sourceTable, sourceReleaseId, sourceSyntax, destinationSyntax);
            AddReplacement(replacementStrings, sourceDb, sourceTable, sourceCohortDefinitionId, sourceSyntax, destinationSyntax);
            AddReplacement(replacementStrings, sourceDb, sourceTable, sourceSyntax, destinationSyntax);

            foreach (KeyValuePair <string, string> r in replacementStrings)
            {
                listener.OnNotify(this, new NotifyEventArgs(ProgressEventType.Information, "Replacing '" + r.Key + "' with '" + r.Value + "'", null));

                if (!sql.Contains(r.Key))
                {
                    listener.OnNotify(this, new NotifyEventArgs(ProgressEventType.Warning, "SQL extraction query string did not contain the text '" + r.Key + "' (which we expected to replace with '" + r.Value + ""));
                }

                sql = sql.Replace(r.Key, r.Value);
            }

            listener.OnNotify(this, new NotifyEventArgs(ProgressEventType.Information, "Adjusted (hacked) SQL was " + sql, null));

            //replace [MyCohortDatabase].. with [tempdb].. (while dealing with Cohort..Cohort replacement correctly as well as 'Cohort.dbo.Cohort.Fish' correctly)
            return(sql);
        }
        public void EnsureWrapped_MultipleCalls(DatabaseType dbType)
        {
            var syntax = new QuerySyntaxHelperFactory().Create(dbType);

            string once  = syntax.EnsureWrapped("ff");
            string twice = syntax.EnsureWrapped(once);

            Assert.AreEqual(once, twice);
        }
Example #3
0
        /// <summary>
        /// Gets an IQuerySyntaxHelper for the <see cref="GetDistinctLiveDatabaseServerType"/> amongst all underlying <see cref="TableInfo"/>.  This can be used to assist query building.
        /// </summary>
        /// <returns></returns>
        public IQuerySyntaxHelper GetQuerySyntaxHelper()
        {
            var f    = new QuerySyntaxHelperFactory();
            var type = GetDistinctLiveDatabaseServerType();

            if (type == null)
            {
                throw new AmbiguousDatabaseTypeException("Catalogue '" + this + "' has no extractable columns so no Database Type could be determined");
            }

            return(f.Create(type.Value));
        }
Example #4
0
        private void AddWHEREToBuilder_CategoryIsTOrNumberGreaterThan42(AggregateBuilder builder, DatabaseType type)
        {
            var syntaxHelper = new QuerySyntaxHelperFactory().Create(type);
            var declaration  = syntaxHelper.GetParameterDeclaration("@category", new DatabaseTypeRequest(typeof(string), 1));

            var repo = new MemoryCatalogueRepository();

            var ORContainer = new SpontaneouslyInventedFilterContainer(repo, null, null, FilterContainerOperation.OR);
            var constParam  = new ConstantParameter(declaration, "'T'", "T Category Only", syntaxHelper);

            //this is deliberately duplication, it tests that the parameter compiles as well as that any dynamic sql doesn't get thrown by quotes
            var filter1 = new SpontaneouslyInventedFilter(repo, ORContainer, "(Category=@category OR Category = 'T')", "Category Is @category",
                                                          "ensures the records belong to the category @category", new ISqlParameter[] { constParam });
            var filter2 = new SpontaneouslyInventedFilter(repo, ORContainer, "NumberInTrouble > 42",
                                                          "number in trouble greater than 42", "See above", null);

            ORContainer.AddChild(filter1);
            ORContainer.AddChild(filter2);

            builder.RootFilterContainer = ORContainer;
        }
Example #5
0
        /// <summary>
        /// This produces the SQL that would retrieve the specified dataset columns including any JOINS
        ///
        /// <para>It uses:
        /// QueryBuilder and then it adds some custom lines for linking to the cohort</para>
        /// </summary>
        /// <returns></returns>
        public QueryBuilder GetSQLCommandForFullExtractionSet(ExtractDatasetCommand request, out List <ReleaseIdentifierSubstitution> substitutions)
        {
            if (request.QueryBuilder != null)
            {
                throw new Exception("Creation of a QueryBuilder from a request can only happen once, to access the results of the creation use the cached answer in the request.QueryBuilder property");
            }

            if (!request.ColumnsToExtract.Any())
            {
                throw new Exception("No columns are marked for extraction in this configuration");
            }

            if (request.ExtractableCohort == null)
            {
                throw new NullReferenceException("No Cohort selected");
            }

            var databaseType = request.Catalogue.GetDistinctLiveDatabaseServerType();

            if (databaseType == null)
            {
                throw new NotSupportedException("Catalogue " + request.Catalogue + " did not know what DatabaseType it hosted, how can we extract from it! does it have no TableInfos?");
            }

            var syntaxHelper = new QuerySyntaxHelperFactory().Create(databaseType.Value);

            substitutions = new List <ReleaseIdentifierSubstitution>();

            var memoryRepository = new MemoryRepository();

            switch (request.ColumnsToExtract.Count(c => c.IsExtractionIdentifier))
            {
            //no extraction identifiers
            case 0: throw new Exception("There are no Columns in this dataset (" + request + ") marked as IsExtractionIdentifier");

            //a single extraction identifier e.g. CHI X died on date Y with conditions a,b and c
            case 1: substitutions.Add(new ReleaseIdentifierSubstitution(memoryRepository, request.ColumnsToExtract.FirstOrDefault(c => c.IsExtractionIdentifier), request.ExtractableCohort, false, syntaxHelper));
                break;

            //multiple extraction identifiers e.g. Mother X had Babies A, B, C where A,B and C are all CHIs that must be subbed for ProCHIs
            default:
                foreach (IColumn columnToSubstituteForReleaseIdentifier in request.ColumnsToExtract.Where(c => c.IsExtractionIdentifier))
                {
                    substitutions.Add(new ReleaseIdentifierSubstitution(memoryRepository, columnToSubstituteForReleaseIdentifier, request.ExtractableCohort, true, syntaxHelper));
                }
                break;
            }

            string hashingAlgorithm = _repository.DataExportPropertyManager.GetValue(DataExportProperty.HashingAlgorithmPattern);

            if (string.IsNullOrWhiteSpace(hashingAlgorithm))
            {
                hashingAlgorithm = null;
            }

            //identify any tables we are supposed to force join to
            var forcedJoins = request.SelectedDataSets.SelectedDataSetsForcedJoins;

            QueryBuilder queryBuilder = new QueryBuilder("DISTINCT ", hashingAlgorithm, forcedJoins.Select(s => s.TableInfo).ToArray());

            queryBuilder.TopX = request.TopX;

            queryBuilder.SetSalt(request.Salt.GetSalt());

            //add the constant parameters
            foreach (ConstantParameter parameter in GetConstantParameters(syntaxHelper, request.Configuration, request.ExtractableCohort))
            {
                queryBuilder.ParameterManager.AddGlobalParameter(parameter);
            }

            //add the global parameters
            foreach (var globalExtractionFilterParameter in request.Configuration.GlobalExtractionFilterParameters)
            {
                queryBuilder.ParameterManager.AddGlobalParameter(globalExtractionFilterParameter);
            }

            //remove the identification column from the query
            request.ColumnsToExtract.RemoveAll(c => c.IsExtractionIdentifier);

            //add in the ReleaseIdentifier in place of the identification column
            queryBuilder.AddColumnRange(substitutions.ToArray());

            //add the rest of the columns to the query
            queryBuilder.AddColumnRange(request.ColumnsToExtract.Cast <IColumn>().ToArray());

            //add the users selected filters
            queryBuilder.RootFilterContainer = request.Configuration.GetFilterContainerFor(request.DatasetBundle.DataSet);

            ExternalCohortTable externalCohortTable = _repository.GetObjectByID <ExternalCohortTable>(request.ExtractableCohort.ExternalCohortTable_ID);

            if (request.ExtractableCohort != null)
            {
                //the JOIN with the cohort table:
                string cohortJoin;

                if (substitutions.Count == 1)
                {
                    cohortJoin = " INNER JOIN " + externalCohortTable.TableName + " ON " + substitutions.Single().JoinSQL;
                }
                else
                {
                    cohortJoin = " INNER JOIN " + externalCohortTable.TableName + " ON " + string.Join(" OR ", substitutions.Select(s => s.JoinSQL));
                }

                //add the JOIN in after any other joins
                queryBuilder.AddCustomLine(cohortJoin, QueryComponent.JoinInfoJoin);

                //add the filter cohortID because our new Cohort system uses ID number and a giant combo table with all the cohorts in it we need to say Select XX from XX join Cohort Where Cohort number = Y
                queryBuilder.AddCustomLine(request.ExtractableCohort.WhereSQL(), QueryComponent.WHERE);
            }



            request.QueryBuilder = queryBuilder;
            return(queryBuilder);
        }