%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 . */ #include #include #include #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.