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