xref: /haiku/src/kits/storage/QueryPredicate.cpp (revision 4f2fd49bdc6078128b1391191e4edac647044c3d)
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 	sprintf(buffer, "0x%08lx", *(int32*)&fValue);
258 	predicate.SetTo(buffer);
259 	return B_OK;
260 }
261 
262 
263 template<>
264 status_t
265 ValueNode<double>::GetString(BString &predicate)
266 {
267 	char buffer[32];
268 	sprintf(buffer, "0x%016Lx", *(int64*)&fValue);
269 	predicate.SetTo(buffer);
270 	return B_OK;
271 }
272 
273 
274 // #pragma mark - SpecialOpNode
275 
276 
277 SpecialOpNode::SpecialOpNode(query_op op)
278 	:
279 	fOp(op)
280 {
281 }
282 
283 
284 status_t
285 SpecialOpNode::GetString(BString &predicate)
286 {
287 	return B_BAD_VALUE;
288 }
289 
290 
291 // #pragma mark - UnaryOpNode
292 
293 
294 UnaryOpNode::UnaryOpNode(query_op op)
295 	:
296 	fOp(op)
297 {
298 }
299 
300 
301 status_t
302 UnaryOpNode::GetString(BString &predicate)
303 {
304 	status_t error = (fChild ? B_OK : B_BAD_VALUE);
305 	if (error == B_OK) {
306 		if (fOp == B_NOT) {
307 			BString childString;
308 			error = fChild->GetString(childString);
309 			predicate.SetTo("(!");
310 			predicate << childString << ")";
311 		} else
312 			error = B_BAD_VALUE;
313 	}
314 	return error;
315 }
316 
317 
318 // #pragma mark - BinaryOpNode
319 
320 
321 BinaryOpNode::BinaryOpNode(query_op op)
322 	:
323 	fOp(op)
324 {
325 }
326 
327 
328 status_t
329 BinaryOpNode::GetString(BString &predicate)
330 {
331 	status_t error = (fChild1 && fChild2 ? B_OK : B_BAD_VALUE);
332 	BString childString1;
333 	BString childString2;
334 	if (error == B_OK)
335 		error = fChild1->GetString(childString1);
336 	if (error == B_OK)
337 		error = fChild2->GetString(childString2);
338 	predicate.SetTo("");
339 	if (error == B_OK) {
340 		switch (fOp) {
341 			case B_EQ:
342 				predicate << "(" << childString1 << "=="
343 					<< childString2 << ")";
344 				break;
345 			case B_GT:
346 				predicate << "(" << childString1 << ">"
347 					<< childString2 << ")";
348 				break;
349 			case B_GE:
350 				predicate << "(" << childString1 << ">="
351 					<< childString2 << ")";
352 				break;
353 			case B_LT:
354 				predicate << "(" << childString1 << "<"
355 					<< childString2 << ")";
356 				break;
357 			case B_LE:
358 				predicate << "(" << childString1 << "<="
359 					<< childString2 << ")";
360 				break;
361 			case B_NE:
362 				predicate << "(" << childString1 << "!="
363 					<< childString2 << ")";
364 				break;
365 			case B_CONTAINS:
366 				if (StringNode *strNode = dynamic_cast<StringNode*>(fChild2)) {
367 					BString value;
368 					value << "*" << strNode->Value() << "*";
369 					error = StringNode(value.String()).GetString(childString2);
370 				}
371 				if (error == B_OK) {
372 					predicate << "(" << childString1 << "=="
373 						<< childString2 << ")";
374 				}
375 				break;
376 			case B_BEGINS_WITH:
377 				if (StringNode *strNode = dynamic_cast<StringNode*>(fChild2)) {
378 					BString value;
379 					value << strNode->Value() << "*";
380 					error = StringNode(value.String()).GetString(childString2);
381 				}
382 				if (error == B_OK) {
383 					predicate << "(" << childString1 << "=="
384 						<< childString2 << ")";
385 				}
386 				break;
387 			case B_ENDS_WITH:
388 				if (StringNode *strNode = dynamic_cast<StringNode*>(fChild2)) {
389 					BString value;
390 					value << "*" << strNode->Value();
391 					error = StringNode(value.String()).GetString(childString2);
392 				}
393 				if (error == B_OK) {
394 					predicate << "(" << childString1 << "=="
395 						<< childString2 << ")";
396 				}
397 				break;
398 			case B_AND:
399 				predicate << "(" << childString1 << "&&"
400 					<< childString2 << ")";
401 				break;
402 			case B_OR:
403 				predicate << "(" << childString1 << "||"
404 					<< childString2 << ")";
405 				break;
406 			default:
407 				error = B_BAD_VALUE;
408 				break;
409 		}
410 	}
411 	return error;
412 }
413 
414 
415 // #pragma mark - QueryStack
416 
417 
418 QueryStack::QueryStack()
419 {
420 }
421 
422 
423 QueryStack::~QueryStack()
424 {
425 	for (int32 i = 0; QueryNode *node = (QueryNode*)fNodes.ItemAt(i); i++)
426 		delete node;
427 }
428 
429 
430 status_t
431 QueryStack::PushNode(QueryNode *node)
432 {
433 	status_t error = (node ? B_OK : B_BAD_VALUE);
434 	if (error == B_OK) {
435 		if (!fNodes.AddItem(node))
436 			error = B_NO_MEMORY;
437 	}
438 	return error;
439 }
440 
441 
442 QueryNode *
443 QueryStack::PopNode()
444 {
445 	return (QueryNode*)fNodes.RemoveItem(fNodes.CountItems() - 1);
446 }
447 
448 
449 status_t
450 QueryStack::ConvertToTree(QueryNode *&rootNode)
451 {
452 	status_t error = _GetSubTree(rootNode);
453 	if (error == B_OK && !fNodes.IsEmpty()) {
454 		error = B_BAD_VALUE;
455 		delete rootNode;
456 		rootNode = NULL;
457 	}
458 	return error;
459 }
460 
461 
462 status_t
463 QueryStack::_GetSubTree(QueryNode *&rootNode)
464 {
465 	QueryNode *node = PopNode();
466 	status_t error = (node ? B_OK : B_BAD_VALUE);
467 	if (error == B_OK) {
468 		uint32 arity = node->Arity();
469 		for (int32 i = (int32)arity - 1; error == B_OK && i >= 0; i--) {
470 			QueryNode *child = NULL;
471 			error = _GetSubTree(child);
472 			if (error == B_OK) {
473 				error = node->SetChildAt(child, i);
474 				if (error != B_OK)
475 					delete child;
476 			}
477 		}
478 	}
479 	// clean up, if something went wrong
480 	if (error != B_OK && node) {
481 		delete node;
482 		node = NULL;
483 	}
484 	rootNode = node;
485 	return error;
486 }
487 
488 
489 }	// namespace Storage
490 }	// namespace BPrivate
491