1 /*
2 * Copyright 2002-2008, Haiku Inc.
3 * Distributed under the terms of the MIT License.
4 *
5 * Authors:
6 * Tyler Dauwalder
7 */
8
9 /*!
10 \file QueryPredicate.cpp
11 BQuery predicate helper classes implementation.
12 */
13
14 #include "QueryPredicate.h"
15
16 #include <ctype.h>
17
18 #include <UnicodeChar.h>
19
20
21 namespace BPrivate {
22 namespace Storage {
23
24 // #pragma mark - QueryNode
25
26
QueryNode()27 QueryNode::QueryNode()
28 {
29 }
30
31
~QueryNode()32 QueryNode::~QueryNode()
33 {
34 }
35
36
37 // #pragma mark - LeafNode
38
39
LeafNode()40 LeafNode::LeafNode()
41 {
42 }
43
44
~LeafNode()45 LeafNode::~LeafNode()
46 {
47 }
48
49
50 uint32
Arity() const51 LeafNode::Arity() const
52 {
53 return 0;
54 }
55
56
57 status_t
SetChildAt(QueryNode * child,int32 index)58 LeafNode::SetChildAt(QueryNode *child, int32 index)
59 {
60 return B_BAD_VALUE;
61 }
62
63
64 QueryNode *
ChildAt(int32 index)65 LeafNode::ChildAt(int32 index)
66 {
67 return NULL;
68 }
69
70
71 // #pragma mark - UnaryNode
72
73
UnaryNode()74 UnaryNode::UnaryNode()
75 :
76 fChild(NULL)
77 {
78 }
79
80
~UnaryNode()81 UnaryNode::~UnaryNode()
82 {
83 delete fChild;
84 }
85
86
87 uint32
Arity() const88 UnaryNode::Arity() const
89 {
90 return 1;
91 }
92
93
94 status_t
SetChildAt(QueryNode * child,int32 index)95 UnaryNode::SetChildAt(QueryNode *child, int32 index)
96 {
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;
104 }
105
106
107 QueryNode *
ChildAt(int32 index)108 UnaryNode::ChildAt(int32 index)
109 {
110 QueryNode *result = NULL;
111 if (index == 0)
112 result = fChild;
113 return result;
114 }
115
116
117 // #pragma mark - BinaryNode
118
119
BinaryNode()120 BinaryNode::BinaryNode()
121 :
122 fChild1(NULL),
123 fChild2(NULL)
124 {
125 }
126
127
~BinaryNode()128 BinaryNode::~BinaryNode()
129 {
130 delete fChild1;
131 delete fChild2;
132 }
133
134
135 uint32
Arity() const136 BinaryNode::Arity() const
137 {
138 return 2;
139 }
140
141
142 status_t
SetChildAt(QueryNode * child,int32 index)143 BinaryNode::SetChildAt(QueryNode *child, int32 index)
144 {
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;
155 }
156
157
158 QueryNode *
ChildAt(int32 index)159 BinaryNode::ChildAt(int32 index)
160 {
161 QueryNode *result = NULL;
162 if (index == 0)
163 result = fChild1;
164 else if (index == 1)
165 result = fChild2;
166 return result;
167 }
168
169
170 // #pragma mark - AttributeNode
171
172
AttributeNode(const char * attribute)173 AttributeNode::AttributeNode(const char *attribute)
174 :
175 fAttribute(attribute)
176 {
177 }
178
179
180 status_t
GetString(BString & predicate)181 AttributeNode::GetString(BString &predicate)
182 {
183 predicate.SetTo(fAttribute);
184 return B_OK;
185 }
186
187
188 // #pragma mark - StringNode
189
190
StringNode(const char * value,bool caseInsensitive)191 StringNode::StringNode(const char *value, bool caseInsensitive)
192 {
193 if (value == NULL)
194 return;
195
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 << "]";
214 }
215 } else if (codePoint == L' ') {
216 fValue << '*';
217 } else {
218 BUnicodeChar::ToUTF8(codePoint, &utf8);
219 fValue.Append(utf8Buffer, utf8 - utf8Buffer);
220 }
221 }
222 } else {
223 fValue = value;
224 fValue.ReplaceAll(' ', '*');
225 }
226 }
227
228
229 status_t
GetString(BString & predicate)230 StringNode::GetString(BString &predicate)
231 {
232 BString escaped(fValue);
233 escaped.CharacterEscape("\"\\'", '\\');
234 predicate.SetTo("");
235 predicate << "\"" << escaped << "\"";
236 return B_OK;
237 }
238
239
240 // #pragma mark - DateNode
241
242
DateNode(const char * value)243 DateNode::DateNode(const char *value)
244 :
245 fValue(value)
246 {
247 }
248
249
250 status_t
GetString(BString & predicate)251 DateNode::GetString(BString &predicate)
252 {
253 BString escaped(fValue);
254 escaped.CharacterEscape("%\"\\'", '\\');
255 predicate.SetTo("");
256 predicate << "%" << escaped << "%";
257 return B_OK;
258 }
259
260
261 // #pragma mark - ValueNode
262
263
264 template<>
265 status_t
GetString(BString & predicate)266 ValueNode<float>::GetString(BString &predicate)
267 {
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;
278 }
279
280
281 template<>
282 status_t
GetString(BString & predicate)283 ValueNode<double>::GetString(BString &predicate)
284 {
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;
295 }
296
297
298 // #pragma mark - SpecialOpNode
299
300
SpecialOpNode(query_op op)301 SpecialOpNode::SpecialOpNode(query_op op)
302 :
303 fOp(op)
304 {
305 }
306
307
308 status_t
GetString(BString & predicate)309 SpecialOpNode::GetString(BString &predicate)
310 {
311 return B_BAD_VALUE;
312 }
313
314
315 // #pragma mark - UnaryOpNode
316
317
UnaryOpNode(query_op op)318 UnaryOpNode::UnaryOpNode(query_op op)
319 :
320 fOp(op)
321 {
322 }
323
324
325 status_t
GetString(BString & predicate)326 UnaryOpNode::GetString(BString &predicate)
327 {
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;
337 }
338 return error;
339 }
340
341
342 // #pragma mark - BinaryOpNode
343
344
BinaryOpNode(query_op op)345 BinaryOpNode::BinaryOpNode(query_op op)
346 :
347 fOp(op)
348 {
349 }
350
351
352 status_t
GetString(BString & predicate)353 BinaryOpNode::GetString(BString &predicate)
354 {
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);
394 }
395 if (error == B_OK) {
396 predicate << "(" << childString1 << "=="
397 << childString2 << ")";
398 }
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);
405 }
406 if (error == B_OK) {
407 predicate << "(" << childString1 << "=="
408 << childString2 << ")";
409 }
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);
416 }
417 if (error == B_OK) {
418 predicate << "(" << childString1 << "=="
419 << childString2 << ")";
420 }
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;
433 }
434 }
435 return error;
436 }
437
438
439 // #pragma mark - QueryStack
440
441
QueryStack()442 QueryStack::QueryStack()
443 {
444 }
445
446
~QueryStack()447 QueryStack::~QueryStack()
448 {
449 for (int32 i = 0; QueryNode *node = (QueryNode*)fNodes.ItemAt(i); i++)
450 delete node;
451 }
452
453
454 status_t
PushNode(QueryNode * node)455 QueryStack::PushNode(QueryNode *node)
456 {
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;
461 }
462 return error;
463 }
464
465
466 QueryNode *
PopNode()467 QueryStack::PopNode()
468 {
469 return (QueryNode*)fNodes.RemoveItem(fNodes.CountItems() - 1);
470 }
471
472
473 status_t
ConvertToTree(QueryNode * & rootNode)474 QueryStack::ConvertToTree(QueryNode *&rootNode)
475 {
476 status_t error = _GetSubTree(rootNode);
477 if (error == B_OK && !fNodes.IsEmpty()) {
478 error = B_BAD_VALUE;
479 delete rootNode;
480 rootNode = NULL;
481 }
482 return error;
483 }
484
485
486 status_t
_GetSubTree(QueryNode * & rootNode)487 QueryStack::_GetSubTree(QueryNode *&rootNode)
488 {
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;
500 }
501 }
502 }
503 // clean up, if something went wrong
504 if (error != B_OK && node) {
505 delete node;
506 node = NULL;
507 }
508 rootNode = node;
509 return error;
510 }
511
512
513 } // namespace Storage
514 } // namespace BPrivate
515