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