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/gram.y

629 lines
17 KiB
Plaintext

%include
{
/*
* 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/>.
*/
#include <stdlib.h>
#include <assert.h>
#include <sql/sql.h>
#include "gram.h"
typedef struct
{
SqlObject * object;
gchar * string;
gchar * current;
gboolean failed;
GError ** error;
}
ParseState;
typedef enum
{
SQL_PARSER_ERROR_EMPTY_QUERY = 1 << 0,
SQL_PARSER_ERROR_PARSING = 1 << 1,
SQL_PARSER_ERROR_STACK_OVERFLOW = 1 << 2,
}
SqlParserError;
static inline SqlList * list_add (gpointer item, SqlList * list)
{
sql_list_add (list, item);
return list;
}
static inline SqlList * list_new (gpointer item, GType gtype)
{
SqlList * list = sql_list_new (gtype);
return list_add (item, list);
}
}
%default_type {SqlObject *}
%token_type {gchar *}
%token_destructor {g_free ($$);}
%token_prefix SQL_PARSER_
// Return pointer
%extra_argument { ParseState * state }
// Error treatment
%syntax_error
{
gchar * pref = ".", * err_str = NULL;
if (state->current)
{
err_str = state->current - 15 >= state->string ?
state->current - 10 : state->string;
pref = err_str == state->string ? " near: " : " near: [...]";
}
g_set_error (state->error, SQL_PARSER_LOG_DOMAIN, SQL_PARSER_ERROR_PARSING,
"Parsing error%s%s", pref, err_str);
state->failed = TRUE;
}
%stack_overflow
{
g_set_error (state->error, SQL_PARSER_LOG_DOMAIN, SQL_PARSER_ERROR_STACK_OVERFLOW,
"Parser stack overflow. Parsing terminated.\n");
state->failed = TRUE;
}
// Operator precedence
%left UNION EXCEPT.
%left INSERSECT.
%left OR.
%left XOR.
%left AND.
%right NOT.
%right EQ NE.
%left GT GE LT LE.
%left LIKE.
%left IS.
%left PLUS MINUS.
%left STAR DIV MOD.
%right SIGN.
// Start symbol:
%start_symbol start
start ::= multi_stmt (A).
{
state->object = SQL_OBJECT (A);
}
//+++++++++++++++++++++++++++++++++++++++++++++++++++ Multi statement
multi_stmt(A) ::= stmt_list(stmt_list).
{
guint len = sql_list_length (stmt_list);
if (len == 1)
{
A = sql_list_get (stmt_list, 0);
g_object_ref_sink (G_OBJECT (A));
g_object_unref (g_object_ref_sink (stmt_list));
}
else
// FIXME Reverse list!
A = g_object_new (SQL_TYPE_MULTI_STMT, "stmts", stmt_list, NULL);
}
%type stmt_list {SqlList *}
stmt_list(A) ::= stmt(X). { A = list_new (X, SQL_TYPE_STMT); }
stmt_list(A) ::= stmt(X) SC. { A = list_new (X, SQL_TYPE_STMT); }
stmt_list(A) ::= stmt(X) SC stmt_list(B). { A = list_add (X, B); }
//+++++++++++++++++++++++++++++++++++++++++++++++++++ Statemet
stmt(A) ::= select_stmt(X). { A = X; }
stmt(A) ::= delete_stmt(X). { A = X; }
stmt(A) ::= update_stmt(X). { A = X; }
stmt(A) ::= insert_stmt(X). { A = X; }
//+++++++++++++++++++++++++++++++++++++++++++++++++++ Select
select_stmt(A) ::= select_stmt(B) set_op(type) simple_select(X).
{
g_object_set (B, "exprs", type, "next", X, NULL);
A = B;
}
select_stmt(A) ::= simple_select(X). { A = X; }
%type set_op {SqlSelectType}
set_op(A) ::= UNION ANY. { A = SQL_SELECT_UNION_ANY; }
set_op(A) ::= UNION ALL. { A = SQL_SELECT_UNION_ALL; }
set_op(A) ::= UNION. { A = SQL_SELECT_UNION_ALL; }
set_op(A) ::= INTERSECT. { A = SQL_SELECT_INTERSECT; }
set_op(A) ::= EXCEPT. { A = SQL_SELECT_EXCEPT; }
simple_select(A) ::= LP simple_select(X) RP. { A = X; }
simple_select(A) ::= SELECT
distinct(distinct_c)
select_field_list(field_list)
from(target)
where(where_c)
group(group_c) having(having_c)
order(order_c)
limit(limit_c).
{
A = g_object_new (SQL_TYPE_SELECT
,"distinct" ,distinct_c
,"fields" ,field_list
,"targets" ,target
,"where" ,where_c
,"group" ,group_c
,"order" ,order_c
,NULL
);
if (having_c)
g_object_set (A, "having", having_c, NULL);
if (limit_c)
g_object_set (A
,"limit-offset" ,limit_c->offset
,"limit-count" ,limit_c->count
,NULL
);
}
%type distinct {gboolean}
distinct(A) ::= DISTINCT. { A = TRUE; }
distinct(A) ::= ALL. { A = FALSE; }
distinct(A) ::= . { A = FALSE; }
select_field(A) ::= expr(X).
{ A = g_object_new (SQL_TYPE_SELECT_FIELD, "expr", X, NULL); }
select_field(A) ::= expr(X) alias(Y).
{ A = g_object_new (SQL_TYPE_SELECT_FIELD, "expr", X, "alias", Y, NULL); }
%type select_field_list {SqlList *}
select_field_list(A) ::= select_field(X). { A = list_new (X, SQL_TYPE_SELECT_FIELD); }
select_field_list(A) ::= select_field_list(B) CM select_field(X). { A = list_add (X, B); }
%type from {SqlList *}
from(A) ::= FROM target_list(X). { A = X; }
from(A) ::= . { A = NULL; }
%type group {SqlList *}
group(A) ::= GROUP expr_list(X). { A = X; }
group(A) ::= . { A = NULL; }
having(A) ::= HAVING expr(X). { A = X; }
having(A) ::= . { A = NULL; }
%type order {SqlList *}
order(A) ::= ORDER order_list (X). { A = X; }
order(A) ::= . { A = NULL; }
%type order_list {SqlList *}
order_list(A) ::= order_expr(X). { A = list_new (X, SQL_TYPE_SELECT_ORDER); }
order_list(A) ::= order_list(B) CM order_expr(X). { A = list_add (X, B); }
order_expr(A) ::= expr(X) order_way(Y). { A = g_object_new (SQL_TYPE_SELECT_ORDER, "expr", X, "way", Y, NULL); }
%type order_way {SqlSelectOrderWay}
order_way(A) ::= ASC. { A = SQL_SELECT_ORDER_ASC; }
order_way(A) ::= DESC. { A = SQL_SELECT_ORDER_DESC; }
order_way(A) ::= . { A = SQL_SELECT_ORDER_ASC; }
%type limit {SelectLimit *}
%destructor limit {g_free ($$);}
%include
{
typedef struct
{
guint offset;
guint count;
}
SelectLimit;
static inline SelectLimit * create_limit (gchar * offset, gchar * count)
{
SelectLimit * limit = g_new (SelectLimit, 1);
limit->offset = offset ? atoi (offset) : 0;
limit->count = count ? atoi (count) : 0;
return limit;
}
}
limit(A) ::= LIMIT INTEGER(X). { A = create_limit (NULL, X); }
limit(A) ::= OFFSET INTEGER(Y). { A = create_limit (Y, NULL); }
limit(A) ::= LIMIT INTEGER(X) OFFSET INTEGER(Y). { A = create_limit (Y, X); }
limit(A) ::= LIMIT INTEGER(X) CM INTEGER(Y). { A = create_limit (Y, X); }
limit(A) ::= . { A = NULL; }
//+++++++++++++++++++++++++++++++++++++++++++++++++++ Delete
delete_stmt(A) ::= DELETE table_list(table_list) del_using(del_using) where(where_c).
{
A = g_object_new (SQL_TYPE_DELETE
,"targets" ,table_list
,"tables" ,del_using
,"where" ,where_c
,NULL
);
}
%type table_list {SqlList *}
table_list(A) ::= table(X). { A = list_new (X, SQL_TYPE_TABLE); }
table_list(A) ::= table_list(B) CM table(X). { A = list_add (X, B); }
%type del_using {SqlList *}
del_using(A) ::= USING target_list(X). { A = X; }
del_using(A) ::= . { A = NULL; }
//+++++++++++++++++++++++++++++++++++++++++++++++++++ Update
update_stmt(A) ::= UPDATE table_list(table) SET update_list(update_list) where(where_c).
{
A = g_object_new (SQL_TYPE_UPDATE
,"targets" ,table
,"sets" ,update_list
,"where" ,where_c
,NULL
);
}
%type update_list {SqlList *}
update_list(A) ::= update_set(X). { A = list_new (X, SQL_TYPE_UPDATE_SET); }
update_list(A) ::= update_list(B) CM update_set(X). { A = list_add (X, B); }
update_set(A) ::= field(X) EQ def_expr(Y).
{
A = g_object_new (SQL_TYPE_UPDATE_SET
,"field" ,X
,"expr" ,Y
,NULL
);
}
//+++++++++++++++++++++++++++++++++++++++++++++++++++ Insert
insert_stmt(A) ::= INSERT table(tab) insert_fields(insert_fields) insert_values(insert_values).
{
A = g_object_new (SQL_TYPE_INSERT
,"table" ,tab
,"fields" ,insert_fields
,NULL
);
if (SQL_IS_SELECT (insert_values))
g_object_set (A, "select", insert_values, NULL);
else
g_object_set (A, "values", insert_values, NULL);
}
%type insert_fields {SqlList *}
insert_fields(A) ::= LP field_list(X) RP. { A = X; }
insert_fields(A) ::= . { A = NULL; }
%type insert_values {gpointer}
insert_values(A) ::= DEFAULT VALUES. { A = NULL; }
insert_values(A) ::= VALUES set_list(X). { A = X; }
//insert_values(A) ::= select_stmt(X). { A = X; }
%type set_list {SqlList *}
set_list(A) ::= set(X). { A = list_new (X, SQL_TYPE_SET); }
set_list(A) ::= set_list(B) CM set(X). { A = list_add (X, B); }
set(A) ::= LP def_expr_list(X) RP. { A = g_object_new (SQL_TYPE_SET, "exprs", X, NULL); }
%type def_expr_list {SqlList *}
def_expr_list(A) ::= def_expr(X). { A = list_new (X, SQL_TYPE_EXPR); }
def_expr_list(A) ::= def_expr_list(B) CM def_expr(X). { A = list_add (X, B); }
//+++++++++++++++++++++++++++++++++++++++++++++++++++ Common to statements
where(A) ::= WHERE expr(X). { A = X; }
where(A) ::= . { A = NULL; }
def_expr(A) ::= expr(X). { A = X; }
def_expr(A) ::= DEFAULT. { A = NULL; }
//+++++++++++++++++++++++++++++++++++++++++++++++++++ Target
target(A) ::= unaliased_target(X). { A = X; }
target(A) ::= unaliased_target(X) alias(Y).
{
g_object_set (X, "alias", Y, NULL);
A = X;
}
//target(A) ::= LP target(X) RP. { A = X; }
%type target_list {SqlList *}
target_list(A) ::= target(X). { A = list_new (X, SQL_TYPE_TARGET); }
target_list(A) ::= target_list(B) CM target(X). { A = list_add (X, B); }
unaliased_target(A) ::= join(X). { A = X; }
unaliased_target(A) ::= subquery(X). { A = X; }
unaliased_target(A) ::= table(X). { A = X; }
//+++++++++++++++++++++++++++++++++++++++++++++++++++ Join
join(A) ::= target(target_left) join_type(join_type) target(target_right) join_cond(join_cond).
{
A = g_object_new (SQL_TYPE_JOIN
,"target-left" ,target_left
,"target-right" ,target_right
,"join-type" ,join_type
,NULL
);
if (SQL_IS_LIST (join_cond)) // USING
{
GList * n;
SqlList * exprs = sql_list_new (SQL_TYPE_EXPR);
SqlOperation * op_and = g_object_new (SQL_TYPE_OPERATION
,"operator" ,SQL_OPERATION_TYPE_AND
,"operands" ,exprs
,NULL
);
for (n = sql_list_get_items (join_cond); n; n = n->next)
{
SqlList * equal = sql_list_new (SQL_TYPE_EXPR);
SqlOperation * op = g_object_new (SQL_TYPE_OPERATION
,"operator" ,SQL_OPERATION_TYPE_EQUAL
,"operands" ,equal
,NULL
);
gchar * target = SQL_TARGET (target_left)->alias ? SQL_TARGET (target_left)->alias : SQL_TABLE (target_left)->name;
gchar * schema = SQL_IS_TABLE(target_left) && SQL_TABLE (target_left)->schema ?
SQL_TABLE (target_left)->schema : NULL;
g_object_set (n->data, "target", target, "schema", schema, NULL);
sql_list_add (equal, n->data);
target = SQL_TARGET (target_right)->alias ? SQL_TARGET (target_right)->alias : SQL_TABLE (target_right)->name;
schema = SQL_IS_TABLE (target_right) && SQL_TABLE (target_right)->schema ?
SQL_TABLE (target_right)->schema : NULL;
sql_list_add (equal,
sql_field_new_with_target (SQL_FIELD (n->data)->name, target, schema));
sql_list_add (exprs, op);
}
g_object_set (A, "condition", op_and, NULL);
g_object_unref (g_object_ref_sink (join_cond));
}
else
g_object_set (A, "condition", join_cond, NULL);
}
%type join_type {SqlJoinType}
join_type(A) ::= INNER JOIN. { A = SQL_JOIN_TYPE_INNER; }
join_type(A) ::= JOIN. { A = SQL_JOIN_TYPE_INNER; }
join_type(A) ::= LEFT JOIN. { A = SQL_JOIN_TYPE_LEFT; }
join_type(A) ::= RIGHT JOIN. { A = SQL_JOIN_TYPE_RIGHT; }
%type join_cond {gpointer}
join_cond(A) ::= ON expr(X). { A = X; }
join_cond(A) ::= USING LP field_list(X) RP. { A = X; }
//+++++++++++++++++++++++++++++++++++++++++++++++++++ Subquery
subquery(A) ::= LP select_stmt(stmts) RP.
{
A = g_object_new (SQL_TYPE_SUBQUERY, "stms", stmts, NULL);
}
//+++++++++++++++++++++++++++++++++++++++++++++++++++ Table
table(A) ::= identifier(X).
{
A = g_object_new (SQL_TYPE_TABLE, "name", X, NULL);
}
table(A) ::= identifier(Y) DOT identifier(X).
{
A = g_object_new (SQL_TYPE_TABLE, "name", X, "schema", Y, NULL);
}
//+++++++++++++++++++++++++++++++++++++++++++++++++++ Expr
expr(A) ::= LP expr(X) RP. { A = X; }
%type expr_list {SqlList *}
expr_list(A) ::= expr(X). { A = list_new (X, SQL_TYPE_EXPR); }
expr_list(A) ::= expr_list(B) CM expr(X). { A = list_add (X, B); }
expr(A) ::= field(X). { A = X; }
expr(A) ::= function(X). { A = X; }
expr(A) ::= operation(X). { A = X; }
expr(A) ::= value(X). { A = X; }
//+++++++++++++++++++++++++++++++++++++++++++++++++++ Field
field(A) ::= unqualified_field(X). { A = X; }
field(A) ::= identifier(Y) DOT unqualified_field(X).
{
g_object_set (X, "target", Y, NULL);
A = X;
}
field(A) ::= identifier(Z) DOT identifier(Y) DOT unqualified_field(X).
{
g_object_set (X, "target", Y, "schema", Z, NULL);
A = X;
}
unqualified_field(A) ::= identifier(X).
{
A = g_object_new (SQL_TYPE_FIELD, "name", X, NULL);
}
unqualified_field(A) ::= STAR.
{
A = g_object_new (SQL_TYPE_FIELD, "name", "*", NULL);
}
%type field_list {SqlList *}
field_list(A) ::= field(X). { A = list_new (X, SQL_TYPE_FIELD); }
field_list(A) ::= field_list(B) CM field(X). { A = list_add (X, B); }
//+++++++++++++++++++++++++++++++++++++++++++++++++++ Function
function(A) ::= unqualified_function(X). { A = X; }
function(A) ::= identifier(Z) DOT unqualified_function(X).
{
g_object_set (X, "schema", Z, NULL);
A = X;
}
unqualified_function(A) ::= identifier(X) LP function_expr_list(Y) RP.
{
A = g_object_new (SQL_TYPE_FUNCTION, "name", X, "params", Y, NULL);
}
%type function_expr_list {SqlList *}
function_expr_list(A) ::= . { A = NULL; }
function_expr_list(A) ::= expr_list(X). { A = X; }
//+++++++++++++++++++++++++++++++++++++++++++++++++++ Operation
%include
{
static inline SqlObject * create_operation
(const gpointer X, const gpointer Y, const SqlOperationType type)
{
SqlList * exprs = sql_list_new (SQL_TYPE_EXPR);
sql_list_add (exprs, X);
if (Y) // Binary operation
sql_list_add (exprs, Y);
return g_object_new (SQL_TYPE_OPERATION, "operator", type, "operands", exprs, NULL);
}
}
operation(A) ::= MINUS expr(X). [SIGN]
{
GValue value = {0};
SqlObject * minus = sql_value_new ();
g_value_init (&value, G_TYPE_INT);
g_value_set_int (&value, -1);
sql_value_set_value (SQL_VALUE (minus), &value);
A = create_operation (X, minus, SQL_OPERATION_TYPE_MULTIPLICATION);
}
operation(A) ::= NOT expr(X).
{ A = create_operation (X, NULL, SQL_OPERATION_TYPE_NOT); }
operation(A) ::= PLUS expr(X). [SIGN]
{ A = create_operation (X, NULL, SQL_OPERATION_TYPE_SUM); }
operation(A) ::= expr(X) PLUS expr(Y).
{ A = create_operation (X, Y, SQL_OPERATION_TYPE_SUM); }
operation(A) ::= expr(X) MINUS expr(Y).
{ A = create_operation (X, Y, SQL_OPERATION_TYPE_SUBTRACTION); }
operation(A) ::= expr(X) STAR expr(Y).
{ A = create_operation (X, Y, SQL_OPERATION_TYPE_MULTIPLICATION); }
operation(A) ::= expr(X) DIV expr(Y).
{ A = create_operation (X, Y, SQL_OPERATION_TYPE_DIVISION); }
operation(A) ::= expr(X) OR expr(Y).
{ A = create_operation (X, Y, SQL_OPERATION_TYPE_OR); }
operation(A) ::= expr(X) XOR expr(Y).
{ A = create_operation (X, Y, SQL_OPERATION_TYPE_XOR); }
operation(A) ::= expr(X) AND expr(Y).
{ A = create_operation (X, Y, SQL_OPERATION_TYPE_AND); }
operation(A) ::= expr(X) EQ expr(Y).
{ A = create_operation (X, Y, SQL_OPERATION_TYPE_EQUAL); }
operation(A) ::= expr(X) NE expr(Y).
{ A = create_operation (X, Y, SQL_OPERATION_TYPE_NOT_EQUAL); }
//XXX the following should be %nonassoc operators but are %left to avoid
// conflicts. The DB will warn about a bad use if used as %left.
operation(A) ::= expr(X) GT expr(Y).
{ A = create_operation (X, Y, SQL_OPERATION_TYPE_GREATER); }
operation(A) ::= expr(X) GE expr(Y).
{ A = create_operation (X, Y, SQL_OPERATION_TYPE_GREATER_EQUAL); }
operation(A) ::= expr(X) LT expr(Y).
{ A = create_operation (X, Y, SQL_OPERATION_TYPE_LOWER); }
operation(A) ::= expr(X) LE expr(Y).
{ A = create_operation (X, Y, SQL_OPERATION_TYPE_LOWER_EQUAL); }
operation(A) ::= expr(X) LIKE expr(Y).
{ A = create_operation (X, Y, SQL_OPERATION_TYPE_LIKE); }
operation(A) ::= expr(X) IS expr(Y).
{ A = create_operation (X, Y, SQL_OPERATION_TYPE_IS); }
operation(A) ::= expr(X) MOD expr(Y).
{ A = create_operation (X, Y, SQL_OPERATION_TYPE_MOD); }
//+++++++++++++++++++++++++++++++++++++++++++++++++++ Value
value(A) ::= INTEGER(X).
{
GValue value = {0};
g_value_set_int (g_value_init (&value, G_TYPE_INT), atoi (X));
A = g_object_new (SQL_TYPE_VALUE, "value", &value, NULL);
g_value_unset (&value);
}
value(A) ::= FLOAT(X).
{
GValue value = {0};
g_value_set_double
(g_value_init (&value, G_TYPE_DOUBLE), g_ascii_strtod (X, NULL));
A = g_object_new (SQL_TYPE_VALUE, "value", &value, NULL);
g_value_unset (&value);
}
value(A) ::= STRING(X).
{
GValue value = {0};
g_value_set_string (g_value_init (&value, G_TYPE_STRING), X);
A = g_object_new (SQL_TYPE_VALUE, "value", &value, NULL);
g_value_unset (&value);
}
value(A) ::= BOOLEAN(X).
{
GValue value = {0};
g_value_set_boolean (g_value_init (&value, G_TYPE_BOOLEAN)
,(!g_strcmp0 (X, "TRUE") || !g_strcmp0 (X, "true")) ? TRUE : FALSE);
A = g_object_new (SQL_TYPE_VALUE, "value", &value, NULL);
g_value_unset (&value);
}
//+++++++++++++++++++++++++++++++++++++++++++++++++++ Alias
%type alias {gchar *}
alias(A) ::= AS identifier(X). { A = X; }
alias(A) ::= identifier(X). { A = X; }
%type identifier {gchar *}
identifier(A) ::= IDENTIFIER(X). { A = X; }
//+++++++++++++++++++++++++++++++++++++++++++++++++++ Placeholder
placeholder(A) ::= PLACEHOLDER(X). { A = g_object_new (SQL_TYPE_HOLDER, "id", X, NULL); }
stmt ::= placeholder.
target ::= placeholder.
expr ::= placeholder.