1 //---------------------------------------------------------------------- 2 // This software is part of the OpenBeOS distribution and is covered 3 // by the OpenBeOS license. 4 //--------------------------------------------------------------------- 5 /*! 6 \file Query.cpp 7 BQuery implementation. 8 */ 9 10 #include <fs_query.h> 11 #include <new> 12 #include <parsedate.h> 13 #include <time.h> 14 15 #include <Entry.h> 16 #include <Query.h> 17 #include <Volume.h> 18 19 #include <MessengerPrivate.h> 20 #include <syscalls.h> 21 22 #include "QueryPredicate.h" 23 #include "storage_support.h" 24 25 using namespace std; 26 using namespace BPrivate::Storage; 27 28 // BQuery 29 30 // constructor 31 /*! \brief Creates an uninitialized BQuery. 32 */ 33 BQuery::BQuery() 34 : BEntryList(), 35 fStack(NULL), 36 fPredicate(NULL), 37 fDevice((dev_t)B_ERROR), 38 fLive(false), 39 fPort(B_ERROR), 40 fToken(0), 41 fQueryFd(-1) 42 { 43 } 44 45 // destructor 46 /*! \brief Frees all resources associated with the object. 47 */ 48 BQuery::~BQuery() 49 { 50 Clear(); 51 } 52 53 // Clear 54 /*! \brief Resets the object to a uninitialized state. 55 \return \c B_OK 56 */ 57 status_t 58 BQuery::Clear() 59 { 60 // close the currently open query 61 status_t error = B_OK; 62 if (fQueryFd >= 0) { 63 error = _kern_close(fQueryFd); 64 fQueryFd = -1; 65 } 66 // delete the predicate stack and the predicate 67 delete fStack; 68 fStack = NULL; 69 delete[] fPredicate; 70 fPredicate = NULL; 71 // reset the other parameters 72 fDevice = (dev_t)B_ERROR; 73 fLive = false; 74 fPort = B_ERROR; 75 fToken = 0; 76 return error; 77 } 78 79 // PushAttr 80 /*! \brief Pushes an attribute name onto the BQuery's predicate stack. 81 \param attrName the attribute name 82 \return 83 - \c B_OK: Everything went fine. 84 - \c B_NO_MEMORY: Not enough memory. 85 - \c B_NOT_ALLOWED: PushAttribute() was called after Fetch(). 86 \note In BeOS R5 this method returns \c void. That is checking the return 87 value will render your code source and binary incompatible! 88 Calling PushXYZ() after a Fetch() does change the predicate on R5, 89 but it doesn't affect the active query and the newly created 90 predicate can not even be used for the next query, since in order 91 to be able to reuse the BQuery object for another query, Clear() has 92 to be called and Clear() also deletes the predicate. 93 */ 94 status_t 95 BQuery::PushAttr(const char *attrName) 96 { 97 return _PushNode(new(nothrow) AttributeNode(attrName), true); 98 } 99 100 // PushOp 101 /*! \brief Pushes an operator onto the BQuery's predicate stack. 102 \param op the code representing the operator 103 \return 104 - \c B_OK: Everything went fine. 105 - \c B_NO_MEMORY: Not enough memory. 106 - \c B_NOT_ALLOWED: PushOp() was called after Fetch(). 107 \note In BeOS R5 this method returns \c void. That is checking the return 108 value will render your code source and binary incompatible! 109 Calling PushXYZ() after a Fetch() does change the predicate on R5, 110 but it doesn't affect the active query and the newly created 111 predicate can not even be used for the next query, since in order 112 to be able to reuse the BQuery object for another query, Clear() has 113 to be called and Clear() also deletes the predicate. 114 */ 115 status_t 116 BQuery::PushOp(query_op op) 117 { 118 status_t error = B_OK; 119 switch (op) { 120 case B_EQ: 121 case B_GT: 122 case B_GE: 123 case B_LT: 124 case B_LE: 125 case B_NE: 126 case B_CONTAINS: 127 case B_BEGINS_WITH: 128 case B_ENDS_WITH: 129 case B_AND: 130 case B_OR: 131 error = _PushNode(new(nothrow) BinaryOpNode(op), true); 132 break; 133 case B_NOT: 134 error = _PushNode(new(nothrow) UnaryOpNode(op), true); 135 break; 136 default: 137 error = _PushNode(new(nothrow) SpecialOpNode(op), true); 138 break; 139 } 140 return error; 141 } 142 143 // PushUInt32 144 /*! \brief Pushes a uint32 value onto the BQuery's predicate stack. 145 \param value the value 146 \return 147 - \c B_OK: Everything went fine. 148 - \c B_NO_MEMORY: Not enough memory. 149 - \c B_NOT_ALLOWED: PushUInt32() was called after Fetch(). 150 \note In BeOS R5 this method returns \c void. That is checking the return 151 value will render your code source and binary incompatible! 152 Calling PushXYZ() after a Fetch() does change the predicate on R5, 153 but it doesn't affect the active query and the newly created 154 predicate can not even be used for the next query, since in order 155 to be able to reuse the BQuery object for another query, Clear() has 156 to be called and Clear() also deletes the predicate. 157 */ 158 status_t 159 BQuery::PushUInt32(uint32 value) 160 { 161 return _PushNode(new(nothrow) UInt32ValueNode(value), true); 162 } 163 164 // PushInt32 165 /*! \brief Pushes an int32 value onto the BQuery's predicate stack. 166 \param value the value 167 \return 168 - \c B_OK: Everything went fine. 169 - \c B_NO_MEMORY: Not enough memory. 170 - \c B_NOT_ALLOWED: PushInt32() was called after Fetch(). 171 \note In BeOS R5 this method returns \c void. That is checking the return 172 value will render your code source and binary incompatible! 173 Calling PushXYZ() after a Fetch() does change the predicate on R5, 174 but it doesn't affect the active query and the newly created 175 predicate can not even be used for the next query, since in order 176 to be able to reuse the BQuery object for another query, Clear() has 177 to be called and Clear() also deletes the predicate. 178 */ 179 status_t 180 BQuery::PushInt32(int32 value) 181 { 182 return _PushNode(new(nothrow) Int32ValueNode(value), true); 183 } 184 185 // PushUInt64 186 /*! \brief Pushes a uint64 value onto the BQuery's predicate stack. 187 \param value the value 188 \return 189 - \c B_OK: Everything went fine. 190 - \c B_NO_MEMORY: Not enough memory. 191 - \c B_NOT_ALLOWED: PushUInt64() was called after Fetch(). 192 \note In BeOS R5 this method returns \c void. That is checking the return 193 value will render your code source and binary incompatible! 194 Calling PushXYZ() after a Fetch() does change the predicate on R5, 195 but it doesn't affect the active query and the newly created 196 predicate can not even be used for the next query, since in order 197 to be able to reuse the BQuery object for another query, Clear() has 198 to be called and Clear() also deletes the predicate. 199 */ 200 status_t 201 BQuery::PushUInt64(uint64 value) 202 { 203 return _PushNode(new(nothrow) UInt64ValueNode(value), true); 204 } 205 206 // PushInt64 207 /*! \brief Pushes an int64 value onto the BQuery's predicate stack. 208 \param value the value 209 \return 210 - \c B_OK: Everything went fine. 211 - \c B_NO_MEMORY: Not enough memory. 212 - \c B_NOT_ALLOWED: PushInt64() was called after Fetch(). 213 \note In BeOS R5 this method returns \c void. That is checking the return 214 value will render your code source and binary incompatible! 215 Calling PushXYZ() after a Fetch() does change the predicate on R5, 216 but it doesn't affect the active query and the newly created 217 predicate can not even be used for the next query, since in order 218 to be able to reuse the BQuery object for another query, Clear() has 219 to be called and Clear() also deletes the predicate. 220 */ 221 status_t 222 BQuery::PushInt64(int64 value) 223 { 224 return _PushNode(new(nothrow) Int64ValueNode(value), true); 225 } 226 227 // PushFloat 228 /*! \brief Pushes a float value onto the BQuery's predicate stack. 229 \param value the value 230 \return 231 - \c B_OK: Everything went fine. 232 - \c B_NO_MEMORY: Not enough memory. 233 - \c B_NOT_ALLOWED: PushFloat() was called after Fetch(). 234 \note In BeOS R5 this method returns \c void. That is checking the return 235 value will render your code source and binary incompatible! 236 Calling PushXYZ() after a Fetch() does change the predicate on R5, 237 but it doesn't affect the active query and the newly created 238 predicate can not even be used for the next query, since in order 239 to be able to reuse the BQuery object for another query, Clear() has 240 to be called and Clear() also deletes the predicate. 241 */ 242 status_t 243 BQuery::PushFloat(float value) 244 { 245 return _PushNode(new(nothrow) FloatValueNode(value), true); 246 } 247 248 // PushDouble 249 /*! \brief Pushes a double value onto the BQuery's predicate stack. 250 \param value the value 251 \return 252 - \c B_OK: Everything went fine. 253 - \c B_NO_MEMORY: Not enough memory. 254 - \c B_NOT_ALLOWED: PushDouble() was called after Fetch(). 255 \note In BeOS R5 this method returns \c void. That is checking the return 256 value will render your code source and binary incompatible! 257 Calling PushXYZ() after a Fetch() does change the predicate on R5, 258 but it doesn't affect the active query and the newly created 259 predicate can not even be used for the next query, since in order 260 to be able to reuse the BQuery object for another query, Clear() has 261 to be called and Clear() also deletes the predicate. 262 */ 263 status_t 264 BQuery::PushDouble(double value) 265 { 266 return _PushNode(new(nothrow) DoubleValueNode(value), true); 267 } 268 269 // PushString 270 /*! \brief Pushes a string value onto the BQuery's predicate stack. 271 \param value the value 272 \param caseInsensitive \c true, if the case of the string should be 273 ignored, \c false otherwise 274 \return 275 - \c B_OK: Everything went fine. 276 - \c B_NO_MEMORY: Not enough memory. 277 - \c B_NOT_ALLOWED: PushString() was called after Fetch(). 278 \note In BeOS R5 this method returns \c void. That is checking the return 279 value will render your code source and binary incompatible! 280 Calling PushXYZ() after a Fetch() does change the predicate on R5, 281 but it doesn't affect the active query and the newly created 282 predicate can not even be used for the next query, since in order 283 to be able to reuse the BQuery object for another query, Clear() has 284 to be called and Clear() also deletes the predicate. 285 */ 286 status_t 287 BQuery::PushString(const char *value, bool caseInsensitive) 288 { 289 return _PushNode(new(nothrow) StringNode(value, caseInsensitive), true); 290 } 291 292 // PushDate 293 /*! \brief Pushes a date value onto the BQuery's predicate stack. 294 The supplied date can be any string understood by the POSIX function 295 parsedate(). 296 \param date the date string 297 \return 298 - \c B_OK: Everything went fine. 299 - \c B_ERROR: Error parsing the string. 300 - \c B_NOT_ALLOWED: PushDate() was called after Fetch(). 301 \note Calling PushXYZ() after a Fetch() does change the predicate on R5, 302 but it doesn't affect the active query and the newly created 303 predicate can not even be used for the next query, since in order 304 to be able to reuse the BQuery object for another query, Clear() has 305 to be called and Clear() also deletes the predicate. 306 */ 307 status_t 308 BQuery::PushDate(const char *date) 309 { 310 status_t error = (date ? B_OK : B_BAD_VALUE); 311 if (error == B_OK) { 312 time_t t; 313 time(&t); 314 t = parsedate(date, t); 315 if (t < 0) 316 error = B_BAD_VALUE; 317 } 318 if (error == B_OK) 319 error = _PushNode(new(nothrow) DateNode(date), true); 320 return error; 321 } 322 323 // SetVolume 324 /*! \brief Sets the BQuery's volume. 325 A query is restricted to one volume. This method sets this volume. It 326 fails, if called after Fetch(). To reuse a BQuery object it has to be 327 reset via Clear(). 328 \param volume the volume 329 \return 330 - \c B_OK: Everything went fine. 331 - \c B_NOT_ALLOWED: SetVolume() was called after Fetch(). 332 */ 333 status_t 334 BQuery::SetVolume(const BVolume *volume) 335 { 336 status_t error = (volume ? B_OK : B_BAD_VALUE); 337 if (error == B_OK && _HasFetched()) 338 error = B_NOT_ALLOWED; 339 if (error == B_OK) { 340 if (volume->InitCheck() == B_OK) 341 fDevice = volume->Device(); 342 else 343 fDevice = (dev_t)B_ERROR; 344 } 345 return error; 346 } 347 348 // SetPredicate 349 /*! \brief Sets the BQuery's predicate. 350 A predicate can be set either using this method or constructing one on 351 the predicate stack. The two methods can not be mixed. The letter one 352 has precedence over this one. 353 The method fails, if called after Fetch(). To reuse a BQuery object it has 354 to be reset via Clear(). 355 \param predicate the predicate string 356 \return 357 - \c B_OK: Everything went fine. 358 - \c B_NOT_ALLOWED: SetPredicate() was called after Fetch(). 359 - \c B_NO_MEMORY: Insufficient memory to store the predicate. 360 */ 361 status_t 362 BQuery::SetPredicate(const char *expression) 363 { 364 status_t error = (expression ? B_OK : B_BAD_VALUE); 365 if (error == B_OK && _HasFetched()) 366 error = B_NOT_ALLOWED; 367 if (error == B_OK) 368 error = _SetPredicate(expression); 369 return error; 370 } 371 372 // SetTarget 373 /*! \brief Sets the BQuery's target and makes the query live. 374 The query update messages are sent to the specified target. They might 375 roll in immediately after calling Fetch(). 376 This methods fails, if called after Fetch(). To reuse a BQuery object it 377 has to be reset via Clear(). 378 \return 379 - \c B_OK: Everything went fine. 380 - \c B_BAD_VALUE: \a messenger was not properly initialized. 381 - \c B_NOT_ALLOWED: SetTarget() was called after Fetch(). 382 */ 383 status_t 384 BQuery::SetTarget(BMessenger messenger) 385 { 386 status_t error = (messenger.IsValid() ? B_OK : B_BAD_VALUE); 387 if (error == B_OK && _HasFetched()) 388 error = B_NOT_ALLOWED; 389 if (error == B_OK) { 390 BMessenger::Private messengerPrivate(messenger); 391 fPort = messengerPrivate.Port(); 392 fToken = (messengerPrivate.IsPreferredTarget() 393 ? -1 : messengerPrivate.Token()); 394 fLive = true; 395 } 396 return error; 397 } 398 399 // IsLive 400 /*! \brief Returns whether the query associated with this object is live. 401 \return \c true, if the query is live, \c false otherwise 402 */ 403 bool 404 BQuery::IsLive() const 405 { 406 return fLive; 407 } 408 409 // GetPredicate 410 /*! \brief Returns the BQuery's predicate. 411 Regardless of whether the predicate has been constructed using the 412 predicate stack or set via SetPredicate(), this method returns a 413 string representation. 414 \param buffer a pointer to a buffer into which the predicate shall be 415 written 416 \param length the size of the provided buffer 417 \return 418 - \c B_OK: Everything went fine. 419 - \c B_NO_INIT: The predicate isn't set. 420 - \c B_BAD_VALUE: \a buffer is \c NULL or too short. 421 \note This method causes the predicate stack to be evaluated and cleared. 422 You can't interleave Push*() and GetPredicate() calls. 423 */ 424 status_t 425 BQuery::GetPredicate(char *buffer, size_t length) 426 { 427 status_t error = (buffer ? B_OK : B_BAD_VALUE); 428 if (error == B_OK) 429 _EvaluateStack(); 430 if (error == B_OK && !fPredicate) 431 error = B_NO_INIT; 432 if (error == B_OK && length <= strlen(fPredicate)) 433 error = B_BAD_VALUE; 434 if (error == B_OK) 435 strcpy(buffer, fPredicate); 436 return error; 437 } 438 439 // GetPredicate 440 /*! \brief Returns the BQuery's predicate. 441 Regardless of whether the predicate has been constructed using the 442 predicate stack or set via SetPredicate(), this method returns a 443 string representation. 444 \param predicate a pointer to a BString which shall be set to the 445 predicate string 446 \return 447 - \c B_OK: Everything went fine. 448 - \c B_NO_INIT: The predicate isn't set. 449 - \c B_BAD_VALUE: \c NULL \a predicate. 450 \note This method causes the predicate stack to be evaluated and cleared. 451 You can't interleave Push*() and GetPredicate() calls. 452 */ 453 status_t 454 BQuery::GetPredicate(BString *predicate) 455 { 456 status_t error = (predicate ? B_OK : B_BAD_VALUE); 457 if (error == B_OK) 458 _EvaluateStack(); 459 if (error == B_OK && !fPredicate) 460 error = B_NO_INIT; 461 if (error == B_OK) 462 predicate->SetTo(fPredicate); 463 return error; 464 } 465 466 // PredicateLength 467 /*! \brief Returns the length of the BQuery's predicate string. 468 Regardless of whether the predicate has been constructed using the 469 predicate stack or set via SetPredicate(), this method returns the length 470 of its string representation (counting the terminating null). 471 \return 472 - the length of the predicate string (counting the terminating null) or 473 - 0, if an error occured 474 \note This method causes the predicate stack to be evaluated and cleared. 475 You can't interleave Push*() and PredicateLength() calls. 476 */ 477 size_t 478 BQuery::PredicateLength() 479 { 480 status_t error = _EvaluateStack(); 481 if (error == B_OK && !fPredicate) 482 error = B_NO_INIT; 483 size_t size = 0; 484 if (error == B_OK) 485 size = strlen(fPredicate) + 1; 486 return size; 487 } 488 489 // TargetDevice 490 /*! \brief Returns the device ID identifying the BQuery's volume. 491 \return the device ID of the BQuery's volume or \c B_NO_INIT, if the 492 volume isn't set. 493 494 */ 495 dev_t 496 BQuery::TargetDevice() const 497 { 498 return fDevice; 499 } 500 501 // Fetch 502 /*! \brief Tells the BQuery to start fetching entries satisfying the predicate. 503 After Fetch() has been called GetNextEntry(), GetNextRef() and 504 GetNextDirents() can be used to retrieve the enties. Live query updates 505 may be sent immediately after this method has been called. 506 Fetch() fails, if it has already been called. To reuse a BQuery object it 507 has to be reset via Clear(). 508 \return 509 - \c B_OK: Everything went fine. 510 - \c B_NO_INIT: The predicate or the volume aren't set. 511 - \c B_BAD_VALUE: The predicate is invalid. 512 - \c B_NOT_ALLOWED: Fetch() has already been called. 513 */ 514 status_t 515 BQuery::Fetch() 516 { 517 if (_HasFetched()) 518 return B_NOT_ALLOWED; 519 _EvaluateStack(); 520 if (!fPredicate || fDevice < 0) 521 return B_NO_INIT; 522 if (fLive) { 523 fQueryFd = _kern_open_query(fDevice, fPredicate, B_LIVE_QUERY, 524 fPort, fToken); 525 } else 526 fQueryFd = _kern_open_query(fDevice, fPredicate, 0, -1, -1); 527 if (fQueryFd < 0) 528 return fQueryFd; 529 return B_OK; 530 } 531 532 533 // BEntryList interface 534 535 // GetNextEntry 536 /*! \brief Returns the BQuery's next entry as a BEntry. 537 Places the next entry in the list in \a entry, traversing symlinks if 538 \a traverse is \c true. 539 \param entry a pointer to a BEntry to be initialized with the found entry 540 \param traverse specifies whether to follow it, if the found entry 541 is a symbolic link. 542 \note The iterator used by this method is the same one used by 543 GetNextRef() and GetNextDirents(). 544 \return 545 - \c B_OK if successful, 546 - \c B_ENTRY_NOT_FOUND when at the end of the list, 547 - \c B_BAD_VALUE: The queries predicate includes unindexed attributes. 548 - \c B_FILE_ERROR: Fetch() has not been called before. 549 */ 550 status_t 551 BQuery::GetNextEntry(BEntry *entry, bool traverse) 552 { 553 status_t error = (entry ? B_OK : B_BAD_VALUE); 554 if (error == B_OK) { 555 entry_ref ref; 556 error = GetNextRef(&ref); 557 if (error == B_OK) 558 error = entry->SetTo(&ref, traverse); 559 } 560 return error; 561 } 562 563 // GetNextRef 564 /*! \brief Returns the BQuery's next entry as an entry_ref. 565 Places an entry_ref to the next entry in the list into \a ref. 566 \param ref a pointer to an entry_ref to be filled in with the data of the 567 found entry 568 \note The iterator used by this method is the same one used by 569 GetNextEntry() and GetNextDirents(). 570 \return 571 - \c B_OK if successful, 572 - \c B_ENTRY_NOT_FOUND when at the end of the list, 573 - \c B_BAD_VALUE: The queries predicate includes unindexed attributes. 574 - \c B_FILE_ERROR: Fetch() has not been called before. 575 */ 576 status_t 577 BQuery::GetNextRef(entry_ref *ref) 578 { 579 status_t error = (ref ? B_OK : B_BAD_VALUE); 580 if (error == B_OK && !_HasFetched()) 581 error = B_FILE_ERROR; 582 if (error == B_OK) { 583 BPrivate::Storage::LongDirEntry entry; 584 bool next = true; 585 while (error == B_OK && next) { 586 if (GetNextDirents(&entry, sizeof(entry), 1) != 1) { 587 error = B_ENTRY_NOT_FOUND; 588 } else { 589 next = (!strcmp(entry.d_name, ".") 590 || !strcmp(entry.d_name, "..")); 591 } 592 } 593 if (error == B_OK) { 594 ref->device = entry.d_pdev; 595 ref->directory = entry.d_pino; 596 error = ref->set_name(entry.d_name); 597 } 598 } 599 return error; 600 } 601 602 // GetNextDirents 603 /*! \brief Returns the BQuery's next entries as dirent structures. 604 Reads a number of entries into the array of dirent structures pointed to by 605 \a buf. Reads as many but no more than \a count entries, as many entries as 606 remain, or as many entries as will fit into the array at \a buf with given 607 length \a length (in bytes), whichever is smallest. 608 \param buf a pointer to a buffer to be filled with dirent structures of 609 the found entries 610 \param length the maximal number of entries to be read. 611 \note The iterator used by this method is the same one used by 612 GetNextEntry() and GetNextRef(). 613 \return 614 - The number of dirent structures stored in the buffer, 0 when there are 615 no more entries to be read. 616 - \c B_BAD_VALUE: The queries predicate includes unindexed attributes. 617 - \c B_FILE_ERROR: Fetch() has not been called before. 618 */ 619 int32 620 BQuery::GetNextDirents(struct dirent *buf, size_t length, int32 count) 621 { 622 if (!buf) 623 return B_BAD_VALUE; 624 if (!_HasFetched()) 625 return B_FILE_ERROR; 626 return _kern_read_dir(fQueryFd, buf, length, count); 627 } 628 629 // Rewind 630 /*! \brief Unimplemented method of the BEntryList interface. 631 \return \c B_ERROR. 632 */ 633 status_t 634 BQuery::Rewind() 635 { 636 return B_ERROR; 637 } 638 639 // CountEntries 640 /*! \brief Unimplemented method of the BEntryList interface. 641 \return 0. 642 */ 643 int32 644 BQuery::CountEntries() 645 { 646 return B_ERROR; 647 } 648 649 // _HasFetched 650 /*! Returns whether Fetch() has already been called on this object. 651 \return \c true, if Fetch() has successfully been invoked, \c false 652 otherwise. 653 */ 654 bool 655 BQuery::_HasFetched() const 656 { 657 return (fQueryFd >= 0); 658 } 659 660 // _PushNode 661 /*! \brief Pushs a node onto the predicate stack. 662 If the stack has not been allocate until this time, this method does 663 allocate it. 664 If the supplied node is \c NULL, it is assumed that there was not enough 665 memory to allocate the node and thus \c B_NO_MEMORY is returned. 666 In case the method fails, the caller retains the ownership of the supplied 667 node and thus is responsible for deleting it, if \a deleteOnError is 668 \c false. If it is \c true, the node is deleted, if an error occurs. 669 \param node the node to be pushed 670 \param deleteOnError 671 \return 672 - \c B_OK: Everything went fine. 673 - \c B_NO_MEMORY: \c NULL \a node or insuffient memory to allocate the 674 predicate stack or push the node. 675 - \c B_NOT_ALLOWED: _PushNode() was called after Fetch(). 676 */ 677 status_t 678 BQuery::_PushNode(QueryNode *node, bool deleteOnError) 679 { 680 status_t error = (node ? B_OK : B_NO_MEMORY); 681 if (error == B_OK && _HasFetched()) 682 error = B_NOT_ALLOWED; 683 // allocate the stack, if necessary 684 if (error == B_OK && !fStack) { 685 fStack = new(nothrow) QueryStack; 686 if (!fStack) 687 error = B_NO_MEMORY; 688 } 689 if (error == B_OK) 690 error = fStack->PushNode(node); 691 if (error != B_OK && deleteOnError) 692 delete node; 693 return error; 694 } 695 696 // _SetPredicate 697 /*! \brief Helper method to set the BQuery's predicate. 698 It is not checked whether Fetch() has already been invoked. 699 \param predicate the predicate string 700 \return 701 - \c B_OK: Everything went fine. 702 - \c B_NO_MEMORY: Insufficient memory to store the predicate. 703 */ 704 status_t 705 BQuery::_SetPredicate(const char *expression) 706 { 707 status_t error = B_OK; 708 // unset the old predicate 709 delete[] fPredicate; 710 fPredicate = NULL; 711 // set the new one 712 if (expression) { 713 fPredicate = new(nothrow) char[strlen(expression) + 1]; 714 if (fPredicate) 715 strcpy(fPredicate, expression); 716 else 717 error = B_NO_MEMORY; 718 } 719 return error; 720 } 721 722 // _EvaluateStack 723 /*! Evaluates the query's predicate stack. 724 The method does nothing (and returns \c B_OK), if the stack is \c NULL. 725 If the stack is non-null and Fetch() has already been called, the method 726 fails. 727 \return 728 - \c B_OK: Everything went fine. 729 - \c B_NO_MEMORY: Insufficient memory. 730 - \c B_NOT_ALLOWED: _EvaluateStack() was called after Fetch(). 731 - another error code 732 */ 733 status_t 734 BQuery::_EvaluateStack() 735 { 736 status_t error = B_OK; 737 if (fStack) { 738 _SetPredicate(NULL); 739 if (_HasFetched()) 740 error = B_NOT_ALLOWED; 741 // convert the stack to a tree and evaluate it 742 QueryNode *node = NULL; 743 if (error == B_OK) 744 error = fStack->ConvertToTree(node); 745 BString predicate; 746 if (error == B_OK) 747 error = node->GetString(predicate); 748 if (error == B_OK) 749 error = _SetPredicate(predicate.String()); 750 delete fStack; 751 fStack = NULL; 752 } 753 return error; 754 } 755 756 757 // FBC 758 void BQuery::_QwertyQuery1() {} 759 void BQuery::_QwertyQuery2() {} 760 void BQuery::_QwertyQuery3() {} 761 void BQuery::_QwertyQuery4() {} 762 void BQuery::_QwertyQuery5() {} 763 void BQuery::_QwertyQuery6() {} 764 765