diff --git a/mysql-test/suite/versioning/r/derived.result b/mysql-test/suite/versioning/r/derived.result index 0792093bbc4..5b8eee4ab4a 100644 --- a/mysql-test/suite/versioning/r/derived.result +++ b/mysql-test/suite/versioning/r/derived.result @@ -211,12 +211,12 @@ id select_type table type possible_keys key key_len ref rows filtered Extra 1 SIMPLE t2 ALL NULL NULL NULL NULL 3 100.00 Using where 1 SIMPLE t1 ALL NULL NULL NULL NULL 5 100.00 Using where; Using join buffer (flat, BNL join) Query A: -Note 1003 select `test`.`t1`.`x` AS `x`,`test`.`t1`.`y` AS `y1`,`test`.`t2`.`x` AS `x2`,`test`.`t2`.`y` AS `y2` from `test`.`t1` FOR SYSTEM_TIME ALL join `test`.`t2` FOR SYSTEM_TIME ALL where `test`.`t1`.`x` = `test`.`t2`.`x` and `test`.`t1`.`row_end` > (current_timestamp(6)) and `test`.`t1`.`row_start` <= (current_timestamp(6)) and `test`.`t2`.`row_end` > (current_timestamp(6)) and `test`.`t2`.`row_start` <= (current_timestamp(6)) +Note 1003 select `test`.`t1`.`x` AS `x`,`test`.`t1`.`y` AS `y1`,`test`.`t2`.`x` AS `x2`,`test`.`t2`.`y` AS `y2` from `test`.`t1` FOR SYSTEM_TIME ALL join `test`.`t2` FOR SYSTEM_TIME ALL where `test`.`t1`.`x` = `test`.`t2`.`x` and `test`.`t2`.`row_end` > (current_timestamp(6)) and `test`.`t2`.`row_start` <= (current_timestamp(6)) and `test`.`t1`.`row_end` > (current_timestamp(6)) and `test`.`t1`.`row_start` <= (current_timestamp(6)) id select_type table type possible_keys key key_len ref rows filtered Extra 1 SIMPLE t2 ALL NULL NULL NULL NULL 3 100.00 Using where 1 SIMPLE t1 ALL NULL NULL NULL NULL 5 100.00 Using where; Using join buffer (flat, BNL join) Query B: -Note 1003 select `test`.`t1`.`x` AS `x`,`test`.`t1`.`y` AS `y1`,`test`.`t2`.`x` AS `x2`,`test`.`t2`.`y` AS `y2` from `test`.`t1` FOR SYSTEM_TIME ALL join `test`.`t2` FOR SYSTEM_TIME ALL where `test`.`t1`.`x` = `test`.`t2`.`x` and `test`.`t1`.`row_end` > (current_timestamp(6)) and `test`.`t1`.`row_start` <= (current_timestamp(6)) and `test`.`t2`.`row_end` > (current_timestamp(6)) and `test`.`t2`.`row_start` <= (current_timestamp(6)) +Note 1003 select `test`.`t1`.`x` AS `x`,`test`.`t1`.`y` AS `y1`,`test`.`t2`.`x` AS `x2`,`test`.`t2`.`y` AS `y2` from `test`.`t1` FOR SYSTEM_TIME ALL join `test`.`t2` FOR SYSTEM_TIME ALL where `test`.`t1`.`x` = `test`.`t2`.`x` and `test`.`t2`.`row_end` > (current_timestamp(6)) and `test`.`t2`.`row_start` <= (current_timestamp(6)) and `test`.`t1`.`row_end` > (current_timestamp(6)) and `test`.`t1`.`row_start` <= (current_timestamp(6)) Fine result: queries A and B are equal. ## LEFT JOIN: t1, t2 versioned select * from ( diff --git a/mysql-test/suite/versioning/r/select.result b/mysql-test/suite/versioning/r/select.result index e1de47ff9fc..26b3a5236f8 100644 --- a/mysql-test/suite/versioning/r/select.result +++ b/mysql-test/suite/versioning/r/select.result @@ -153,21 +153,21 @@ id select_type table type possible_keys key key_len ref rows filtered Extra 1 SIMPLE t2 ALL NULL NULL NULL NULL 3 100.00 Using where 1 SIMPLE t1 ALL NULL NULL NULL NULL 5 100.00 Using where; Using join buffer (flat, BNL join) Warnings: -Note 1003 select `test`.`t1`.`x` AS `IJ2_x1`,`test`.`t1`.`y` AS `y1`,`test`.`t2`.`x` AS `x2`,`test`.`t2`.`y` AS `y2` from `test`.`t1` FOR SYSTEM_TIME ALL join `test`.`t2` FOR SYSTEM_TIME ALL where `test`.`t1`.`x` = `test`.`t2`.`x` and `test`.`t1`.`row_end` > @`t0` and `test`.`t1`.`row_start` <= @`t0` and `test`.`t2`.`row_end` > @`t0` and `test`.`t2`.`row_start` <= @`t0` +Note 1003 select `test`.`t1`.`x` AS `IJ2_x1`,`test`.`t1`.`y` AS `y1`,`test`.`t2`.`x` AS `x2`,`test`.`t2`.`y` AS `y2` from `test`.`t1` FOR SYSTEM_TIME ALL join `test`.`t2` FOR SYSTEM_TIME ALL where `test`.`t1`.`x` = `test`.`t2`.`x` and `test`.`t2`.`row_end` > @`t0` and `test`.`t2`.`row_start` <= @`t0` and `test`.`t1`.`row_end` > @`t0` and `test`.`t1`.`row_start` <= @`t0` explain extended select * from (select t1.x as LJ2_x1, t1.y as y1, t2.x as x2, t2.y as y2 from t1 left join t2 on t1.x = t2.x) for system_time as of timestamp @t0 as t; id select_type table type possible_keys key key_len ref rows filtered Extra -1 SIMPLE t1 ALL NULL NULL NULL NULL 5 100.00 +1 SIMPLE t1 ALL NULL NULL NULL NULL 5 100.00 Using where 1 SIMPLE t2 ALL NULL NULL NULL NULL 3 100.00 Using where; Using join buffer (flat, BNL join) Warnings: -Note 1003 select `test`.`t1`.`x` AS `LJ2_x1`,`test`.`t1`.`y` AS `y1`,`test`.`t2`.`x` AS `x2`,`test`.`t2`.`y` AS `y2` from `test`.`t1` FOR SYSTEM_TIME ALL left join `test`.`t2` FOR SYSTEM_TIME ALL on(`test`.`t2`.`x` = `test`.`t1`.`x` and `test`.`t1`.`row_end` > @`t0` and `test`.`t1`.`row_start` <= @`t0` and `test`.`t2`.`row_end` > @`t0` and `test`.`t2`.`row_start` <= @`t0`) where 1 +Note 1003 select `test`.`t1`.`x` AS `LJ2_x1`,`test`.`t1`.`y` AS `y1`,`test`.`t2`.`x` AS `x2`,`test`.`t2`.`y` AS `y2` from `test`.`t1` FOR SYSTEM_TIME ALL left join `test`.`t2` FOR SYSTEM_TIME ALL on(`test`.`t2`.`x` = `test`.`t1`.`x` and `test`.`t2`.`row_end` > @`t0` and `test`.`t2`.`row_start` <= @`t0`) where `test`.`t1`.`row_end` > @`t0` and `test`.`t1`.`row_start` <= @`t0` explain extended select * from (select t1.x as RJ2_x1, t1.y as y1, t2.x as x2, t2.y as y2 from t1 right join t2 on t1.x = t2.x) for system_time as of timestamp @t0 as t; id select_type table type possible_keys key key_len ref rows filtered Extra -1 SIMPLE t2 ALL NULL NULL NULL NULL 3 100.00 +1 SIMPLE t2 ALL NULL NULL NULL NULL 3 100.00 Using where 1 SIMPLE t1 ALL NULL NULL NULL NULL 5 100.00 Using where; Using join buffer (flat, BNL join) Warnings: -Note 1003 select `test`.`t1`.`x` AS `RJ2_x1`,`test`.`t1`.`y` AS `y1`,`test`.`t2`.`x` AS `x2`,`test`.`t2`.`y` AS `y2` from `test`.`t2` FOR SYSTEM_TIME ALL left join `test`.`t1` FOR SYSTEM_TIME ALL on(`test`.`t1`.`x` = `test`.`t2`.`x` and `test`.`t1`.`row_end` > @`t0` and `test`.`t1`.`row_start` <= @`t0` and `test`.`t2`.`row_end` > @`t0` and `test`.`t2`.`row_start` <= @`t0`) where 1 +Note 1003 select `test`.`t1`.`x` AS `RJ2_x1`,`test`.`t1`.`y` AS `y1`,`test`.`t2`.`x` AS `x2`,`test`.`t2`.`y` AS `y2` from `test`.`t2` FOR SYSTEM_TIME ALL left join `test`.`t1` FOR SYSTEM_TIME ALL on(`test`.`t1`.`x` = `test`.`t2`.`x` and `test`.`t1`.`row_end` > @`t0` and `test`.`t1`.`row_start` <= @`t0`) where `test`.`t2`.`row_end` > @`t0` and `test`.`t2`.`row_start` <= @`t0` select * from (select t1.x as IJ2_x1, t1.y as y1, t2.x as x2, t2.y as y2 from t1 inner join t2 on t1.x = t2.x) for system_time as of timestamp @t0 as t; IJ2_x1 y1 x2 y2 @@ -287,6 +287,14 @@ create or replace table t1 (a int) with system versioning; insert into t1 values (1); insert into t1 values (2); insert into t1 values (3); +explain extended +select * from t1 left outer join (t1 as t2 left join t1 as t3 using (a)) on t1.a>1; +id select_type table type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 3 100.00 Using where +1 SIMPLE t2 ALL NULL NULL NULL NULL 3 100.00 Using where; Using join buffer (flat, BNL join) +1 SIMPLE t3 ALL NULL NULL NULL NULL 3 100.00 Using where; Using join buffer (incremental, BNL join) +Warnings: +Note 1003 select `test`.`t1`.`a` AS `a`,`test`.`t2`.`a` AS `a` from `test`.`t1` FOR SYSTEM_TIME ALL left join (`test`.`t1` FOR SYSTEM_TIME ALL `t2` left join `test`.`t1` FOR SYSTEM_TIME ALL `t3` on(`test`.`t3`.`a` = `test`.`t2`.`a` and `test`.`t3`.`row_end` = TIMESTAMP'2038-01-19 03:14:07.999999')) on(`test`.`t2`.`row_end` = TIMESTAMP'2038-01-19 03:14:07.999999' and `test`.`t1`.`a` > 1) where `test`.`t1`.`row_end` = TIMESTAMP'2038-01-19 03:14:07.999999' select * from t1 left outer join (t1 as t2 left join t1 as t3 using (a)) on t1.a>1; a a 2 1 @@ -382,20 +390,24 @@ create or replace table t1 (x int) with system versioning; select * from t1 for system_time as of current_timestamp; x select * from t1 for system_time as of now; -ERROR 42S22: Unknown column 'now' in 'where clause' +ERROR 42S22: Unknown column 'now' in 'on clause' ### Issue #405, NATURAL JOIN failure create or replace table t1 (a int) with system versioning; create or replace table t2 (b int); create or replace view v1 as select a, row_start, row_end from t1 where a > round(rand()*1000); select * from v1 natural join t2; a b -### Issue #406, MDEV-14633 Assertion on TRT read +# +# Issue #406, MDEV-14633 Assertion on TRT read +# create or replace table t1 (pk int primary key, i int, t time, key (i)) with system versioning; insert into t1 values (1, 10, '15:01:53'), (2, 20, '00:00:00'); delete from t1; select * from t1 where t = '00:00:00' and i > 0 and row_end <> '2012-12-12 00:00:00'; pk i t -### MDEV-14816 Assertion `join->best_read < double(1.797...e+308L)' failed in bool greedy_search +# +# MDEV-14816 Assertion `join->best_read < double(1.797...e+308L)' failed in bool greedy_search +# create or replace table t1 (f1 int) with system versioning; create or replace table t2 (f2 int) with system versioning; create or replace table t3 (f3 int); @@ -464,7 +476,9 @@ f1 f2 f3 f1 f2 f3 f4 3 3 NULL NULL 3 1 1 3 3 NULL NULL 3 2 1 4 NULL NULL NULL NULL NULL NULL -### MDEV-15004 parser greedily parses AS OF TIMESTAMP +# +# MDEV-15004 parser greedily parses AS OF TIMESTAMP +# select timestamp'2016-02-30 08:07:06'; ERROR HY000: Incorrect DATETIME value: '2016-02-30 08:07:06' select * from t1 for system_time as of timestamp'2016-02-30 08:07:06'; @@ -474,6 +488,28 @@ timestamp('2003-12-31 12:00:00','12:00:00') 2004-01-01 00:00:00 select * from t1 for system_time as of timestamp('2003-12-31 12:00:00','12:00:00'); f1 +# +# MDEV-15391 Server crashes in JOIN::fix_all_splittings_in_plan or Assertion `join->best_read < double(1.79...e+308L)' failed [tempesta-tech#475] +# +create or replace table t1 (f1 int) with system versioning; +insert t1 values (1),(2); +create or replace table t2 (f2 int); +create or replace table t3 (f3 int); +create or replace table t4 (f4 int) with system versioning; +select f1 from t1 join t2 left join t3 left join t4 on f3 = f4 on f3 = f2; +f1 +insert t2 values (1),(2); +insert t3 values (1),(2); +insert t4 values (1),(2); +explain extended +select f1 from t1 join t2 left join t3 left join t4 on f3 = f4 on f3 = f2; +id select_type table type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 2 100.00 Using where +1 SIMPLE t2 ALL NULL NULL NULL NULL 2 100.00 Using join buffer (flat, BNL join) +1 SIMPLE t3 ALL NULL NULL NULL NULL 2 100.00 Using where; Using join buffer (incremental, BNL join) +1 SIMPLE t4 ALL NULL NULL NULL NULL 2 100.00 Using where; Using join buffer (incremental, BNL join) +Warnings: +Note 1003 select `test`.`t1`.`f1` AS `f1` from `test`.`t1` FOR SYSTEM_TIME ALL join `test`.`t2` left join (`test`.`t3` left join `test`.`t4` FOR SYSTEM_TIME ALL on(`test`.`t4`.`f4` = `test`.`t2`.`f2` and `test`.`t4`.`row_end` = TIMESTAMP'2038-01-19 03:14:07.999999')) on(`test`.`t3`.`f3` = `test`.`t2`.`f2`) where `test`.`t1`.`row_end` = TIMESTAMP'2038-01-19 03:14:07.999999' drop view v1; drop table t1, t2, t3, t4; call verify_vtq_dummy(34); diff --git a/mysql-test/suite/versioning/t/select.test b/mysql-test/suite/versioning/t/select.test index 2f24f7d8fc0..ac8406320e8 100644 --- a/mysql-test/suite/versioning/t/select.test +++ b/mysql-test/suite/versioning/t/select.test @@ -182,6 +182,8 @@ create or replace table t1 (a int) with system versioning; insert into t1 values (1); insert into t1 values (2); insert into t1 values (3); +explain extended +select * from t1 left outer join (t1 as t2 left join t1 as t3 using (a)) on t1.a>1; select * from t1 left outer join (t1 as t2 left join t1 as t3 using (a)) on t1.a>1; create or replace table t1 (x int) with system versioning; @@ -269,7 +271,9 @@ create or replace table t2 (b int); create or replace view v1 as select a, row_start, row_end from t1 where a > round(rand()*1000); select * from v1 natural join t2; ---echo ### Issue #406, MDEV-14633 Assertion on TRT read +--echo # +--echo # Issue #406, MDEV-14633 Assertion on TRT read +--echo # create or replace table t1 (pk int primary key, i int, t time, key (i)) with system versioning; insert into t1 values (1, 10, '15:01:53'), (2, 20, '00:00:00'); delete from t1; @@ -277,7 +281,9 @@ delete from t1; select * from t1 where t = '00:00:00' and i > 0 and row_end <> '2012-12-12 00:00:00'; --enable_warnings ---echo ### MDEV-14816 Assertion `join->best_read < double(1.797...e+308L)' failed in bool greedy_search +--echo # +--echo # MDEV-14816 Assertion `join->best_read < double(1.797...e+308L)' failed in bool greedy_search +--echo # create or replace table t1 (f1 int) with system versioning; create or replace table t2 (f2 int) with system versioning; create or replace table t3 (f3 int); @@ -291,7 +297,9 @@ select * from left join t2 as t2a left join (t3 as t3a inner join t1) on t2a.f2 = t3a.f3 on t1a.f1 = t2a.f2 left join (t2 join t3 inner join t4) on t2a.f2 = t1a.f1; ---echo ### MDEV-15004 parser greedily parses AS OF TIMESTAMP +--echo # +--echo # MDEV-15004 parser greedily parses AS OF TIMESTAMP +--echo # --error ER_WRONG_VALUE select timestamp'2016-02-30 08:07:06'; --error ER_WRONG_VALUE @@ -299,6 +307,22 @@ select * from t1 for system_time as of timestamp'2016-02-30 08:07:06'; select timestamp('2003-12-31 12:00:00','12:00:00'); select * from t1 for system_time as of timestamp('2003-12-31 12:00:00','12:00:00'); + +--echo # +--echo # MDEV-15391 Server crashes in JOIN::fix_all_splittings_in_plan or Assertion `join->best_read < double(1.79...e+308L)' failed [tempesta-tech#475] +--echo # +create or replace table t1 (f1 int) with system versioning; +insert t1 values (1),(2); +create or replace table t2 (f2 int); +create or replace table t3 (f3 int); +create or replace table t4 (f4 int) with system versioning; +select f1 from t1 join t2 left join t3 left join t4 on f3 = f4 on f3 = f2; +insert t2 values (1),(2); +insert t3 values (1),(2); +insert t4 values (1),(2); +explain extended +select f1 from t1 join t2 left join t3 left join t4 on f3 = f4 on f3 = f2; + drop view v1; drop table t1, t2, t3, t4; diff --git a/sql/sql_delete.cc b/sql/sql_delete.cc index b92dd4139b2..0a12d01596b 100644 --- a/sql/sql_delete.cc +++ b/sql/sql_delete.cc @@ -318,9 +318,13 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds, DBUG_ASSERT(table); DBUG_ASSERT(!conds || thd->stmt_arena->is_stmt_execute()); - if (select_lex->vers_setup_conds(thd, table_list, &conds)) + if (select_lex->vers_setup_conds(thd, table_list)) DBUG_RETURN(TRUE); + DBUG_ASSERT(!conds); + conds= table_list->on_expr; + table_list->on_expr= NULL; + // trx_sees() in InnoDB reads row_start if (!table->versioned(VERS_TIMESTAMP)) { @@ -941,7 +945,7 @@ int mysql_prepare_delete(THD *thd, TABLE_LIST *table_list, my_error(ER_IT_IS_A_VIEW, MYF(0), table_list->table_name.str); DBUG_RETURN(true); } - if (select_lex->vers_setup_conds(thd, table_list, conds)) + if (select_lex->vers_setup_conds(thd, table_list)) DBUG_RETURN(true); } if ((wild_num && setup_wild(thd, table_list, field_list, NULL, wild_num)) || diff --git a/sql/sql_lex.h b/sql/sql_lex.h index 3027d67f86b..02c2ffb6a12 100644 --- a/sql/sql_lex.h +++ b/sql/sql_lex.h @@ -1044,7 +1044,7 @@ public: /** System Versioning */ public: uint versioned_tables; - int vers_setup_conds(THD *thd, TABLE_LIST *tables, COND **where_expr); + int vers_setup_conds(THD *thd, TABLE_LIST *tables); /* push new Item_field into item_list */ bool vers_push_field(THD *thd, TABLE_LIST *table, const LEX_CSTRING field_name); diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 50c525743ff..e375f5a014e 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -718,7 +718,7 @@ void vers_select_conds_t::print(String *str, enum_query_type query_type) } } -int SELECT_LEX::vers_setup_conds(THD *thd, TABLE_LIST *tables, COND **where_expr) +int SELECT_LEX::vers_setup_conds(THD *thd, TABLE_LIST *tables) { DBUG_ENTER("SELECT_LEX::vers_setup_cond"); #define newx new (thd->mem_root) @@ -777,9 +777,6 @@ int SELECT_LEX::vers_setup_conds(THD *thd, TABLE_LIST *tables, COND **where_expr } } - COND** dst_cond= where_expr; - COND* vers_cond= NULL; - for (table= tables; table; table= table->next_local) { if (!table->table || !table->table->versioned()) @@ -830,11 +827,6 @@ int SELECT_LEX::vers_setup_conds(THD *thd, TABLE_LIST *tables, COND **where_expr lock_type= TL_READ; // ignore TL_WRITE, history is immutable anyway } - if (table->on_expr) - { - dst_cond= &table->on_expr; - } - const LEX_CSTRING *fstart= &table->table->vers_start_field()->field_name; const LEX_CSTRING *fend= &table->table->vers_end_field()->field_name; @@ -875,7 +867,6 @@ int SELECT_LEX::vers_setup_conds(THD *thd, TABLE_LIST *tables, COND **where_expr max_time.second_part= TIME_MAX_SECOND_PART; curr= newx Item_datetime_literal(thd, &max_time, TIME_SECOND_PART_DIGITS); cond1= newx Item_func_eq(thd, row_end, curr); - cond1= or_items(thd, cond1, newx Item_func_isnull(thd, row_end)); break; case SYSTEM_TIME_AS_OF: cond1= newx Item_func_le(thd, row_start, vers_conditions.start.item); @@ -938,43 +929,16 @@ int SELECT_LEX::vers_setup_conds(THD *thd, TABLE_LIST *tables, COND **where_expr DBUG_ASSERT(0); } } - vers_conditions.type= SYSTEM_TIME_ALL; if (cond1) { - vers_cond= and_items(thd, - vers_cond, - and_items(thd, - cond2, - cond1)); - if (table->is_view_or_derived()) - vers_cond= or_items(thd, vers_cond, newx Item_func_isnull(thd, row_end)); + cond1= and_items(thd, cond2, cond1); + table->on_expr= and_items(thd, table->on_expr, cond1); } + + table->vers_conditions.type= SYSTEM_TIME_ALL; } // for (table= tables; ...) - if (vers_cond) - { - COND *all_cond= and_items(thd, *dst_cond, vers_cond); - bool from_where= dst_cond == where_expr; - if (on_stmt_arena.arena_replaced()) - *dst_cond= all_cond; - else - thd->change_item_tree(dst_cond, all_cond); - - if (from_where) - { - this->where= *dst_cond; - this->where->top_level_item(); - } - - // Invalidate current SP [#52, #422] - if (thd->spcont) - { - DBUG_ASSERT(thd->spcont->m_sp); - thd->spcont->m_sp->set_sp_cache_version(0); - } - } - DBUG_RETURN(0); #undef newx } @@ -1059,7 +1023,7 @@ JOIN::prepare(TABLE_LIST *tables_init, } /* System Versioning: handle FOR SYSTEM_TIME clause. */ - if (select_lex->vers_setup_conds(thd, tables_list, &conds) < 0) + if (select_lex->vers_setup_conds(thd, tables_list) < 0) DBUG_RETURN(-1); /* @@ -7533,7 +7497,7 @@ static int compare_embedding_subqueries(JOIN_TAB *jt1, JOIN_TAB *jt2) b: dependent = 0x0 table->map = 0x2 found_records = 3 ptr = 0x907e838 c: dependent = 0x6 table->map = 0x10 found_records = 2 ptr = 0x907ecd0 - As for subuqueries, this function must produce order that can be fed to + As for subqueries, this function must produce order that can be fed to choose_initial_table_order(). @retval @@ -7871,7 +7835,7 @@ greedy_search(JOIN *join, 'best_read < DBL_MAX' means that optimizer managed to find some plan and updated 'best_positions' array accordingly. */ - DBUG_ASSERT(join->best_read < DBL_MAX); + DBUG_ASSERT(join->best_read < DBL_MAX); if (size_remain <= search_depth) { @@ -8629,7 +8593,7 @@ best_extension_by_limited_search(JOIN *join, /* Find the best access method from 's' to the current partial plan */ POSITION loose_scan_pos; best_access_path(join, s, remaining_tables, idx, disable_jbuf, - record_count, join->positions + idx, &loose_scan_pos); + record_count, position, &loose_scan_pos); /* Compute the cost of extending the plan with 's', avoid overflow */ if (position->records_read < DBL_MAX / record_count)