예제 #1
0
        private static ObjectName ResolveGroupMax(TableSelectExpression expression, TableExpressionFromSet fromSet)
        {
            // Resolve GROUP MAX variable to a reference in this from set
            ObjectName groupmaxColumn = expression.GroupMax;

            if (groupmaxColumn != null)
            {
                ObjectName v = fromSet.ResolveReference(groupmaxColumn);
                if (v == null)
                {
                    throw new ApplicationException("Could find GROUP MAX reference '" + groupmaxColumn + "'");
                }

                groupmaxColumn = v;
            }

            return(groupmaxColumn);
        }
예제 #2
0
        internal static TableExpressionFromSet GenerateFromSet(TableSelectExpression selectExpression, ITableSpaceContext db)
        {
            // Get the 'from_clause' from the table expression
            FromClause fromClause = selectExpression.From;

            // Create a TableExpressionFromSet for this table expression
            var fromSet = new TableExpressionFromSet(db.IsInCaseInsensitive);

            // Add all tables from the 'fromClause'
            foreach (FromTable fromTable in fromClause.AllTables)
            {
                string     uniqueKey = fromTable.UniqueKey;
                ObjectName alias     = fromTable.Alias;

                // If this is a sub-command table,
                if (fromTable.IsSubQueryTable)
                {
                    // eg. FROM ( SELECT id FROM Part )
                    TableSelectExpression  subQuery        = fromTable.SubSelect;
                    TableExpressionFromSet subQueryFromSet = GenerateFromSet(subQuery, db);

                    // The aliased name of the table
                    ObjectName aliasTableName = null;
                    if (alias != null)
                    {
                        aliasTableName = alias.Clone();
                    }

                    var source = new FromTableSubQuerySource(db.IsInCaseInsensitive, uniqueKey, subQuery, subQueryFromSet, aliasTableName);
                    // Add to list of subquery tables to add to command,
                    fromSet.AddTable(source);
                }
                else
                {
                    // Else must be a standard command table,
                    ObjectName name = fromTable.Name;

                    // Resolve to full table name
                    ObjectName tableName = db.ResolveTableName(name);

                    if (!db.TableExists(tableName))
                    {
                        throw new ApplicationException("Table '" + tableName + "' was not found.");
                    }

                    ObjectName givenName = null;
                    if (alias != null)
                    {
                        givenName = alias.Clone();
                    }

                    // Get the ITableQueryInfo object for this table name (aliased).
                    ITableQueryInfo tableQueryInfo = db.GetTableQueryInfo(tableName, givenName);
                    var             source         = new FromTableDirectSource(db.IsInCaseInsensitive, tableQueryInfo, uniqueKey, givenName, tableName);

                    fromSet.AddTable(source);
                }
            }              // foreach

            // Set up functions, aliases and exposed variables for this from set,

            // For each column being selected
            foreach (SelectColumn col in selectExpression.Columns)
            {
                // Is this a glob?  (eg. Part.* )
                if (col.IsGlob)
                {
                    // Find the columns globbed and add to the 'selectedColumns' result.
                    if (col.IsAll)
                    {
                        fromSet.ExposeAllColumns();
                    }
                    else
                    {
                        // Otherwise the glob must be of the form '[table name].*'
                        string     tname = col.GlobPrefix;
                        ObjectName tn    = ObjectName.Parse(tname);
                        fromSet.ExposeAllColumnsFromSource(tn);
                    }
                }
                else
                {
                    // Otherwise must be a standard column reference.  Note that at this
                    // time we aren't sure if a column expression is correlated and is
                    // referencing an outer source.  This means we can't verify if the
                    // column expression is valid or not at this point.

                    // If this column is aliased, add it as a function reference to the
                    // TableExpressionFromSet.
                    var varExpression = (VariableExpression)col.Expression;

                    ObjectName alias       = col.Alias;
                    ObjectName v           = varExpression.VariableName;
                    bool       aliasMatchV = (v != null && alias != null && fromSet.StringCompare(v.Name, alias.Name));
                    if (alias != null && !aliasMatchV)
                    {
                        fromSet.AddFunctionRef(alias.Name, col.Expression);
                        fromSet.ExposeVariable(alias.Clone());
                    }
                    else if (v != null)
                    {
                        ObjectName resolved = fromSet.ResolveReference(v);
                        fromSet.ExposeVariable(resolved ?? v);
                    }
                    else
                    {
                        string funName = col.Expression.ToString();
                        fromSet.AddFunctionRef(funName, col.Expression);
                        fromSet.ExposeVariable(ObjectName.Parse(funName));
                    }
                }
            }              // for each column selected

            return(fromSet);
        }
