Search code examples
sqlc++14dslboost-spirit-x3

Parse SQL like query with boost spirit x3


I'm trying to parse a simple SQL like query using boost spirit x3. There were a similar post for the previous version of spirit. But With spirit x3, we don't need grammar.
So here is my attempt:

// SELECT chr, pos FROM table
// Select chr, pos FROM table WHERE a=5 and b = 6
// SELECT chr, pos FROM table WHERE a =5 and b=6 INSIDE region

// I would like to extract :
// vector<string> fields = {chr, pos}
// string tablename = "table"
// string where  = "a=5 and b=6"
// string region = "region"

string source ="SELECT chr,pos FROM table WHERE a=5 AND b=6 INSIDE region";

// varname = chr, pos, table, region
auto varname =  x3::rule<class varname, string>()
             =  x3::lexeme[(x3::alpha >> *(x3::alnum|'_'|'.'))];

// any character except "INSIDE" 
auto condition =  x3::rule<class condition, string>()
               =  x3::lexeme[*x3::char_]-"INSIDE";

// fields selection
auto selectRule = x3::rule<class fields, vector<string>> ()
                = "SELECT" >> varname % ",";

 //   table name 
auto fromRule   = x3::rule<class fromRule, string>()
                = "FROM" >> varname;

// where clause
auto whereRule  = x3::rule<class whereRule, vector<string>>()
                = "WHERE" >> condition ;

// inside clause
auto insideRule = x3::rule<class insideRule, string>()
                = "INSIDE" >> varname;

auto begin = source.begin();
auto end   = source.end();

vector<string> results;

x3::phrase_parse(begin,end,
                 selectRule >> fromRule >> -(whereRule >>-insideRule),
                 x3::space, results);

if (begin != end)
    cout<<"COULD NOT PARSE"<<endl;
else
    cout<<"parse succes"<<endl;

for (auto i : results)
    cout<<i<<endl;

It returns:

chr
pos
table
a=5 AND b=6 INSIDE region

results contains all attribut data extracted except the insideRule attribut data which is keept in the condition string. Any clue to make my parser work ?


Solution

  • This is working now :

       struct VqlResult {
       std::vector<std::string> selectData;
       std::string fromData;
       std::string whereData;
       std::string insideData;
    
    };
    
    BOOST_FUSION_ADAPT_STRUCT
    (
        VqlResult,
        selectData,
        fromData,
        whereData,
        insideData
    );
    
     // Pseudo Sql parser
     // e.g : SELECT chr,pos FROM table WHERE a=5 AND b=6 INSIDE region
     bool parseSql(const std::string& sql)
    {
        auto varnameRule =  x3::rule<class varname, string>()
                =  x3::lexeme[(x3::alpha >> *(x3::alnum|'_'|'.'))];
    
    
        auto columnsRule =  x3::rule<class varname, string>()
                =  x3::lexeme[*(x3::char_ - '"' - "FROM")];
    
        auto conditionRule =  x3::lexeme[*(x3::char_ - "INSIDE")];
    
        auto selectRule = x3::rule<class fields, vector<string>> ()
                = "SELECT" >> columnsRule % ",";
    
        auto fromRule   = "FROM" >> varnameRule;
    
        auto whereRule  = "WHERE" >> conditionRule;
    
        auto insideRule = "INSIDE" >> varnameRule;
    
        auto begin = sql.begin();
        auto end   = sql.end();
    
        VqlResult results;
    
        x3::phrase_parse(begin,end,
                         selectRule >> fromRule >> -whereRule >> -insideRule,
                         x3::space, results);
    
        // parse all
        if (begin != end){
            cout<<"cannot parse "<<endl;
            return false;
        }
    
        return true;
    }