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