headers/bsd: Add sys/queue.h.
[haiku.git] / src / kits / storage / QueryPredicate.cpp
blobbb48f961cc1aca3166dae3728140f56fcee45c9d
1 /*
2 * Copyright 2002-2008, Haiku Inc.
3 * Distributed under the terms of the MIT License.
5 * Authors:
6 * Tyler Dauwalder
7 */
9 /*!
10 \file QueryPredicate.cpp
11 BQuery predicate helper classes implementation.
14 #include "QueryPredicate.h"
16 #include <ctype.h>
18 #include <UnicodeChar.h>
21 namespace BPrivate {
22 namespace Storage {
24 // #pragma mark - QueryNode
27 QueryNode::QueryNode()
32 QueryNode::~QueryNode()
37 // #pragma mark - LeafNode
40 LeafNode::LeafNode()
45 LeafNode::~LeafNode()
50 uint32
51 LeafNode::Arity() const
53 return 0;
57 status_t
58 LeafNode::SetChildAt(QueryNode *child, int32 index)
60 return B_BAD_VALUE;
64 QueryNode *
65 LeafNode::ChildAt(int32 index)
67 return NULL;
71 // #pragma mark - UnaryNode
74 UnaryNode::UnaryNode()
76 fChild(NULL)
81 UnaryNode::~UnaryNode()
83 delete fChild;
87 uint32
88 UnaryNode::Arity() const
90 return 1;
94 status_t
95 UnaryNode::SetChildAt(QueryNode *child, int32 index)
97 status_t error = B_OK;
98 if (index == 0) {
99 delete fChild;
100 fChild = child;
101 } else
102 error = B_BAD_VALUE;
103 return error;
107 QueryNode *
108 UnaryNode::ChildAt(int32 index)
110 QueryNode *result = NULL;
111 if (index == 0)
112 result = fChild;
113 return result;
117 // #pragma mark - BinaryNode
120 BinaryNode::BinaryNode()
122 fChild1(NULL),
123 fChild2(NULL)
128 BinaryNode::~BinaryNode()
130 delete fChild1;
131 delete fChild2;
135 uint32
136 BinaryNode::Arity() const
138 return 2;
142 status_t
143 BinaryNode::SetChildAt(QueryNode *child, int32 index)
145 status_t error = B_OK;
146 if (index == 0) {
147 delete fChild1;
148 fChild1 = child;
149 } else if (index == 1) {
150 delete fChild2;
151 fChild2 = child;
152 } else
153 error = B_BAD_VALUE;
154 return error;
158 QueryNode *
159 BinaryNode::ChildAt(int32 index)
161 QueryNode *result = NULL;
162 if (index == 0)
163 result = fChild1;
164 else if (index == 1)
165 result = fChild2;
166 return result;
170 // #pragma mark - AttributeNode
173 AttributeNode::AttributeNode(const char *attribute)
175 fAttribute(attribute)
180 status_t
181 AttributeNode::GetString(BString &predicate)
183 predicate.SetTo(fAttribute);
184 return B_OK;
188 // #pragma mark - StringNode
191 StringNode::StringNode(const char *value, bool caseInsensitive)
193 if (value == NULL)
194 return;
196 if (caseInsensitive) {
197 while (uint32 codePoint = BUnicodeChar::FromUTF8(&value)) {
198 char utf8Buffer[4];
199 char *utf8 = utf8Buffer;
200 if (BUnicodeChar::IsAlpha(codePoint)) {
201 uint32 lower = BUnicodeChar::ToLower(codePoint);
202 uint32 upper = BUnicodeChar::ToUpper(codePoint);
203 if (lower == upper) {
204 BUnicodeChar::ToUTF8(codePoint, &utf8);
205 fValue.Append(utf8Buffer, utf8 - utf8Buffer);
206 } else {
207 fValue << "[";
208 BUnicodeChar::ToUTF8(lower, &utf8);
209 fValue.Append(utf8Buffer, utf8 - utf8Buffer);
210 utf8 = utf8Buffer;
211 BUnicodeChar::ToUTF8(upper, &utf8);
212 fValue.Append(utf8Buffer, utf8 - utf8Buffer);
213 fValue << "]";
215 } else if (codePoint == L' ') {
216 fValue << '*';
217 } else {
218 BUnicodeChar::ToUTF8(codePoint, &utf8);
219 fValue.Append(utf8Buffer, utf8 - utf8Buffer);
222 } else {
223 fValue = value;
224 fValue.ReplaceAll(' ', '*');
229 status_t
230 StringNode::GetString(BString &predicate)
232 BString escaped(fValue);
233 escaped.CharacterEscape("\"\\'", '\\');
234 predicate.SetTo("");
235 predicate << "\"" << escaped << "\"";
236 return B_OK;
240 // #pragma mark - DateNode
243 DateNode::DateNode(const char *value)
245 fValue(value)
250 status_t
251 DateNode::GetString(BString &predicate)
253 BString escaped(fValue);
254 escaped.CharacterEscape("%\"\\'", '\\');
255 predicate.SetTo("");
256 predicate << "%" << escaped << "%";
257 return B_OK;
261 // #pragma mark - ValueNode
264 template<>
265 status_t
266 ValueNode<float>::GetString(BString &predicate)
268 char buffer[32];
269 union {
270 int32 asInteger;
271 float asFloat;
272 } value;
273 value.asFloat = fValue;
274 // int32 value = *reinterpret_cast<int32*>(&fValue);
275 sprintf(buffer, "0x%08" B_PRIx32, value.asInteger);
276 predicate.SetTo(buffer);
277 return B_OK;
281 template<>
282 status_t
283 ValueNode<double>::GetString(BString &predicate)
285 char buffer[32];
286 union {
287 int64 asInteger;
288 double asFloat;
289 } value;
290 // int64 value = *reinterpret_cast<int64*>(&fValue);
291 value.asFloat = fValue;
292 sprintf(buffer, "0x%016" B_PRIx64, value.asInteger);
293 predicate.SetTo(buffer);
294 return B_OK;
298 // #pragma mark - SpecialOpNode
301 SpecialOpNode::SpecialOpNode(query_op op)
303 fOp(op)
308 status_t
309 SpecialOpNode::GetString(BString &predicate)
311 return B_BAD_VALUE;
315 // #pragma mark - UnaryOpNode
318 UnaryOpNode::UnaryOpNode(query_op op)
320 fOp(op)
325 status_t
326 UnaryOpNode::GetString(BString &predicate)
328 status_t error = (fChild ? B_OK : B_BAD_VALUE);
329 if (error == B_OK) {
330 if (fOp == B_NOT) {
331 BString childString;
332 error = fChild->GetString(childString);
333 predicate.SetTo("(!");
334 predicate << childString << ")";
335 } else
336 error = B_BAD_VALUE;
338 return error;
342 // #pragma mark - BinaryOpNode
345 BinaryOpNode::BinaryOpNode(query_op op)
347 fOp(op)
352 status_t
353 BinaryOpNode::GetString(BString &predicate)
355 status_t error = (fChild1 && fChild2 ? B_OK : B_BAD_VALUE);
356 BString childString1;
357 BString childString2;
358 if (error == B_OK)
359 error = fChild1->GetString(childString1);
360 if (error == B_OK)
361 error = fChild2->GetString(childString2);
362 predicate.SetTo("");
363 if (error == B_OK) {
364 switch (fOp) {
365 case B_EQ:
366 predicate << "(" << childString1 << "=="
367 << childString2 << ")";
368 break;
369 case B_GT:
370 predicate << "(" << childString1 << ">"
371 << childString2 << ")";
372 break;
373 case B_GE:
374 predicate << "(" << childString1 << ">="
375 << childString2 << ")";
376 break;
377 case B_LT:
378 predicate << "(" << childString1 << "<"
379 << childString2 << ")";
380 break;
381 case B_LE:
382 predicate << "(" << childString1 << "<="
383 << childString2 << ")";
384 break;
385 case B_NE:
386 predicate << "(" << childString1 << "!="
387 << childString2 << ")";
388 break;
389 case B_CONTAINS:
390 if (StringNode *strNode = dynamic_cast<StringNode*>(fChild2)) {
391 BString value;
392 value << "*" << strNode->Value() << "*";
393 error = StringNode(value.String()).GetString(childString2);
395 if (error == B_OK) {
396 predicate << "(" << childString1 << "=="
397 << childString2 << ")";
399 break;
400 case B_BEGINS_WITH:
401 if (StringNode *strNode = dynamic_cast<StringNode*>(fChild2)) {
402 BString value;
403 value << strNode->Value() << "*";
404 error = StringNode(value.String()).GetString(childString2);
406 if (error == B_OK) {
407 predicate << "(" << childString1 << "=="
408 << childString2 << ")";
410 break;
411 case B_ENDS_WITH:
412 if (StringNode *strNode = dynamic_cast<StringNode*>(fChild2)) {
413 BString value;
414 value << "*" << strNode->Value();
415 error = StringNode(value.String()).GetString(childString2);
417 if (error == B_OK) {
418 predicate << "(" << childString1 << "=="
419 << childString2 << ")";
421 break;
422 case B_AND:
423 predicate << "(" << childString1 << "&&"
424 << childString2 << ")";
425 break;
426 case B_OR:
427 predicate << "(" << childString1 << "||"
428 << childString2 << ")";
429 break;
430 default:
431 error = B_BAD_VALUE;
432 break;
435 return error;
439 // #pragma mark - QueryStack
442 QueryStack::QueryStack()
447 QueryStack::~QueryStack()
449 for (int32 i = 0; QueryNode *node = (QueryNode*)fNodes.ItemAt(i); i++)
450 delete node;
454 status_t
455 QueryStack::PushNode(QueryNode *node)
457 status_t error = (node ? B_OK : B_BAD_VALUE);
458 if (error == B_OK) {
459 if (!fNodes.AddItem(node))
460 error = B_NO_MEMORY;
462 return error;
466 QueryNode *
467 QueryStack::PopNode()
469 return (QueryNode*)fNodes.RemoveItem(fNodes.CountItems() - 1);
473 status_t
474 QueryStack::ConvertToTree(QueryNode *&rootNode)
476 status_t error = _GetSubTree(rootNode);
477 if (error == B_OK && !fNodes.IsEmpty()) {
478 error = B_BAD_VALUE;
479 delete rootNode;
480 rootNode = NULL;
482 return error;
486 status_t
487 QueryStack::_GetSubTree(QueryNode *&rootNode)
489 QueryNode *node = PopNode();
490 status_t error = (node ? B_OK : B_BAD_VALUE);
491 if (error == B_OK) {
492 uint32 arity = node->Arity();
493 for (int32 i = (int32)arity - 1; error == B_OK && i >= 0; i--) {
494 QueryNode *child = NULL;
495 error = _GetSubTree(child);
496 if (error == B_OK) {
497 error = node->SetChildAt(child, i);
498 if (error != B_OK)
499 delete child;
503 // clean up, if something went wrong
504 if (error != B_OK && node) {
505 delete node;
506 node = NULL;
508 rootNode = node;
509 return error;
513 } // namespace Storage
514 } // namespace BPrivate