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