xref: /haiku/src/kits/storage/Query.cpp (revision 32b8ee2e940cad78263723c8fd52062db2478dea)
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