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 int32 value = *reinterpret_cast<int32*>(&fValue); 258 sprintf(buffer, "0x%08lx", value); 259 predicate.SetTo(buffer); 260 return B_OK; 261 } 262 263 264 template<> 265 status_t 266 ValueNode<double>::GetString(BString &predicate) 267 { 268 char buffer[32]; 269 int64 value = *reinterpret_cast<int64*>(&fValue); 270 sprintf(buffer, "0x%016Lx", value); 271 predicate.SetTo(buffer); 272 return B_OK; 273 } 274 275 276 // #pragma mark - SpecialOpNode 277 278 279 SpecialOpNode::SpecialOpNode(query_op op) 280 : 281 fOp(op) 282 { 283 } 284 285 286 status_t 287 SpecialOpNode::GetString(BString &predicate) 288 { 289 return B_BAD_VALUE; 290 } 291 292 293 // #pragma mark - UnaryOpNode 294 295 296 UnaryOpNode::UnaryOpNode(query_op op) 297 : 298 fOp(op) 299 { 300 } 301 302 303 status_t 304 UnaryOpNode::GetString(BString &predicate) 305 { 306 status_t error = (fChild ? B_OK : B_BAD_VALUE); 307 if (error == B_OK) { 308 if (fOp == B_NOT) { 309 BString childString; 310 error = fChild->GetString(childString); 311 predicate.SetTo("(!"); 312 predicate << childString << ")"; 313 } else 314 error = B_BAD_VALUE; 315 } 316 return error; 317 } 318 319 320 // #pragma mark - BinaryOpNode 321 322 323 BinaryOpNode::BinaryOpNode(query_op op) 324 : 325 fOp(op) 326 { 327 } 328 329 330 status_t 331 BinaryOpNode::GetString(BString &predicate) 332 { 333 status_t error = (fChild1 && fChild2 ? B_OK : B_BAD_VALUE); 334 BString childString1; 335 BString childString2; 336 if (error == B_OK) 337 error = fChild1->GetString(childString1); 338 if (error == B_OK) 339 error = fChild2->GetString(childString2); 340 predicate.SetTo(""); 341 if (error == B_OK) { 342 switch (fOp) { 343 case B_EQ: 344 predicate << "(" << childString1 << "==" 345 << childString2 << ")"; 346 break; 347 case B_GT: 348 predicate << "(" << childString1 << ">" 349 << childString2 << ")"; 350 break; 351 case B_GE: 352 predicate << "(" << childString1 << ">=" 353 << childString2 << ")"; 354 break; 355 case B_LT: 356 predicate << "(" << childString1 << "<" 357 << childString2 << ")"; 358 break; 359 case B_LE: 360 predicate << "(" << childString1 << "<=" 361 << childString2 << ")"; 362 break; 363 case B_NE: 364 predicate << "(" << childString1 << "!=" 365 << childString2 << ")"; 366 break; 367 case B_CONTAINS: 368 if (StringNode *strNode = dynamic_cast<StringNode*>(fChild2)) { 369 BString value; 370 value << "*" << strNode->Value() << "*"; 371 error = StringNode(value.String()).GetString(childString2); 372 } 373 if (error == B_OK) { 374 predicate << "(" << childString1 << "==" 375 << childString2 << ")"; 376 } 377 break; 378 case B_BEGINS_WITH: 379 if (StringNode *strNode = dynamic_cast<StringNode*>(fChild2)) { 380 BString value; 381 value << strNode->Value() << "*"; 382 error = StringNode(value.String()).GetString(childString2); 383 } 384 if (error == B_OK) { 385 predicate << "(" << childString1 << "==" 386 << childString2 << ")"; 387 } 388 break; 389 case B_ENDS_WITH: 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_AND: 401 predicate << "(" << childString1 << "&&" 402 << childString2 << ")"; 403 break; 404 case B_OR: 405 predicate << "(" << childString1 << "||" 406 << childString2 << ")"; 407 break; 408 default: 409 error = B_BAD_VALUE; 410 break; 411 } 412 } 413 return error; 414 } 415 416 417 // #pragma mark - QueryStack 418 419 420 QueryStack::QueryStack() 421 { 422 } 423 424 425 QueryStack::~QueryStack() 426 { 427 for (int32 i = 0; QueryNode *node = (QueryNode*)fNodes.ItemAt(i); i++) 428 delete node; 429 } 430 431 432 status_t 433 QueryStack::PushNode(QueryNode *node) 434 { 435 status_t error = (node ? B_OK : B_BAD_VALUE); 436 if (error == B_OK) { 437 if (!fNodes.AddItem(node)) 438 error = B_NO_MEMORY; 439 } 440 return error; 441 } 442 443 444 QueryNode * 445 QueryStack::PopNode() 446 { 447 return (QueryNode*)fNodes.RemoveItem(fNodes.CountItems() - 1); 448 } 449 450 451 status_t 452 QueryStack::ConvertToTree(QueryNode *&rootNode) 453 { 454 status_t error = _GetSubTree(rootNode); 455 if (error == B_OK && !fNodes.IsEmpty()) { 456 error = B_BAD_VALUE; 457 delete rootNode; 458 rootNode = NULL; 459 } 460 return error; 461 } 462 463 464 status_t 465 QueryStack::_GetSubTree(QueryNode *&rootNode) 466 { 467 QueryNode *node = PopNode(); 468 status_t error = (node ? B_OK : B_BAD_VALUE); 469 if (error == B_OK) { 470 uint32 arity = node->Arity(); 471 for (int32 i = (int32)arity - 1; error == B_OK && i >= 0; i--) { 472 QueryNode *child = NULL; 473 error = _GetSubTree(child); 474 if (error == B_OK) { 475 error = node->SetChildAt(child, i); 476 if (error != B_OK) 477 delete child; 478 } 479 } 480 } 481 // clean up, if something went wrong 482 if (error != B_OK && node) { 483 delete node; 484 node = NULL; 485 } 486 rootNode = node; 487 return error; 488 } 489 490 491 } // namespace Storage 492 } // namespace BPrivate 493