764 lines
19 KiB
Plaintext
764 lines
19 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;
|
|
}
|
|
|
|
%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;
|
|
}
|
|
|
|
%parse_accept {}
|
|
|
|
// 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);
|
|
}
|
|
|
|
// SqlMultiStmt
|
|
%type multi_stmt {SqlStmt *}
|
|
|
|
multi_stmt(multi) ::= stmt_list(stmt).
|
|
{
|
|
gint len = g_slist_length (stmt);
|
|
|
|
if (len > 1)
|
|
{
|
|
multi = SQL_STMT (sql_multi_stmt_new ());
|
|
GSList * n;
|
|
for (n = stmt; n; n = n->next)
|
|
sql_multi_stmt_add_stmt (SQL_MULTI_STMT (multi), n->data);
|
|
}
|
|
else if (len != 0)
|
|
multi = SQL_STMT (stmt->data);
|
|
else
|
|
multi = NULL;
|
|
|
|
g_slist_free (stmt);
|
|
}
|
|
|
|
%type stmt_list {GSList *}
|
|
%destructor stmt_list {g_slist_free ($$);}
|
|
stmt_list(A) ::= stmt(X) SC stmt_list(B). { A = g_slist_prepend (B, X); }
|
|
stmt_list(A) ::= stmt(X). { A = g_slist_prepend (A, X); }
|
|
stmt_list(A) ::= stmt(X) SC. { A = g_slist_prepend (A, X); }
|
|
|
|
// SqlStmt
|
|
%type stmt {SqlStmt *}
|
|
|
|
// SqlSelect
|
|
stmt(stmt) ::= multi_select(select). { stmt = SQL_STMT (select); }
|
|
|
|
%type multi_select {SqlSelect *}
|
|
multi_select(A) ::= multi_select(B) set_op(type) select_stmt(X).
|
|
{
|
|
sql_select_set_next (B, X, type);
|
|
A = B;
|
|
}
|
|
multi_select(A) ::= select_stmt(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 select_stmt {SqlSelect *}
|
|
select_stmt(A) ::= LP select_stmt(X) RP. { A = X; }
|
|
select_stmt(select) ::= SELECT distinct(distinct) select_expr(expr_l)
|
|
from(target_l)
|
|
where(where)
|
|
group(group_l) having(having)
|
|
order(order_l) orderway(way)
|
|
limit(limit).
|
|
{
|
|
GSList * n;
|
|
|
|
select = sql_select_new ();
|
|
|
|
sql_select_set_distinct (select, distinct);
|
|
|
|
for (n = expr_l; n; n = n->next)
|
|
{
|
|
SelectExpr * se = n->data;
|
|
sql_select_add_expr (select, se->expr);
|
|
|
|
if (se->alias)
|
|
{
|
|
sql_select_set_alias (select, se->expr, se->alias);
|
|
g_free (se->alias);
|
|
}
|
|
|
|
g_free (se);
|
|
}
|
|
|
|
g_slist_free (expr_l);
|
|
|
|
for (n = target_l; n; n = n->next)
|
|
sql_dml_add_target (SQL_DML (select), n->data);
|
|
|
|
g_slist_free (target_l);
|
|
|
|
if (where)
|
|
sql_dml_set_where (SQL_DML (select), where);
|
|
|
|
if (group_l)
|
|
{
|
|
for (n = group_l; n; n = n->next)
|
|
sql_select_add_group (select, n->data);
|
|
|
|
g_slist_free (group_l);
|
|
|
|
if (having)
|
|
sql_select_set_having (select, having);
|
|
}
|
|
|
|
if (order_l)
|
|
{
|
|
for (n = order_l; n; n = n->next)
|
|
sql_select_add_order (select, n->data, way);
|
|
|
|
g_slist_free (order_l);
|
|
}
|
|
|
|
if (limit)
|
|
{
|
|
sql_select_set_limit (select
|
|
,limit[0] ? (guint) atoi (limit[0]): 0
|
|
,limit[1] ? (guint) atoi (limit[1]): 0
|
|
);
|
|
|
|
g_strfreev (limit);
|
|
}
|
|
}
|
|
|
|
%type distinct {gboolean}
|
|
distinct(A) ::= DISTINCT. { A = TRUE; }
|
|
distinct(A) ::= ALL. { A = FALSE; }
|
|
distinct(A) ::= . { A = FALSE; }
|
|
|
|
// Expressions with optional alias, only found in the SELECT clause
|
|
%type select_expr {GSList *}
|
|
%include
|
|
{
|
|
typedef struct
|
|
{
|
|
SqlExpr * expr;
|
|
gchar * alias;
|
|
}
|
|
SelectExpr;
|
|
|
|
static inline GSList * sql_parser_alias_expr_add
|
|
(GSList * list, SqlExpr * expr, gchar * alias)
|
|
{
|
|
SelectExpr * sexpr = g_new (SelectExpr, 1);
|
|
sexpr->expr = expr;
|
|
sexpr->alias = alias;
|
|
return g_slist_append (list, sexpr);
|
|
}
|
|
}
|
|
%destructor select_expr {g_slist_free_full ($$, (GDestroyNotify) g_free);}
|
|
select_expr(A) ::= select_expr(B) CM expr(X).
|
|
{ A = sql_parser_alias_expr_add (B, X, NULL); }
|
|
select_expr(A) ::= select_expr(B) CM expr(X) alias(Y).
|
|
{ A = sql_parser_alias_expr_add (B, X, Y); }
|
|
select_expr(A) ::= expr(X).
|
|
{ A = sql_parser_alias_expr_add (A, X, NULL); }
|
|
select_expr(A) ::= expr(X) alias(Y).
|
|
{ A = sql_parser_alias_expr_add (A, X, Y); }
|
|
|
|
%type from {GSList *}
|
|
%destructor from {g_slist_free ($$);}
|
|
from(A) ::= FROM target_list(X). { A = X; }
|
|
from(A) ::= . { A = NULL; }
|
|
|
|
%type group {GSList *}
|
|
%destructor group {g_slist_free ($$);}
|
|
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 {GSList *}
|
|
%destructor order {g_slist_free ($$);}
|
|
order(A) ::= ORDER expr_list (X). { A = X; }
|
|
order(A) ::= . { A = NULL; }
|
|
|
|
%type orderway {SqlOrderWay}
|
|
orderway(A) ::= ASC. { A = SQL_ORDER_ASC; }
|
|
orderway(A) ::= DESC. { A = SQL_ORDER_DESC; }
|
|
orderway(A) ::= . { A = SQL_ORDER_ASC; }
|
|
|
|
%type limit {gchar **}
|
|
%include
|
|
{
|
|
gchar ** sql_parser_limit (gchar * limit, gchar * offset)
|
|
{
|
|
gchar ** r = g_new (gchar *, 3);
|
|
r[0] = limit;
|
|
r[1] = offset;
|
|
r[2] = NULL;
|
|
return r;
|
|
}
|
|
}
|
|
limit(A) ::= LIMIT INTEGER(X). { A = sql_parser_limit (X, NULL); }
|
|
limit(A) ::= OFFSET INTEGER(Y). { A = sql_parser_limit (NULL, Y); }
|
|
limit(A) ::= LIMIT INTEGER(X)
|
|
OFFSET INTEGER(Y). { A = sql_parser_limit (X, Y); }
|
|
limit(A) ::= LIMIT INTEGER(X)
|
|
CM INTEGER(Y). { A = sql_parser_limit (Y, X); }
|
|
limit(A) ::= . { A = NULL; }
|
|
|
|
// SqlDelete
|
|
stmt(stmt) ::= delete_stmt(delete). { stmt = SQL_STMT (delete); }
|
|
|
|
%type delete_stmt {SqlDelete *}
|
|
delete_stmt(delete) ::= DELETE table_list(target) del_using(using) where(where).
|
|
{
|
|
GSList * n;
|
|
delete = sql_delete_new ();
|
|
|
|
for (n = target; n; n = n->next)
|
|
sql_dml_add_target (SQL_DML (delete), n->data);
|
|
g_slist_free (target);
|
|
|
|
for (n = using; n; n = n->next)
|
|
sql_delete_add_table (delete, n->data);
|
|
g_slist_free (using);
|
|
|
|
if (where)
|
|
sql_dml_set_where (SQL_DML (delete), where);
|
|
}
|
|
|
|
%type table_list {GSList *}
|
|
%destructor table_list {g_slist_free ($$);}
|
|
table_list(A) ::= table_list(B) CM table(X). { A = g_slist_append (B, X); }
|
|
table_list(A) ::= table(X). { A = g_slist_append (A, X); }
|
|
|
|
%type del_using {GSList *}
|
|
del_using(A) ::= USING target_list(X). { A = X; }
|
|
del_using(A) ::= . { A = NULL; }
|
|
|
|
// SqlUpdate
|
|
stmt(stmt) ::= update_stmt(update). { stmt = SQL_STMT (update); }
|
|
|
|
%type update_stmt {SqlUpdate *}
|
|
update_stmt(update) ::= UPDATE table(table) SET update_list(u_list) where(where).
|
|
{
|
|
GSList * n;
|
|
update = sql_update_new ();
|
|
|
|
sql_dml_add_target (SQL_DML (update), table);
|
|
|
|
for (n = u_list; n; n = n->next)
|
|
{
|
|
sql_update_add_set (update
|
|
,((SqlUpdateSet *) n->data)->field
|
|
,((SqlUpdateSet *) n->data)->expr
|
|
);
|
|
g_free (n->data);
|
|
}
|
|
g_slist_free (u_list);
|
|
|
|
if (where)
|
|
sql_dml_set_where (SQL_DML (update), where);
|
|
}
|
|
|
|
%type update_list {GSList *}
|
|
%destructor update_list {g_slist_free ($$);}
|
|
update_list(A) ::= update_list(B) CM update_set(X). { A = g_slist_append (B, X); }
|
|
update_list(A) ::= update_set(X). { A = g_slist_append (A, X); }
|
|
|
|
%type update_set {SqlUpdateSet *}
|
|
update_set(A) ::= field(X) EQ expr(Y).
|
|
{
|
|
A = g_new (SqlUpdateSet, 1);
|
|
A->field = SQL_FIELD (X);
|
|
A->expr = Y;
|
|
}
|
|
update_set(A) ::= field(X) EQ DEFAULT.
|
|
{
|
|
A = g_new (SqlUpdateSet, 1);
|
|
A->field = SQL_FIELD (X);
|
|
A->expr = NULL;
|
|
}
|
|
|
|
// Common to SELECT, DELETE and UPDATE
|
|
%type where {SqlExpr *}
|
|
where(A) ::= WHERE expr(X). { A = SQL_EXPR (X); }
|
|
where(A) ::= . { A = NULL; }
|
|
|
|
// SqlInsert
|
|
stmt(stmt) ::= insert_stmt(insert). { stmt = SQL_STMT (insert); }
|
|
|
|
%type insert_stmt {SqlInsert *}
|
|
insert_stmt(insert) ::= INSERT table(table) ins_fields(field) ins_values(value).
|
|
{
|
|
GSList * ll, * n;
|
|
insert = sql_insert_new ();
|
|
sql_insert_set_table (insert, SQL_TABLE (table));
|
|
|
|
for (n = field; n; n = n->next)
|
|
sql_insert_add_field (insert, n->data);
|
|
|
|
g_slist_free (field);
|
|
|
|
for (ll = value; ll; ll = ll->next)
|
|
{
|
|
sql_insert_add_row (insert);
|
|
|
|
for (n = ll->data; n; n = n->next)
|
|
sql_insert_add_expr (insert, n->data);
|
|
g_slist_free (ll->data);
|
|
}
|
|
|
|
g_slist_free (ll);
|
|
}
|
|
|
|
%type ins_fields {GSList *}
|
|
%destructor ins_fields {g_slist_free ($$);}
|
|
ins_fields(A) ::= LP field_list(X) RP. { A = X; }
|
|
ins_fields(A) ::= . { A = NULL; }
|
|
|
|
%type ins_values {GSList *}
|
|
ins_values ::= DEFAULT VALUES.
|
|
ins_values(A) ::= VALUES list_list(X). { A = X; }
|
|
//ins_values ::= multi_select.// not supported by the parsetree;
|
|
|
|
%type list_list {GSList *}
|
|
%destructor list_list {g_slist_free ($$);}
|
|
list_list(A) ::= list_list(B) CM LP def_expr_list(X) RP. { A = g_slist_append (B, X); }
|
|
list_list(A) ::= LP def_expr_list(X) RP. { A = g_slist_append (A, X); }
|
|
|
|
%type def_expr_list {GSList *}
|
|
%destructor def_expr_list {g_slist_free ($$);}
|
|
def_expr_list(A) ::= def_expr_list(B) CM def_expr(X). { A = g_slist_append (B, X); }
|
|
def_expr_list(A) ::= def_expr(X). { A = g_slist_append (A, X); }
|
|
|
|
%type def_expr {SqlExpr *}
|
|
def_expr(A) ::= DEFAULT. { A = NULL; }
|
|
def_expr(A) ::= expr(X). { A = X; }
|
|
|
|
// Common to all the statements
|
|
|
|
// SqlTarget
|
|
%type target {SqlTarget *}
|
|
//target(A) ::= LP target(B) RP. { A = B; }
|
|
target(A) ::= target(B) alias(X).
|
|
{
|
|
sql_target_set_alias (B, X);
|
|
g_free (X);
|
|
A = B;
|
|
}
|
|
|
|
%type target_list {GSList *}
|
|
%destructor target_list {g_slist_free ($$);}
|
|
target_list(A) ::= target_list(B) CM target(X). { A = g_slist_append (B, X); }
|
|
target_list(A) ::= target(X). { A = g_slist_append (A, X); }
|
|
|
|
target(A) ::= join(X). { A = X; }
|
|
target(A) ::= subquery(X). { A = X; }
|
|
target(A) ::= table(X). { A = X; }
|
|
|
|
// SqlJoin
|
|
%type join {SqlTarget *}
|
|
join(join) ::= target(left) join_type(jtype) target(right) join_cond(condition).
|
|
{
|
|
join = sql_join_new (left, right, jtype);
|
|
|
|
if (condition)
|
|
{
|
|
if (SQL_IS_EXPR (condition))
|
|
sql_join_set_condition (SQL_JOIN (join), condition);
|
|
else // USING list (GSList of SqlField)
|
|
{
|
|
SqlOperation * op = NULL;
|
|
GSList * n, * cond_list = condition;
|
|
gboolean use_cond = cond_list && cond_list->next ? TRUE : FALSE;
|
|
SqlOperation * cond = use_cond ?
|
|
sql_operation_new (SQL_OPERATION_TYPE_AND) :
|
|
NULL;
|
|
|
|
for (n = condition; n; n = n->next)
|
|
{
|
|
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;
|
|
op = sql_operation_new (SQL_OPERATION_TYPE_EQUAL);
|
|
|
|
g_object_set (n->data, "target", target, "schema", schema, NULL);
|
|
|
|
sql_operation_add_expr (op, 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_operation_add_expr (op,
|
|
sql_field_new (SQL_FIELD (n->data)->name, target, schema));
|
|
|
|
if (use_cond)
|
|
sql_operation_add_expr (cond, SQL_EXPR (op));
|
|
}
|
|
|
|
g_slist_free (condition);
|
|
|
|
sql_join_set_condition (SQL_JOIN (join),
|
|
use_cond ? SQL_EXPR (cond) : SQL_EXPR (op));
|
|
}
|
|
}
|
|
}
|
|
|
|
%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; }// A : SqlExpr
|
|
join_cond(A) ::= USING LP field_list(X) RP. { A = X; }// A : GSList
|
|
|
|
// SqlSubquery
|
|
%type subquery {SqlTarget *}
|
|
|
|
subquery(sub) ::= LP multi_select(stmt) RP.
|
|
{ sub = SQL_TARGET (sql_subquery_new (stmt)); }
|
|
|
|
//SqlTable
|
|
%type table {SqlTarget *}
|
|
|
|
table(A) ::= identifier(X).
|
|
{
|
|
A = sql_table_new (X);
|
|
g_free (X);
|
|
}
|
|
table(A) ::= identifier(Y) DOT identifier(X).
|
|
{
|
|
A = sql_table_new (X);
|
|
g_object_set (A, "schema", Y, NULL);
|
|
g_free (Y);
|
|
g_free (X);
|
|
}
|
|
|
|
// SqlExpr
|
|
%type expr {SqlExpr *}
|
|
expr(A) ::= LP expr(X) RP. { A = X; }
|
|
|
|
%type expr_list {GSList *}
|
|
%destructor expr_list {g_slist_free ($$);}
|
|
expr_list(A) ::= expr_list(B) CM expr(X). { A = g_slist_append (B, X); }
|
|
expr_list(A) ::= expr(X). { A = g_slist_append (A, X); }
|
|
|
|
expr(A) ::= field(X). { A = X; }
|
|
expr(A) ::= function(X). { A = X; }
|
|
expr(A) ::= operation(X). { A = SQL_EXPR (X); }
|
|
expr(A) ::= value(X). { A = X; }
|
|
|
|
// SqlField
|
|
%type field {SqlExpr *}
|
|
field(A) ::= identifier(X).
|
|
{
|
|
A = sql_field_new (X, NULL, NULL);
|
|
g_free (X);
|
|
}
|
|
field(A) ::= STAR.
|
|
{
|
|
A = sql_field_new ("*", NULL, NULL);
|
|
}
|
|
field(A) ::= identifier(Y) DOT identifier(X).
|
|
{
|
|
A = sql_field_new (X, Y, NULL);
|
|
g_free (X);
|
|
g_free (Y);
|
|
}
|
|
field(A) ::= identifier(Y) DOT STAR.
|
|
{
|
|
A = sql_field_new ("*", Y, NULL);
|
|
g_free (Y);
|
|
}
|
|
field(A) ::= identifier(Z) DOT identifier(Y) DOT identifier(X).
|
|
{
|
|
A = sql_field_new (X, Y, Z);
|
|
g_free (X);
|
|
g_free (Y);
|
|
g_free (Z);
|
|
}
|
|
field(A) ::= identifier(Z) DOT identifier(Y) DOT STAR.
|
|
{
|
|
A = sql_field_new ("*", Y, Z);
|
|
g_free (Y);
|
|
g_free (Z);
|
|
}
|
|
|
|
%type field_list {GSList *}
|
|
%destructor field_list {g_slist_free ($$);}
|
|
field_list(A) ::= field_list(B) CM field(X). { A = g_slist_append (B, X); }
|
|
field_list(A) ::= field(X). { A = g_slist_append (A, X); }
|
|
|
|
// SqlFunction
|
|
%type function {SqlExpr *}
|
|
|
|
function(A) ::= identifier(Y) DOT identifier(X) LP RP.
|
|
{
|
|
A = SQL_EXPR (sql_function_new (X, Y));
|
|
g_free (X);
|
|
g_free (Y);
|
|
}
|
|
function(A) ::= identifier(X) LP RP.
|
|
{
|
|
A = SQL_EXPR (sql_function_new (X, NULL));
|
|
g_free (X);
|
|
}
|
|
function(A) ::= identifier(Z) DOT identifier(X) LP expr_list(Y) RP.
|
|
{
|
|
GSList * n = NULL;
|
|
A = SQL_EXPR (sql_function_new (X, Z));
|
|
for ( n = Y; n; n = n->next)
|
|
sql_function_add_param (SQL_FUNCTION (A), n->data);
|
|
g_slist_free (Y);
|
|
g_free (X);
|
|
}
|
|
function(A) ::= identifier(X) LP expr_list(Y) RP.
|
|
{
|
|
GSList * n = NULL;
|
|
A = SQL_EXPR (sql_function_new (X, NULL));
|
|
for ( n = Y; n; n = n->next)
|
|
sql_function_add_param (SQL_FUNCTION (A), n->data);
|
|
g_slist_free (Y);
|
|
g_free (X);
|
|
}
|
|
function(A) ::= expr(X) MOD expr(Y).
|
|
{
|
|
A = SQL_EXPR (sql_function_new ("MOD", NULL));
|
|
sql_function_add_param (SQL_FUNCTION (A), SQL_EXPR (X));
|
|
sql_function_add_param (SQL_FUNCTION (A), SQL_EXPR (Y));
|
|
}
|
|
|
|
// SqlOperation
|
|
%type operation {SqlOperation *}
|
|
%include
|
|
{
|
|
static inline SqlOperation * sql_parser_create_operation
|
|
(const gpointer X, const gpointer Y, const SqlOperationType type)
|
|
{
|
|
SqlOperation * op = sql_operation_new (type);
|
|
sql_operation_add_expr (op, SQL_EXPR (X));
|
|
if (Y) // Y == NULL for unary operations
|
|
sql_operation_add_expr (op, SQL_EXPR (Y));
|
|
return op;
|
|
}
|
|
}
|
|
|
|
operation(A) ::= MINUS expr(X). [SIGN]
|
|
{
|
|
GValue value = G_VALUE_INIT;
|
|
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 = sql_parser_create_operation (X, minus, SQL_OPERATION_TYPE_MULTIPLICATION);
|
|
}
|
|
|
|
operation(A) ::= PLUS expr(X). [SIGN]
|
|
{ A = sql_parser_create_operation (X, NULL, SQL_OPERATION_TYPE_SUM); }
|
|
|
|
operation(A) ::= expr(X) PLUS expr(Y).
|
|
{ A = sql_parser_create_operation (X, Y, SQL_OPERATION_TYPE_SUM); }
|
|
|
|
operation(A) ::= expr(X) MINUS expr(Y).
|
|
{ A = sql_parser_create_operation (X, Y, SQL_OPERATION_TYPE_REST); }
|
|
|
|
operation(A) ::= expr(X) STAR expr(Y).
|
|
{ A = sql_parser_create_operation (X, Y, SQL_OPERATION_TYPE_MULTIPLICATION); }
|
|
|
|
operation(A) ::= expr(X) DIV expr(Y).
|
|
{ A = sql_parser_create_operation (X, Y, SQL_OPERATION_TYPE_DIVISION); }
|
|
|
|
operation(A) ::= expr(X) OR expr(Y).
|
|
{ A = sql_parser_create_operation (X, Y, SQL_OPERATION_TYPE_OR); }
|
|
|
|
operation(A) ::= expr(X) XOR expr(Y).
|
|
{ A = sql_parser_create_operation (X, Y, SQL_OPERATION_TYPE_XOR); }
|
|
|
|
operation(A) ::= expr(X) AND expr(Y).
|
|
{ A = sql_parser_create_operation (X, Y, SQL_OPERATION_TYPE_AND); }
|
|
|
|
operation(A) ::= NOT expr(X).
|
|
{ A = sql_parser_create_operation (X, NULL, SQL_OPERATION_TYPE_NOT); }
|
|
|
|
operation(A) ::= expr(X) EQ expr(Y).
|
|
{ A = sql_parser_create_operation (X, Y, SQL_OPERATION_TYPE_EQUAL); }
|
|
|
|
operation(A) ::= expr(X) NE expr(Y).
|
|
{ A = sql_parser_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 = sql_parser_create_operation (X, Y, SQL_OPERATION_TYPE_GREATER); }
|
|
|
|
operation(A) ::= expr(X) GE expr(Y).
|
|
{ A = sql_parser_create_operation (X, Y, SQL_OPERATION_TYPE_GREATER_EQUAL); }
|
|
|
|
operation(A) ::= expr(X) LT expr(Y).
|
|
{ A = sql_parser_create_operation (X, Y, SQL_OPERATION_TYPE_LOWER); }
|
|
|
|
operation(A) ::= expr(X) LE expr(Y).
|
|
{ A = sql_parser_create_operation (X, Y, SQL_OPERATION_TYPE_LOWER_EQUAL); }
|
|
|
|
operation(A) ::= expr(X) LIKE expr(Y).
|
|
{ A = sql_parser_create_operation (X, Y, SQL_OPERATION_TYPE_LIKE); }
|
|
|
|
operation(A) ::= expr(X) IS expr(Y).
|
|
{ A = sql_parser_create_operation (X, Y, SQL_OPERATION_TYPE_IS); }
|
|
|
|
// SqlValue
|
|
%type value {SqlExpr *}
|
|
|
|
value(A) ::= INTEGER(X).
|
|
{
|
|
GValue value = G_VALUE_INIT;
|
|
SqlExpr * v = sql_value_new ();
|
|
g_value_set_int (g_value_init (&value, G_TYPE_INT), atoi (X));
|
|
sql_value_set_value (SQL_VALUE (v), &value);
|
|
g_free (X);
|
|
A = v;
|
|
}
|
|
|
|
value(A) ::= FLOAT(X).
|
|
{
|
|
GValue value = G_VALUE_INIT;
|
|
SqlExpr * v = sql_value_new ();
|
|
g_value_set_double
|
|
(g_value_init (&value, G_TYPE_DOUBLE), g_ascii_strtod (X, NULL));
|
|
sql_value_set_value (SQL_VALUE (v), &value);
|
|
g_free (X);
|
|
A = v;
|
|
}
|
|
|
|
value(A) ::= STRING(X).
|
|
{
|
|
GValue value = G_VALUE_INIT;
|
|
SqlExpr * v = sql_value_new ();
|
|
g_value_set_string (g_value_init (&value, G_TYPE_STRING), X);
|
|
sql_value_set_value (SQL_VALUE (v), &value);
|
|
g_free (X);
|
|
A = v;
|
|
}
|
|
|
|
value(A) ::= BOOLEAN(X).
|
|
{
|
|
GValue value = G_VALUE_INIT;
|
|
SqlExpr * v = sql_value_new ();
|
|
g_value_set_boolean (g_value_init (&value, G_TYPE_BOOLEAN)
|
|
,(!g_strcmp0 (X, "TRUE") || !g_strcmp0 (X, "true")) ? TRUE : FALSE);
|
|
sql_value_set_value (SQL_VALUE (v), &value);
|
|
g_free (X);
|
|
A = v;
|
|
}
|
|
|
|
// 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; }
|
|
|
|
// Placeholders
|
|
%type placeholder {gchar *}
|
|
%destructor expr {g_free ($$);}
|
|
placeholder(A) ::= PLACEHOLDER(X). { A = X; }
|
|
|
|
stmt ::= placeholder.
|
|
target ::= placeholder.
|
|
expr ::= placeholder.
|