NCBI C++ Toolkit Cross Reference

  C++/include/gui/objutils/query_func_promote.hpp


1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602
#ifndef GUI_OBJUTILS___QUERY_FUNC_PROMOTE_HPP #define GUI_OBJUTILS___QUERY_FUNC_PROMOTE_HPP /* $Id: query_func_promote.hpp 30856 2014-07-31 03:26:51Z ucko $ * =========================================================================== * * PUBLIC DOMAIN NOTICE * National Center for Biotechnology Information * * This software/database is a "United States Government Work" under the * terms of the United States Copyright Act. It was written as part of * the author's official duties as a United States Government employee and * thus cannot be copyrighted. This software/database is freely available * to the public for use. The National Library of Medicine and the U.S. * Government have not placed any restriction on its use or reproduction. * * Although all reasonable efforts have been taken to ensure the accuracy * and reliability of the software and data, the NLM and the U.S. * Government do not and cannot warrant the performance or results that * may be obtained by using this software or data. The NLM and the U.S. * Government disclaim all warranties, express or implied, including * warranties of performance, merchantability or fitness for any particular * purpose. * * Please cite the author in any work or product based on this material. * * =========================================================================== * * Authors: Bob Falk * * File Description: * Header file for classes needed to implement query execution using a * type-promotion approach for comparisons * */ #include <corelib/ncbistl.hpp> #include <gui/gui_export.h> #include <objmgr/scope.hpp> #include <util/qparse/query_exec.hpp> BEGIN_NCBI_SCOPE //////////////////////////////////////////////////////////////////////////////// /// class CQueryExecException /// /// The different types of errors that can occur after the query is parsed while /// it is being executed. class NCBI_GUIOBJUTILS_EXPORT CQueryExecException : public CException { public: enum EErrCode { eNotPromotable, // Used if a type can't be promoted to another // type, e.g. 'dog' can't be prmoted to float. eIncompatibleType, // types which can't be compared, e.g. true AND "cat" eWrongArgumentCount, // Number of arguments for an operand are incorrect, // e.g. '==' has 3 operands. The initial parser // should catch all of these. eExecParseError, // If there are strings with multiple tokens during // execution, those may be parsed and evaluted, e.g. // in "dist>(2.0 * OtherDist)", (2 * OtherDist) // may be further parsed and found to be valid, // or it may throw this error if not. eObjManagerError, // Error when looking up/comparing seq-ids // during query execution eUnableToResolveData, // Unable to retrieve a field value from the data // source for a particular entry eFunctionExedError // Called a function but function execution failed }; virtual const char* GetErrCodeString(void) const { switch (GetErrCode()) { case eNotPromotable: return "eNotPromotable"; case eIncompatibleType: return "eIncompatibleType"; case eWrongArgumentCount: return "eWrongArgumentCount"; case eExecParseError: return "eExecParseError"; case eObjManagerError: return "eObjManagerError"; case eUnableToResolveData: return "eUnableToResolveData"; case eFunctionExedError: return "eFunctionExedError"; default: return CException::GetErrCodeString(); } } NCBI_EXCEPTION_DEFAULT(CQueryExecException, CException); }; namespace QueryValueType { /// Set of all possible types for nodes. Basic types are repeated based /// on their source to allow us to include the source of the data when /// deciding on how to promote somethig (e.g. did an int get parsed from /// a string in the query (e.g. the number "27" in (a=="27")), or was the /// int retrieved from a data field (e.g. in dist>0.4, the value /// for 'dist' comes from the current record/node being evaluated). enum EBaseType { eBoolResult, // result value from computing results in query sub-tree eBool, // boolean const eInt, // int const eFloat, // float const eString, // string which cannot be converted to another type eSeqID, // possible seq-id identifier eStringBool, // bool converted from a string in the query eStringInt, // integer converted form a string in the query eStringFloat, // float converted from a string in the query eFieldSeqID, // possible seq-id field value eFieldString, // string field value eFieldBool, // boolean field value eFieldFloat, // float field value eFieldInt, // integer field value eUndefined // incompatible types or other error }; string GetTypeAsString(EBaseType et); }; //////////////////////////////////////////////////////////////////////////////// /// class CPromoteRule /// /// This is a simple class meant to be an entry in a table representing /// promotion rules. Given the table, you can determine for any two types /// (and type information incldudes the source of the data such as whether it /// came from the tree) and their operator, which type should be used as the /// basis for comparison, or if comparison does not make any sense. (An example /// of non-promotable pair would be a boolean and a string where that string /// is not converible to a boolean or numeric value). class NCBI_GUIOBJUTILS_EXPORT CPromoteRule { public: /// Default ctor initializes to undefined values CPromoteRule() : m_CompareOperator(CQueryParseNode::eNotSet) , m_Type1(QueryValueType::eUndefined) , m_Type2(QueryValueType::eUndefined) , m_PromotedType(QueryValueType::eUndefined) {} /// Set the values for the type and their comparison operator CPromoteRule(CQueryParseNode::EType op, QueryValueType::EBaseType type1, QueryValueType::EBaseType type2, QueryValueType::EBaseType ptype) : m_CompareOperator(op) , m_Type1(type1) , m_Type2(type2) , m_PromotedType(ptype) {} /// Allow table to be sorted for faster lookup bool operator<(const CPromoteRule& rhs) const { if (m_Type1 < rhs.m_Type1) return true; else if (m_Type1 == rhs.m_Type1 && m_Type2 < rhs.m_Type2) return true; else if (m_Type1 == rhs.m_Type1 && m_Type2 == rhs.m_Type2 && m_CompareOperator < rhs.m_CompareOperator) return true; return false; } /// Allows us to check to see if we found requested table entry bool operator==(const CPromoteRule& rhs) const { return ((m_Type1 == rhs.m_Type1) && (m_Type2 == rhs.m_Type2) && (m_CompareOperator == rhs.m_CompareOperator)); } /// The comparison operator applied to the two values, e.g. ==, <, ... CQueryParseNode::EType m_CompareOperator; /// The extended type for the first element to compare QueryValueType::EBaseType m_Type1; /// The extended type for the second element to compare QueryValueType::EBaseType m_Type2; /// The type to be used for the comparison. This is the type from the /// CQueryParseNode class since it does not care where the data came from QueryValueType::EBaseType m_PromotedType; }; //////////////////////////////////////////////////////////////////////////////// /// class CQueryNodeValue /// /// Subclass of the IQueryParseUserObject which is held as the user-defined object /// in each CQueryParseNode. Holds a boolean value that tells us if the /// subexpression evaluted to true or not, so tht that value can be passed up the /// tree. Also keeps track of whether that value has been set. /// /// This class also holds data similar to CQueryParseNode, but with more information /// about the type (includes both the underlying type and source of the data). /// More than one data element may be valid, e.g. if the data is an integer /// parsed from a string (eStringInt), both the string and integer fields will /// be set. class NCBI_GUIOBJUTILS_EXPORT CQueryNodeValue : public IQueryParseUserObject { public: CQueryNodeValue() : m_Node(NULL) , m_DataType(QueryValueType::eUndefined) , m_IsField(false) , m_Scope(NULL) , m_Value(false) {} CQueryNodeValue(CQueryParseTree::TNode* n) : m_Node(n) , m_DataType(QueryValueType::eUndefined) , m_IsField(false) , m_Scope(NULL) , m_Value(false) {} // specifically does not reset m_IsField - that sticks between evaluations virtual void Reset() { m_Value = false; } virtual string GetVisibleValue() const; /// Set boolean result value (result of (sub)expression). bool GetValue() const { return m_Value; } void SetValue(int v) { m_Value = v; } /// Convert current value to the type 'pt'. Does not update m_DataType void PromoteTo(QueryValueType::EBaseType pt); /// Get corresponding query node CQueryParseTree::TNode* GetQueryNode() { return m_Node; } /// Set/get underlying data type void SetDataType(QueryValueType::EBaseType dt) {m_DataType = dt; } QueryValueType::EBaseType GetDataType() const { return m_DataType; } /// Set/Get to indicate if this is a field from the tree or simple string /// The type of field may not yet be avialable (if it has to be determined /// for each separate data element) void SetIsDataField(bool b) { m_IsField = b; } bool IsDataField() const { return m_IsField; } /// Set/Get CScope used for comparing seq-ids void SetScope(objects::CScope* s) {m_Scope = s;} objects::CScope* GetScope() { return m_Scope; } /// Return promotion rule(s) defined for this operator. std::vector<CPromoteRule>& GetPromoteRules() { return m_PromoteRules; } /// Get the promotion type for a specific argument pair, or eUndefined /// if no rule is available. QueryValueType::EBaseType GetPromoteType(size_t arg_idx); /// Return true if there is a promote entry defined for the specified /// argument pair at 'idx' only if the types for the rule match t1 and t2. bool HasPromoteType(size_t arg_idx, QueryValueType::EBaseType t1, QueryValueType::EBaseType t2); /// Append a new promote rule void AddPromotedType(const CPromoteRule& pr) { m_PromoteRules.push_back(pr); } /// String data, if data came from a string or data fied in the tree std::string m_String; /// Bool data, if data base a constant boolean or converted into one bool m_Bool; /// Int data, if data was an integer or converted into one int m_Int; /// Floating point data, if data was a double or converted into one double m_Double; protected: /// Node from parsed query tree CQueryParseTree::TNode* m_Node; /// Data type, including source of the data (const, string field, or tree) QueryValueType::EBaseType m_DataType; /// True if the data comes from field int the tree bool m_IsField; /// Used for comparing seq-ids objects::CScope* m_Scope; /// The promote rules defined for the current operator. This will be empty /// for atomic types. For operator type query nodes (e.g. ==, <, etc) this /// will have the comparison (promotion) type for each pair of operands. If /// one or more types will be defined at runtime, e.g. an untyped field /// from the data source, this will be empty std::vector<CPromoteRule> m_PromoteRules; /// Boolean result of the (sub)expression attached to the corresponding /// query node. bool m_Value; }; //////////////////////////////////////////////////////////////////////////////// /// class CQueryFuncPromoteBase /// /// Base class for query executtion functions. The base class holds /// the type-promotion rules needed to convert types apprpriately to allow /// for different kinds of comparisons. class NCBI_GUIOBJUTILS_EXPORT CQueryFuncPromoteBase : public CQueryFunctionBase { public: typedef CQueryNodeValue TEvalResult; CQueryFuncPromoteBase() : m_CaseSensitive(NStr::eCase) {} /// Get/set case sensitivity for all string compares for this function void SetCaseSensitive(NStr::ECase e) {m_CaseSensitive = e;} NStr::ECase GetCaseSensitive() const { return m_CaseSensitive; } /// Get the user object for node 'qnode' or NULL if not created TEvalResult* GetQueryNodeValue(CQueryParseTree::TNode& qnode); /// Get user object for 'qnode' or create a new object if it doesn't exist TEvalResult* MakeQueryNodeValue(CQueryParseTree::TNode& qnode); /// Resolve, if possible, the data type for the query node tr and, /// for operator nodes (e.g. ==, <), determine if possible types /// to be used for comparison (not always possible for untyped data /// from data source) void PreProcess(CQueryParseTree::TNode& tr, objects::CScope* scope); /// For the operator in 'qnode', retrive from data source (if ncessary) /// the data values arg1 and arg2 and promote the values, if needed, to /// the required type needed for comparison. QueryValueType::EBaseType ResolveAndPromote(size_t comparison_idx, CQueryParseTree::TNode& qnode, CQueryParseTree::TNode* arg1, CQueryParseTree::TNode* arg2); /// Given data from two nodes and a comparison operator (e.g. <, ==, >..) /// determine the best type for comparing them (e.g. if one is a string /// and one is an integer should they be compared as strings, integers, or /// not at all). QueryValueType::EBaseType GetPromotedType(const CPromoteRule& pr); /// Get the value of a field from the data source and store the /// result in the CQueryNodeValue object. Returns true on success. bool ResolveFieldValue(CQueryNodeValue& tree_val); /// Given data for a node, determine its underlying data type (e.g. if /// its a string, can it also be converted to a bool? int? float?) void SetCompareType(CQueryNodeValue& tree_value); // functions which do not take 2 arguments (e.g. 'In', 'Not'), should // override these functions. virtual size_t GetArgCountMin(CQueryParseNode::EType /* t */) { return 2; } virtual size_t GetArgCountMax(CQueryParseNode::EType /* t */) { return 2; } protected: /// Add the promtion rules for both 'type1 op type2' and 'type2 op type1' void AddPromoteTypes(CQueryParseNode::EType op, QueryValueType::EBaseType type1, QueryValueType::EBaseType type2, QueryValueType::EBaseType ptype); /// Vector of sorted promotion rules std::vector<CPromoteRule> m_PromoteRules; /// If true, all string comparisons by subclasses will use case-sensitive /// comparisons, otherwise not. NStr::ECase m_CaseSensitive; }; //////////////////////////////////////////////////////////////////////////////// /// class CQueryFuncPromoteValue /// /// Query execution function for simple atomic values. These are /// 'leaf' nodes of the query tree. class NCBI_GUIOBJUTILS_EXPORT CQueryFuncPromoteValue : public CQueryFuncPromoteBase { public: CQueryFuncPromoteValue() {} /// /// Create the user object for the node if it does not yet exist /// and reset the boolean 'result' value for the node evaluation virtual void Evaluate(CQueryParseTree::TNode& qnode); virtual size_t GetArgCountMin(CQueryParseNode::EType /* t */) { return 0; } virtual size_t GetArgCountMax(CQueryParseNode::EType /* t */) { return 0; } }; //////////////////////////////////////////////////////////////////////////////// /// class CQueryFuncPromoteLogic /// /// Query execution function for logical operators like AND, OR, etc. class NCBI_GUIOBJUTILS_EXPORT CQueryFuncPromoteLogic : public CQueryFuncPromoteBase { public: CQueryFuncPromoteLogic() : CQueryFuncPromoteBase() {} /// Try to convert the arguments into boolean values and, if successful, /// apply the specified boolean operator to those values. virtual void Evaluate(CQueryParseTree::TNode& qnode); virtual size_t GetArgCountMin(CQueryParseNode::EType t) { return (t==CQueryParseNode::eNot ? 1 : 2); } virtual size_t GetArgCountMax(CQueryParseNode::EType t) { return (t==CQueryParseNode::eNot ? 1 : 2); } }; //////////////////////////////////////////////////////////////////////////////// /// class CQueryFuncPromoteCompare /// /// Query execution function base class for all comparison classes including: /// >, <, >=, <=, ==, 'In', 'Between', and Like. class NCBI_GUIOBJUTILS_EXPORT CQueryFuncPromoteCompare : public CQueryFuncPromoteBase { public: /// Ctors for compare must include op_type for loading promotion rules CQueryFuncPromoteCompare(CQueryParseNode::EType op_type, NStr::ECase c = NStr::eCase); /// Subclass to create vector of promotion rules in m_PromoteRules virtual void InitTypePromotionRules(CQueryParseNode::EType /*op_type*/) {} }; //////////////////////////////////////////////////////////////////////////////// /// class CQueryFuncEqualityCompares /// /// Base class for query execution functions that use comparison operators /// (for now that is == and In). These functions both use the same type /// promotion rules class NCBI_GUIOBJUTILS_EXPORT CQueryFuncEqualityCompares : public CQueryFuncPromoteCompare { public: /// Ctor CQueryFuncEqualityCompares(CQueryParseNode::EType op_type, NStr::ECase c = NStr::eCase) : CQueryFuncPromoteCompare(op_type, c) {} /// Initialize promotion table for eqaulity comparisons (e.g. == or In) virtual void InitTypePromotionRules(CQueryParseNode::EType op_type); }; //////////////////////////////////////////////////////////////////////////////// /// class CQueryFuncPromoteEq /// /// Query execution function for equality comparison: == class NCBI_GUIOBJUTILS_EXPORT CQueryFuncPromoteEq : public CQueryFuncEqualityCompares { public: /// Ctor CQueryFuncPromoteEq(NStr::ECase c = NStr::eCase); /// Evaluate the node to see if '==' returns true virtual void Evaluate(CQueryParseTree::TNode& qnode); }; //////////////////////////////////////////////////////////////////////////////// /// class CQueryFuncPromoteIn /// /// Query execution function for the 'In' comparison class NCBI_GUIOBJUTILS_EXPORT CQueryFuncPromoteIn : public CQueryFuncEqualityCompares { public: /// ctor CQueryFuncPromoteIn(NStr::ECase c = NStr::eCase); /// Evaluate the node to see if 'In' returns true virtual void Evaluate(CQueryParseTree::TNode& qnode); /// In can have just one argument (a in ()) or a very large number /// a in (dog, cat, bird mouse......) virtual size_t GetArgCountMin(CQueryParseNode::EType /* t */) { return 1; } virtual size_t GetArgCountMax(CQueryParseNode::EType /* t */) { return 4096; } }; //////////////////////////////////////////////////////////////////////////////// /// class CQueryFuncLike /// /// Query execution function for 'Like' comparison. class NCBI_GUIOBJUTILS_EXPORT CQueryFuncLike : public CQueryFuncPromoteCompare { public: /// Ctor CQueryFuncLike(NStr::ECase c = NStr::eCase); /// Initialize promotion rules for 'Like' comparison virtual void InitTypePromotionRules(CQueryParseNode::EType op_type); /// Evaluate the node to see if 'Like' returns true virtual void Evaluate(CQueryParseTree::TNode& qnode); }; //////////////////////////////////////////////////////////////////////////////// /// class CQueryFuncGtLtCompares /// /// Base class for query execution functions that use greater than/ less /// than comparisons (for now that is >,<,>=,<= and Between). These functions /// all use the same promotion rules. class NCBI_GUIOBJUTILS_EXPORT CQueryFuncGtLtCompares : public CQueryFuncPromoteCompare { public: /// Ctor CQueryFuncGtLtCompares(CQueryParseNode::EType op_type, NStr::ECase c = NStr::eCase) : CQueryFuncPromoteCompare(op_type, c) {} /// Initialize promotion table for the comparisons. virtual void InitTypePromotionRules(CQueryParseNode::EType op_type); }; //////////////////////////////////////////////////////////////////////////////// /// class CQueryFuncPromoteGtLt /// /// Query execution function for the >,<,>= and <= operators class NCBI_GUIOBJUTILS_EXPORT CQueryFuncPromoteGtLt : public CQueryFuncGtLtCompares { public: /// Ctor includes op_type since we will create a separate /// instance for each of >,<, >= and <=. CQueryFuncPromoteGtLt(CQueryParseNode::EType op_type, NStr::ECase c = NStr::eCase); /// Evaluate the node to see if 'greater than/less than' returns true virtual void Evaluate(CQueryParseTree::TNode& qnode); }; //////////////////////////////////////////////////////////////////////////////// /// class CQueryFuncPromoteBetween /// /// Query execution function for the 'Between' operator class NCBI_GUIOBJUTILS_EXPORT CQueryFuncPromoteBetween : public CQueryFuncGtLtCompares { public: /// Ctor CQueryFuncPromoteBetween(NStr::ECase c = NStr::eCase); /// Evaluate the node to see if 'Between' returns true virtual void Evaluate(CQueryParseTree::TNode& qnode); /// 27 between 10 and 30 => 3 arguments for between operator virtual size_t GetArgCountMin(CQueryParseNode::EType /* t */) { return 3; } virtual size_t GetArgCountMax(CQueryParseNode::EType /* t */) { return 3; } }; //////////////////////////////////////////////////////////////////////////////// /// class CQueryExecPreProcessFunc /// /// This class applies a function to the query to do any needed optiminzation /// or preprocessing of the query prior to execution. class CQueryExecPreProcessFunc { public: CQueryExecPreProcessFunc(objects::CScope* scope, CQueryExec& exec) : m_Exec(exec) , m_Scope(scope) {} ETreeTraverseCode operator()(CTreeNode<CQueryParseNode>& tr, int delta) { CQueryParseNode& qnode = tr.GetValue(); if (delta == 0 || delta == 1) { // If node has children, we skip it and process on the way back if (!tr.IsLeaf()) { return eTreeTraverse; } } CQueryParseNode::EType func_type = qnode.GetType(); CQueryFuncPromoteBase* func = 0; func = dynamic_cast<CQueryFuncPromoteBase*>( m_Exec.GetFunc(func_type) ); if (func == 0) { // function not registered NCBI_THROW(CQueryParseException, eUnknownFunction, "Query pre-processing faild. Unknown function:" + qnode.GetOrig()); } func->PreProcess(tr, m_Scope); return eTreeTraverse; } private: CQueryExec& m_Exec; objects::CScope* m_Scope; }; END_NCBI_SCOPE #endif // GUI_OBJUTILS___QUERY_FUNC_PROMOTE_HPP

source navigation ]   [ diff markup ]   [ identifier search ]   [ freetext search ]   [ file search ]  

This page was automatically generated by the LXR engine.
Visit the LXR main site for more information.