public virtual async ValueTask <QsiTableStructure> BuildTableStructure(TableCompileContext context, IQsiTableNode table) { context.ThrowIfCancellationRequested(); switch (table) { case IQsiTableReferenceNode tableReference: return(await BuildTableReferenceStructure(context, tableReference)); case IQsiTableFunctionNode tableFunction: return(await BuildTableFunctionStructure(context, tableFunction)); case IQsiDerivedTableNode derivedTable: return(await BuildDerivedTableStructure(context, derivedTable)); case IQsiInlineDerivedTableNode inlineDerivedTableNode: return(await BuildInlineDerivedTableStructure(context, inlineDerivedTableNode)); case IQsiJoinedTableNode joinedTable: return(await BuildJoinedTableStructure(context, joinedTable)); case IQsiCompositeTableNode compositeTable: return(await BuildCompositeTableStructure(context, compositeTable)); } throw new InvalidOperationException(); }
protected virtual async ValueTask <QsiTableStructure> BuildTableAccessStructure(TableCompileContext context, IQsiTableAccessNode table) { context.ThrowIfCancellationRequested(); var lookup = ResolveTableStructure(context, table.Identifier); // view if (context.Options.UseViewTracing && !lookup.IsSystem && (lookup.Type == QsiTableType.View || lookup.Type == QsiTableType.MaterializedView)) { var script = context.Engine.RepositoryProvider.LookupDefinition(lookup.Identifier, lookup.Type) ?? throw new QsiException(QsiError.UnableResolveDefinition, lookup.Identifier); var viewTable = (IQsiTableNode)context.Engine.TreeParser.Parse(script) ?? throw new QsiException(QsiError.Internal, "Invalid view node"); var typeBackup = lookup.Type; using var viewCompileContext = new TableCompileContext(context); if (lookup.Identifier.Level > 1) { viewCompileContext.PushIdentifierScope(lookup.Identifier.SubIdentifier(..^ 1)); } var viewTableStructure = await BuildTableStructure(viewCompileContext, viewTable); viewTableStructure.Identifier = ResolveQualifiedIdentifier(context, viewTableStructure.Identifier); lookup = viewTableStructure; lookup.Type = typeBackup; } return(lookup); }
protected virtual ValueTask <QsiTableStructure> BuildInlineDerivedTableStructure(TableCompileContext context, IQsiInlineDerivedTableNode table) { context.ThrowIfCancellationRequested(); var alias = table.Alias?.Name; if (alias == null && table.Parent is IQsiDerivedColumnNode && !context.Options.AllowNoAliasInDerivedTable) { throw new QsiException(QsiError.NoAlias); } var declaredTable = new QsiTableStructure { Type = QsiTableType.Inline, Identifier = alias == null ? null : new QsiQualifiedIdentifier(alias) }; int?columnCount = null; switch (table.Columns) { case null: case var cd when cd.All(c => c is IQsiAllColumnNode { Path: null }) : // Skip break;
protected virtual async ValueTask <QsiTableStructure> BuildRecursiveCompositeTableStructure(TableCompileContext context, IQsiDerivedTableNode table, IQsiCompositeTableNode source) { context.ThrowIfCancellationRequested(); var declaredTable = new QsiTableStructure { Type = QsiTableType.Derived, Identifier = new QsiQualifiedIdentifier(table.Alias.Name) }; int sourceOffset = 0; var structures = new List <QsiTableStructure>(source.Sources.Length); if (table.Columns.Any(c => c is not IQsiAllColumnNode)) { foreach (var columnNode in table.Columns.Cast <IQsiSequentialColumnNode>()) { var column = declaredTable.NewColumn(); column.Name = columnNode.Alias.Name; } }
protected virtual ValueTask <QsiTableStructure> BuildInlineDerivedTableStructure(TableCompileContext context, IQsiInlineDerivedTableNode table) { context.ThrowIfCancellationRequested(); var alias = table.Alias?.Name; if (alias == null && table.Parent is IQsiDerivedColumnNode && !context.Options.AllowNoAliasInDerivedTable) { throw new QsiException(QsiError.NoAlias); } var declaredTable = new QsiTableStructure { Type = QsiTableType.Inline, Identifier = alias == null ? null : new QsiQualifiedIdentifier(alias) }; int?columnCount = null; switch (table.Columns) { case null: case var cd when cd.All(c => c is IQsiAllColumnNode { Path: null } all) : // Skip break; case var cd when cd.TryCast(out IQsiSequentialColumnNode[] sequentialColumns): foreach (var column in sequentialColumns) { var c = declaredTable.NewColumn(); c.Name = column.Alias.Name; } columnCount = sequentialColumns.Length; break; default: throw new NotSupportedException("Not supported columns in inline derived table."); } // Skip trace columns in expression. // Because don't know the possibility of declaring a referenceable column in the expression. // ISSUE: row.ColumnValues foreach (var row in table.Rows ?? Enumerable.Empty <IQsiRowValueExpressionNode>()) { if (!columnCount.HasValue) { columnCount = row.ColumnValues.Length; } else if (columnCount != row.ColumnValues.Length) { throw new QsiException(QsiError.DifferentColumnsCount); } } if ((columnCount ?? 0) == 0) { if (!context.Options.AllowEmptyColumnsInInline) { throw new QsiException(QsiError.NoColumnsSpecified, alias); } columnCount = 0; } if (declaredTable.Columns.Count != columnCount) { for (int i = 0; i < columnCount; i++) { declaredTable.NewColumn(); } } return(new ValueTask <QsiTableStructure>(declaredTable)); }
protected virtual async ValueTask <QsiTableStructure> BuildDerivedTableStructure(TableCompileContext context, IQsiDerivedTableNode table) { context.ThrowIfCancellationRequested(); using var scopedContext = new TableCompileContext(context); // Directives if (table.Directives?.Tables?.Length > 0) { await BuildDirectives(scopedContext, table.Directives); } // Table Source var alias = table.Alias?.Name; if (alias == null && table.Parent is IQsiDerivedColumnNode && !context.Options.AllowNoAliasInDerivedTable) { throw new QsiException(QsiError.NoAlias); } if (table.Source is IQsiJoinedTableNode joinedTableNode) { scopedContext.SourceTable = await BuildJoinedTableStructure(scopedContext, joinedTableNode); } else if (table.Source != null) { using var sourceContext = new TableCompileContext(scopedContext); scopedContext.SourceTable = await BuildTableStructure(scopedContext, table.Source); } var declaredTable = new QsiTableStructure { Type = QsiTableType.Derived, Identifier = alias == null ? null : new QsiQualifiedIdentifier(alias) }; if (scopedContext.SourceTable != null) { declaredTable.References.Add(scopedContext.SourceTable); } var columns = table.Columns; if (columns == null || columns.Count == 0) { if (!context.Options.AllowEmptyColumnsInSelect) { throw new QsiException(QsiError.Syntax); } } else if (columns.TryCast(out IQsiSequentialColumnNode[] sequentialColumns)) { // Sequential columns definition if (scopedContext.SourceTable == null) { throw new QsiException(QsiError.NoTablesUsed); } var columnType = sequentialColumns[0].ColumnType; QsiTableColumn[] allColumns = scopedContext.SourceTable.VisibleColumns.ToArray(); int columnLength = allColumns.Length; if (sequentialColumns.Length > allColumns.Length) { throw new QsiException(QsiError.SpecifiesMoreColumnNames); } if (columnType == QsiSequentialColumnType.Default) { if (sequentialColumns.Length != allColumns.Length) { throw new QsiException(QsiError.DifferentColumnsCount); } columnLength = sequentialColumns.Length; } for (int i = 0; i < columnLength; i++) { var column = allColumns[i]; var declaredColumn = declaredTable.NewColumn(); declaredColumn.Name = i < sequentialColumns.Length ? sequentialColumns[i].Alias?.Name : column.Name; declaredColumn.References.Add(column); } } else { // Compund columns definition foreach (var column in columns) { IEnumerable <QsiTableColumn> resolvedColumns = ResolveColumns(scopedContext, column); switch (column) { case IQsiDerivedColumnNode derivedColum: { var declaredColumn = declaredTable.NewColumn(); declaredColumn.Name = derivedColum.Alias?.Name; declaredColumn.IsExpression = derivedColum.IsExpression; declaredColumn.References.AddRange(resolvedColumns); break; } case IQsiBindingColumnNode bindingColumn: { var declaredColumn = declaredTable.NewColumn(); declaredColumn.Name = new QsiIdentifier(bindingColumn.Id, false); declaredColumn.IsBinding = true; break; } default: { foreach (var c in resolvedColumns) { var declaredColumn = declaredTable.NewColumn(); declaredColumn.Name = c.Name; declaredColumn.References.Add(c); } break; } } } } return(declaredTable); }
protected virtual async ValueTask <QsiTableStructure> BuildTableReferenceStructure(TableCompileContext context, IQsiTableReferenceNode table) { context.ThrowIfCancellationRequested(); var lookup = ResolveTableStructure(context, table.Identifier); // view if (context.Options.UseViewTracing && !lookup.IsSystem && lookup.Type is QsiTableType.View or QsiTableType.MaterializedView) { var script = context.Engine.RepositoryProvider.LookupDefinition(lookup.Identifier, lookup.Type) ?? throw new QsiException(QsiError.UnableResolveDefinition, lookup.Identifier); var viewNode = context.Engine.TreeParser.Parse(script); using var viewCompileContext = new TableCompileContext(context); if (lookup.Identifier.Level > 1) { viewCompileContext.PushIdentifierScope(lookup.Identifier.SubIdentifier(..^ 1)); } QsiTableStructure viewStructure; switch (viewNode) { /* TODO: Remove old view node * [V] Cql * [-] JSql (Deprecated) * [V] MySql * [V] PhoenixSql * [V] SqlServer */ case IQsiTableNode viewTableNode: { var viewTableStructure = await BuildTableStructure(viewCompileContext, viewTableNode); viewTableStructure.Identifier = ResolveQualifiedIdentifier(context, viewTableStructure.Identifier); viewStructure = viewTableStructure; break; } case IQsiDefinitionNode definitionNode: { viewStructure = await BuildDefinitionStructure(viewCompileContext, definitionNode); break; } default: throw TreeHelper.NotSupportedTree(viewNode); } if (viewStructure.Columns.Count != lookup.Columns.Count) { throw new QsiException(QsiError.DifferentColumnsCount, "View definition"); } lookup.References.Add(viewStructure); for (int i = 0; i < viewStructure.Columns.Count; i++) { lookup.Columns[i].References.Add(viewStructure.Columns[i]); } } return(lookup); }