1 /* Copyright (C) 2004 - 2009  Versant Inc.  http://www.db4o.com */
2 
3 using System;
4 using System.Collections;
5 using Db4objects.Db4o;
6 using Db4objects.Db4o.Config;
7 using Db4objects.Db4o.Foundation;
8 using Db4objects.Db4o.Internal;
9 using Db4objects.Db4o.Internal.Handlers;
10 using Db4objects.Db4o.Internal.Query.Processor;
11 using Db4objects.Db4o.Marshall;
12 using Db4objects.Db4o.Query;
13 using Db4objects.Db4o.Reflect;
14 
15 namespace Db4objects.Db4o.Internal.Query.Processor
16 {
17 	/// <summary>Object constraint on queries</summary>
18 	/// <exclude></exclude>
19 	public class QConObject : QCon
20 	{
21 		private object i_object;
22 
23 		private int i_objectID;
24 
25 		[System.NonSerialized]
26 		internal ClassMetadata _classMetadata;
27 
28 		private int i_classMetadataID;
29 
30 		private QField i_field;
31 
32 		[System.NonSerialized]
33 		internal IPreparedComparison _preparedComparison;
34 
35 		private IObjectAttribute i_attributeProvider;
36 
37 		[System.NonSerialized]
38 		private bool _checkClassMetadataOnly = false;
39 
QConObject()40 		public QConObject()
41 		{
42 		}
43 
QConObject(Transaction a_trans, QCon a_parent, QField a_field, object a_object )44 		public QConObject(Transaction a_trans, QCon a_parent, QField a_field, object a_object
45 			) : base(a_trans)
46 		{
47 			// the constraining object
48 			// cache for the db4o object ID
49 			// the YapClass
50 			// needed for marshalling the request
51 			// C/S only
52 			i_parent = a_parent;
53 			if (a_object is ICompare)
54 			{
55 				a_object = ((ICompare)a_object).Compare();
56 			}
57 			i_object = a_object;
58 			i_field = a_field;
59 		}
60 
AssociateYapClass(Transaction a_trans, object a_object)61 		private void AssociateYapClass(Transaction a_trans, object a_object)
62 		{
63 			if (a_object == null)
64 			{
65 			}
66 			else
67 			{
68 				//It seems that we need not result the following field
69 				//i_object = null;
70 				//i_comparator = Null.INSTANCE;
71 				//i_classMetadata = null;
72 				// FIXME: Setting the YapClass to null will prevent index use
73 				// If the field is typed we can guess the right one with the
74 				// following line. However this does break some SODA test cases.
75 				// Revisit!
76 				//            if(i_field != null){
77 				//                i_classMetadata = i_field.getYapClass();
78 				//            }
79 				_classMetadata = a_trans.Container().ProduceClassMetadata(a_trans.Reflector().ForObject
80 					(a_object));
81 				if (_classMetadata != null)
82 				{
83 					i_object = _classMetadata.GetComparableObject(a_object);
84 					if (a_object != i_object)
85 					{
86 						i_attributeProvider = _classMetadata.Config().QueryAttributeProvider();
87 						_classMetadata = a_trans.Container().ProduceClassMetadata(a_trans.Reflector().ForObject
88 							(i_object));
89 					}
90 					if (_classMetadata != null)
91 					{
92 						_classMetadata.CollectConstraints(a_trans, this, i_object, new _IVisitor4_84(this
93 							));
94 					}
95 					else
96 					{
97 						AssociateYapClass(a_trans, null);
98 					}
99 				}
100 				else
101 				{
102 					AssociateYapClass(a_trans, null);
103 				}
104 			}
105 		}
106 
107 		private sealed class _IVisitor4_84 : IVisitor4
108 		{
_IVisitor4_84(QConObject _enclosing)109 			public _IVisitor4_84(QConObject _enclosing)
110 			{
111 				this._enclosing = _enclosing;
112 			}
113 
Visit(object obj)114 			public void Visit(object obj)
115 			{
116 				this._enclosing.AddConstraint((QCon)obj);
117 			}
118 
119 			private readonly QConObject _enclosing;
120 		}
121 
CanBeIndexLeaf()122 		public override bool CanBeIndexLeaf()
123 		{
124 			return i_object == null || ((_classMetadata != null && _classMetadata.IsValueType
125 				()) || Evaluator().Identity());
126 		}
127 
CanLoadByIndex()128 		public override bool CanLoadByIndex()
129 		{
130 			if (i_field == null)
131 			{
132 				return false;
133 			}
134 			if (i_field._fieldMetadata == null)
135 			{
136 				return false;
137 			}
138 			if (!i_field._fieldMetadata.HasIndex())
139 			{
140 				return false;
141 			}
142 			if (!i_evaluator.SupportsIndex())
143 			{
144 				return false;
145 			}
146 			return i_field._fieldMetadata.CanLoadByIndex();
147 		}
148 
Evaluate(QCandidate a_candidate)149 		internal override bool Evaluate(QCandidate a_candidate)
150 		{
151 			try
152 			{
153 				return a_candidate.Evaluate(this, i_evaluator);
154 			}
155 			catch (Exception e)
156 			{
157 				return false;
158 			}
159 		}
160 
EvaluateEvaluationsExec(QCandidates a_candidates, bool rereadObject )161 		internal override void EvaluateEvaluationsExec(QCandidates a_candidates, bool rereadObject
162 			)
163 		{
164 			if (i_field.IsQueryLeaf())
165 			{
166 				bool hasEvaluation = false;
167 				IEnumerator i = IterateChildren();
168 				while (i.MoveNext())
169 				{
170 					if (i.Current is QConEvaluation)
171 					{
172 						hasEvaluation = true;
173 						break;
174 					}
175 				}
176 				if (hasEvaluation)
177 				{
178 					a_candidates.Traverse(i_field);
179 					IEnumerator j = IterateChildren();
180 					while (j.MoveNext())
181 					{
182 						((QCon)j.Current).EvaluateEvaluationsExec(a_candidates, false);
183 					}
184 				}
185 			}
186 		}
187 
EvaluateSelf()188 		internal override void EvaluateSelf()
189 		{
190 			if (DTrace.enabled)
191 			{
192 				DTrace.EvaluateSelf.Log(Id());
193 			}
194 			if (_classMetadata != null)
195 			{
196 				if (!(_classMetadata is PrimitiveTypeMetadata))
197 				{
198 					if (!i_evaluator.Identity() && (_classMetadata.TypeHandler() is StandardReferenceTypeHandler
199 						))
200 					{
201 						_checkClassMetadataOnly = true;
202 					}
203 					object transactionalObject = _classMetadata.WrapWithTransactionContext(Transaction
204 						(), i_object);
205 					_preparedComparison = _classMetadata.PrepareComparison(Context(), transactionalObject
206 						);
207 				}
208 			}
209 			base.EvaluateSelf();
210 			_checkClassMetadataOnly = false;
211 		}
212 
Context()213 		private IContext Context()
214 		{
215 			return Transaction().Context();
216 		}
217 
Collect(QCandidates a_candidates)218 		internal override void Collect(QCandidates a_candidates)
219 		{
220 			if (i_field.IsClass())
221 			{
222 				a_candidates.Traverse(i_field);
223 				a_candidates.Filter(i_candidates);
224 			}
225 		}
226 
EvaluateSimpleExec(QCandidates a_candidates)227 		internal override void EvaluateSimpleExec(QCandidates a_candidates)
228 		{
229 			// TODO: The following can be skipped if we used the index on
230 			//       this field to load the objects, if hasOrdering() is false
231 			if (i_field.IsQueryLeaf() || IsNullConstraint())
232 			{
233 				a_candidates.Traverse(i_field);
234 				PrepareComparison(i_field);
235 				a_candidates.Filter(this);
236 			}
237 		}
238 
PrepareComparison(QCandidate candidate)239 		internal virtual IPreparedComparison PrepareComparison(QCandidate candidate)
240 		{
241 			if (_preparedComparison != null)
242 			{
243 				return _preparedComparison;
244 			}
245 			return candidate.PrepareComparison(Container(), i_object);
246 		}
247 
GetYapClass()248 		internal override ClassMetadata GetYapClass()
249 		{
250 			return _classMetadata;
251 		}
252 
GetField()253 		public override QField GetField()
254 		{
255 			return i_field;
256 		}
257 
GetObjectID()258 		internal virtual int GetObjectID()
259 		{
260 			if (i_objectID == 0)
261 			{
262 				i_objectID = i_trans.Container().GetID(i_trans, i_object);
263 				if (i_objectID == 0)
264 				{
265 					i_objectID = -1;
266 				}
267 			}
268 			return i_objectID;
269 		}
270 
HasObjectInParentPath(object obj)271 		public override bool HasObjectInParentPath(object obj)
272 		{
273 			if (obj == i_object)
274 			{
275 				return true;
276 			}
277 			return base.HasObjectInParentPath(obj);
278 		}
279 
IdentityID()280 		public override int IdentityID()
281 		{
282 			if (i_evaluator.Identity())
283 			{
284 				int id = GetObjectID();
285 				if (id != 0)
286 				{
287 					if (!(i_evaluator is QENot))
288 					{
289 						return id;
290 					}
291 				}
292 			}
293 			return 0;
294 		}
295 
IsNullConstraint()296 		internal override bool IsNullConstraint()
297 		{
298 			return i_object == null;
299 		}
300 
Log(string indent)301 		internal override void Log(string indent)
302 		{
303 		}
304 
LogObject()305 		internal override string LogObject()
306 		{
307 			return string.Empty;
308 		}
309 
Marshall()310 		internal override void Marshall()
311 		{
312 			base.Marshall();
313 			GetObjectID();
314 			if (_classMetadata != null)
315 			{
316 				i_classMetadataID = _classMetadata.GetID();
317 			}
318 		}
319 
OnSameFieldAs(QCon other)320 		public override bool OnSameFieldAs(QCon other)
321 		{
322 			if (!(other is Db4objects.Db4o.Internal.Query.Processor.QConObject))
323 			{
324 				return false;
325 			}
326 			return i_field == ((Db4objects.Db4o.Internal.Query.Processor.QConObject)other).i_field;
327 		}
328 
PrepareComparison(QField a_field)329 		internal virtual void PrepareComparison(QField a_field)
330 		{
331 			if (IsNullConstraint() & !a_field.IsArray())
332 			{
333 				_preparedComparison = Null.Instance;
334 			}
335 			else
336 			{
337 				_preparedComparison = a_field.PrepareComparison(Context(), i_object);
338 			}
339 		}
340 
RemoveChildrenJoins()341 		internal override void RemoveChildrenJoins()
342 		{
343 			base.RemoveChildrenJoins();
344 			_children = null;
345 		}
346 
ShareParent(object a_object, BooleanByRef removeExisting)347 		internal override QCon ShareParent(object a_object, BooleanByRef removeExisting)
348 		{
349 			if (i_parent == null)
350 			{
351 				return null;
352 			}
353 			object obj = i_field.Coerce(a_object);
354 			if (obj == No4.Instance)
355 			{
356 				return null;
357 			}
358 			return i_parent.AddSharedConstraint(i_field, obj);
359 		}
360 
ShareParentForClass(IReflectClass a_class, BooleanByRef removeExisting)361 		internal override QConClass ShareParentForClass(IReflectClass a_class, BooleanByRef
362 			 removeExisting)
363 		{
364 			if (i_parent == null)
365 			{
366 				return null;
367 			}
368 			QConClass newConstraint = new QConClass(i_trans, i_parent, i_field, a_class);
369 			i_parent.AddConstraint(newConstraint);
370 			return newConstraint;
371 		}
372 
Translate(object candidate)373 		internal object Translate(object candidate)
374 		{
375 			if (i_attributeProvider != null)
376 			{
377 				i_candidates.i_trans.Container().Activate(i_candidates.i_trans, candidate);
378 				return i_attributeProvider.Attribute(candidate);
379 			}
380 			return candidate;
381 		}
382 
Unmarshall(Transaction trans)383 		internal override void Unmarshall(Transaction trans)
384 		{
385 			if (i_trans != null)
386 			{
387 				return;
388 			}
389 			base.Unmarshall(trans);
390 			if (i_object == null)
391 			{
392 				_preparedComparison = Null.Instance;
393 			}
394 			if (i_classMetadataID != 0)
395 			{
396 				_classMetadata = trans.Container().ClassMetadataForID(i_classMetadataID);
397 			}
398 			if (i_field != null)
399 			{
400 				i_field.Unmarshall(trans);
401 			}
402 			if (i_objectID > 0)
403 			{
404 				object obj = trans.Container().TryGetByID(trans, i_objectID);
405 				if (obj != null)
406 				{
407 					i_object = obj;
408 				}
409 			}
410 		}
411 
Visit(object obj)412 		public override void Visit(object obj)
413 		{
414 			QCandidate qc = (QCandidate)obj;
415 			bool res = true;
416 			bool processed = false;
417 			if (_checkClassMetadataOnly)
418 			{
419 				ClassMetadata yc = qc.ReadClassMetadata();
420 				if (yc != null)
421 				{
422 					res = i_evaluator.Not(_classMetadata.GetHigherHierarchy(yc) == _classMetadata);
423 					processed = true;
424 				}
425 			}
426 			if (!processed)
427 			{
428 				res = Evaluate(qc);
429 			}
430 			Visit1(qc.GetRoot(), this, res);
431 		}
432 
Contains()433 		public override IConstraint Contains()
434 		{
435 			lock (StreamLock())
436 			{
437 				i_evaluator = i_evaluator.Add(new QEContains(true));
438 				return this;
439 			}
440 		}
441 
Equal()442 		public override IConstraint Equal()
443 		{
444 			lock (StreamLock())
445 			{
446 				i_evaluator = i_evaluator.Add(new QEEqual());
447 				return this;
448 			}
449 		}
450 
GetObject()451 		public override object GetObject()
452 		{
453 			return i_object;
454 		}
455 
Greater()456 		public override IConstraint Greater()
457 		{
458 			lock (StreamLock())
459 			{
460 				i_evaluator = i_evaluator.Add(new QEGreater());
461 				return this;
462 			}
463 		}
464 
Identity()465 		public override IConstraint Identity()
466 		{
467 			lock (StreamLock())
468 			{
469 				if (i_object == null)
470 				{
471 					return this;
472 				}
473 				GetObjectID();
474 				// TODO: this may not be correct for NOT
475 				// It may be necessary to add an if(i_evaluator.identity())
476 				RemoveChildrenJoins();
477 				i_evaluator = i_evaluator.Add(new QEIdentity());
478 				return this;
479 			}
480 		}
481 
ByExample()482 		public override IConstraint ByExample()
483 		{
484 			lock (StreamLock())
485 			{
486 				AssociateYapClass(i_trans, i_object);
487 				return this;
488 			}
489 		}
490 
SetEvaluationMode()491 		internal virtual void SetEvaluationMode()
492 		{
493 			if ((i_object == null) || EvaluationModeAlreadySet())
494 			{
495 				return;
496 			}
497 			int id = GetObjectID();
498 			if (id < 0)
499 			{
500 				ByExample();
501 			}
502 			else
503 			{
504 				_classMetadata = i_trans.Container().ProduceClassMetadata(i_trans.Reflector().ForObject
505 					(i_object));
506 				Identity();
507 			}
508 		}
509 
EvaluationModeAlreadySet()510 		internal virtual bool EvaluationModeAlreadySet()
511 		{
512 			return _classMetadata != null;
513 		}
514 
Like()515 		public override IConstraint Like()
516 		{
517 			lock (StreamLock())
518 			{
519 				i_evaluator = i_evaluator.Add(new QEContains(false));
520 				return this;
521 			}
522 		}
523 
Smaller()524 		public override IConstraint Smaller()
525 		{
526 			lock (StreamLock())
527 			{
528 				i_evaluator = i_evaluator.Add(new QESmaller());
529 				return this;
530 			}
531 		}
532 
StartsWith(bool caseSensitive)533 		public override IConstraint StartsWith(bool caseSensitive)
534 		{
535 			lock (StreamLock())
536 			{
537 				i_evaluator = i_evaluator.Add(new QEStartsWith(caseSensitive));
538 				return this;
539 			}
540 		}
541 
EndsWith(bool caseSensitive)542 		public override IConstraint EndsWith(bool caseSensitive)
543 		{
544 			lock (StreamLock())
545 			{
546 				i_evaluator = i_evaluator.Add(new QEEndsWith(caseSensitive));
547 				return this;
548 			}
549 		}
550 
ToString()551 		public override string ToString()
552 		{
553 			string str = "QConObject ";
554 			if (i_object != null)
555 			{
556 				str += i_object.ToString();
557 			}
558 			return str;
559 		}
560 	}
561 }
562