예제 #3
0
        /// <summary>
        /// Plans an ORDER BY set.
        /// </summary>
        /// <param name="plan"></param>
        /// <param name="orderBy"></param>
        /// <param name="fromSet"></param>
        /// <param name="selectedColumns"></param>
        /// <remarks>
        /// This is given its own function because we may want to plan
        /// this at the end of a number of composite functions.
        /// </remarks>
        /// <returns></returns>
        private static IQueryPlanNode PlanForOrderBy(IQueryPlanNode plan, IList <ByColumn> orderBy, TableExpressionFromSet fromSet, IList <SelectColumn> selectedColumns)
        {
            var functionTable = new ObjectName("FUNCTIONTABLE");

            // Sort on the ORDER BY clause
            if (orderBy.Count > 0)
            {
                int sz            = orderBy.Count;
                var orderList     = new ObjectName[sz];
                var ascendingList = new bool[sz];

                var functionOrders = new List <Expression>();

                for (int i = 0; i < sz; ++i)
                {
                    ByColumn   column = orderBy[i];
                    Expression exp    = column.Expression;
                    ascendingList[i] = column.Ascending;
                    ObjectName v = exp.AsVariable();
                    if (v != null)
                    {
                        ObjectName newV = fromSet.ResolveReference(v);
                        if (newV == null)
                        {
                            throw new ApplicationException("Can not resolve ORDER BY variable: " + v);
                        }

                        newV         = SubstituteAliasedVariable(newV, selectedColumns);
                        orderList[i] = newV;
                    }
                    else
                    {
                        // Otherwise we must be ordering by an expression such as
                        // '0 - a'.

                        // Resolve the expression,
                        exp = exp.Prepare(fromSet.ExpressionQualifier);

                        // Make sure we substitute any aliased columns in the order by
                        // columns.
                        exp = SubstituteAliasedVariables(exp, selectedColumns);

                        // The new ordering functions are called 'FUNCTIONTABLE.#ORDER-n'
                        // where n is the number of the ordering expression.
                        orderList[i] = new ObjectName(functionTable, "#ORDER-" + functionOrders.Count);
                        functionOrders.Add(exp);
                    }
                }

                // If there are functional orderings,
                // For this we must define a new FunctionTable with the expressions,
                // then order by those columns, and then use another SubsetNode
                // command node.
                int fsz = functionOrders.Count;
                if (fsz > 0)
                {
                    var funs   = new Expression[fsz];
                    var fnames = new String[fsz];
                    for (int n = 0; n < fsz; ++n)
                    {
                        funs[n]   = functionOrders[n];
                        fnames[n] = "#ORDER-" + n;
                    }

                    if (plan is SubsetNode)
                    {
                        // If the top plan is a QueryPlan.SubsetNode then we use the
                        //   information from it to create a new SubsetNode that
                        //   doesn't include the functional orders we have attached here.
                        var          topSubsetNode = (SubsetNode)plan;
                        ObjectName[] mappedNames   = topSubsetNode.NewColumnNames;

                        // Defines the sort functions
                        plan = new CreateFunctionsNode(plan, funs, fnames);
                        // Then plan the sort
                        plan = new SortNode(plan, orderList, ascendingList);
                        // Then plan the subset
                        plan = new SubsetNode(plan, mappedNames, mappedNames);
                    }
                    else
                    {
                        // Defines the sort functions
                        plan = new CreateFunctionsNode(plan, funs, fnames);
                        // Plan the sort
                        plan = new SortNode(plan, orderList, ascendingList);
                    }
                }
                else
                {
                    // No functional orders so we only need to sort by the columns
                    // defined.
                    plan = new SortNode(plan, orderList, ascendingList);
                }
            }

            return(plan);
        }
        internal static TableExpressionFromSet GenerateFromSet(TableSelectExpression selectExpression, ITableSpaceContext db)
        {
            // Get the 'from_clause' from the table expression
            FromClause fromClause = selectExpression.From;

            // Create a TableExpressionFromSet for this table expression
            var fromSet = new TableExpressionFromSet(db.IsInCaseInsensitive);

            // Add all tables from the 'fromClause'
            foreach (FromTable fromTable in fromClause.AllTables) {
                string uniqueKey = fromTable.UniqueKey;
                ObjectName alias = fromTable.Alias;

                // If this is a sub-command table,
                if (fromTable.IsSubQueryTable) {
                    // eg. FROM ( SELECT id FROM Part )
                    TableSelectExpression subQuery = fromTable.SubSelect;
                    TableExpressionFromSet subQueryFromSet = GenerateFromSet(subQuery, db);

                    // The aliased name of the table
                    ObjectName aliasTableName = null;
                    if (alias != null)
                        aliasTableName = alias.Clone();

                    var source = new FromTableSubQuerySource(db.IsInCaseInsensitive, uniqueKey, subQuery, subQueryFromSet, aliasTableName);
                    // Add to list of subquery tables to add to command,
                    fromSet.AddTable(source);
                } else {
                    // Else must be a standard command table,
                    ObjectName name = fromTable.Name;

                    // Resolve to full table name
                    ObjectName tableName = db.ResolveTableName(name);

                    if (!db.TableExists(tableName))
                        throw new ApplicationException("Table '" + tableName + "' was not found.");

                    ObjectName givenName = null;
                    if (alias != null)
                        givenName = alias.Clone();

                    // Get the ITableQueryInfo object for this table name (aliased).
                    ITableQueryInfo tableQueryInfo = db.GetTableQueryInfo(tableName, givenName);
                    var source = new FromTableDirectSource(db.IsInCaseInsensitive, tableQueryInfo, uniqueKey, givenName, tableName);

                    fromSet.AddTable(source);
                }
            }  // foreach

            // Set up functions, aliases and exposed variables for this from set,

            // For each column being selected
            foreach (SelectColumn col in selectExpression.Columns) {
                // Is this a glob?  (eg. Part.* )
                if (col.IsGlob) {
                    // Find the columns globbed and add to the 'selectedColumns' result.
                    if (col.IsAll) {
                        fromSet.ExposeAllColumns();
                    } else {
                        // Otherwise the glob must be of the form '[table name].*'
                        string tname = col.GlobPrefix;
                        ObjectName tn = ObjectName.Parse(tname);
                        fromSet.ExposeAllColumnsFromSource(tn);
                    }
                } else {
                    // Otherwise must be a standard column reference.  Note that at this
                    // time we aren't sure if a column expression is correlated and is
                    // referencing an outer source.  This means we can't verify if the
                    // column expression is valid or not at this point.

                    // If this column is aliased, add it as a function reference to the
                    // TableExpressionFromSet.
                    var varExpression = (VariableExpression)col.Expression;

                    ObjectName alias = col.Alias;
                    ObjectName v =  varExpression.VariableName;
                    bool aliasMatchV = (v != null && alias != null && fromSet.StringCompare(v.Name, alias.Name));
                    if (alias != null && !aliasMatchV) {
                        fromSet.AddFunctionRef(alias.Name, col.Expression);
                        fromSet.ExposeVariable(alias.Clone());
                    } else if (v != null) {
                        ObjectName resolved = fromSet.ResolveReference(v);
                        fromSet.ExposeVariable(resolved ?? v);
                    } else {
                        string funName = col.Expression.ToString();
                        fromSet.AddFunctionRef(funName, col.Expression);
                        fromSet.ExposeVariable(ObjectName.Parse(funName));
                    }
                }

            }  // for each column selected

            return fromSet;
        }
