xref: /haiku/src/kits/storage/QueryPredicate.cpp (revision b289aaf66bbf6e173aa90fa194fc256965f1b34d)
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 
19 namespace BPrivate {
20 namespace Storage {
21 
22 // #pragma mark - QueryNode
23 
24 
25 QueryNode::QueryNode()
26 {
27 }
28 
29 
30 QueryNode::~QueryNode()
31 {
32 }
33 
34 
35 // #pragma mark - LeafNode
36 
37 
38 LeafNode::LeafNode()
39 {
40 }
41 
42 
43 LeafNode::~LeafNode()
44 {
45 }
46 
47 
48 uint32
49 LeafNode::Arity() const
50 {
51 	return 0;
52 }
53 
54 
55 status_t
56 LeafNode::SetChildAt(QueryNode *child, int32 index)
57 {
58 	return B_BAD_VALUE;
59 }
60 
61 
62 QueryNode *
63 LeafNode::ChildAt(int32 index)
64 {
65 	return NULL;
66 }
67 
68 
69 // #pragma mark - UnaryNode
70 
71 
72 UnaryNode::UnaryNode()
73 	:
74 	fChild(NULL)
75 {
76 }
77 
78 
79 UnaryNode::~UnaryNode()
80 {
81 	delete fChild;
82 }
83 
84 
85 uint32
86 UnaryNode::Arity() const
87 {
88 	return 1;
89 }
90 
91 
92 status_t
93 UnaryNode::SetChildAt(QueryNode *child, int32 index)
94 {
95 	status_t error = B_OK;
96 	if (index == 0) {
97 		delete fChild;
98 		fChild = child;
99 	} else
100 		error = B_BAD_VALUE;
101 	return error;
102 }
103 
104 
105 QueryNode *
106 UnaryNode::ChildAt(int32 index)
107 {
108 	QueryNode *result = NULL;
109 	if (index == 0)
110 		result = fChild;
111 	return result;
112 }
113 
114 
115 // #pragma mark - BinaryNode
116 
117 
118 BinaryNode::BinaryNode()
119 	:
120 	fChild1(NULL),
121 	fChild2(NULL)
122 {
123 }
124 
125 
126 BinaryNode::~BinaryNode()
127 {
128 	delete fChild1;
129 	delete fChild2;
130 }
131 
132 
133 uint32
134 BinaryNode::Arity() const
135 {
136 	return 2;
137 }
138 
139 
140 status_t
141 BinaryNode::SetChildAt(QueryNode *child, int32 index)
142 {
143 	status_t error = B_OK;
144 	if (index == 0) {
145 		delete fChild1;
146 		fChild1 = child;
147 	} else if (index == 1) {
148 		delete fChild2;
149 		fChild2 = child;
150 	} else
151 		error = B_BAD_VALUE;
152 	return error;
153 }
154 
155 
156 QueryNode *
157 BinaryNode::ChildAt(int32 index)
158 {
159 	QueryNode *result = NULL;
160 	if (index == 0)
161 		result = fChild1;
162 	else if (index == 1)
163 		result = fChild2;
164 	return result;
165 }
166 
167 
168 // #pragma mark - AttributeNode
169 
170 
171 AttributeNode::AttributeNode(const char *attribute)
172 	:
173 	fAttribute(attribute)
174 {
175 }
176 
177 
178 status_t
179 AttributeNode::GetString(BString &predicate)
180 {
181 	predicate.SetTo(fAttribute);
182 	return B_OK;
183 }
184 
185 
186 // #pragma mark - StringNode
187 
188 
189 StringNode::StringNode(const char *value, bool caseInsensitive)
190 {
191 	if (value == NULL)
192 		return;
193 
194 	if (caseInsensitive) {
195 		int32 len = strlen(value);
196 		for (int32 i = 0; i < len; i++) {
197 			char c = value[i];
198 			if (isalpha(c)) {
199 				int lower = tolower(c);
200 				int upper = toupper(c);
201 				if (lower < 0 || upper < 0)
202 					fValue << c;
203 				else
204 					fValue << "[" << (char)lower << (char)upper << "]";
205 			} else if (c == ' ')
206 				fValue << '*';
207 			else
208 				fValue << c;
209 		}
210 	} else {
211 		fValue = value;
212 		fValue.ReplaceAll(' ', '*');
213 	}
214 }
215 
216 
217 status_t
218 StringNode::GetString(BString &predicate)
219 {
220 	BString escaped(fValue);
221 	escaped.CharacterEscape("\"\\'", '\\');
222 	predicate.SetTo("");
223 	predicate << "\"" << escaped << "\"";
224 	return B_OK;
225 }
226 
227 
228 // #pragma mark - DateNode
229 
230 
231 DateNode::DateNode(const char *value)
232 	:
233 	fValue(value)
234 {
235 }
236 
237 
238 status_t
239 DateNode::GetString(BString &predicate)
240 {
241 	BString escaped(fValue);
242 	escaped.CharacterEscape("%\"\\'", '\\');
243 	predicate.SetTo("");
244 	predicate << "%" << escaped << "%";
245 	return B_OK;
246 }
247 
248 
249 // #pragma mark - ValueNode
250 
251 
252 template<>
253 status_t
254 ValueNode<float>::GetString(BString &predicate)
255 {
256 	char buffer[32];
257 	int32 value = *reinterpret_cast<int32*>(&fValue);
258 	sprintf(buffer, "0x%08lx", value);
259 	predicate.SetTo(buffer);
260 	return B_OK;
261 }
262 
263 
264 template<>
265 status_t
266 ValueNode<double>::GetString(BString &predicate)
267 {
268 	char buffer[32];
269 	int64 value = *reinterpret_cast<int64*>(&fValue);
270 	sprintf(buffer, "0x%016Lx", value);
271 	predicate.SetTo(buffer);
272 	return B_OK;
273 }
274 
275 
276 // #pragma mark - SpecialOpNode
277 
278 
279 SpecialOpNode::SpecialOpNode(query_op op)
280 	:
281 	fOp(op)
282 {
283 }
284 
285 
286 status_t
287 SpecialOpNode::GetString(BString &predicate)
288 {
289 	return B_BAD_VALUE;
290 }
291 
292 
293 // #pragma mark - UnaryOpNode
294 
295 
296 UnaryOpNode::UnaryOpNode(query_op op)
297 	:
298 	fOp(op)
299 {
300 }
301 
302 
303 status_t
304 UnaryOpNode::GetString(BString &predicate)
305 {
306 	status_t error = (fChild ? B_OK : B_BAD_VALUE);
307 	if (error == B_OK) {
308 		if (fOp == B_NOT) {
309 			BString childString;
310 			error = fChild->GetString(childString);
311 			predicate.SetTo("(!");
312 			predicate << childString << ")";
313 		} else
314 			error = B_BAD_VALUE;
315 	}
316 	return error;
317 }
318 
319 
320 // #pragma mark - BinaryOpNode
321 
322 
323 BinaryOpNode::BinaryOpNode(query_op op)
324 	:
325 	fOp(op)
326 {
327 }
328 
329 
330 status_t
331 BinaryOpNode::GetString(BString &predicate)
332 {
333 	status_t error = (fChild1 && fChild2 ? B_OK : B_BAD_VALUE);
334 	BString childString1;
335 	BString childString2;
336 	if (error == B_OK)
337 		error = fChild1->GetString(childString1);
338 	if (error == B_OK)
339 		error = fChild2->GetString(childString2);
340 	predicate.SetTo("");
341 	if (error == B_OK) {
342 		switch (fOp) {
343 			case B_EQ:
344 				predicate << "(" << childString1 << "=="
345 					<< childString2 << ")";
346 				break;
347 			case B_GT:
348 				predicate << "(" << childString1 << ">"
349 					<< childString2 << ")";
350 				break;
351 			case B_GE:
352 				predicate << "(" << childString1 << ">="
353 					<< childString2 << ")";
354 				break;
355 			case B_LT:
356 				predicate << "(" << childString1 << "<"
357 					<< childString2 << ")";
358 				break;
359 			case B_LE:
360 				predicate << "(" << childString1 << "<="
361 					<< childString2 << ")";
362 				break;
363 			case B_NE:
364 				predicate << "(" << childString1 << "!="
365 					<< childString2 << ")";
366 				break;
367 			case B_CONTAINS:
368 				if (StringNode *strNode = dynamic_cast<StringNode*>(fChild2)) {
369 					BString value;
370 					value << "*" << strNode->Value() << "*";
371 					error = StringNode(value.String()).GetString(childString2);
372 				}
373 				if (error == B_OK) {
374 					predicate << "(" << childString1 << "=="
375 						<< childString2 << ")";
376 				}
377 				break;
378 			case B_BEGINS_WITH:
379 				if (StringNode *strNode = dynamic_cast<StringNode*>(fChild2)) {
380 					BString value;
381 					value << strNode->Value() << "*";
382 					error = StringNode(value.String()).GetString(childString2);
383 				}
384 				if (error == B_OK) {
385 					predicate << "(" << childString1 << "=="
386 						<< childString2 << ")";
387 				}
388 				break;
389 			case B_ENDS_WITH:
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_AND:
401 				predicate << "(" << childString1 << "&&"
402 					<< childString2 << ")";
403 				break;
404 			case B_OR:
405 				predicate << "(" << childString1 << "||"
406 					<< childString2 << ")";
407 				break;
408 			default:
409 				error = B_BAD_VALUE;
410 				break;
411 		}
412 	}
413 	return error;
414 }
415 
416 
417 // #pragma mark - QueryStack
418 
419 
420 QueryStack::QueryStack()
421 {
422 }
423 
424 
425 QueryStack::~QueryStack()
426 {
427 	for (int32 i = 0; QueryNode *node = (QueryNode*)fNodes.ItemAt(i); i++)
428 		delete node;
429 }
430 
431 
432 status_t
433 QueryStack::PushNode(QueryNode *node)
434 {
435 	status_t error = (node ? B_OK : B_BAD_VALUE);
436 	if (error == B_OK) {
437 		if (!fNodes.AddItem(node))
438 			error = B_NO_MEMORY;
439 	}
440 	return error;
441 }
442 
443 
444 QueryNode *
445 QueryStack::PopNode()
446 {
447 	return (QueryNode*)fNodes.RemoveItem(fNodes.CountItems() - 1);
448 }
449 
450 
451 status_t
452 QueryStack::ConvertToTree(QueryNode *&rootNode)
453 {
454 	status_t error = _GetSubTree(rootNode);
455 	if (error == B_OK && !fNodes.IsEmpty()) {
456 		error = B_BAD_VALUE;
457 		delete rootNode;
458 		rootNode = NULL;
459 	}
460 	return error;
461 }
462 
463 
464 status_t
465 QueryStack::_GetSubTree(QueryNode *&rootNode)
466 {
467 	QueryNode *node = PopNode();
468 	status_t error = (node ? B_OK : B_BAD_VALUE);
469 	if (error == B_OK) {
470 		uint32 arity = node->Arity();
471 		for (int32 i = (int32)arity - 1; error == B_OK && i >= 0; i--) {
472 			QueryNode *child = NULL;
473 			error = _GetSubTree(child);
474 			if (error == B_OK) {
475 				error = node->SetChildAt(child, i);
476 				if (error != B_OK)
477 					delete child;
478 			}
479 		}
480 	}
481 	// clean up, if something went wrong
482 	if (error != B_OK && node) {
483 		delete node;
484 		node = NULL;
485 	}
486 	rootNode = node;
487 	return error;
488 }
489 
490 
491 }	// namespace Storage
492 }	// namespace BPrivate
493