From: <mro...@us...> - 2014-11-29 15:40:28
|
Revision: 60305 http://sourceforge.net/p/firebird/code/60305 Author: mrotteveel Date: 2014-11-29 15:39:59 +0000 (Sat, 29 Nov 2014) Log Message: ----------- CORE-4526 Support for SQL:2008 OFFSET and FETCH clauses Modified Paths: -------------- firebird/trunk/doc/sql.extensions/README.rows firebird/trunk/src/dsql/parse.y firebird/trunk/src/include/gen/msgs.h firebird/trunk/src/msgs/messages2.sql firebird/trunk/src/yvalve/keywords.cpp Added Paths: ----------- firebird/trunk/doc/sql.extensions/README.offset_fetch.txt Added: firebird/trunk/doc/sql.extensions/README.offset_fetch.txt =================================================================== --- firebird/trunk/doc/sql.extensions/README.offset_fetch.txt (rev 0) +++ firebird/trunk/doc/sql.extensions/README.offset_fetch.txt 2014-11-29 15:39:59 UTC (rev 60305) @@ -0,0 +1,53 @@ +----------------------- +OFFSET and FETCH clause +----------------------- + + Function: + SQL:2008 compliant equivalent for FIRST/SKIP, and an alternative for ROWS. + The OFFSET clause specifies the number of rows to skip. The FETCH clause + specifies the number of rows to fetch. + + OFFSET and FETCH can be applied independently on top-level and nested query + expressions. + + Author: + Mark Rotteveel <mro...@us...> + + Syntax rules: + SELECT ... [ ORDER BY <expr_list> ] + [ OFFSET <simple_value_expr> { ROW | ROWS } ] + [ FETCH { FIRST | NEXT } [ <simple_value_expr> ] { ROW | ROWS } ONLY ] + + Where <simple_value_expr> is a (numeric) literal, a SQL parameter (?) or + PSQL named parameter (:namedparameter). + + Scope: + DSQL, PSQL + + Example(s): + 1. SELECT * FROM T1 + ORDER BY COL1 + OFFSET 10 ROWS + 2. SELECT * FROM T1 + ORDER BY COL1 + FETCH FIRST 10 ROWS ONLY + 3. SELECT * FROM ( + SELECT * FROM T1 + ORDER BY COL1 DESC + OFFSET 1 ROW + FETCH NEXT 10 ROWS ONLY + ) a + ORDER BY a.COL1 + FETCH FIRST ROW ONLY + + Note(s): + 1. Firebird doesn't support the percentage FETCH defined in the SQL + standard. + 2. Firebird doesn't support the FETCH ... WITH TIES defined in the SQL + standard. + 3. The FIRST/SKIP and ROWS clause are non-standard alternatives. + 4. The OFFSET and/or FETCH clauses cannot be combined with ROWS or + FIRST/SKIP on the same query expression. + 5. Expressions, column references, etc are not allowed within either clause. + 6. Contrary to the ROWS clause, OFFSET and FETCH are only available on + SELECT statements. \ No newline at end of file Property changes on: firebird/trunk/doc/sql.extensions/README.offset_fetch.txt ___________________________________________________________________ Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Modified: firebird/trunk/doc/sql.extensions/README.rows =================================================================== --- firebird/trunk/doc/sql.extensions/README.rows 2014-11-29 06:00:26 UTC (rev 60304) +++ firebird/trunk/doc/sql.extensions/README.rows 2014-11-29 15:39:59 UTC (rev 60305) @@ -3,8 +3,9 @@ ----------- Function: - Allow to limit a number of rows retrieved from a select expression. For a highest level - select statement, it would mean a number of rows sent to the host program. + Limits the number of rows retrieved from a select expression. For the + top-level select statement, it would mean a number of rows sent to the host + program. Author: Dmitry Yemanov <ye...@ya...> @@ -28,10 +29,13 @@ ROWS 1 Note(s): - 1. ROWS is a more understandable alternative to the FIRST/SKIP clauses with some extra benefits. - It can be used in unions and all kind of subqueries. Also it's available in the UPDATE/DELETE - statements. - 2. When <expr2> is omitted, then ROWS <expr1> is a semantical equivalent for FIRST <expr1>. When - both <expr1> and <expr2> are used, then ROWS <expr1> TO <expr2> means: - FIRST (<expr2> - <expr1> + 1) SKIP (<expr1> - 1). Note that there's no semantical equivalent - for a SKIP clause used without a FIRST clause. + 1. ROWS is a more understandable alternative to the FIRST/SKIP clauses with + some extra benefits. It can be used in unions and all kind of subqueries. + It is also available in the UPDATE/DELETE statements. + 2. When <expr2> is omitted, then ROWS <expr1> is a semantical equivalent for + FIRST <expr1>. When both <expr1> and <expr2> are used, then ROWS <expr1> + TO <expr2> means: + FIRST (<expr2> - <expr1> + 1) SKIP (<expr1> - 1). Note that there's no + semantic equivalent for a SKIP clause used without a FIRST clause. + 3. The ROWS-clause is not defined in the SQL standard. For SELECT, consider + the alternative OFFSET and FETCH clauses defined in the SQL standard. Modified: firebird/trunk/src/dsql/parse.y =================================================================== --- firebird/trunk/src/dsql/parse.y 2014-11-29 06:00:26 UTC (rev 60304) +++ firebird/trunk/src/dsql/parse.y 2014-11-29 15:39:59 UTC (rev 60305) @@ -570,6 +570,8 @@ %token <metaNamePtr> SERVERWIDE %token <metaNamePtr> INCREMENT %token <metaNamePtr> TRUSTED +%token <metaNamePtr> ROW +%token <metaNamePtr> OFFSET // precedence declarations for expression evaluation @@ -3809,9 +3811,11 @@ | KW_BOOLEAN // added in FB 3.0 | DETERMINISTIC | KW_FALSE + | OFFSET | OVER | RETURN | RDB_RECORD_VERSION + | ROW | SCROLL | SQLSTATE | KW_TRUE @@ -4898,6 +4902,21 @@ node->rowsClause = $4; node->withClause = $1; } + | with_clause select_expr_body order_clause result_offset_clause fetch_first_clause + { + SelectExprNode* node = $$ = newNode<SelectExprNode>(); + node->querySpec = $2; + node->orderClause = $3; + if ($4 || $5) { + RowsClause* rowsNode = newNode<RowsClause>(); + rowsNode->skip = $4; + rowsNode->length = $5; + node->rowsClause = rowsNode; + } else { + node->rowsClause = NULL; + } + node->withClause = $1; + } ; %type <withClause> with_clause @@ -5451,14 +5470,13 @@ | LAST { $$ = OrderNode::NULLS_LAST; } ; -// ROWS clause +// ROWS clause - ROWS clause is a non-standard alternative to OFFSET .. FETCH .. +// Non-optional - for use in select_expr (so it doesn't cause conflicts with OFFSET .. FETCH ..) %type <rowsClause> rows_clause rows_clause - : // nothing - { $$ = NULL; } // equivalent to FIRST value - | ROWS value + : ROWS value { $$ = newNode<RowsClause>(); $$->length = $2; @@ -5473,7 +5491,46 @@ } ; +// Optional - for use in delete_searched and update_searched +%type <rowsClause> rows_clause_optional +rows_clause_optional + : // nothing + { $$ = NULL; } + | rows_clause + ; +// OFFSET n {ROW | ROWS} + +row_noise + : ROW + | ROWS + ; + +%type <valueExprNode> result_offset_clause +result_offset_clause + : // nothing + { $$ = NULL; } + | OFFSET simple_value_spec row_noise + { $$ = $2; } + ; + +// FETCH {FIRST | NEXT} [ n ] {ROW | ROWS} ONLY + +first_next_noise + : FIRST + | NEXT + ; + +%type <valueExprNode> fetch_first_clause +fetch_first_clause + : // nothing + { $$ = NULL; } + | FETCH first_next_noise simple_value_spec row_noise ONLY + { $$ = $3; } + | FETCH first_next_noise row_noise ONLY + { $$ = MAKE_const_slong(1); } + ; + // INSERT statement // IBO hack: replace column_parens_opt by ins_column_parens_opt. %type <storeNode> insert @@ -5588,7 +5645,7 @@ %type <stmtNode> delete_searched delete_searched - : KW_DELETE FROM table_name where_clause plan_clause order_clause rows_clause returning_clause + : KW_DELETE FROM table_name where_clause plan_clause order_clause rows_clause_optional returning_clause { EraseNode* node = newNode<EraseNode>(); node->dsqlRelation = $3; @@ -5625,7 +5682,7 @@ %type <stmtNode> update_searched update_searched : UPDATE table_name SET assignments where_clause plan_clause - order_clause rows_clause returning_clause + order_clause rows_clause_optional returning_clause { ModifyNode* node = newNode<ModifyNode>(); node->dsqlRelation = $2; @@ -6344,6 +6401,14 @@ | '(' value_primary ')' { $$ = $2; } ; +// Matches definition of <simple value specification> in SQL standard +%type <valueExprNode> simple_value_spec +simple_value_spec + : constant + | variable + | parameter + ; + %type <valueExprNode> nonparenthesized_value nonparenthesized_value : column_name Modified: firebird/trunk/src/include/gen/msgs.h =================================================================== --- firebird/trunk/src/include/gen/msgs.h 2014-11-29 06:00:26 UTC (rev 60304) +++ firebird/trunk/src/include/gen/msgs.h 2014-11-29 15:39:59 UTC (rev 60305) @@ -518,8 +518,8 @@ {335544814, "Services functionality will be supported in a later version of the product"}, /* service_not_supported */ {335544815, "GENERATOR @1"}, /* generator_name */ {335544816, "UDF @1"}, /* udf_name */ - {335544817, "Invalid parameter to FIRST. Only integers >= 0 are allowed."}, /* bad_limit_param */ - {335544818, "Invalid parameter to SKIP. Only integers >= 0 are allowed."}, /* bad_skip_param */ + {335544817, "Invalid parameter to FETCH or FIRST. Only integers >= 0 are allowed."}, /* bad_limit_param */ + {335544818, "Invalid parameter to OFFSET or SKIP. Only integers >= 0 are allowed."}, /* bad_skip_param */ {335544819, "File exceeded maximum size of 2GB. Add another database file or use a 64 bit I/O version of Firebird."}, /* io_32bit_exceeded_err */ {335544820, "Unable to find savepoint with name @1 in transaction context"}, /* invalid_savepoint */ {335544821, "Invalid column position used in the @1 clause"}, /* dsql_column_pos_err */ @@ -1158,7 +1158,7 @@ {336397324, "CREATE GENERATOR @1 failed"}, /* dsql_create_generator_failed */ {336397325, "SET GENERATOR @1 failed"}, /* dsql_set_generator_failed */ {336397326, "WITH LOCK can be used only with a single physical table"}, /* dsql_wlock_simple */ - {336397327, "FIRST/SKIP cannot be used with ROWS"}, /* dsql_firstskip_rows */ + {336397327, "FIRST/SKIP cannot be used with OFFSET/FETCH or ROWS"}, /* dsql_firstskip_rows */ {336397328, "WITH LOCK cannot be used with aggregates"}, /* dsql_wlock_aggregates */ {336397329, "WITH LOCK cannot be used with @1"}, /* dsql_wlock_conflict */ {336723983, "unable to open database"}, /* gsec_cant_open_db */ Modified: firebird/trunk/src/msgs/messages2.sql =================================================================== --- firebird/trunk/src/msgs/messages2.sql 2014-11-29 06:00:26 UTC (rev 60304) +++ firebird/trunk/src/msgs/messages2.sql 2014-11-29 15:39:59 UTC (rev 60305) @@ -593,8 +593,8 @@ ('service_not_supported', 'SVC_attach', 'svc.c', NULL, 0, 494, NULL, 'Services functionality will be supported in a later version of the product', NULL, NULL); ('generator_name', 'check_dependencies', 'dfw.e', NULL, 0, 495, NULL, 'GENERATOR @1', NULL, NULL); ('udf_name', 'check_dependencies', 'dfw.e', NULL, 0, 496, NULL, 'UDF @1', NULL, NULL); -('bad_limit_param', 'RSE_open', 'rse.c', NULL, 0, 497, NULL, 'Invalid parameter to FIRST. Only integers >= 0 are allowed.', NULL, NULL); -('bad_skip_param', 'RSE_open', 'rse.c', NULL, 0, 498, NULL, 'Invalid parameter to SKIP. Only integers >= 0 are allowed.', NULL, NULL); +('bad_limit_param', 'RSE_open', 'rse.c', NULL, 0, 497, NULL, 'Invalid parameter to FETCH or FIRST. Only integers >= 0 are allowed.', NULL, NULL); +('bad_skip_param', 'RSE_open', 'rse.c', NULL, 0, 498, NULL, 'Invalid parameter to OFFSET or SKIP. Only integers >= 0 are allowed.', NULL, NULL); ('io_32bit_exceeded_err', 'seek_file', 'unix.c', NULL, 0, 499, NULL, 'File exceeded maximum size of 2GB. Add another database file or use a 64 bit I/O version of Firebird.', NULL, NULL); ('invalid_savepoint', 'looper', 'exe.cpp', NULL, 0, 500, NULL, 'Unable to find savepoint with name @1 in transaction context', NULL, NULL); ('dsql_column_pos_err', '(several)', 'pass1.cpp', NULL, 0, 501, NULL, 'Invalid column position used in the @1 clause', NULL, NULL); @@ -2607,7 +2607,7 @@ ('dsql_create_generator_failed', 'putErrorPrefix', 'DdlNodes.h', NULL, 13, 1036, NULL, 'CREATE GENERATOR @1 failed', NULL, NULL); ('dsql_set_generator_failed', 'putErrorPrefix', 'DdlNodes.h', NULL, 13, 1037, NULL, 'SET GENERATOR @1 failed', NULL, NULL); ('dsql_wlock_simple', 'pass1_rse_impl', 'pass1.cpp', NULL, 13, 1038, NULL, 'WITH LOCK can be used only with a single physical table', NULL, NULL); -('dsql_firstskip_rows', 'pass1_rse_impl', 'pass1.cpp', NULL, 13, 1039, NULL, 'FIRST/SKIP cannot be used with ROWS', NULL, NULL); +('dsql_firstskip_rows', 'pass1_rse_impl', 'pass1.cpp', NULL, 13, 1039, NULL, 'FIRST/SKIP cannot be used with OFFSET/FETCH or ROWS', NULL, NULL); ('dsql_wlock_aggregates', 'pass1_rse_impl', 'pass1.cpp', NULL, 13, 1040, NULL, 'WITH LOCK cannot be used with aggregates', NULL, NULL); ('dsql_wlock_conflict', NULL, 'pass1.cpp', NULL, 13, 1041, NULL, 'WITH LOCK cannot be used with @1', NULL, NULL); -- SQLWARN Modified: firebird/trunk/src/yvalve/keywords.cpp =================================================================== --- firebird/trunk/src/yvalve/keywords.cpp 2014-11-29 06:00:26 UTC (rev 60304) +++ firebird/trunk/src/yvalve/keywords.cpp 2014-11-29 15:39:59 UTC (rev 60305) @@ -283,6 +283,7 @@ {KW_NUMERIC, "NUMERIC", 1, false}, {OCTET_LENGTH, "OCTET_LENGTH", 2, false}, {OF, "OF", 1, false}, + {OFFSET, "OFFSET", 2, false}, {ON, "ON", 1, false}, {ONLY, "ONLY", 1, false}, {OPEN, "OPEN", 2, false}, @@ -348,6 +349,7 @@ {ROLE, "ROLE", 1, true}, {ROLLBACK, "ROLLBACK", 1, false}, {ROUND, "ROUND", 2, false}, + {ROW, "ROW", 2, false}, {ROW_COUNT, "ROW_COUNT", 2, false}, {ROW_NUMBER, "ROW_NUMBER", 2, false}, {ROWS, "ROWS", 2, false}, This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |