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

651 lines
18 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 error;
}
ParseState;
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);
}
}
%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_log (g_quark_to_string (SQL_PARSER_LOG_DOMAIN), G_LOG_LEVEL_WARNING,
"Parsing error%s%s", pref, err_str);
state->error = TRUE;
}
%stack_overflow
{
g_log (g_quark_to_string (SQL_PARSER_LOG_DOMAIN)
,G_LOG_LEVEL_WARNING
,"Parser stack overflow. Parsing terminated.\n");
}
// 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
%type start {SqlObject *}
start ::= multi_stmt (A).
{
state->object = SQL_OBJECT (A);
}
//+++++++++++++++++++++++++++++++++++++++++++++++++++ Multi statement
%type multi_stmt {SqlStmt *}
multi_stmt(A) ::= stmt_list(stmts).
{
guint len = sql_list_length (stmts);
if (len == 1)
{
A = sql_list_get (stmts, 0);
g_object_unref (g_object_ref_sink (stmts));
}
else
A = g_object_new (SQL_TYPE_MULTI_STMT, "stmts", stmts, 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
%type stmt {SqlStmt *}
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
%type select_stmt {SqlStmt *}
select_stmt(A) ::= select_stmt(B) set_op(type) simple_select(X).
{
g_object_set (B, "type", 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; }
%type simple_select {SqlStmt *}
simple_select(A) ::= LP simple_select(X) RP. { A = X; }
simple_select(A) ::= SELECT
distinct(distinct)
select_field_list(fields)
from(targets)
where(where)
group(group) having(having)
order(order)
limit(limit).
{
A = g_object_new (SQL_TYPE_SELECT
,"distinct" ,distinct
,"fields" ,fields
,"targets" ,targets
,"where" ,where
,"group" ,group
,"having" ,having
,"having" ,having
,"order" ,order
,NULL
);
if (limit)
g_object_set (A
,"limit-offset" ,limit->offset
,"limit-count" ,limit->count
,NULL
);
}
%type distinct {gboolean}
distinct(A) ::= DISTINCT. { A = TRUE; }
distinct(A) ::= ALL. { A = FALSE; }
distinct(A) ::= . { A = FALSE; }
%type select_field {SqlSelectField *}
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; }
%type having {SqlExpr *}
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); }
%type order_expr {SqlSelectOrder *}
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
%type delete_stmt {SqlStmt *}
delete_stmt(A) ::= DELETE table_list(targets) del_using(tables) where(where).
{
A = g_object_new (SQL_TYPE_DELETE
,"targets" ,targets
,"tables" ,tables
,"where" ,where
,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
%type update_stmt {SqlStmt *}
update_stmt(A) ::= UPDATE table(table) SET update_list(sets) where(where).
{
A = g_object_new (SQL_TYPE_UPDATE
,"targets" ,table
,"sets" ,sets
,"where" ,where
,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); }
%type update_set {SqlUpdateSet *}
update_set(A) ::= field(X) EQ def_expr(Y).
{
A = g_object_new (SQL_TYPE_UPDATE_SET
,"field" ,X
,"expr" ,Y
,NULL
);
}
//+++++++++++++++++++++++++++++++++++++++++++++++++++ Insert
%type insert_stmt {SqlStmt *}
insert_stmt(A) ::= INSERT table(table) insert_fields(fields) insert_values(values).
{
A = g_object_new (SQL_TYPE_INSERT
,"table" ,table
,"fields" ,fields
,NULL
);
if (SQL_IS_SELECT (values))
g_object_set (A, "select", values, NULL);
else
g_object_set (A, "values", 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); }
%type set {SqlSet *}
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
%type where {SqlExpr *}
where(A) ::= WHERE expr(X). { A = SQL_EXPR (X); }
where(A) ::= . { A = NULL; }
%type def_expr {SqlExpr *}
def_expr(A) ::= expr(X). { A = X; }
def_expr(A) ::= DEFAULT. { A = NULL; }
//+++++++++++++++++++++++++++++++++++++++++++++++++++ Target
%type target {SqlTarget *}
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); }
%type unaliased_target {SqlTarget *}
unaliased_target(A) ::= join(X). { A = X; }
unaliased_target(A) ::= subquery(X). { A = X; }
unaliased_target(A) ::= table(X). { A = X; }
//+++++++++++++++++++++++++++++++++++++++++++++++++++ Join
%type join {SqlTarget *}
join(A) ::= target(left) join_type(type) target(right) join_cond(condition).
{
A = g_object_new (SQL_TYPE_JOIN
,"target-left" ,left
,"target-right" ,right
,"join-type" ,type
,NULL
);
if (SQL_IS_LIST (condition)) // USING
{
GList * n;
SqlList * exprs = sql_list_new (SQL_TYPE_EXPR);
SqlOperation * op_and = g_object_new (SQL_TYPE_OPERATION
,"type" ,SQL_OPERATION_TYPE_AND
,"exprs" ,exprs
,NULL
);
for (n = sql_list_get_items (condition); n; n = n->next)
{
SqlList * equal = sql_list_new (SQL_TYPE_EXPR);
SqlOperation * op = g_object_new (SQL_TYPE_OPERATION
,"type" ,SQL_OPERATION_TYPE_EQUAL
,"exprs" ,equal
,NULL
);
gchar * target = left->alias ?
left->alias : SQL_TABLE (left)->name;
gchar * schema = SQL_IS_TABLE(left) && SQL_TABLE (left)->schema ?
SQL_TABLE (left)->schema : NULL;
g_object_set (n->data, "target", target, "schema", schema, NULL);
sql_list_add (equal, n->data);
target = right->alias ? right->alias : SQL_TABLE (right)->name;
schema = SQL_IS_TABLE (right) && SQL_TABLE (right)->schema ?
SQL_TABLE (right)->schema : NULL;
sql_list_add (equal,
sql_field_new (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 (condition));
}
else
g_object_set (A, "condition", condition, 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
%type subquery {SqlTarget *}
subquery(A) ::= LP select_stmt(stmts) RP.
{
A = g_object_new (SQL_TYPE_SUBQUERY, "stms", stmts, NULL);
}
//+++++++++++++++++++++++++++++++++++++++++++++++++++ Table
%type table {SqlTarget *}
table(A) ::= identifier(X).
{
A = g_object_new (SQL_TYPE_TABLE, "table", X, NULL);
}
table(A) ::= identifier(Y) DOT identifier(X).
{
A = g_object_new (SQL_TYPE_TABLE, "table", X, "schema", Y, NULL);
}
//+++++++++++++++++++++++++++++++++++++++++++++++++++ Expr
%type expr {SqlExpr *}
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
%type field {SqlExpr *}
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;
}
%type unqualified_field {SqlExpr *}
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
%type function {SqlExpr *}
function(A) ::= unqualified_function(X). { A = X; }
function(A) ::= identifier(Z) DOT unqualified_function(X).
{
g_object_set (X, "schema", Z, NULL);
A = X;
}
%type unqualified_function {SqlExpr *}
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
%type operation {SqlExpr *}
%include
{
static inline SqlExpr * 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, "type", type, "exprs", exprs, NULL);
}
}
operation(A) ::= MINUS expr(X). [SIGN]
{
GValue value = {0};
SqlExpr * 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
%type value {SqlExpr *}
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 *}
%destructor alias {g_free ($$);}
alias(A) ::= AS identifier(X). { A = X; }
alias(A) ::= identifier(X). { A = X; }
identifier(A) ::= IDENTIFIER(X). { A = X; }
//+++++++++++++++++++++++++++++++++++++++++++++++++++ Placeholder
%type placeholder {gchar *}
%destructor expr {g_free ($$);}
placeholder(A) ::= PLACEHOLDER(X). { A = X; }
stmt ::= placeholder.
target ::= placeholder.
expr ::= placeholder.