public static void ValidateLateArrivingLookup(AstLateArrivingLookupNode lookup) { if (!lookup.Table.LateArriving) { MessageEngine.Trace(lookup, Severity.Error, "V0128", "Table {0} is not designated for Late Arriving Lookup. Set LateArriving = true.", lookup.Table.Name); } AstTableKeyBaseNode eligibleKey = null; foreach (AstTableKeyBaseNode key in lookup.Table.Keys) { if (key.Columns.Any(keyColumn => !keyColumn.Column.IsComputed)) { eligibleKey = key; break; // Safe to do since we already verified single eligble key in the table processing pass } } if (eligibleKey == null) { MessageEngine.Trace(lookup, Severity.Error, "V0129", "Late Arriving Table {0} must specify an eligible key.", lookup.Table.Name); } // TODO: Finish checking this logic foreach (AstTableKeyColumnNode eligibleKeyColumn in eligibleKey.Columns) { if (!lookup.Inputs.Any(io => io.RemoteColumnName == eligibleKeyColumn.Column.Name)) { MessageEngine.Trace(lookup, Severity.Error, "V0123", "Late Arriving Lookup {0} must specify inputs for every column of constraint: {1}", lookup.Name, eligibleKey.Name); } } }
private static AstOleDBCommandNode CreateInsertNode(AstLateArrivingLookupNode lookup, AstLookupNode codegenLookup) { var insertPlaceholder = new AstOleDBCommandNode(lookup.ParentItem) { Name = String.Format(CultureInfo.InvariantCulture, "__LALookupPlaceholderInsert_{0}", lookup.Name), Connection = lookup.Table.Connection, }; insertPlaceholder.Query = new AstTransformationMappedQueryNode(insertPlaceholder) { Body = TableLowerer.EmitInsertDefaultRowStatement(lookup.Table) }; insertPlaceholder.InputPath = new AstDataflowMappedInputPathNode(insertPlaceholder) { OutputPath = codegenLookup.NoMatchPath }; return insertPlaceholder; }
private static void ProcessLateArrivingLookup(AstLateArrivingLookupNode lookup) { AstLowererValidation.ValidateLateArrivingLookup(lookup); var workflowFragment = new List<AstTransformationNode>(); AstLookupNode codegenLookup = CreateLookupNode(lookup); AstOleDBCommandNode insertPlaceholder = CreateInsertNode(lookup, codegenLookup); AstUnionAllNode unionAll = CreateUnionAllNode(lookup, codegenLookup, insertPlaceholder); workflowFragment.Add(codegenLookup); workflowFragment.Add(insertPlaceholder); workflowFragment.Add(unionAll); Utility.Replace(lookup, workflowFragment); }
private static AstUnionAllNode CreateUnionAllNode(AstLateArrivingLookupNode lookup, AstLookupNode codegenLookup, AstOleDBCommandNode insertPlaceholder) { var unionAll = new AstUnionAllNode(lookup.ParentItem) { Name = String.Format(CultureInfo.InvariantCulture, "__LALookupUnionAll_{0}", lookup.Name) }; unionAll.InputPaths.Add(new AstDataflowMappedInputPathNode(unionAll) { OutputPath = codegenLookup.MatchPath }); unionAll.InputPaths.Add(new AstDataflowMappedInputPathNode(unionAll) { OutputPath = insertPlaceholder.OutputPath }); foreach (var outgoingPath in lookup.OutputPath.References) { if (outgoingPath.ReferencingItem != null && outgoingPath.PropertyName != null) { PropertyInfo propertyInfo = outgoingPath.GetType().GetProperty(outgoingPath.PropertyName); if (propertyInfo != null) { propertyInfo.SetValue(outgoingPath.ReferencingItem, unionAll.OutputPath, null); } } } return unionAll; }
private static AstLookupNode CreateLookupNode(AstLateArrivingLookupNode lookup) { var codegenLookup = new AstLookupNode(lookup.ParentItem) { Name = String.Format(CultureInfo.InvariantCulture, "__LALookupEntryPoint_{0}", lookup.Name), Connection = lookup.Table.Connection }; var requiredColumns = new List<string>(); foreach (var input in lookup.Inputs) { if (!requiredColumns.Contains(input.RemoteColumnName)) { requiredColumns.Add(input.RemoteColumnName); } codegenLookup.Inputs.Add(input); } foreach (var output in lookup.Outputs) { if (!requiredColumns.Contains(output.RemoteColumnName)) { requiredColumns.Add(output.RemoteColumnName); } codegenLookup.Outputs.Add(output); } codegenLookup.Query = new AstQueryNode(codegenLookup) { Body = TableLowerer.EmitSelectAllStatement(lookup.Table, requiredColumns) }; if (lookup.InputPath != null) { codegenLookup.InputPath = new AstDataflowMappedInputPathNode(codegenLookup) { OutputPath = lookup.InputPath.OutputPath }; } return codegenLookup; }