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.h> 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 24 25 enum { 26 NOT_IMPLEMENTED = B_ERROR, 27 }; 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(B_ERROR), 39 fLive(false), 40 fPort(B_ERROR), 41 fToken(0), 42 fQueryFd(NullFd) 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 != NullFd) { 64 error = close_query(fQueryFd); 65 fQueryFd = NullFd; 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 = 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 = t; 318 error = B_BAD_VALUE; 319 } 320 } 321 if (error == B_OK) 322 error = _PushNode(new(nothrow) DateNode(date), true); 323 return error; 324 } 325 326 // SetVolume 327 /*! \brief Sets the BQuery's volume. 328 A query is restricted to one volume. This method sets this volume. It 329 fails, if called after Fetch(). To reuse a BQuery object it has to be 330 reset via Clear(). 331 \param volume the volume 332 \return 333 - \c B_OK: Everything went fine. 334 - \c B_NOT_ALLOWED: SetVolume() was called after Fetch(). 335 */ 336 status_t 337 BQuery::SetVolume(const BVolume *volume) 338 { 339 status_t error = (volume ? B_OK : B_BAD_VALUE); 340 if (error == B_OK && _HasFetched()) 341 error = B_NOT_ALLOWED; 342 if (error == B_OK) { 343 if (volume->InitCheck() == B_OK) 344 fDevice = volume->Device(); 345 else 346 fDevice = B_ERROR; 347 } 348 return error; 349 } 350 351 // SetPredicate 352 /*! \brief Sets the BQuery's predicate. 353 A predicate can be set either using this method or constructing one on 354 the predicate stack. The two methods can not be mixed. The letter one 355 has precedence over this one. 356 The method fails, if called after Fetch(). To reuse a BQuery object it has 357 to be reset via Clear(). 358 \param predicate the predicate string 359 \return 360 - \c B_OK: Everything went fine. 361 - \c B_NOT_ALLOWED: SetPredicate() was called after Fetch(). 362 - \c B_NO_MEMORY: Insufficient memory to store the predicate. 363 */ 364 status_t 365 BQuery::SetPredicate(const char *expression) 366 { 367 status_t error = (expression ? B_OK : B_BAD_VALUE); 368 if (error == B_OK && _HasFetched()) 369 error = B_NOT_ALLOWED; 370 if (error == B_OK) 371 error = _SetPredicate(expression); 372 return error; 373 } 374 375 // SetTarget 376 /*! \brief Sets the BQuery's target and makes the query live. 377 The query update messages are sent to the specified target. They might 378 roll in immediately after calling Fetch(). 379 This methods fails, if called after Fetch(). To reuse a BQuery object it 380 has to be reset via Clear(). 381 \return 382 - \c B_OK: Everything went fine. 383 - \c B_BAD_VALUE: \a messenger was not properly initialized. 384 - \c B_NOT_ALLOWED: SetTarget() was called after Fetch(). 385 */ 386 status_t 387 BQuery::SetTarget(BMessenger messenger) 388 { 389 status_t error = (messenger.IsValid() ? B_OK : B_BAD_VALUE); 390 if (error == B_OK && _HasFetched()) 391 error = B_NOT_ALLOWED; 392 if (error == B_OK) { 393 fPort = messenger.fPort; 394 fToken = messenger.fHandlerToken; 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 // error = _EvaluateStack(); 431 _EvaluateStack(); 432 if (error == B_OK && !fPredicate) 433 error = B_NO_INIT; 434 if (error == B_OK && length <= strlen(fPredicate)) 435 error = B_BAD_VALUE; 436 if (error == B_OK) 437 strcpy(buffer, fPredicate); 438 return error; 439 } 440 441 // GetPredicate 442 /*! \brief Returns the BQuery's predicate. 443 Regardless of whether the predicate has been constructed using the 444 predicate stack or set via SetPredicate(), this method returns a 445 string representation. 446 \param predicate a pointer to a BString which shall be set to the 447 predicate string 448 \return 449 - \c B_OK: Everything went fine. 450 - \c B_NO_INIT: The predicate isn't set. 451 - \c B_BAD_VALUE: \c NULL \a predicate. 452 \note This method causes the predicate stack to be evaluated and cleared. 453 You can't interleave Push*() and GetPredicate() calls. 454 */ 455 status_t 456 BQuery::GetPredicate(BString *predicate) 457 { 458 status_t error = (predicate ? B_OK : B_BAD_VALUE); 459 if (error == B_OK) 460 // error = _EvaluateStack(); 461 _EvaluateStack(); 462 if (error == B_OK && !fPredicate) 463 error = B_NO_INIT; 464 if (error == B_OK) 465 predicate->SetTo(fPredicate); 466 return error; 467 } 468 469 // PredicateLength 470 /*! \brief Returns the length of the BQuery's predicate string. 471 Regardless of whether the predicate has been constructed using the 472 predicate stack or set via SetPredicate(), this method returns the length 473 of its string representation (counting the terminating null). 474 \return 475 - the length of the predicate string (counting the terminating null) or 476 - 0, if an error occured 477 \note This method causes the predicate stack to be evaluated and cleared. 478 You can't interleave Push*() and PredicateLength() calls. 479 */ 480 size_t 481 BQuery::PredicateLength() 482 { 483 status_t error = _EvaluateStack(); 484 if (error == B_OK && !fPredicate) 485 error = B_NO_INIT; 486 size_t size = 0; 487 if (error == B_OK) 488 size = strlen(fPredicate) + 1; 489 return size; 490 } 491 492 // TargetDevice 493 /*! \brief Returns the device ID identifying the BQuery's volume. 494 \return the device ID of the BQuery's volume or \c B_NO_INIT, if the 495 volume isn't set. 496 497 */ 498 dev_t 499 BQuery::TargetDevice() const 500 { 501 return fDevice; 502 } 503 504 // Fetch 505 /*! \brief Tells the BQuery to start fetching entries satisfying the predicate. 506 After Fetch() has been called GetNextEntry(), GetNextRef() and 507 GetNextDirents() can be used to retrieve the enties. Live query updates 508 may be sent immediately after this method has been called. 509 Fetch() fails, if it has already been called. To reuse a BQuery object it 510 has to be reset via Clear(). 511 \return 512 - \c B_OK: Everything went fine. 513 - \c B_NO_INIT: The predicate or the volume aren't set. 514 - \c B_BAD_VALUE: The predicate is invalid. 515 - \c B_NOT_ALLOWED: Fetch() has already been called. 516 */ 517 status_t 518 BQuery::Fetch() 519 { 520 status_t error = (_HasFetched() ? B_NOT_ALLOWED : B_OK); 521 if (error == B_OK) 522 // error = _EvaluateStack(); 523 _EvaluateStack(); 524 if (error == B_OK && (!fPredicate || fDevice < 0)) 525 error = B_NO_INIT; 526 if (error == B_OK) { 527 if (fLive) { 528 error = open_live_query(fDevice, fPredicate, B_LIVE_QUERY, fPort, 529 fToken, fQueryFd); 530 } else 531 error = open_query(fDevice, fPredicate, 0, fQueryFd); 532 } 533 return error; 534 } 535 536 537 // BEntryList interface 538 539 // GetNextEntry 540 /*! \brief Returns the BQuery's next entry as a BEntry. 541 Places the next entry in the list in \a entry, traversing symlinks if 542 \a traverse is \c true. 543 \param entry a pointer to a BEntry to be initialized with the found entry 544 \param traverse specifies whether to follow it, if the found entry 545 is a symbolic link. 546 \note The iterator used by this method is the same one used by 547 GetNextRef() and GetNextDirents(). 548 \return 549 - \c B_OK if successful, 550 - \c B_ENTRY_NOT_FOUND when at the end of the list, 551 - \c B_BAD_VALUE: The queries predicate includes unindexed attributes. 552 - \c B_FILE_ERROR: Fetch() has not been called before. 553 */ 554 status_t 555 BQuery::GetNextEntry(BEntry *entry, bool traverse) 556 { 557 status_t error = (entry ? B_OK : B_BAD_VALUE); 558 if (error == B_OK) { 559 entry_ref ref; 560 error = GetNextRef(&ref); 561 if (error == B_OK) 562 error = entry->SetTo(&ref, traverse); 563 } 564 return error; 565 } 566 567 // GetNextRef 568 /*! \brief Returns the BQuery's next entry as an entry_ref. 569 Places an entry_ref to the next entry in the list into \a ref. 570 \param ref a pointer to an entry_ref to be filled in with the data of the 571 found entry 572 \note The iterator used by this method is the same one used by 573 GetNextEntry() and GetNextDirents(). 574 \return 575 - \c B_OK if successful, 576 - \c B_ENTRY_NOT_FOUND when at the end of the list, 577 - \c B_BAD_VALUE: The queries predicate includes unindexed attributes. 578 - \c B_FILE_ERROR: Fetch() has not been called before. 579 */ 580 status_t 581 BQuery::GetNextRef(entry_ref *ref) 582 { 583 status_t error = (ref ? B_OK : B_BAD_VALUE); 584 if (error == B_OK && !_HasFetched()) 585 error = B_FILE_ERROR; 586 if (error == B_OK) { 587 BPrivate::Storage::LongDirEntry entry; 588 if (BPrivate::Storage::read_query(fQueryFd, &entry, sizeof(entry), 1) != 1) 589 error = B_ENTRY_NOT_FOUND; 590 if (error == B_OK) 591 *ref = entry_ref(entry.d_pdev, entry.d_pino, entry.d_name); 592 } 593 return error; 594 } 595 596 // GetNextDirents 597 /*! \brief Returns the BQuery's next entries as dirent structures. 598 Reads a number of entries into the array of dirent structures pointed to by 599 \a buf. Reads as many but no more than \a count entries, as many entries as 600 remain, or as many entries as will fit into the array at \a buf with given 601 length \a length (in bytes), whichever is smallest. 602 \param buf a pointer to a buffer to be filled with dirent structures of 603 the found entries 604 \param length the maximal number of entries to be read. 605 \note The iterator used by this method is the same one used by 606 GetNextEntry() and GetNextRef(). 607 \return 608 - The number of dirent structures stored in the buffer, 0 when there are 609 no more entries to be read. 610 - \c B_BAD_VALUE: The queries predicate includes unindexed attributes. 611 - \c B_FILE_ERROR: Fetch() has not been called before. 612 */ 613 int32 614 BQuery::GetNextDirents(struct dirent *buf, size_t length, int32 count) 615 { 616 int32 result = (buf ? B_OK : B_BAD_VALUE); 617 if (result == B_OK && !_HasFetched()) 618 result = B_FILE_ERROR; 619 if (result == B_OK) 620 result = read_query(fQueryFd, buf, length, count); 621 return result; 622 } 623 624 // Rewind 625 /*! \brief Unimplemented method of the BEntryList interface. 626 \return \c B_ERROR. 627 */ 628 status_t 629 BQuery::Rewind() 630 { 631 return B_ERROR; 632 } 633 634 // CountEntries 635 /*! \brief Unimplemented method of the BEntryList interface. 636 \return 0. 637 */ 638 int32 639 BQuery::CountEntries() 640 { 641 return B_ERROR; 642 } 643 644 // _HasFetched 645 /*! Returns whether Fetch() has already been called on this object. 646 \return \c true, if Fetch() has successfully been invoked, \c false 647 otherwise. 648 */ 649 bool 650 BQuery::_HasFetched() const 651 { 652 return (fQueryFd != NullFd); 653 } 654 655 // _PushNode 656 /*! \brief Pushs a node onto the predicate stack. 657 If the stack has not been allocate until this time, this method does 658 allocate it. 659 If the supplied node is \c NULL, it is assumed that there was not enough 660 memory to allocate the node and thus \c B_NO_MEMORY is returned. 661 In case the method fails, the caller retains the ownership of the supplied 662 node and thus is responsible for deleting it, if \a deleteOnError is 663 \c false. If it is \c true, the node is deleted, if an error occurs. 664 \param node the node to be pushed 665 \param deleteOnError 666 \return 667 - \c B_OK: Everything went fine. 668 - \c B_NO_MEMORY: \c NULL \a node or insuffient memory to allocate the 669 predicate stack or push the node. 670 - \c B_NOT_ALLOWED: _PushNode() was called after Fetch(). 671 */ 672 status_t 673 BQuery::_PushNode(QueryNode *node, bool deleteOnError) 674 { 675 status_t error = (node ? B_OK : B_NO_MEMORY); 676 if (error == B_OK && _HasFetched()) 677 error = B_NOT_ALLOWED; 678 // allocate the stack, if necessary 679 if (error == B_OK && !fStack) { 680 fStack = new(nothrow) QueryStack; 681 if (!fStack) 682 error = B_NO_MEMORY; 683 } 684 if (error == B_OK) 685 error = fStack->PushNode(node); 686 if (error != B_OK && deleteOnError) 687 delete node; 688 return error; 689 } 690 691 // _SetPredicate 692 /*! \brief Helper method to set the BQuery's predicate. 693 It is not checked whether Fetch() has already been invoked. 694 \param predicate the predicate string 695 \return 696 - \c B_OK: Everything went fine. 697 - \c B_NO_MEMORY: Insufficient memory to store the predicate. 698 */ 699 status_t 700 BQuery::_SetPredicate(const char *expression) 701 { 702 status_t error = B_OK; 703 // unset the old predicate 704 delete[] fPredicate; 705 fPredicate = NULL; 706 // set the new one 707 if (expression) { 708 fPredicate = new(nothrow) char[strlen(expression) + 1]; 709 if (fPredicate) 710 strcpy(fPredicate, expression); 711 else 712 error = B_NO_MEMORY; 713 } 714 return error; 715 } 716 717 // _EvaluateStack 718 /*! Evaluates the query's predicate stack. 719 The method does nothing (and returns \c B_OK), if the stack is \c NULL. 720 If the stack is non-null and Fetch() has already been called, the method 721 fails. 722 \return 723 - \c B_OK: Everything went fine. 724 - \c B_NO_MEMORY: Insufficient memory. 725 - \c B_NOT_ALLOWED: _EvaluateStack() was called after Fetch(). 726 - another error code 727 */ 728 status_t 729 BQuery::_EvaluateStack() 730 { 731 status_t error = B_OK; 732 if (fStack) { 733 _SetPredicate(NULL); 734 if (_HasFetched()) 735 error = B_NOT_ALLOWED; 736 // convert the stack to a tree and evaluate it 737 QueryNode *node = NULL; 738 if (error == B_OK) 739 error = fStack->ConvertToTree(node); 740 BString predicate; 741 if (error == B_OK) 742 error = node->GetString(predicate); 743 if (error == B_OK) 744 error = _SetPredicate(predicate.String()); 745 delete fStack; 746 fStack = NULL; 747 } 748 return error; 749 } 750 751 752 // FBC 753 void BQuery::_QwertyQuery1() {} 754 void BQuery::_QwertyQuery2() {} 755 void BQuery::_QwertyQuery3() {} 756 void BQuery::_QwertyQuery4() {} 757 void BQuery::_QwertyQuery5() {} 758 void BQuery::_QwertyQuery6() {} 759 760 761 762