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
21namespace BPrivate {
22namespace Storage {
23
24// #pragma mark - QueryNode
25
26
27QueryNode::QueryNode()
28{
29}
30
31
32QueryNode::~QueryNode()
33{
34}
35
36
37// #pragma mark - LeafNode
38
39
40LeafNode::LeafNode()
41{
42}
43
44
45LeafNode::~LeafNode()
46{
47}
48
49
50uint32
51LeafNode::Arity() const
52{
53	return 0;
54}
55
56
57status_t
58LeafNode::SetChildAt(QueryNode *child, int32 index)
59{
60	return B_BAD_VALUE;
61}
62
63
64QueryNode *
65LeafNode::ChildAt(int32 index)
66{
67	return NULL;
68}
69
70
71// #pragma mark - UnaryNode
72
73
74UnaryNode::UnaryNode()
75	:
76	fChild(NULL)
77{
78}
79
80
81UnaryNode::~UnaryNode()
82{
83	delete fChild;
84}
85
86
87uint32
88UnaryNode::Arity() const
89{
90	return 1;
91}
92
93
94status_t
95UnaryNode::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
107QueryNode *
108UnaryNode::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
120BinaryNode::BinaryNode()
121	:
122	fChild1(NULL),
123	fChild2(NULL)
124{
125}
126
127
128BinaryNode::~BinaryNode()
129{
130	delete fChild1;
131	delete fChild2;
132}
133
134
135uint32
136BinaryNode::Arity() const
137{
138	return 2;
139}
140
141
142status_t
143BinaryNode::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
158QueryNode *
159BinaryNode::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
173AttributeNode::AttributeNode(const char *attribute)
174	:
175	fAttribute(attribute)
176{
177}
178
179
180status_t
181AttributeNode::GetString(BString &predicate)
182{
183	predicate.SetTo(fAttribute);
184	return B_OK;
185}
186
187
188// #pragma mark - StringNode
189
190
191StringNode::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
229status_t
230StringNode::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
243DateNode::DateNode(const char *value)
244	:
245	fValue(value)
246{
247}
248
249
250status_t
251DateNode::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
264template<>
265status_t
266ValueNode<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
281template<>
282status_t
283ValueNode<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
301SpecialOpNode::SpecialOpNode(query_op op)
302	:
303	fOp(op)
304{
305}
306
307
308status_t
309SpecialOpNode::GetString(BString &predicate)
310{
311	return B_BAD_VALUE;
312}
313
314
315// #pragma mark - UnaryOpNode
316
317
318UnaryOpNode::UnaryOpNode(query_op op)
319	:
320	fOp(op)
321{
322}
323
324
325status_t
326UnaryOpNode::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
345BinaryOpNode::BinaryOpNode(query_op op)
346	:
347	fOp(op)
348{
349}
350
351
352status_t
353BinaryOpNode::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
442QueryStack::QueryStack()
443{
444}
445
446
447QueryStack::~QueryStack()
448{
449	for (int32 i = 0; QueryNode *node = (QueryNode*)fNodes.ItemAt(i); i++)
450		delete node;
451}
452
453
454status_t
455QueryStack::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
466QueryNode *
467QueryStack::PopNode()
468{
469	return (QueryNode*)fNodes.RemoveItem(fNodes.CountItems() - 1);
470}
471
472
473status_t
474QueryStack::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
486status_t
487QueryStack::_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