Example #1
0
        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();
        }
Example #2
0
        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);
        }
Example #3
0
        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;
Example #4
0
        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;
                }
            }
Example #5
0
        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));
        }
Example #6
0
        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);
        }
Example #7
0
        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);
        }