xref: /haiku/src/kits/storage/QueryPredicate.cpp (revision 25a7b01d15612846f332751841da3579db313082)
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