/* * Copyright (C) 2012 - Juan Ferrer Toribio * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ /* THIS FILE HAS BEEN GENERATED USING THE SOURCE IN parser/scan.rl */ #include #include "sql-parser.h" #include "parser/gram.c" #define PARSE(token, value) \ state->current = ts; \ Parse(parser, SQL_PARSER_##token, value, state) /** * SECTION: sql-parser * @Short_description: a simple DML query parser * @Title: SqlParser * * This is the parser used by Hedera to transform a string containing one or * more SQL data management queries into an #SqlObject and thus have an idea * of what must happen when a change is made in the affected data. **/ static gchar * get_token (const gchar * ts, const gchar * te) { if (!(ts && te)) return NULL; gsize len = (gsize) (te-ts); gchar * str = g_malloc (len+1); g_memmove (str, ts, len); str[len] = '\0'; return str; } %%{ machine sql_scanner; #/*-----------------------# SYMBOL Definition #-----------------------*/# # Keywords AS = "AS"i; UNION = "UNION"i; ALL = "ALL"i; ANY = "ANY"i; EXCEPT = "EXCEPT"i; INTERSECT = "INTERSECT"i; SELECT = "SELECT"i; FROM = "FROM"i; WHERE = "WHERE"i; DISTINCT = "DISTINCT"i; JOIN = "JOIN"i; INNER = "INNER"i; LEFT = ("OUTER"i space+|"") "LEFT"i; RIGHT = ("OUTER"i space+|"") "RIGHT"i; ON = "ON"i; USING = "USING"i; NATURAL = "NATURAL"i; GROUP = "GROUP" space+ "BY"i; HAVING = "HAVING"i; ORDER = "ORDER"i space+ "BY"i; ASC = "ASC"i; DESC = "DESC"i; LIMIT = "LIMIT"i; OFFSET = "OFFSET"i; UPDATE = "UPDATE"i; SET = "SET"i; INSERT = "INSERT"i space+ "INTO"i; DEFAULT = "DEFAULT"i; VALUES = "VALUES"i; DELETE = "DELETE"i space+ "FROM"i; RETURNING = "RETURNING"i; # Parenthesis LP = "("; RP = ")"; # Colon DOT = "."; # Semicolon SC = ";"; # Comma CM = ","; # Identifier quote IQ = ("\"" | "`"); # Operators PLUS = "+"; MINUS = "-"; STAR = "*"; DIV = "/"; MOD = "%"; EQ = "="; NE = ("<>" | "!="); GT = ">"; GE = ">="; LT = "<"; LE = "<="; # Operator Keywords AND = "AND"i; OR = "OR"i; NOT = ("NOT"i | "!"); LIKE = "LIKE"i; IS = "IS"i; XOR = "XOR"i; # Boolean Keywords BOOLEAN = ("TRUE"i | "FALSE"i); Op = (AND | OR | NOT | LIKE | IS | XOR); keyword = ( Op | BOOLEAN | AS | UNION | ALL | ANY | EXCEPT | INTERSECT | SELECT | FROM | WHERE | DISTINCT | JOIN | INNER | LEFT| RIGHT | ON | USING | NATURAL | GROUP | HAVING | ORDER | ASC | DESC | LIMIT | OFFSET | UPDATE | SET | INSERT | DEFAULT | VALUES | RETURNING | DELETE); # Identifiers Iescape = ("\"\"" | "" ); IDENTIFIER = ((alpha | "_" | "$") (alnum | "_" | "$")*) - keyword; QIDENTIFIER = IQ ((any - IQ)* Iescape (any - IQ)*) IQ; PLACEHOLDER = "#" IDENTIFIER; # Escaped string characters escape = ("\\'"| "''" | ""); # Data values STRING = "'" (any - "'")* escape (any - "'")* "'"; INTEGER = digit+; FLOAT = digit+ ("." digit+)?; # Comments comment = ("-- " (any - "\n")* "\n" | "/*" (any* -- "*/") "*/"); #/*-----------------------# SCANNER Definition #-----------------------*/# main := |* #// Keywords AS => { PARSE (AS, 0); }; UNION => { PARSE (UNION, 0); }; ALL => { PARSE (ALL, 0); }; ANY => { PARSE (ANY, 0); }; EXCEPT => { PARSE (EXCEPT, 0); }; INTERSECT => { PARSE (INTERSECT, 0); }; SELECT => { PARSE (SELECT, 0); }; DISTINCT => { PARSE (DISTINCT, 0); }; FROM => { PARSE (FROM, 0); }; WHERE => { PARSE (WHERE, 0); }; JOIN => { PARSE (JOIN, 0); }; INNER => { PARSE (INNER, 0); }; LEFT => { PARSE (LEFT, 0); }; RIGHT => { PARSE (RIGHT, 0); }; ON => { PARSE (ON, 0); }; USING => { PARSE (USING, 0); }; #// NATURAL => { PARSE (NATURAL, 0); }; GROUP => { PARSE (GROUP, 0); }; HAVING => { PARSE (HAVING, 0); }; ORDER => { PARSE (ORDER, 0); }; ASC => { PARSE (ASC, 0); }; DESC => { PARSE (DESC, 0); }; LIMIT => { PARSE (LIMIT, 0); }; OFFSET => { PARSE (OFFSET, 0); }; UPDATE => { PARSE (UPDATE, 0); }; SET => { PARSE (SET, 0); }; INSERT => { PARSE (INSERT, 0); }; DEFAULT => { PARSE (DEFAULT, 0); }; VALUES => { PARSE (VALUES, 0); }; DELETE => { PARSE (DELETE, 0); }; #// Punctuation symbols LP => { PARSE (LP, 0); }; RP => { PARSE (RP, 0); }; DOT => { PARSE (DOT, 0); }; SC => { PARSE (SC, 0); }; CM => { PARSE (CM, 0); }; #// Identifiers IDENTIFIER => { PARSE (IDENTIFIER, get_token (ts, te)); }; QIDENTIFIER => { PARSE (IDENTIFIER, get_token (ts+1, te-1)); }; PLACEHOLDER => { PARSE (PLACEHOLDER, get_token (ts+1, te)); }; #// Data values STRING => { PARSE (STRING, get_token (ts+1, te-1)); }; INTEGER => { PARSE (INTEGER, get_token (ts, te)); }; FLOAT => { PARSE (FLOAT, get_token (ts, te)); }; BOOLEAN => { PARSE (BOOLEAN, get_token(ts, te)); }; #// Operators PLUS => { PARSE (PLUS, 0); }; MINUS => { PARSE (MINUS, 0); }; STAR => { PARSE (STAR, 0); }; DIV => { PARSE (DIV, 0); }; MOD => { PARSE (MOD, 0); }; EQ => { PARSE (EQ, 0); }; NE => { PARSE (NE, 0); }; GT => { PARSE (GT, 0); }; GE => { PARSE (GE, 0); }; LT => { PARSE (LT, 0); }; LE => { PARSE (LE, 0); }; #// Operator Keywords AND => { PARSE (AND, 0); }; OR => { PARSE (OR, 0); }; NOT => { PARSE (NOT, 0); }; LIKE => { PARSE (LIKE, 0); }; IS => { PARSE (IS, 0); }; XOR => { PARSE (XOR, 0); }; #// Ignored space; comment; *|; }%% %% write data; SqlObject * sql_parser_parse (gchar * sql) { gint cs, act; gchar * p, * pe, * ts, * te; gpointer eof, parser; ParseState * state; SqlObject * object; if (!sql) { g_log (g_quark_to_string (SQL_PARSER_LOG_DOMAIN) ,G_LOG_LEVEL_WARNING ,"Empty query!\n"); return NULL; } state = g_new (ParseState, 1); state->object = NULL; state->error = FALSE; state->string = state->current = p = sql; pe = p + strlen (p) + 1; eof = pe; parser = ParseAlloc (g_malloc); %% write init; %% write exec; Parse (parser, 0, 0, state); ParseFree (parser, g_free); if (state->error) { if (state->object && G_IS_OBJECT (state->object)) g_object_unref (g_object_ref_sink (state->object)); object = NULL; } else object = g_object_ref_sink (state->object); g_free (state); return object; }