public static ITable Length(QueryProcessor processor, Expression[] args) { if (args.Length != 1) throw new ArgumentException("The function LENGTH accepts only 1 argument."); Expression arg = args[0]; SqlObject resultLength; SqlObject obj = QueryProcessor.Result(processor.Execute(arg))[0]; if (obj.IsNull) { resultLength = SqlObject.MakeNull(SqlType.Numeric); } else { int length; SqlType obType = obj.Type; SqlValue obValue = obj.Value; // If it's a string, if (obType.IsString) { length = obValue.ToString().Length; } // If it's a binary, else if (obType.IsBinary) { length = obValue.Length - 1; } // Otherwise, return null, else { length = -1; } resultLength = length == -1 ? SqlObject.MakeNull(SqlType.Numeric) : new SqlObject((long) length); } return QueryProcessor.ResultTable(resultLength); }
public ITable EvaluateAggregate(QueryProcessor processor, bool distinct, ITable group, Expression[] args) { if (!function.IsAggregate) throw new InvalidOperationException("The function is not an aggregate."); try { // Execute it object[] funArgs; if (invokeType == 6) { funArgs = new object[] { function.Name, processor, distinct, group, args }; } // The QueryProcessor, Expression[] construct else if (invokeType == 1) { funArgs = new object[] { processor, distinct, group, args }; } else { throw new ApplicationException("Unknown invoke type"); } return (ITable)method.Invoke(null, funArgs); } catch (MethodAccessException e) { throw new ApplicationException(e.Message, e); } catch (TargetInvocationException e) { throw new ApplicationException(e.InnerException.Message, e.InnerException); } }
public static ITable If(QueryProcessor processor, Expression[] args) { SqlObject[] conditional = QueryProcessor.Result(processor.Execute(args[0])); // If it evaluated to true, bool? b = conditional[0].Value.ToBoolean(); return b != null && b == true ? processor.Execute(args[1]) : processor.Execute(args[2]); }
public static ITable GroupConcat(QueryProcessor processor, bool distinct, ITable group, Expression[] args) { // The output string StringBuilder return_string = new StringBuilder(); // Find the distinct subset of group if (distinct) group = processor.DistinctSubset(group, args); // Push the group table onto the processor stack processor.PushTable(group); // Iterator over the group IRowCursor i = group.GetRowCursor(); bool first = true; while (i.MoveNext()) { RowId rowid = i.Current; processor.UpdateTableRow(rowid); foreach (Expression op in args) { ITable val = processor.Execute(op); SqlObject ob = QueryProcessor.Result(val)[0]; if (!ob.IsNull) { if (!first) { return_string.Append(", "); } return_string.Append(SqlValue.FromObject(ob.Value).ToString()); first = false; } } } // Pop the table and return the result processor.PopTable(); return QueryProcessor.ResultTable(new SqlObject(return_string.ToString())); }
public static ITable Avg(QueryProcessor processor, bool distinct, ITable group, Expression[] args) { // Aggregate function only can have 1 argument if (args.Length > 1) throw new ArgumentException("Only one argument permitted for SUM function."); return ProcessAggregate(processor, distinct, group, args, new AvgAggregateInspector()); }
public void InitGroups(QueryProcessor processor, IIndex<long> emptyIndexContainer) { Debug.Assert(emptyIndexContainer.Count == 0); ITable child = BaseTable; // No groups, so make the entire child table the group, if (aggregateComposite == null || child.RowCount <= 1) { emptyIndexContainer.Add(0); emptyIndexContainer.Add(child.RowCount); } // Populate the index by the aggregate composite, else { // Create a resolver for the composite function IndexResolver resolver = processor.CreateResolver(child, aggregateComposite); // The groups state long groupPos = 0; long groupSize = 0; SqlObject[] lastComposite = null; // Scan over the child IRowCursor cursor = child.GetRowCursor(); while (cursor.MoveNext()) { RowId rowid = cursor.Current; // Get the group term SqlObject[] groupValue = resolver.GetValue(rowid); if (lastComposite == null) { lastComposite = groupValue; } else { int c = SqlObject.Compare(groupValue, lastComposite); // If group_val > the last composite, we are on a new group if (c > 0) { // New group, emptyIndexContainer.Add(groupPos); emptyIndexContainer.Add(groupSize); lastComposite = groupValue; groupPos = groupPos + groupSize; groupSize = 0; } else if (c < 0) { // This will happen if the child table is not sorted by the // composite expression. throw new ApplicationException("Aggregate child is not sorted correctly."); } } ++groupSize; } // Final group // (the below check probably not necessary since we already check for the // empty child so group size will always be >1 at this point). if (groupSize > 0) { emptyIndexContainer.Add(groupPos); emptyIndexContainer.Add(groupSize); } } // Set the group index childGroupsIndex = emptyIndexContainer; lookupCursor = BaseTable.GetRowCursor(); }
public ExpressionTable(ITable child, QueryProcessor processor) : base(child) { // Make a copy of the processor this.processor = new QueryProcessor(processor); // Push the parent table onto the processor stack this.processor.PushTable(child); outputExps = new List<OutputExpression>(); columns = new ExpressionColumnCollection(this); }
public ITable Evaluate(QueryProcessor processor, Expression[] args) { // 'CAST' is a special case, if (function.Name.Equals("@cast")) { // Get the value to cast, and the type to cast it to, SqlObject val = QueryProcessor.Result(processor.Execute(args[0]))[0]; SqlObject castType = QueryProcessor.Result(processor.Execute(args[1]))[0]; string castTypeString = castType.Value.ToString(); SqlType type = SqlType.Parse(castTypeString); // Do the cast, SqlObject result = val.CastTo(type); // And return the result, return QueryProcessor.ResultTable(result); } if (function.IsAggregate) throw new InvalidOperationException("The function is aggregate."); try { // Execute it if (invokeType == 6) { object[] funArgs = { function.Name, processor, args }; return (ITable)method.Invoke(null, funArgs); } // The QueryProcessor, Expression[] construct if (invokeType == 1) { object[] funArgs = { processor, args }; return (ITable)method.Invoke(null, funArgs); } // The SqlObject construct if (invokeType == 2) { int sz = args.Length; // Resolve the arguments into TypedValues SqlObject[] obs = new SqlObject[sz]; for (int i = 0; i < sz; ++i) { obs[i] = QueryProcessor.Result(processor.Execute(args[i]))[0]; } // Set up the arguments and invoke the method object[] funArgs = { obs }; SqlObject result = (SqlObject)method.Invoke(null, funArgs); // Wrap on a FunctionTable and return return QueryProcessor.ResultTable(result); } throw new ApplicationException("Unknown invoke type"); } catch (MethodAccessException e) { throw new ApplicationException(e.Message, e); } catch (TargetInvocationException e) { throw new ApplicationException(e.InnerException.Message, e.InnerException); } }
public static ITable Least(QueryProcessor processor, Expression[] args) { SqlObject least = null; for (int i = 0; i < args.Length; ++i) { SqlObject ob = QueryProcessor.Result(processor.Execute(args[i]))[0]; if (ob.IsNull) return QueryProcessor.ResultTable(ob); if (least == null || SqlObject.Compare(ob, least) < 0) least = ob; } return QueryProcessor.ResultTable(least); }
public static ITable Count(QueryProcessor processor, bool distinct, ITable group, Expression[] args) { // Only 1 argument allowed if (args.Length > 1) throw new ArgumentException("Only one argument permitted for COUNT function."); // If the parameter is a function operation with name "star" then this is // a simple group size result Expression arg = args[0]; if (arg.Type == ExpressionType.Function && arg.GetArgument("name").Equals("star")) { return QueryProcessor.ResultTable(SqlObject.CastTo(group.RowCount, SqlType.Numeric)); } // Otherwise, if this is a distinct, if (distinct) { group = processor.DistinctSubset(group, args); // The above process removes null values so we return the count, return QueryProcessor.ResultTable(SqlObject.CastTo(group.RowCount, SqlType.Numeric)); } // Otherwise, we need to iterate through a count all none null values, return ProcessAggregate(processor, false, group, args, new CountAggregateInspector()); }
internal QueryProcessor(QueryProcessor src) { transaction = src.transaction; tableStack = new List<ITable>(src.tableStack); rowIdStack = new List<RowId>(src.rowIdStack); }
private static IRowCursor QueryAllMatches(SystemTransaction transaction, TableName tableName, SystemTable table, IList<string> columns, SqlObject val) { // Try and find an index on these columns SystemIndexSetDataSource indexSet = transaction.FindIndexOn(tableName, columns); // If index found if (indexSet != null) // Query the index and find all matches return indexSet.Select(SelectableRange.Is(val)); // Otherwise no index, so scan the table for matches // Make an Expression for the operation; // (column1, column2, ...columnn) = val Expression compExp; int sz = columns.Count; if (sz > 1) { FunctionExpression cfunExp = new FunctionExpression("composite_fetch"); for (int i = 0; i < sz; ++i) { Expression varRef = new FetchVariableExpression(new Variable(tableName, columns[i])); cfunExp.Parameters.Add(varRef); } compExp = cfunExp; } else if (sz == 1) { compExp = new FetchVariableExpression(new Variable(tableName, columns[0])); } else { throw new ApplicationException("Invalid columns list size"); } // Equality test FunctionExpression funExp = new FunctionExpression("@is_sql"); funExp.Parameters.Add(compExp); funExp.Parameters.Add(new FetchStaticExpression(val)); // Create a query processor and perform the scan operation QueryProcessor processor = new QueryProcessor(transaction); ITable result = processor.FilterByScan(table, funExp); // Return the row cursor return result.GetRowCursor(); }
internal static void SetInsertRowToDefault(SystemTransaction transaction, TableName table_name, IMutableTable table, RowId rowid) { // Get all column defaults on the table IList<object> table_defaults = transaction.QueryTableDefaults(table_name); int sz = table_defaults.Count / 2; // Exit quickly if there's no default values if (sz == 0) return; // Create a query processor QueryProcessor processor = new QueryProcessor(transaction); // For each default value, TableRow row = table.GetRow(rowid); for (int i = 0; i < sz; ++i) { string colName = (string)table_defaults[i * 2]; Expression colDefault = (Expression)table_defaults[(i * 2) + 1]; // Execute the default value expression ITable defaultResult = processor.Execute(colDefault); // Turn it into a TObject SqlObject val = defaultResult.GetValue(0, new RowId(0)); // The col num of the column name int colIndex = table.Columns.IndexOf(colName); if (colIndex < 0) throw new ApplicationException("Column '" + colName + "' not found for DEFAULT value"); // And insert it row.SetValue(colIndex, val); } }
public ITable Execute(Query query, Expression expression) { // Create the QueryProcessor QueryProcessor processor = new QueryProcessor(transaction); // If it's a select, if (expression is SelectExpression) { QueryOptimizer optimizer = new QueryOptimizer(transaction); expression = optimizer.SubstituteParameters(expression, query); expression = optimizer.Qualify(expression); expression = optimizer.Optimize(expression); // Execute the query, return processor.Execute(expression); } // Set the parameter as the base table, and the base rowid (the // parameters table only has 1 row). processor.PushTable(new QueryParametersTable(query)); processor.UpdateTableRow(new RowId(0)); // Otherwise it must be an interpretable function if (expression is FunctionExpression) { string fun_name = (string)expression.GetArgument("name"); if (fun_name.Equals("create_table")) return CreateTable(expression); /* TODO: if (fun_name.Equals("drop_table")) return DropTable(processor, expression); if (fun_name.Equals("create_index")) return CreateIndex(processor, expression); if (fun_name.Equals("drop_index")) return DropIndex(processor, expression); if (fun_name.Equals("explain_expression")) return ExplainExpression(expression); */ } throw new NotSupportedException(); }
public static ITable AllLesserOrEqualThan(QueryProcessor processor, Expression[] args) { return NestedAllScan(processor, args[0], args[1], LesserOrEqualThan); }
public ITable EvaluateAggregate(QueryProcessor processor, bool distinct, ITable group, Expression[] args) { if (evalContext == null) throw new InvalidOperationException("Evaluation context was not set"); return evalContext.EvaluateAggregate(processor, distinct, group, args); }
public static ITable CharLength(QueryProcessor processor, Expression[] args) { return Length(processor, args); }
private static ITable ProcessAggregate(QueryProcessor processor, bool distinct, ITable group, Expression[] args, IAggregateInspector aggregator) { // Qualify the return type of the parameter SqlType type = processor.GetExpressionType(group, args[0]); // If an empty group if (group.RowCount == 0) { // Null return type if group is empty, return QueryProcessor.ResultTable(SqlObject.MakeNull(type)); } // Find the distinct subset of group if (distinct) group = processor.DistinctSubset(group, args); // Push the group table onto the processor stack processor.PushTable(group); // Scan the group table, returning null on a null value IRowCursor i = group.GetRowCursor(); while (i.MoveNext()) { RowId rowid = i.Current; processor.UpdateTableRow(rowid); ITable val = processor.Execute(args[0]); SqlObject ob = QueryProcessor.Result(val)[0]; // If we hit a null value, we ignore it. SQL-92 apparently says we // should generate a warning for nulls that are eliminated by set // functions. if (!ob.IsNull) { aggregator.Accumulate(ob); } } // Pop the table and return the result processor.PopTable(); SqlObject result = aggregator.Result(); return QueryProcessor.ResultTable(result ?? SqlObject.MakeNull(type)); }
public QueryPlanner(SystemTransaction transaction) { this.transaction = transaction; random = new Random(); simpleProcessor = new QueryProcessor(transaction); }
public static ITable AnyNotEqual(QueryProcessor processor, Expression[] args) { return NestedAnyScan(processor, args[0], args[1], NotEqual); }
public static ITable AnyLesserThan(QueryProcessor processor, Expression[] args) { return NestedAnyScan(processor, args[0], args[1], LesserThan); }
public static ITable AnyGreaterOrEqualThan(QueryProcessor processor, Expression[] args) { return NestedAnyScan(processor, args[0], args[1], GreaterOrEqualThan); }
public ExpressionIndexResolver(QueryProcessor processor, ITable table, SqlType[] type, bool[] ascending_type, Expression[] column_ops) { this.processor = new QueryProcessor(processor); this.table = table; this.columnExps = column_ops; this.collationType = type; this.ascending = ascending_type; // Push the table onto the top of the processor this.processor.PushTable(this.table); // NOTE: we don't need to pop the table since we are using a processor // that isn't shared with anything else. }
private static ITable NestedAnyScan(QueryProcessor processor, Expression leftExp, Expression rightExp, NestedEvaluate evaluate) { // Evaluate the left and right side of the operation ITable left = processor.Execute(leftExp); ITable right = processor.Execute(rightExp); // Turn left into a SqlObject SqlObject leftOb = QueryProcessor.Result(left)[0]; // Scan right, return true on the first that's equal IRowCursor i = right.GetRowCursor(); try { while (i.MoveNext()) { RowId rowid = i.Current; SqlObject scanVal = right.GetValue(0, rowid); SqlObject[] args = new SqlObject[] { leftOb, scanVal }; SqlObject r = evaluate(args); if (Equals(r, new SqlObject(true))) { return QueryProcessor.ResultTable(new SqlObject(true)); } } } catch (AccessViolationException e) { throw new ApplicationException(e.Message, e); } catch (TargetInvocationException e) { throw new ApplicationException(e.InnerException.Message, e.InnerException); } return QueryProcessor.ResultTable(new SqlObject(false)); }
public static ITable Exists(QueryProcessor processor, Expression[] args) { // The nested expression to evaluate Expression nested_op = args[0]; // Execute the nested operation, ITable result = processor.Execute(nested_op); // If there are elements, then 'exists' is true return QueryProcessor.ResultTable(result.RowCount > 0 ? SqlObject.True : SqlObject.False); }
public ITable Evaluate(QueryProcessor processor, Expression[] args) { if (evalContext == null) throw new InvalidOperationException("Evaluation context was not set"); return evalContext.Evaluate(processor, args); }
public QueryCostModel(SystemTransaction transaction) { this.transaction = transaction; processor = new QueryProcessor(transaction); }
public static ITable BitLength(QueryProcessor processor, Expression[] args) { SqlObject ob = QueryProcessor.Result(Length(processor, args))[0]; SqlObject eight = new SqlObject(8L); return QueryProcessor.ResultTable(Add(new SqlObject[] { ob, eight })); }
public static ITable AllGreaterThan(QueryProcessor processor, Expression[] args) { return NestedAllScan(processor, args[0], args[1], GreaterThan); }