예제 #5
0
        private static ObjectName ResolveGroupMax(TableSelectExpression expression, TableExpressionFromSet fromSet)
        {
            // Resolve GROUP MAX variable to a reference in this from set
            ObjectName groupmaxColumn = expression.GroupMax;
            if (groupmaxColumn != null) {
                ObjectName v = fromSet.ResolveReference(groupmaxColumn);
                if (v == null)
                    throw new ApplicationException("Could find GROUP MAX reference '" + groupmaxColumn + "'");

                groupmaxColumn = v;
            }

            return groupmaxColumn;
        }
예제 #6
0
        /// <summary>
        /// Plans an ORDER BY set.
        /// </summary>
        /// <param name="plan"></param>
        /// <param name="orderBy"></param>
        /// <param name="fromSet"></param>
        /// <param name="selectedColumns"></param>
        /// <remarks>
        /// This is given its own function because we may want to plan 
        /// this at the end of a number of composite functions.
        /// </remarks>
        /// <returns></returns>
        private static IQueryPlanNode PlanForOrderBy(IQueryPlanNode plan, IList<ByColumn> orderBy, TableExpressionFromSet fromSet, IList<SelectColumn> selectedColumns)
        {
            var functionTable = new ObjectName("FUNCTIONTABLE");

            // Sort on the ORDER BY clause
            if (orderBy.Count > 0) {
                int sz = orderBy.Count;
                var orderList = new ObjectName[sz];
                var ascendingList = new bool[sz];

                var functionOrders = new List<Expression>();

                for (int i = 0; i < sz; ++i) {
                    ByColumn column = orderBy[i];
                    Expression exp = column.Expression;
                    ascendingList[i] = column.Ascending;
                    ObjectName v = exp.AsVariable();
                    if (v != null) {
                        ObjectName newV = fromSet.ResolveReference(v);
                        if (newV == null)
                            throw new ApplicationException("Can not resolve ORDER BY variable: " + v);

                        newV = SubstituteAliasedVariable(newV, selectedColumns);
                        orderList[i] = newV;
                    } else {
                        // Otherwise we must be ordering by an expression such as
                        // '0 - a'.

                        // Resolve the expression,
                        exp = exp.Prepare(fromSet.ExpressionQualifier);

                        // Make sure we substitute any aliased columns in the order by
                        // columns.
                        exp = SubstituteAliasedVariables(exp, selectedColumns);

                        // The new ordering functions are called 'FUNCTIONTABLE.#ORDER-n'
                        // where n is the number of the ordering expression.
                        orderList[i] = new ObjectName(functionTable, "#ORDER-" + functionOrders.Count);
                        functionOrders.Add(exp);
                    }
                }

                // If there are functional orderings,
                // For this we must define a new FunctionTable with the expressions,
                // then order by those columns, and then use another SubsetNode
                // command node.
                int fsz = functionOrders.Count;
                if (fsz > 0) {
                    var funs = new Expression[fsz];
                    var fnames = new String[fsz];
                    for (int n = 0; n < fsz; ++n) {
                        funs[n] = functionOrders[n];
                        fnames[n] = "#ORDER-" + n;
                    }

                    if (plan is SubsetNode) {
                        // If the top plan is a QueryPlan.SubsetNode then we use the
                        //   information from it to create a new SubsetNode that
                        //   doesn't include the functional orders we have attached here.
                        var topSubsetNode = (SubsetNode)plan;
                        ObjectName[] mappedNames = topSubsetNode.NewColumnNames;

                        // Defines the sort functions
                        plan = new CreateFunctionsNode(plan, funs, fnames);
                        // Then plan the sort
                        plan = new SortNode(plan, orderList, ascendingList);
                        // Then plan the subset
                        plan = new SubsetNode(plan, mappedNames, mappedNames);
                    } else {
                        // Defines the sort functions
                        plan = new CreateFunctionsNode(plan, funs, fnames);
                        // Plan the sort
                        plan = new SortNode(plan, orderList, ascendingList);
                    }

                } else {
                    // No functional orders so we only need to sort by the columns
                    // defined.
                    plan = new SortNode(plan, orderList, ascendingList);
                }
            }

            return plan;
        }