1
/* Copyright (C) 2004 - 2009 Versant Inc. http://www.db4o.com */
4
using System.Collections;
5
using Db4objects.Db4o.Foundation;
6
using Db4objects.Db4o.Instrumentation.Api;
7
using Db4objects.Db4o.Internal.Query;
8
using Db4objects.Db4o.NativeQueries.Expr;
9
using Db4objects.Db4o.NativeQueries.Expr.Cmp;
10
using Db4objects.Db4o.NativeQueries.Expr.Cmp.Operand;
11
using Db4objects.Db4o.NativeQueries.Instrumentation;
12
using Db4objects.Db4o.NativeQueries.Optimization;
13
using Db4objects.Db4o.Query;
15
namespace Db4objects.Db4o.NativeQueries.Instrumentation
17
public class SODAMethodBuilder
19
private const bool LogBytecode = false;
21
private IMethodRef descendRef;
23
private IMethodRef constrainRef;
25
private IMethodRef greaterRef;
27
private IMethodRef smallerRef;
29
private IMethodRef containsRef;
31
private IMethodRef startsWithRef;
33
private IMethodRef endsWithRef;
35
private IMethodRef notRef;
37
private IMethodRef andRef;
39
private IMethodRef orRef;
41
private IMethodRef identityRef;
43
private readonly ITypeEditor _editor;
45
private IMethodBuilder _builder;
47
public static readonly string OptimizeQueryMethodName = "optimizeQuery";
49
private class SODAExpressionBuilder : IExpressionVisitor
51
private ITypeRef predicateClass;
53
public SODAExpressionBuilder(SODAMethodBuilder _enclosing, ITypeRef predicateClass
56
this._enclosing = _enclosing;
57
this.predicateClass = predicateClass;
60
public virtual void Visit(AndExpression expression)
62
expression.Left().Accept(this);
63
expression.Right().Accept(this);
64
this._enclosing.Invoke(this._enclosing.andRef);
67
public virtual void Visit(BoolConstExpression expression)
72
//throw new RuntimeException("No boolean constants expected in parsed expression tree");
73
private void LoadQuery()
75
this._enclosing.LoadArgument(1);
78
public virtual void Visit(OrExpression expression)
80
expression.Left().Accept(this);
81
expression.Right().Accept(this);
82
this._enclosing.Invoke(this._enclosing.orRef);
85
public virtual void Visit(ComparisonExpression expression)
88
this.Descend(this.FieldNames(expression.Left()));
89
expression.Right().Accept(this.ComparisonEmitter());
90
this.Constrain(expression.Op());
93
private void Descend(IEnumerator fieldNames)
95
while (fieldNames.MoveNext())
97
this.Descend(fieldNames.Current);
101
private ComparisonBytecodeGeneratingVisitor ComparisonEmitter()
103
return new ComparisonBytecodeGeneratingVisitor(this._enclosing._builder, this.predicateClass
107
private void Constrain(ComparisonOperator op)
109
this._enclosing.Invoke(this._enclosing.constrainRef);
110
if (op.Equals(ComparisonOperator.ValueEquality))
114
if (op.Equals(ComparisonOperator.ReferenceEquality))
116
this._enclosing.Invoke(this._enclosing.identityRef);
119
if (op.Equals(ComparisonOperator.Greater))
121
this._enclosing.Invoke(this._enclosing.greaterRef);
124
if (op.Equals(ComparisonOperator.Smaller))
126
this._enclosing.Invoke(this._enclosing.smallerRef);
129
if (op.Equals(ComparisonOperator.Contains))
131
this._enclosing.Invoke(this._enclosing.containsRef);
134
if (op.Equals(ComparisonOperator.StartsWith))
136
this._enclosing.Ldc(1);
137
this._enclosing.Invoke(this._enclosing.startsWithRef);
140
if (op.Equals(ComparisonOperator.EndsWith))
142
this._enclosing.Ldc(1);
143
this._enclosing.Invoke(this._enclosing.endsWithRef);
146
throw new Exception("Cannot interpret constraint: " + op);
149
private void Descend(object fieldName)
151
this._enclosing.Ldc(fieldName);
152
this._enclosing.Invoke(this._enclosing.descendRef);
155
public virtual void Visit(NotExpression expression)
157
expression.Expr().Accept(this);
158
this._enclosing.Invoke(this._enclosing.notRef);
161
private IEnumerator FieldNames(FieldValue fieldValue)
163
Collection4 coll = new Collection4();
164
IComparisonOperand curOp = fieldValue;
165
while (curOp is FieldValue)
167
FieldValue curField = (FieldValue)curOp;
168
coll.Prepend(curField.FieldName());
169
curOp = curField.Parent();
171
return coll.GetEnumerator();
174
private readonly SODAMethodBuilder _enclosing;
177
public SODAMethodBuilder(ITypeEditor editor)
180
BuildMethodReferences();
183
public virtual void InjectOptimization(IExpression expr)
185
_editor.AddInterface(TypeRef(typeof(IDb4oEnhancedFilter)));
186
_builder = _editor.NewPublicMethod(PlatformName(OptimizeQueryMethodName), TypeRef
187
(typeof(void)), new ITypeRef[] { TypeRef(typeof(IQuery)) });
188
ITypeRef predicateClass = _editor.Type;
189
expr.Accept(new SODAMethodBuilder.SODAExpressionBuilder(this, predicateClass));
191
_builder.EndMethod();
194
private ITypeRef TypeRef(Type type)
196
return _editor.References.ForType(type);
199
private string PlatformName(string name)
201
return NativeQueriesPlatform.ToPlatformName(name);
204
private void LoadArgument(int index)
206
_builder.LoadArgument(index);
209
private void Invoke(IMethodRef method)
211
_builder.Invoke(method, CallingConvention.Interface);
214
private void Ldc(object value)
219
private void BuildMethodReferences()
221
descendRef = MethodRef(typeof(IQuery), "descend", new Type[] { typeof(string) });
222
constrainRef = MethodRef(typeof(IQuery), "constrain", new Type[] { typeof(object)
224
greaterRef = MethodRef(typeof(IConstraint), "greater", new Type[] { });
225
smallerRef = MethodRef(typeof(IConstraint), "smaller", new Type[] { });
226
containsRef = MethodRef(typeof(IConstraint), "contains", new Type[] { });
227
startsWithRef = MethodRef(typeof(IConstraint), "startsWith", new Type[] { typeof(
229
endsWithRef = MethodRef(typeof(IConstraint), "endsWith", new Type[] { typeof(bool
231
notRef = MethodRef(typeof(IConstraint), "not", new Type[] { });
232
andRef = MethodRef(typeof(IConstraint), "and", new Type[] { typeof(IConstraint) }
234
orRef = MethodRef(typeof(IConstraint), "or", new Type[] { typeof(IConstraint) });
235
identityRef = MethodRef(typeof(IConstraint), "identity", new Type[] { });
238
private IMethodRef MethodRef(Type parent, string name, Type[] args)
242
return _editor.References.ForMethod(parent.GetMethod(PlatformName(name), args));
246
throw new InstrumentationException(e);