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