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