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