This repository has been archived on 2024-07-15. You can view files and clone it, but cannot push or open issues or pull requests.
hedera/sql/parser/scan.rl

310 lines
7.4 KiB
Plaintext
Raw Normal View History

2013-10-11 23:07:35 +00:00
/*
* 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 <http://www.gnu.org/licenses/>.
*/
/* THIS FILE HAS BEEN GENERATED USING THE SOURCE IN parser/scan.rl */
#include <string.h>
#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 (const gchar * sql, GError ** err)
2013-10-11 23:07:35 +00:00
{
gint cs, act;
gchar * p, * pe, * ts, * te;
gpointer eof, parser;
ParseState * state;
SqlObject * object;
gchar * query;
2013-10-11 23:07:35 +00:00
if (!sql)
{
g_set_error (err, SQL_PARSER_LOG_DOMAIN,
SQL_PARSER_ERROR_EMPTY_QUERY, "Empty query!\n");
2013-10-11 23:07:35 +00:00
return NULL;
}
query = g_strdup (sql);
2013-10-11 23:07:35 +00:00
state = g_new (ParseState, 1);
state->object = NULL;
state->error = err;
state->string = state->current = p = query;
2013-10-11 23:07:35 +00:00
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->failed)
2013-10-11 23:07:35 +00:00
{
if (state->object && G_IS_OBJECT (state->object))
2013-10-14 12:08:06 +00:00
g_object_unref (state->object);
2013-10-11 23:07:35 +00:00
object = NULL;
}
else
object = g_object_ref_sink (state->object);
g_free (state);
g_free (query);
2013-10-11 23:07:35 +00:00
return object;
}
SqlField * sql_parser_parse_field (const gchar * field)
{
gchar ** split;
SqlExpr * object = NULL;
if (!field || !g_strcmp0 (field, ""))
return NULL;
split = g_strsplit (field, ".", 0);
switch (g_strv_length (split))
{
case 3:
{
object = sql_field_new
(g_strstrip (g_strdelimit (split[2], "`\"", ' '))
,g_strstrip (g_strdelimit (split[1], "`\"", ' '))
,g_strstrip (g_strdelimit (split[0], "`\"", ' ')));
break;
}
case 2:
{
object = sql_field_new
(g_strstrip (g_strdelimit (split[1], "`\"", ' '))
,g_strstrip (g_strdelimit (split[0], "`\"", ' '))
,NULL);
break;
}
case 1:
{
object = sql_field_new
(g_strstrip (g_strdelimit (split[0], "`\"", ' '))
,NULL
,NULL);
break;
}
}
g_strfreev (split);
return (SqlField *) object;
}