internal ColumnStatistics(Variable var) { if (var == null) throw new ArgumentNullException("var"); this.var = var; divisionPoints = new SqlObject[DivisionPointCount]; }
public AliasVariableNameExpression(Expression child, Variable alias, SqlType returnType) : base(ExpressionType.AliasVariableName) { SetArgument("alias", alias); SetArgument("child", child); if (returnType != null) SetArgument("return_type", returnType); }
protected override void OnVariableDropped(Variable variable) { // We should never come to this ... if (executeContext.HasArgument(variable.Name)) { throw new InvalidOperationException(); } base.OnVariableDropped(variable); }
protected override void OnVariableDefined(Variable variable) { if (executeContext.HasArgument(variable.Name)) { VariableManager.DropVariable(variable.Name); throw new InvalidOperationException(); } base.OnVariableDefined(variable); }
public void DefineVariable(VariableInfo variableInfo) { if (variableInfo == null) throw new ArgumentNullException("variableInfo"); if (variables.ContainsKey(variableInfo.VariableName)) throw new ArgumentException(); var variable = new Variable(variableInfo); variables[variableInfo.VariableName] = variable; Scope.OnVariableDefined(variable); }
void IVariableScope.OnVariableDropped(Variable variable) { if (variable.Name.Equals(TransactionSettingKeys.CurrentSchema, StringComparison.OrdinalIgnoreCase)) { currentSchema = Database.DatabaseContext.DefaultSchema(); } else if (variable.Name.Equals(TransactionSettingKeys.ReadOnly, StringComparison.OrdinalIgnoreCase)) { readOnly = dbReadOnly; } else if (variable.Name.Equals(TransactionSettingKeys.IgnoreIdentifiersCase, StringComparison.OrdinalIgnoreCase)) { ignoreCase = Database.DatabaseContext.IgnoreIdentifiersCase(); } else if (variable.Name.Equals(TransactionSettingKeys.AutoCommit, StringComparison.OrdinalIgnoreCase)) { autoCommit = Database.DatabaseContext.AutoCommit(); } else if (variable.Name.Equals(TransactionSettingKeys.ParameterStyle, StringComparison.OrdinalIgnoreCase)) { // TODO: Get it from the configuration... parameterStyle = null; } }
public FetchVariableExpression(Variable var) : base(ExpressionType.FetchVariable) { SetArgument("var", var); }
void IVariableScope.OnVariableDefined(Variable variable) { if (variable.Name.Equals(TransactionSettingKeys.CurrentSchema, StringComparison.OrdinalIgnoreCase)) { currentSchema = variable.Value; } else if (variable.Name.Equals(TransactionSettingKeys.ReadOnly, StringComparison.OrdinalIgnoreCase)) { if (dbReadOnly) throw new InvalidOperationException("The database is read-only: cannot change access of the transaction."); // TODO: handle special cases like "ON", "OFF", "ENABLE" and "DISABLE" readOnly = variable.Value; } else if (variable.Name.Equals(TransactionSettingKeys.IgnoreIdentifiersCase, StringComparison.OrdinalIgnoreCase)) { ignoreCase = variable.Value; } else if (variable.Name.Equals(TransactionSettingKeys.AutoCommit, StringComparison.OrdinalIgnoreCase)) { autoCommit = variable.Value; } else if (variable.Name.Equals(TransactionSettingKeys.ParameterStyle, StringComparison.OrdinalIgnoreCase)) { parameterStyle = variable.Value; } }
private bool GlobMatch(string globString, Variable v) { // TODO: case insensitive qualification (globString may be variable case // however table_name and col_name is information directly from the // current metadata) if (globString.Equals("*")) return true; // Must be something.* string tableName = globString.Substring(0, globString.Length - 2); // The table name to resolve against TableName searchTableName = TableName.Resolve(tableName); searchTableName = searchTableName.ResolveSchema(transaction.CurrentSchema); return searchTableName.Equals(v.TableName); }
private Expression RemapTables(Expression joinGraph, int[] uniqueId, IDictionary<Variable, Variable> varRemap) { // Exit early if join graph is null if (joinGraph == null) return joinGraph; bool makeAlias = false; TableName newName; if (joinGraph is JoinExpression) { JoinExpression joinExp = (JoinExpression)joinGraph; // Search the left and right for matching terms joinExp.Left = RemapTables(joinExp.Left, uniqueId, varRemap); joinExp.Right = RemapTables(joinExp.Right, uniqueId, varRemap); return joinGraph; } if (joinGraph is FetchTableExpression) { // The new name of this int un_id = uniqueId[0]; newName = new TableName("#TT" + un_id); makeAlias = true; } else if (joinGraph is AliasTableNameExpression) { // The new name of this int un_id = uniqueId[0]; newName = new TableName("#TT" + un_id); } else if (joinGraph is SelectExpression) { newName = ((SelectExpression)joinGraph).UniqueName; makeAlias = true; } else { return joinGraph; } // If this is an alias table name then we need to promote the aliased // information to the child if it's a nested query if (joinGraph is AliasTableNameExpression) { AliasTableNameExpression aliasExp = (AliasTableNameExpression)joinGraph; // The child Expression child = aliasExp.Child; // If the child is a nested query if (child is SelectExpression) { SelectExpression selectExp = (SelectExpression)child; // Promote the old aliased information // The current alias name TableName curAliasName = aliasExp.Alias; // Get the output from the select and update the info int sz = selectExp.Output.Count; for (int i = 0; i < sz; ++i) { SelectOutput outExp = selectExp.Output[i]; if (outExp.Expression is AliasVariableNameExpression) { AliasVariableNameExpression varAliasExp = (AliasVariableNameExpression)outExp.Expression; Variable oldVar = varAliasExp.Alias; Variable newVar = new Variable(curAliasName, oldVar.Name); varAliasExp.Alias = newVar; } else { throw new ApplicationException("Expected alias."); } } // The new name of this alias is the unique name of the table newName = selectExp.UniqueName; } } // The list of all vars referencable from this operation List<FetchVariableExpression> allRefs = new List<FetchVariableExpression>(); PopulateVariables(allRefs, joinGraph); // Map them to new values, int colr = 0; foreach (FetchVariableExpression varExp in allRefs) { Variable v = varExp.Variable; varRemap[v] = new Variable(newName, v.Name); ++colr; } // Rename the alias, ++uniqueId[0]; if (makeAlias) { joinGraph = new AliasTableNameExpression(joinGraph, newName); } else { ((AliasTableNameExpression)joinGraph).Alias = newName; } return joinGraph; }
/// <summary> /// Sets this <see cref="Variable"/> object with information /// from the given <see cref="Variable"/>. /// </summary> /// <param name="from"></param> /// <returns></returns> public Variable Set(Variable from) { table_name = from.table_name; column_name = from.column_name; return this; }
public AliasVariableNameExpression(Expression child, Variable alias) : this(child, alias, null) { }
private ITable FetchVariable(Variable var) { return ResultTable(new SqlObject[] { GetValue(var.Name) }); }
private Variable MakeBooleanVariable(string name, bool value) { var variable = new Variable(new VariableInfo(name, PrimitiveTypes.Boolean(), false)); variable.SetValue(DataObject.Boolean(value)); return variable; }
private static bool AttemptRangeSetMerge(Variable v, FunctionExpression rangeSetTerm, Expression toMergeWith, string logicalOpName) { if (toMergeWith is FunctionExpression) { FunctionExpression functionExp = (FunctionExpression) toMergeWith; // If the type is the same logical operation, we recurse string funType = functionExp.Name; if (funType.Equals(logicalOpName)) { // Recurse condition, we try left and right merge // We attempt left and right param if (AttemptRangeSetMerge(v, rangeSetTerm, (Expression)functionExp.Parameters[0], logicalOpName)) return true; return AttemptRangeSetMerge(v, rangeSetTerm, (Expression) functionExp.Parameters[1], logicalOpName); } // If it's a range set, if (funType.Equals("range_set")) { // Get the var Variable targetVariable = ((FetchVariableExpression) functionExp.Parameters[0]).Variable; // If they match, we merge if (v.Equals(targetVariable)) { // Get the range sets SelectableRange rangeSet1 = (SelectableRange) functionExp.Parameters[1]; SelectableRange rangeSet2 = (SelectableRange) rangeSetTerm.Parameters[1]; // Make sure the range types are the same SqlObject[] ob1 = (SqlObject[])toMergeWith.GetArgument("full_range_object"); SqlObject[] ob2 = (SqlObject[])rangeSetTerm.GetArgument("full_range_object"); if (ob1.Length != 1 || ob2.Length != 1) // PENDING: Handle composite terms, return false; SqlType rs1Type = ob1[0].Type; SqlType rs2Type = ob2[0].Type; if (!rs1Type.Equals(rs2Type)) // Types are not strictly comparable, therefore can't merge, return false; // Merge (note that range_set1 which is part of 'to_merge_with' // will be modified). if (logicalOpName.Equals("@and_sql")) { // intersect (and) rangeSet1 = rangeSet1.Intersect(rangeSet2); } else { // union (or) rangeSet1 = rangeSet1.Union(rangeSet2); } // Update the simplified term, functionExp.Parameters[1] = rangeSet1; return true; } // Not equal variables so return false return false; } // fun_type isn't named "range_set", "or" or "and" so we return false // indicating no merge is possible. return false; } return false; }
private void MarkUpIndexCandidates(Expression expression) { // If it's a fetch variable operation if (expression is FetchVariableExpression) { Variable var = ((FetchVariableExpression)expression).Variable; // Get the table name TableName tname = var.TableName; // Get the TableDataSource for this table, ITable tableSource = FetchTable(joinGraph, tname); if (tableSource != null) { // Get the list of indexes defined on this table, TableName index_tname = tableSource.Name; IIndexSetDataSource[] indexes = transaction.GetTableIndexes(index_tname); foreach (IIndexSetDataSource ind in indexes) { IndexCollation collation = ind.Collation; // If the collation matches the var name then we have a match if (collation.Columns.Length == 1 && collation.Columns[0].Equals(var.Name)) { // Match found so mark it up expression.IndexTableName = index_tname; expression.IndexCandidate = ind.Name; return; } } } } // If it's a function, else if (expression is FunctionExpression) { FunctionExpression functionExp = (FunctionExpression) expression; // If the exp is a range_set function then it's an index candidate, String fuunctionName = functionExp.Name; if (fuunctionName.Equals("range_set")) { // Mark the fetch variable exp as an index candidate if we can FetchVariableExpression fetch_var_op = (FetchVariableExpression)functionExp.Parameters[0]; MarkUpIndexCandidates(fetch_var_op); } // If its a simple comparison else if (IsSimpleComparison(fuunctionName) || IsSimpleLogical(fuunctionName)) { // Something like 'a = ?' is an index possibility Expression p1 = (Expression) functionExp.Parameters[0]; Expression p2 = (Expression) functionExp.Parameters[1]; // Mark up them up if we can MarkUpIndexCandidates(p1); MarkUpIndexCandidates(p2); } // If it is a composite function else if (fuunctionName.Equals("composite")) { // A composite index int paramCount = functionExp.Parameters.Count; int termCount = paramCount / 2; // If 1 term, if (termCount == 1) { // Recurse to the term, MarkUpIndexCandidates((Expression) functionExp.Parameters[0]); } // Multiple terms, else { Variable[] vars = new Variable[termCount]; TableName tname = null; bool valid = true; for (int i = 0; i < termCount; ++i) { // If the collation of the composite is descending, then we can't // represent it as a composite index, SqlObject tv = (SqlObject)functionExp.Parameters[(i * 2) + 1]; if (!tv.Value.ToBoolean()) { valid = false; break; } // Get the composite part operation Expression compVar = (Expression)functionExp.Parameters[i * 2]; // Is it a var? if (!(compVar is FetchVariableExpression)) { valid = false; break; } // Fetch the var, Variable v = ((FetchVariableExpression)compVar).Variable; // This var is in a different table, if (i > 0 && !v.TableName.Equals(tname)) { valid = false; break; } // Ok, we know the composite part is a fetch var, and that the vars // reference the same source, and it's ascending, tname = v.TableName; vars[i] = v; } // If the composite meets the indexable requirement look for an // index, if (valid) { ITable tableSource = FetchTable(joinGraph, tname); if (tableSource != null) { // Get the list of indexes defined on this table, TableName indexTableName = tableSource.Name; IIndexSetDataSource[] indexes = transaction.GetTableIndexes(indexTableName); foreach (IIndexSetDataSource ind in indexes) { IndexCollation collation = ind.Collation; // If the collation matches the number of terms, if (collation.Columns.Length == termCount) { bool matchFound = true; for (int i = 0; i < termCount; ++i) { if (!collation.Columns[i].Equals(vars[i].Name)) { matchFound = false; break; } } // If match found, mark up the function, if (matchFound) { expression.IndexTableName = indexTableName; expression.IndexCandidate = ind.Name; return; } } } } } } } else { // index would not make sense so stop descending return; } } }
private static Variable Dereference(Expression graph, Variable v) { if (graph is FilterExpression) // Recurse to the child return Dereference(((FilterExpression)graph).Child, v); if (graph is JoinExpression) { JoinExpression joinExp = (JoinExpression) graph; // Recurse the left and right nodes Variable v2 = Dereference(joinExp.Left, v); if (v2 == null || !v2.Equals(v)) return v2; return Dereference(joinExp.Right, v); } if (graph is AliasTableNameExpression) { AliasTableNameExpression aliasExp = (AliasTableNameExpression) graph; if (aliasExp.Alias.Equals(v.TableName)) { // Ok, match found, table name is in the child Expression child = aliasExp.Child; if (child is FetchTableExpression) { TableName newTableName = ((FetchTableExpression)child).TableName; return new Variable(newTableName, v.Name); } // Return null if the reference is to a nested query return null; } return null; } if (graph is FunctionExpression) return null; throw new ApplicationException("Unknown operation type in graph."); }
private Variable MakeStringVariable(string name, string value) { var variable = new Variable(new VariableInfo(name, PrimitiveTypes.String(), false)); variable.SetValue(DataObject.String(value)); return variable; }
public Expression OnAfterWalk(Expression expression) { if (expression.Type == ExpressionType.Select) { SelectExpression selectExp = (SelectExpression)expression; // The current table name TableName uniqueName = selectExp.UniqueName; // Exiting a select, so first update the output vars // The top remap stack for this select Dictionary<Variable, Variable> curRemap = remapStack[remapStack.Count - 1]; remapStack.RemoveAt(remapStack.Count - 1); List<Variable> outList = new List<Variable>(); int sz = selectExp.Output.Count; for (int i = 0; i < sz; ++i) { Expression outExp = selectExp.Output[i].Expression; // What the output is currently called Variable currentName = GetVariable(outExp); // The new reference we are assigning it, Variable newName = new Variable(uniqueName, "#C" + i); // This is how we are mapping the output outList.Add(currentName); outList.Add(newName); } RemapAllVariables(selectExp, curRemap); if (remapStack.Count > 0) { if (selectExp.IsSourceSelect) { for (int i = 0; i < sz; ++i) { Expression outExp = selectExp.Output[i].Expression; Variable curName = outList[i * 2]; Variable newName = outList[(i * 2) + 1]; if (outExp is AliasVariableNameExpression) { ((AliasVariableNameExpression) outExp).Alias = newName; } else { throw new ApplicationException("Unexpected operation."); } // Tell the parent map of these changes, if applicable, Dictionary<Variable, Variable> parentRemap = remapStack[remapStack.Count - 1]; // Get any existing remap for this name Variable existingMapTo = parentRemap[curName]; if (existingMapTo != null) { // We just remap the name parentRemap[curName] = new Variable(existingMapTo.TableName, newName.Name); } else { parentRemap[curName] = newName; } } } } } return expression; }
public SelectOutput(Expression expression, Variable alias) { this.expression = expression; this.alias = alias; }
public Expression OnAfterWalk(Expression expression) { if (expression is SelectExpression) { SelectExpression selectExp = (SelectExpression)expression; // Exiting select, we expand the select output list to a complete // form. int sz = selectExp.Output.Count; // Create a list of all forward referencable variables in the join // graph List<FetchVariableExpression> varList = new List<FetchVariableExpression>(); optimizer.PopulateVariables(varList, selectExp.Join); // The unique table name of this select TableName uniqueTableName = selectExp.UniqueName; if (uniqueTableName == null) throw new SystemException("Select must have a unique name."); List<Expression> newOutList = new List<Expression>(); for (int i = 0; i < sz; ++i) { // The Expression SelectOutput selectOut = selectExp.Output[i]; // Is this a glob type? if (selectOut.Expression is FetchGlobExpression) { // Get the glob string string str = ((FetchGlobExpression)selectOut.Expression).GlobString; // Search the referencable list for matches, bool matchFound = false; foreach(FetchVariableExpression varExp in varList) { Variable v = varExp.Variable; // Found a match, add it to the list if (optimizer.GlobMatch(str, v)) { SqlType returnType = varExp.ReturnType; Expression globExp = new FetchVariableExpression(v); globExp = new AliasVariableNameExpression(globExp, v); globExp.ReturnType = returnType; newOutList.Add(globExp); matchFound = true; } } // If we searched the whole referencable list and no matches, // we report the error. This doesn't apply to the general // glob "*" which is valid for results with no columns. if (!str.Equals("*") && !matchFound) throw new SqlParseException("'" + str + "' does not match anything", selectOut.Expression); } else { // The makes sure all other types of output from a select are // named variable references. // If this is an alias, we need to make sure we qualify it with // this table name if (selectOut.Expression is AliasVariableNameExpression) { // Rewrite this alias name with the new unique table id Variable v = selectOut.Alias; if (v.TableName != null) throw new SqlParseException("Incorrect alias format", selectOut.Expression); v = new Variable(uniqueTableName, v.Name); selectOut.Alias = v; } // If it's not a fetchvar operation, we need to assign a // unique alias name for this value else if (!(selectOut.Expression is FetchVariableExpression)) { string label = (string)selectOut.Expression.GetArgument("label"); if (label == null) label = "nolabel"; selectOut = new SelectOutput( new AliasVariableNameExpression(selectOut.Expression, new Variable(uniqueTableName, "#" + newOutList.Count + "#" + label)), selectOut.Alias); } // If it's a regular fetch variable operation, we need to // forward qualify it and label it. else { selectOut.Expression = QualifyExpression(selectOut.Expression, varList, true); Variable var = ((FetchVariableExpression)selectOut.Expression).Variable; SqlType returnType = selectOut.Expression.ReturnType; selectOut.Expression = new AliasVariableNameExpression(selectOut.Expression, var); selectOut.Expression.ReturnType = returnType; } // Add it to the new select output list newOutList.Add(selectOut.Expression); } } // new_out_list is now the new expanded select output list sz = newOutList.Count; selectExp.Output.Clear(); for (int i = 0; i < sz; ++i) { selectExp.Output.Add(new SelectOutput(newOutList[i])); } // Set the qualified flag for each select statement, selectExp.IsQualified = true; } return expression; }
public Variable(Variable v) { table_name = v.table_name; column_name = v.column_name; }
private static IList<FetchVariableExpression> QualifyVariables(Variable v, IList<FetchVariableExpression> varList) { List<FetchVariableExpression> outList = new List<FetchVariableExpression>(); int sz = varList.Count; for (int i = 0; i < sz; ++i) { FetchVariableExpression varExp = varList[i]; Variable vin = varExp.Variable; // Assume match unless shown otherwise if (StringsMatch(v.Name, vin.Name)) { TableName vtname = v.TableName; TableName vintname = vin.TableName; if (vtname == null || (StringsMatch(vtname.Name, vintname.Name) && StringsMatch(vtname.Schema, vintname.Schema))) { outList.Add(varExp); } } } // Return the qualifying vars return outList; }