From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from smtpng3.m.smailru.net (smtpng3.m.smailru.net [94.100.177.149]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by dev.tarantool.org (Postfix) with ESMTPS id 390614696C6 for ; Fri, 27 Dec 2019 14:18:19 +0300 (MSK) From: imeevma@tarantool.org Date: Fri, 27 Dec 2019 14:18:18 +0300 Message-Id: In-Reply-To: References: Subject: [Tarantool-patches] [PATCH v5 5/5] sql: refactor PRAGMA-related code List-Id: Tarantool development patches List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , To: v.shpilevoy@tarantool.org Cc: tarantool-patches@dev.tarantool.org --- src/box/sql/parse.y | 34 +----- src/box/sql/pragma.c | 252 +++++++++++++++++++-------------------- src/box/sql/pragma.h | 101 ++++++---------- src/box/sql/sqlInt.h | 16 ++- test/sql-tap/index-info.test.lua | 2 +- 5 files changed, 176 insertions(+), 229 deletions(-) diff --git a/src/box/sql/parse.y b/src/box/sql/parse.y index 1d0c95f..b5bae5d 100644 --- a/src/box/sql/parse.y +++ b/src/box/sql/parse.y @@ -1542,40 +1542,14 @@ cmd ::= DROP INDEX ifexists(E) nm(X) ON fullname(Y). { ///////////////////////////// The PRAGMA command ///////////////////////////// // cmd ::= PRAGMA nm(X). { - sqlPragma(pParse,&X,0,0,0); + sqlPragma(pParse,&X,0,0); } -cmd ::= PRAGMA nm(X) EQ nmnum(Y). { - sqlPragma(pParse,&X,&Y,0,0); -} -cmd ::= PRAGMA nm(X) LP nmnum(Y) RP. { - sqlPragma(pParse,&X,&Y,0,0); -} -cmd ::= PRAGMA nm(X) EQ minus_num(Y). { - sqlPragma(pParse,&X,&Y,0,1); -} -cmd ::= PRAGMA nm(X) LP minus_num(Y) RP. { - sqlPragma(pParse,&X,&Y,0,1); +cmd ::= PRAGMA nm(X) LP nm(Y) RP. { + sqlPragma(pParse,&X,&Y,0); } cmd ::= PRAGMA nm(X) LP nm(Z) DOT nm(Y) RP. { - sqlPragma(pParse,&X,&Y,&Z,0); + sqlPragma(pParse,&X,&Y,&Z); } -cmd ::= PRAGMA . { - sqlPragma(pParse, 0,0,0,0); -} - -nmnum(A) ::= plus_num(A). -nmnum(A) ::= STRING(A). -nmnum(A) ::= TRUE(A). -nmnum(A) ::= FALSE(A). -nmnum(A) ::= nm(A). -nmnum(A) ::= ON(A). -nmnum(A) ::= DELETE(A). -nmnum(A) ::= DEFAULT(A). - -%token_class number INTEGER|FLOAT. -plus_num(A) ::= PLUS number(X). {A = X;} -plus_num(A) ::= number(A). -minus_num(A) ::= MINUS number(X). {A = X;} //////////////////////////// The CREATE TRIGGER command ///////////////////// cmd ::= createkw trigger_decl(A) BEGIN trigger_cmd_list(S) END(Z). { diff --git a/src/box/sql/pragma.c b/src/box/sql/pragma.c index ee1348c..3f3dac3 100644 --- a/src/box/sql/pragma.c +++ b/src/box/sql/pragma.c @@ -43,22 +43,6 @@ #include "vdbeInt.h" #include "box/schema.h" #include "box/session.h" - -/* - ************************************************************************ - * pragma.h contains several pragmas, including utf's pragmas. - * All that is not utf-8 should be omitted - ************************************************************************ - */ - -/*************************************************************************** - * The "pragma.h" include file is an automatically generated file that - * that includes the PragType_XXXX macro definitions and the aPragmaName[] - * object. This ensures that the aPragmaName[] table is arranged in - * lexicographical order to facility a binary search of the pragma name. - * Do not edit pragma.h directly. Edit and rerun the script in at - * ../tool/mkpragmatab.tcl. - */ #include "pragma.h" #include "tarantoolInt.h" @@ -78,7 +62,7 @@ vdbe_set_pragma_result_columns(struct Vdbe *v, const struct PragmaName *pragma) /* * Locate a pragma in the aPragmaName[] array. */ -static const PragmaName * +static const struct PragmaName * pragmaLocate(const char *zName) { int upr, lwr, mid, rc; @@ -200,7 +184,7 @@ sql_pragma_table_stats(struct space *space, void *data) */ static void sql_pragma_index_info(struct Parse *parse, - MAYBE_UNUSED const PragmaName *pragma, + MAYBE_UNUSED const struct PragmaName *pragma, const char *tbl_name, const char *idx_name) { if (idx_name == NULL || tbl_name == NULL) @@ -239,12 +223,54 @@ sql_pragma_index_info(struct Parse *parse, } /** + * This function handles PRAGMA collation_list. + * + * Return a list of available collations. + * + * - seqno: Zero-based column id within the index. + * - name: Collation name. + * + * @param parse_context Current parsing content. + */ +static void +sql_pragma_collation_list(struct Parse *parse_context) +{ + struct Vdbe *v = sqlGetVdbe(parse_context); + assert(v != NULL); + int i = 0; + struct space *space = space_by_name("_collation"); + /* 16 is enough to encode 0 len array */ + char key_buf[16]; + char *key_end = key_buf; + key_end = mp_encode_array(key_end, 0); + box_tuple_t *tuple; + box_iterator_t* it; + it = box_index_iterator(space->def->id, 0, ITER_ALL, key_buf, key_end); + if (it == NULL) { + parse_context->is_aborted = true; + return; + } + int rc = box_iterator_next(it, &tuple); + assert(rc == 0); + (void) rc; + for (i = 0; tuple != NULL; i++, box_iterator_next(it, &tuple)) { + /* 1 is name field number */ + const char *str = tuple_field_cstr(tuple, 1); + assert(str != NULL); + /* this procedure should reallocate and copy str */ + sqlVdbeMultiLoad(v, 1, "is", i, str); + sqlVdbeAddOp2(v, OP_ResultRow, 1, 2); + } + box_iterator_free(it); +} + +/** * This function handles PRAGMA INDEX_LIST statement. * * @param parse Current parsing content. * @param table_name Name of table to display list of indexes. */ -void +static void sql_pragma_index_list(struct Parse *parse, const char *tbl_name) { if (tbl_name == NULL) @@ -262,156 +288,120 @@ sql_pragma_index_list(struct Parse *parse, const char *tbl_name) } } -/* - * Process a pragma statement. - * - * Pragmas are of this form: - * - * PRAGMA [schema.]id [= value] - * - * The identifier might also be a string. The value is a string, and - * identifier, or a number. If minusFlag is true, then the value is - * a number that was preceded by a minus sign. +/** + * This function handles PRAGMA foreign_key_list(). * - * If the left side is "database.id" then pId1 is the database name - * and pId2 is the id. If the left side is just "id" then pId1 is the - * id and pId2 is any empty string. + * @param parse_context Current parsing content. + * @param table_name Name of table to display list of FK. */ +static void +sql_pragma_foreign_key_list(struct Parse *parse_context, const char *table_name) +{ + if (table_name == NULL) + return; + struct space *space = space_by_name(table_name); + if (space == NULL) + return; + struct Vdbe *v = sqlGetVdbe(parse_context); + assert(v != NULL); + int i = 0; + parse_context->nMem = 8; + struct fk_constraint *fk_c; + rlist_foreach_entry(fk_c, &space->child_fk_constraint, in_child_space) { + struct fk_constraint_def *fk_def = fk_c->def; + for (uint32_t j = 0; j < fk_def->field_count; j++) { + struct space *parent = space_by_id(fk_def->parent_id); + assert(parent != NULL); + uint32_t ch_fl = fk_def->links[j].child_field; + const char *child_col = space->def->fields[ch_fl].name; + uint32_t pr_fl = fk_def->links[j].parent_field; + const char *parent_col = + parent->def->fields[pr_fl].name; + const char *on_delete_action = + fk_constraint_action_strs[fk_def->on_delete]; + const char *on_update_action = + fk_constraint_action_strs[fk_def->on_update]; + sqlVdbeMultiLoad(v, 1, "iissssss", i, j, + parent->def->name, child_col, + parent_col, on_delete_action, + on_update_action, "NONE"); + sqlVdbeAddOp2(v, OP_ResultRow, 1, 8); + } + ++i; + } +} + void -sqlPragma(Parse * pParse, Token * pId, /* First part of [schema.]id field */ - Token * pValue, /* Token for , or NULL */ - Token * pValue2, /* Token for , or NULL */ - int minusFlag /* True if a '-' sign preceded */ - ) +sqlPragma(Parse *pParse, Token *pragma, Token *table, Token *index) { - char *zLeft = 0; /* Nul-terminated UTF-8 string */ - char *zRight = 0; /* Nul-terminated UTF-8 string , or NULL */ - char *zTable = 0; /* Nul-terminated UTF-8 string or NULL */ - sql *db = pParse->db; /* The database connection */ - Vdbe *v = sqlGetVdbe(pParse); /* Prepared statement */ - const PragmaName *pPragma; /* The pragma */ + char *pragma_name = NULL; + char *table_name = NULL; + char *index_name = NULL; + sql *db = pParse->db; + Vdbe *v = sqlGetVdbe(pParse); + const struct PragmaName *pPragma; - if (v == 0) + if (v == NULL) return; sqlVdbeRunOnlyOnce(v); pParse->nMem = 2; - zLeft = sql_name_from_token(db, pId); - if (zLeft == NULL) { + pragma_name = sql_name_from_token(db, pragma); + if (pragma_name == NULL) { pParse->is_aborted = true; goto pragma_out; } - if (minusFlag) { - zRight = sqlMPrintf(db, "-%T", pValue); - } else if (pValue != NULL) { - zRight = sql_name_from_token(db, pValue); - if (zRight == NULL) { + if (table != NULL) { + table_name = sql_name_from_token(db, table); + if (table_name == NULL) { pParse->is_aborted = true; goto pragma_out; } } - if (pValue2 != NULL) { - zTable = sql_name_from_token(db, pValue2); - if (zTable == NULL) { + if (index != NULL) { + index_name = sql_name_from_token(db, index); + if (index_name == NULL) { pParse->is_aborted = true; goto pragma_out; } } + /* Locate the pragma in the lookup table */ - pPragma = pragmaLocate(zLeft); + pPragma = pragmaLocate(pragma_name); if (pPragma == 0) { - diag_set(ClientError, ER_SQL_NO_SUCH_PRAGMA, zLeft); + diag_set(ClientError, ER_SQL_NO_SUCH_PRAGMA, pragma_name); pParse->is_aborted = true; goto pragma_out; } /* Register the result column names for pragmas that return results */ vdbe_set_pragma_result_columns(v, pPragma); + /* Jump to the appropriate pragma handler */ switch (pPragma->ePragTyp) { - - case PragTyp_TABLE_INFO: - sql_pragma_table_info(pParse, zRight); + case PRAGMA_TABLE_INFO: + sql_pragma_table_info(pParse, table_name); break; - case PragTyp_STATS: + case PRAGMA_STATS: space_foreach(sql_pragma_table_stats, (void *) pParse); break; - case PragTyp_INDEX_INFO: - sql_pragma_index_info(pParse, pPragma, zTable, zRight); + case PRAGMA_INDEX_INFO: + sql_pragma_index_info(pParse, pPragma, index_name, table_name); break; - case PragTyp_INDEX_LIST: - sql_pragma_index_list(pParse, zRight); + case PRAGMA_INDEX_LIST: + sql_pragma_index_list(pParse, table_name); break; - - case PragTyp_COLLATION_LIST:{ - int i = 0; - struct space *space = space_by_name("_collation"); - char key_buf[16]; /* 16 is enough to encode 0 len array */ - char *key_end = key_buf; - key_end = mp_encode_array(key_end, 0); - box_tuple_t *tuple; - box_iterator_t* iter; - iter = box_index_iterator(space->def->id, 0,ITER_ALL, key_buf, key_end); - if (iter == NULL) { - pParse->is_aborted = true; - goto pragma_out; - } - int rc = box_iterator_next(iter, &tuple); - (void) rc; - assert(rc == 0); - for (i = 0; tuple!=NULL; i++, box_iterator_next(iter, &tuple)){ - /* 1 is name field number */ - const char *str = tuple_field_cstr(tuple, 1); - assert(str != NULL); - /* this procedure should reallocate and copy str */ - sqlVdbeMultiLoad(v, 1, "is", i, str); - sqlVdbeAddOp2(v, OP_ResultRow, 1, 2); - } - box_iterator_free(iter); + case PRAGMA_COLLATION_LIST: + sql_pragma_collation_list(pParse); break; - } - - case PragTyp_FOREIGN_KEY_LIST:{ - if (zRight == NULL) - break; - struct space *space = space_by_name(zRight); - if (space == NULL) - break; - int i = 0; - pParse->nMem = 8; - struct fk_constraint *fk_c; - rlist_foreach_entry(fk_c, &space->child_fk_constraint, - in_child_space) { - - struct fk_constraint_def *fk_def = fk_c->def; - for (uint32_t j = 0; j < fk_def->field_count; j++) { - struct space *parent = - space_by_id(fk_def->parent_id); - assert(parent != NULL); - uint32_t ch_fl = fk_def->links[j].child_field; - const char *child_col = - space->def->fields[ch_fl].name; - uint32_t pr_fl = fk_def->links[j].parent_field; - const char *parent_col = - parent->def->fields[pr_fl].name; - sqlVdbeMultiLoad(v, 1, "iissssss", i, j, - parent->def->name, - child_col, parent_col, - fk_constraint_action_strs[fk_def->on_delete], - fk_constraint_action_strs[fk_def->on_update], - "NONE"); - sqlVdbeAddOp2(v, OP_ResultRow, 1, 8); - } - ++i; - } + case PRAGMA_FOREIGN_KEY_LIST: + sql_pragma_foreign_key_list(pParse, table_name); break; - } - default: unreachable(); - } /* End of the PRAGMA switch */ + } pragma_out: - sqlDbFree(db, zLeft); - sqlDbFree(db, zRight); - sqlDbFree(db, zTable); + sqlDbFree(db, pragma_name); + sqlDbFree(db, table_name); + sqlDbFree(db, index_name); } diff --git a/src/box/sql/pragma.h b/src/box/sql/pragma.h index 6c66d97..178746b 100644 --- a/src/box/sql/pragma.h +++ b/src/box/sql/pragma.h @@ -1,23 +1,19 @@ -/* DO NOT EDIT! - * This file is automatically generated by the script at - * ../tool/mkpragmatab.tcl. To update the set of pragmas, edit - * that script and rerun it. - */ - -/* The various pragma types */ -#define PragTyp_COLLATION_LIST 3 -#define PragTyp_FOREIGN_KEY_LIST 9 -#define PragTyp_INDEX_INFO 10 -#define PragTyp_INDEX_LIST 11 -#define PragTyp_STATS 15 -#define PragTyp_TABLE_INFO 17 - -/* Property flags associated with various pragma. */ -#define PragFlg_NeedSchema 0x01 /* Force schema load before running */ -#define PragFlg_Result0 0x10 /* Acts as query when no argument */ -#define PragFlg_Result1 0x20 /* Acts as query when has one argument */ -#define PragFlg_SchemaOpt 0x40 /* Schema restricts name search if present */ -#define PragFlg_SchemaReq 0x80 /* Schema required - "main" is default */ +/** List of ID of pragmas. */ +enum +{ + /** Pragma collation_list. */ + PRAGMA_COLLATION_LIST = 0, + /** Pragma foreign_key_list. */ + PRAGMA_FOREIGN_KEY_LIST, + /** Pragma index_info. */ + PRAGMA_INDEX_INFO, + /** Pragma index_list. */ + PRAGMA_INDEX_LIST, + /** Pragma stats. */ + PRAGMA_STATS, + /** Pragma table_info. */ + PRAGMA_TABLE_INFO, +}; /** * Column names and types for pragmas. The type of the column is @@ -90,54 +86,27 @@ static const char *const pragCName[] = { /* 57 */ "text", }; -/* Definitions of all built-in pragmas */ -typedef struct PragmaName { - const char *const zName; /* Name of pragma */ - u8 ePragTyp; /* PragTyp_XXX value */ - u8 mPragFlg; /* Zero or more PragFlg_XXX values */ - u8 iPragCName; /* Start of column names in pragCName[] */ - u8 nPragCName; /* Num of col names. */ - u32 iArg; /* Extra argument */ -} PragmaName; +/** Definitions of all built-in pragmas */ +struct PragmaName { + /** Name of pragma. */ + const char *const zName; + /** Id of pragma. */ + u8 ePragTyp; + /** Start of column names in pragCName[] */ + u8 iPragCName; + /** Number of column names. */ + u8 nPragCName; +}; + /** * The order of pragmas in this array is important: it has * to be sorted. For more info see pragma_locate function. */ -static const PragmaName aPragmaName[] = { - { /* zName: */ "collation_list", - /* ePragTyp: */ PragTyp_COLLATION_LIST, - /* ePragFlg: */ PragFlg_Result0, - /* ColNames: */ 38, 2, - /* iArg: */ 0}, - { /* zName: */ "foreign_key_list", - /* ePragTyp: */ PragTyp_FOREIGN_KEY_LIST, - /* ePragFlg: */ - PragFlg_NeedSchema | PragFlg_Result1 | PragFlg_SchemaOpt, - /* ColNames: */ 42, 8, - /* iArg: */ 0}, - { /* zName: */ "index_info", - /* ePragTyp: */ PragTyp_INDEX_INFO, - /* ePragFlg: */ - PragFlg_NeedSchema | PragFlg_Result1 | PragFlg_SchemaOpt, - /* ColNames: */ 20, 6, - /* iArg: */ 1}, - { /* zName: */ "index_list", - /* ePragTyp: */ PragTyp_INDEX_LIST, - /* ePragFlg: */ - PragFlg_NeedSchema | PragFlg_Result1 | PragFlg_SchemaOpt, - /* ColNames: */ 32, 3, - /* iArg: */ 0}, - { /* zName: */ "stats", - /* ePragTyp: */ PragTyp_STATS, - /* ePragFlg: */ - PragFlg_NeedSchema | PragFlg_Result0 | PragFlg_SchemaReq, - /* ColNames: */ 12, 4, - /* iArg: */ 0}, - { /* zName: */ "table_info", - /* ePragTyp: */ PragTyp_TABLE_INFO, - /* ePragFlg: */ - PragFlg_NeedSchema | PragFlg_Result1 | PragFlg_SchemaOpt, - /* ColNames: */ 0, 6, - /* iArg: */ 0}, +static const struct PragmaName aPragmaName[] = { + {"collation_list", PRAGMA_COLLATION_LIST, 38, 2}, + {"foreign_key_list", PRAGMA_FOREIGN_KEY_LIST, 42, 8}, + {"index_info", PRAGMA_INDEX_INFO, 20, 6}, + {"index_list", PRAGMA_INDEX_LIST, 32, 3}, + {"stats", PRAGMA_STATS, 12, 4}, + {"table_info", PRAGMA_TABLE_INFO, 0, 6}, }; -/* Number of pragmas: 36 on by default, 47 total. */ diff --git a/src/box/sql/sqlInt.h b/src/box/sql/sqlInt.h index d859d63..02f6ad3 100644 --- a/src/box/sql/sqlInt.h +++ b/src/box/sql/sqlInt.h @@ -2767,7 +2767,21 @@ void sqlExprListSetSpan(Parse *, ExprList *, ExprSpan *); u32 sqlExprListFlags(const ExprList *); int sqlInit(sql *); -void sqlPragma(Parse *, Token *, Token *, Token *, int); +/* + * Process a pragma statement. + * + * Pragmas are of this form: + * PRAGMA ; + * PRAGMA (); + * PRAGMA (.); + * + * @param pParse Parse context. + * @param pragma Name of the pragma. + * @param table Name of the table. + * @param index Name of the index. + */ +void +sqlPragma(Parse *pParse, Token *pragma, Token *table, Token *index); /** * Return true if given column is part of primary key. diff --git a/test/sql-tap/index-info.test.lua b/test/sql-tap/index-info.test.lua index a5ed9a9..69eac39 100755 --- a/test/sql-tap/index-info.test.lua +++ b/test/sql-tap/index-info.test.lua @@ -26,7 +26,7 @@ test:do_catchsql_test( "index-info-1.2", "PRAGMA index_info = t1.a;", { - 1, "Syntax error near '.'", + 1, "Syntax error near '='", }) -- Case: single column index with an integer column. -- 2.7.4