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