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