Commit 0f02d8fc authored by unknown's avatar unknown

Merge sgluhov@work.mysql.com:/home/bk/mysql-4.1

into gluh.mysql.r18.ru:/home/gluh/mysql-4.1.uvar

parents c40bcc57 0b8c701d
...@@ -53,6 +53,8 @@ This is a manual about @strong{MySQL} internals. ...@@ -53,6 +53,8 @@ This is a manual about @strong{MySQL} internals.
* caching:: How MySQL Handles Caching * caching:: How MySQL Handles Caching
* flush tables:: How MySQL Handles @code{FLUSH TABLES} * flush tables:: How MySQL Handles @code{FLUSH TABLES}
* filesort:: How MySQL Does Sorting (@code{filesort}) * filesort:: How MySQL Does Sorting (@code{filesort})
* selects:: How MySQL performs different selects
* transformations:: How MySQL transforms subqueries
* coding guidelines:: Coding Guidelines * coding guidelines:: Coding Guidelines
* mysys functions:: Functions In The @code{mysys} Library * mysys functions:: Functions In The @code{mysys} Library
* DBUG:: DBUG Tags To Use * DBUG:: DBUG Tags To Use
...@@ -220,7 +222,7 @@ After this it will give other threads a chance to open the same tables. ...@@ -220,7 +222,7 @@ After this it will give other threads a chance to open the same tables.
@end itemize @end itemize
@node filesort, coding guidelines, flush tables, Top @node filesort, selects, flush tables, Top
@chapter How MySQL Does Sorting (@code{filesort}) @chapter How MySQL Does Sorting (@code{filesort})
@itemize @bullet @itemize @bullet
...@@ -260,8 +262,584 @@ and then we read the rows in the sorted order into a row buffer ...@@ -260,8 +262,584 @@ and then we read the rows in the sorted order into a row buffer
@end itemize @end itemize
@node selects, transformations, flush tables, Top
@chapter How MySQL performs different selects
@node coding guidelines, mysys functions, filesort, Top @node select steps,,,
@section Steps of select executing
Every select performed in such base steps:
@itemize
@item
JOIN::prepare
@itemize @bullet
@item
initialization and linking JOIN structure to st_select_lex
@item
fix_fields() for all items (after fix_fields we know everything
about item)
@item
moving HAVING to WHERE if possible
@item
initialization procedure if exists
@end itemize
@item
JOIN::optimize
@itemize @bullet
@item
single select optimization
@item
creation first temporary table if need
@end itemize
@item
JOIN::exec
@itemize @bullet
@item
performing select (may be created second temporary table)
@end itemize
@item
JOIN::cleanup
@itemize @bullet
@item
removing all temporary tables, other cleanup
@end itemize
@item
JOIN::reinit
@itemize @bullet
@item
prepare all structures to SELECT executing (with JOIN::exec)
@end itemize
@end itemize
@node select select_result
@section select_result CLASS
Very important role in SELECT performing have select_result class and
classes inherited from it (usually called with "select_" prefix). This
class provide interface for results transmitting.
Key methods in this class are following:
@itemize @bullet
@item
@strong{send_fields} sends giving item list headers (type, name, etc..)
@item
@strong{send_data} sends giving item list values as row of table of result
@item
@strong{send_error} send error to used used mainly for error interception,
making some operation and then ::send_error will be called.
@end itemize
For example there are fillowing select_result classes:
@itemize
@item
@strong{select_send} used for sending results though network layer
@item
@strong{select_export} used for exporting data to file
@item
@strong{multi_delete} used for multi-delete
@item
@strong{select_insert} used for INSERT ... SELECT ...
@item
@strong{multi_update} used for multi-update
@end itemize
@node select simple
@section SIMPLE or PRIMARY SELECT.
For performing single primary select SELECT used function mysql_select,
which:
@itemize @bullet
@item
allocate JOIN;
@item
JOIN::prepare;
@item
JOIN::optimize;
@item
JOIN::exec;
@item
JOIN::cleanup.
@end itemize
In previous versions of mysql all SELECTs was performed with help of this
function and mysql_select() was not divided on parts.
@node select structure
@section Structure Of Complex Select
There 2 structures which describe SELECTS:
@itemize @bullet
@item
st_select_lex (SELECT_LEX) it represent SELECT itself
@item
st_select_lex_unit (SELECT_LEX_UNIT) group several selects in bunch
@end itemize
and represent UNION operation (absence of UNION is union
with 1 SELECT and this structure present in any case). In future this
structure will be used for EXCEPT and INTERSECT.
For example:
@example
(SELECT ... )UNION(SELECT ... (SELECT...)...(SELECT...UNION...SELECT))
1 2 3 4 5 6 7
@end example
will be represent as
@example
------------------------------------------------------------------------
level 1
SELECT_LEX_UNIT(2)
|
+---------------+
| |
SELECT_LEX(1) SELECT_LEX(3)
|
--------------- | ------------------------------------------------------
| level 2
+-------------------+
| |
SELECT_LEX_UNIT(4) SELECT_LEX_UNIT(6)
| |
| +--------------+
| | |
SELECT_LEX(4) SELECT_LEX(5) SELECT_LEX(7)
------------------------------------------------------------------------
@end example
Note: single subselect 4 have it's own SELECT_LEX_UNIT.
Most upper SELECT_LEX_UNIT (#2 in example) stored in LEX.
First and most upper SELECT_LEX (#1 in example) stored in LEX, too.
This two structures always exist.
In time of creating or performing any JOIN::* operation
LEX::current_select point on appropriate SELECT_LEX.
Only during parsing global (for whole UNION) ORDER_BY & LIMIT clauses
LEX::current_select points to SELECT_LEX_UNIT of this unit to store this
parameter in this SELECT_LEX_UNIT (SELECT_LEX and SELECT_LEX_UNIT are
inherited from st_select_lex_node).
@node select union
@section Non-Subselect UNIONs Executing
Non subselect unions performed with help of mysql_union(). for now it
divided on following steps:
@itemize
@item
st_select_lex_unit::prepare
@itemize @bullet
@item
create temporary table for union results storing (if UNION witout
ALL option, 'distinct' parameter will be passed to table creation
procedure). Types/lengths of table's fields will be determinated
by first SELECT item list.
@item
create select_union (inherited from select_result) which will
write selects results in this temporary table
@item
allocate JOIN and perform JOIN::prepare for all SELECTs belonged
to UNION
@end itemize
@item
st_select_lex_unit::exec
@itemize @bullet
@item
delete rows from temporary table if it is not first call
@item
if first call call JOIN::optimize else JOIN::reinit and then
JOIN::exec for all SELECTs (select_union will write result for
temporary table). If union is cacheable and this method called
second, (third, ...) time it will do nothing.
@item
call mysql_select on temporary table with global ORDER BY and
LIMIT parameters after collecting results from all SELECTs.
@end itemize
@end itemize
As far as mysql_select need SELECT_LEX structure SELECT_LEX of first
SELECT of this UNION will be passed to it, but also fake_select_lex
parameter will be passed to mysql_select() too, to prevent linking
this SELECT_LEX with JOIN on this mysql_select() session.
PROBLEM: this fake select need workaround in many places.
@node select derived
@section Derived Tables Executing
Derived tables processing is first operation on any query. It performed
before creation list of tables of whole query and opening/locking this
tables.
If lex->derived_tables flag present will be scanned all SELECT_LEX (there
are list of all SELECT_LEX in reverse order (first SELECT in query will
be last in this list) lex->all_selects_list).
Pointer on derived table SELECT_LEX_UNIT stored in TABLE_LIST structure
(TABLE_LIST::derived). And for any table which have this pointer will
be called mysql_derived().
mysql_derived():
@itemize @bullet
@item
Creates list of all tables used in this query, opens and locks it
@item
Creates temporary table for storing results
@item
Creates union_result for writing result in this table
@item
Calls mysql_select or mysql_union for execute query
@item
Removes all derived table subtree from SELECTs tree (if it is
not EXPLAIN)
@item
Stores pointer to this temporary table in TABLE_LIST structure, then
this table will be used by outer query. This table table will not be
skipped in checking grants, because tables from which this table was
received was checked in mysql_derived.
@item
Links this temporary table in thd->derived_tables for removing after
query executing. this table will be closed in close_thread_tables if
second parameter of it (bool skip_derived) will be true.
@end itemize
@node select subselect
@section Subselects
In expression subselect represented by Item inherited from Item_subselect.
To hide difference in performing single SELECTs and UNIONs
Item_subselect use two different engines, which provide uniformed
interface for access to underplaid SELECT or UNION
(subselect_single_select_engine and subselect_union_engine, both are
inherited from subselect_engine).
Engine will be created in time of Item_select constructing
(Item_subselect::init method).
On Item_subselect::fix_fields() will be called engine->prepare().
Before calling any value getting method (val, val_int, val_str,
bring_value (in case of row result)) will be called engine->exec(),
which execute query or just do nothing if subselect is cacheable and
already executed.
Items inherited from provide it's own select_result classes. There are
2 type of it:
@itemize @bullet
@item
select_singlerow_subselect it store values of giving row in
Item_singlerow_subselect cache on send_data() call and report error
if Item_subselect have 'assigned' attribute.
@item
select_exists_subselect just store 1 as value of
Item_exists_subselect on send_data() call. As far as
Item_in_subselect and Item_allany_subselect inherited from
Item_exists_subselect, they use same select_result class.
@end itemize
Item_select will never call cleanup() procedure for JOIN. Every
JOIN::cleanup will call cleanup() for inner JOINs. Most upper
JOIN::cleanup will be called by mysql_select() or mysql_union().
@node select select engine
@section Single Select Engine
subselect_single_select_engine:
@itemize @bullet
@item
@strong{constructor} allocate JOIN and store pointers on SELECT_LEX and JOIN
@item
@strong{prepare()} call JOIN::prepare
@item
@strong{fix_length_and_dec()} prepare cache and receive type and
parameters of returning items (it called only by
Item_singlerow_subselect)
@item
@strong{exec()} drop 'assigned flag of Item_subselect. If called first time
JOIN::optimize and JOINexec(), else do nothing or JOIN::reinit()
JOIN::exec() depending of type of subquery.
@end itemize
@node select union engine
@section Union Engine
subselect_union_engine:
@itemize @bullet
@item
@strong{constructor} just store pointer to st_select_lex_union
(SELECT_LEX_UNION)
@item
@strong{prepare()} call st_select_lex_unit::prepare
@item
@strong{fix_length_and_dec()} prepare cache and receive type and
parameters (maximum of length) of returning items (it called
only by Item_singlerow_subselect)
@item
@strong{exec()} call st_select_lex_unit::exec(). st_select_lex_unit::exec()
can drop 'assigned' flag of Item_subselect if
st_select_lex_unit::item is not 0.
@end itemize
@node selectexplain
@section Explain Execution
For EXPLAIN result showing for every SELECT will be called mysql_select
with option SELECT_DESCRIBE.
For main UNION will be called mysql_explain_union.
mysql_explain_union call mysql_explain_select for every SELECT in given
union.
mysql_explain_select call mysql_select with SELECT_DESCRIBE.
mysql_select create JOIN for select (if it not exists, because if it
called for subselect JOIN can be created in JOIN::optimize of outer
query when it decided to calculate value of subselect). Then it call
JOIN::prepare, JOIN::optimize, JOIN exec and JOIN::cleanup as usual.
JOIN::exec called for SELECT with SELECT_DESCRIBE option call
select_describe.
select_describe return to user description of SELECT and call
mysql_explain_union for every inner UNION
PROBLEM: how it will work with global query optimization?
@node transformations, coding guidelines, selects, Top
@chapter How MySQL transforms subqueries
Item_subselect virtual method select_transformer is used to rewrite
subqueries. It is called from Item_subselect::init (which called in
Item_subselect constructor)
@node transformation IN
@section Item_in_subselect::select_transformer
Item_in_subselect::select_transformer is divided on two parts for
scalar left part and row left part:
@node transformation scalar IN
@subsection Scalar IN Subselect
To rewrite scalar IN subselect used method
Item_in_subselect::single_value_transformer, Scalar IN subselect will
be replaced with Item_in_optimizer.
Item_in_optimizer item is special boolean function. On value request
(one of val, val_int or val_str methods) it evaluate left expression of
IN by storing it value in cache item (one of Item_cache* items), then it
test cache is it NULL. If left expression (cache) is NULL then
Item_in_optimizer return NULL, else it evaluate Item_in_subselect.
Example queries.
@example
a) SELECT * from t1 where t1.a in (SELECT t2.a FROM t2);
b) SELECT * from t1 where t1.a in (SELECT t2.a FROM t2 GROUP BY t2.a);
@end example
@itemize
@item
Item_in_subselect inherit mechanism of getting value from
Item_exists_subselect.
@item
Select_transformer stores reference to left expression in its
conditions: (in WHERE in case 'a' and in a HAVING in case 'b')
@item
Item from item list of this select (t2.a) can be referred with special
reference (Item_ref_null_helper or Item_asterisk_remover).
This reference informs Item_in_optimizer if item (t2.a) is NULL by
setting the 'was_null' flag.
@item
The return value from Item_in_subselect will be evaluated as following:
@itemize @bullet
@item
If TRUE return true
@item
If NULL return null
@item
If FALSE and 'was_null' is set, return null
@item
return FALSE
@end itemize
@end itemize
<left_expression> IN (SELECT <item> ...) will be represented like
following:
@example
+-----------------+
|Item_in_optimizer|
+-----------------+
|
+---------------------+------------+
| |
+-----------------------+ +-----------------+
| <left_expression> | |Item_in_subselect|
| | +-----------------+
+-----------------------+ |
|<left_expression cache>| +-----------+-----------+
| | | |
+-----------------------+ | |
^ +----------+ +--------------------+
+<<<<<<<<<<<<<<<<<| Item_ref | +<<<|Item_ref_null_helper|
+----------+ V +--------------------+
V +--------------------+
+>>>| <item> |
+--------------------+
@end example
where '<<<<<<<<<' is reference in meaning of Item_ref.
Item_ref used for point to <left_expression cache>, because in time of
transformation we know only address of variable where pointer on cache
will be stored.
If select have ORDER BY clause it will be wiped out, because no sense in
ORDER BY without LIMIT here.
If IN subselect union condition of every select in UNION will be changed
personally.
Following is examples of IN transformations:
@example
a) <left_expression> IN (SELECT <item> FROM t
WHERE <where_exp>)
will be represented as
(SELECT 1 FROM t
WHERE <where_exp> and
Item_ref(<cached_left_expression>)=<Item_asterisk_remover(<Item>)>)
b) <left_expression> IN (SELECT <item> FROM t
HAVING <having_expr>
ORDER BY 1)
will be represented as
(SELECT <item> as ref_null_helper FROM t
HAVING <having_exp> AND
Item_ref(<cached_left_expression>) = ref_null_helper)
c) <left_expression> IN (SELECT <item> UNION ...)
will be represented as
(SELECT 1
HAVING Item_ref(<cached_left_expression>)=
<Item_asterisk_remover(<Item>)>
UNION ...)
(having without FROM is syntax error, but having condition is checked
even for subselect without FROM)
d) <left_expression> IN (select <item>)
will be completely replaced with <left_expression> = <item>
@end example
Now conditions (WHERE (a) or HAVING (b)) will be changed depends of
select in following way:
If subselect have HAVING , sum function or GROUP BY (case a) then item
list will be unchanged and Item_ref_null_helper reference will be
created on item list element. Condition will be added to HAVING condition.
If subselect have not HAVING, sum function or GROUP BY (case b) then:
@itemize @bullet
@item
@strong{item list} will be replaced with 1.
@item
@strong{<item>} from item list will be stored in Item_asterisk_remover, which
inherit from Item_ref_null_helper, but store item on which refer by
itself, and also it can resolve '*' item.
@item
@strong{<left_expression cache> = <Item_ref_null_helper>} will be added to
WHERE clause this item or to HAVING clause if this subselect have
no FROM clause and subselect is union (case c).
@end itemize
Single select without FROM will be reduced to just
<left_expression> = <item> without using Item_in_optimizer.
@node transformations row IN
@subsection Row IN Subselect
To rewrite row IN subselect used method
Item_in_subselect::row_value_transformer. It work in almost same way as
scalar analog, but work with Item_cache_row for caching left expression
and use references on elements of Item_cache_row.
To refer on item list it use Item_ref_on_list_position.
Item_ref_on_list_position::fix_fields will find item in item list of
subselect by number and create Item_ref_null_helper to refer on it. It
used to find reference when all '*' items will be translated in item
list. Subselect with have HAVING, sum functions or GROUP BY will
transformed in following way:
@example
ROW(l1, l2, ... lN) IN (SELECT i1, i2, ... iM FROM t HAVING <having_expr>)
will be following:
(SELECT i1, i2, ... iM FROM t
HAVING <having_expr> and
<cache_l1> = <ref_on_list_position(1)> AND
<cache_l2> = <ref_on_list_position(2)> AND
...
<cache_lN> = <ref_on_list_position(N)>)
@end example
In this way will be transformed select without FROM, too.
For other subselect it will be same but for WHERE clause.
@node transformations all any
@section Item_allany_subselect
Item_allany_subselect is inherited from Item_in_subselect.
ALL/ANY/SOME use same algorithm (and same method of Item_in_subselect)
as scalar IN, but use different function instead of '='.
ANY/SOME use same function that was listed after left expression.
ALL use inverted function, and all subselect passed as argument to
Item_func_not.
@node transformations singlerow
@section Item_singlerow_subselect
Item_singlerow_subselect will be rewritten only if it have not FROM
clause, it is not part of UNION and it is scalar subselect. For now will
not be converted subselects with field or reference on top of item list
(we can't change name of such items from one hand, but from other hand
we should assign to it name of whole subselect which will be reduced);
Following will not be reduced:
@example
SELECT a;
SELECT 1 UNION SELECT 2;
SELECT 1 FROM t1;
@end example
Following select will be reduced:
@example
SELECT 1;
SELECT a+2;
@end example
Such subselect will be completely replaced by its expression from item
list and its SELECT_LEX and SELECT_LEX_UNIT will be removed from
SELECT_LEX's tree.
But all Item_fields and Item_ref of that expression will be marked for
special fix_fields() procedure. fix_fields() for such Item will be
performed is same way as for items of inner subselect. Also if this
expression is Item_fields or Item_ref then name of this new item will
be same as name of this item (but not '(SELECT ...)'). It is done to
prevent broke references on such items from more inner subselects.
@node coding guidelines, mysys functions, transformations, Top
@chapter Coding Guidelines @chapter Coding Guidelines
@itemize @bullet @itemize @bullet
...@@ -1836,7 +2414,7 @@ able to provide the optimal information for all parameters. ...@@ -1836,7 +2414,7 @@ able to provide the optimal information for all parameters.
If number of columns, in the header packet, is not 0 then the If number of columns, in the header packet, is not 0 then the
prepared statement will contain a result set. In this case the packet prepared statement will contain a result set. In this case the packet
is followed by a field description result set. @xref{4.1 field descr}. is followed by a field description result set. @xref{4.1 field desc}.
@node 4.1 long data,,, @node 4.1 long data,,,
......
...@@ -124,13 +124,9 @@ int main(int argc,char *argv[]) ...@@ -124,13 +124,9 @@ int main(int argc,char *argv[])
{ {
keylen=*(info->lastkey); keylen=*(info->lastkey);
#if HA_FT_WTYPE == HA_KEYTYPE_FLOAT subkeys=ft_sintXkorr(info->lastkey+keylen+1);
subkeys=mi_sint4korr(info->lastkey+keylen+1);
if (subkeys >= 0) if (subkeys >= 0)
weight=*(float*)&subkeys; weight=*(float*)&subkeys;
#else
#error
#endif
snprintf(buf,MAX_LEN,"%.*s",(int) keylen,info->lastkey+1); snprintf(buf,MAX_LEN,"%.*s",(int) keylen,info->lastkey+1);
my_casedn_str(default_charset_info,buf); my_casedn_str(default_charset_info,buf);
......
...@@ -1893,6 +1893,7 @@ int mi_repair_by_sort(MI_CHECK *param, register MI_INFO *info, ...@@ -1893,6 +1893,7 @@ int mi_repair_by_sort(MI_CHECK *param, register MI_INFO *info,
{ {
sort_param.read_cache=param->read_cache; sort_param.read_cache=param->read_cache;
sort_param.keyinfo=share->keyinfo+sort_param.key; sort_param.keyinfo=share->keyinfo+sort_param.key;
sort_param.seg=sort_param.keyinfo->seg;
if (!(((ulonglong) 1 << sort_param.key) & key_map)) if (!(((ulonglong) 1 << sort_param.key) & key_map))
{ {
/* Remember old statistics for key */ /* Remember old statistics for key */
...@@ -1906,7 +1907,7 @@ int mi_repair_by_sort(MI_CHECK *param, register MI_INFO *info, ...@@ -1906,7 +1907,7 @@ int mi_repair_by_sort(MI_CHECK *param, register MI_INFO *info,
if ((!(param->testflag & T_SILENT))) if ((!(param->testflag & T_SILENT)))
printf ("- Fixing index %d\n",sort_param.key+1); printf ("- Fixing index %d\n",sort_param.key+1);
sort_param.max_pos=sort_param.pos=share->pack.header_length; sort_param.max_pos=sort_param.pos=share->pack.header_length;
keyseg=sort_param.keyinfo->seg; keyseg=sort_param.seg;
bzero((char*) sort_param.unique,sizeof(sort_param.unique)); bzero((char*) sort_param.unique,sizeof(sort_param.unique));
sort_param.key_length=share->rec_reflength; sort_param.key_length=share->rec_reflength;
for (i=0 ; keyseg[i].type != HA_KEYTYPE_END; i++) for (i=0 ; keyseg[i].type != HA_KEYTYPE_END; i++)
...@@ -2255,6 +2256,7 @@ int mi_repair_parallel(MI_CHECK *param, register MI_INFO *info, ...@@ -2255,6 +2256,7 @@ int mi_repair_parallel(MI_CHECK *param, register MI_INFO *info,
{ {
sort_param[i].key=key; sort_param[i].key=key;
sort_param[i].keyinfo=share->keyinfo+key; sort_param[i].keyinfo=share->keyinfo+key;
sort_param[i].seg=sort_param[i].keyinfo->seg;
if (!(((ulonglong) 1 << key) & key_map)) if (!(((ulonglong) 1 << key) & key_map))
{ {
/* Remember old statistics for key */ /* Remember old statistics for key */
...@@ -2292,7 +2294,7 @@ int mi_repair_parallel(MI_CHECK *param, register MI_INFO *info, ...@@ -2292,7 +2294,7 @@ int mi_repair_parallel(MI_CHECK *param, register MI_INFO *info,
(share->base.pack_reclength * i)); (share->base.pack_reclength * i));
sort_param[i].key_length=share->rec_reflength; sort_param[i].key_length=share->rec_reflength;
for (keyseg=sort_param[i].keyinfo->seg; keyseg->type != HA_KEYTYPE_END; for (keyseg=sort_param[i].seg; keyseg->type != HA_KEYTYPE_END;
keyseg++) keyseg++)
{ {
sort_param[i].key_length+=keyseg->length; sort_param[i].key_length+=keyseg->length;
...@@ -3051,7 +3053,7 @@ static int sort_key_cmp(MI_SORT_PARAM *sort_param, const void *a, ...@@ -3051,7 +3053,7 @@ static int sort_key_cmp(MI_SORT_PARAM *sort_param, const void *a,
const void *b) const void *b)
{ {
uint not_used; uint not_used;
return (ha_key_cmp(sort_param->keyinfo->seg, *((uchar**) a), *((uchar**) b), return (ha_key_cmp(sort_param->seg, *((uchar**) a), *((uchar**) b),
USE_WHOLE_KEY, SEARCH_SAME,&not_used)); USE_WHOLE_KEY, SEARCH_SAME,&not_used));
} /* sort_key_cmp */ } /* sort_key_cmp */
...@@ -3066,7 +3068,7 @@ static int sort_key_write(MI_SORT_PARAM *sort_param, const void *a) ...@@ -3066,7 +3068,7 @@ static int sort_key_write(MI_SORT_PARAM *sort_param, const void *a)
if (sort_info->key_block->inited) if (sort_info->key_block->inited)
{ {
cmp=ha_key_cmp(sort_param->keyinfo->seg,sort_info->key_block->lastkey, cmp=ha_key_cmp(sort_param->seg,sort_info->key_block->lastkey,
(uchar*) a, USE_WHOLE_KEY,SEARCH_FIND | SEARCH_UPDATE, (uchar*) a, USE_WHOLE_KEY,SEARCH_FIND | SEARCH_UPDATE,
&diff_pos); &diff_pos);
sort_param->unique[diff_pos-1]++; sort_param->unique[diff_pos-1]++;
...@@ -3091,7 +3093,7 @@ static int sort_key_write(MI_SORT_PARAM *sort_param, const void *a) ...@@ -3091,7 +3093,7 @@ static int sort_key_write(MI_SORT_PARAM *sort_param, const void *a)
llbuff2)); llbuff2));
param->testflag|=T_RETRY_WITHOUT_QUICK; param->testflag|=T_RETRY_WITHOUT_QUICK;
if (sort_info->param->testflag & T_VERBOSE) if (sort_info->param->testflag & T_VERBOSE)
_mi_print_key(stdout,sort_param->keyinfo->seg,(uchar*) a, USE_WHOLE_KEY); _mi_print_key(stdout,sort_param->seg,(uchar*) a, USE_WHOLE_KEY);
return (sort_delete_record(sort_param)); return (sort_delete_record(sort_param));
} }
#ifndef DBUG_OFF #ifndef DBUG_OFF
...@@ -3182,7 +3184,7 @@ static int sort_ft_key_write(MI_SORT_PARAM *sort_param, const void *a) ...@@ -3182,7 +3184,7 @@ static int sort_ft_key_write(MI_SORT_PARAM *sort_param, const void *a)
get_key_full_length_rdonly(val_off, ft_buf->lastkey); get_key_full_length_rdonly(val_off, ft_buf->lastkey);
if (val_off == a_len && if (val_off == a_len &&
mi_compare_text(sort_param->keyinfo->seg->charset, mi_compare_text(sort_param->seg->charset,
((uchar *)a)+1,a_len-1, ((uchar *)a)+1,a_len-1,
ft_buf->lastkey+1,val_off-1, 0)==0) ft_buf->lastkey+1,val_off-1, 0)==0)
{ {
......
...@@ -295,6 +295,7 @@ typedef struct st_mi_sort_param ...@@ -295,6 +295,7 @@ typedef struct st_mi_sort_param
uint maxbuffers, keys, find_length, sort_keys_length; uint maxbuffers, keys, find_length, sort_keys_length;
my_bool fix_datafile, master; my_bool fix_datafile, master;
MI_KEYDEF *keyinfo; MI_KEYDEF *keyinfo;
HA_KEYSEG *seg;
SORT_INFO *sort_info; SORT_INFO *sort_info;
uchar **sort_keys; uchar **sort_keys;
byte *rec_buff; byte *rec_buff;
......
...@@ -785,7 +785,7 @@ int rtree_delete(MI_INFO *info, uint keynr, uchar *key, uint key_length) ...@@ -785,7 +785,7 @@ int rtree_delete(MI_INFO *info, uint keynr, uchar *key, uint key_length)
goto err1; goto err1;
} }
if (ReinsertList.pages) if (ReinsertList.pages)
free(ReinsertList.pages); my_free((byte*) ReinsertList.pages, MYF(0));
/* check for redundant root (not leaf, 1 child) and eliminate */ /* check for redundant root (not leaf, 1 child) and eliminate */
if ((old_root = info->s->state.key_root[keynr]) == HA_OFFSET_ERROR) if ((old_root = info->s->state.key_root[keynr]) == HA_OFFSET_ERROR)
......
...@@ -56,7 +56,7 @@ int rtree_add_key(MI_INFO *info, MI_KEYDEF *keyinfo, uchar *key, ...@@ -56,7 +56,7 @@ int rtree_add_key(MI_INFO *info, MI_KEYDEF *keyinfo, uchar *key,
} }
return (rtree_split_page(info, keyinfo, page_buf, key, key_length, return (rtree_split_page(info, keyinfo, page_buf, key, key_length,
new_page) ? -1 : 0); new_page) ? -1 : 1);
} }
/* /*
...@@ -69,7 +69,7 @@ int rtree_delete_key(MI_INFO *info, uchar *page_buf, uchar *key, ...@@ -69,7 +69,7 @@ int rtree_delete_key(MI_INFO *info, uchar *page_buf, uchar *key,
uchar *key_start; uchar *key_start;
key_start= key - nod_flag; key_start= key - nod_flag;
if (nod_flag) if (!nod_flag)
key_length += info->s->base.rec_reflength; key_length += info->s->base.rec_reflength;
memmove(key_start, key + key_length, page_size - key_length - memmove(key_start, key + key_length, page_size - key_length -
......
...@@ -263,7 +263,7 @@ int rtree_split_page(MI_INFO *info, MI_KEYDEF *keyinfo, uchar *page, uchar *key, ...@@ -263,7 +263,7 @@ int rtree_split_page(MI_INFO *info, MI_KEYDEF *keyinfo, uchar *page, uchar *key,
int max_keys = (mi_getint(page)-2) / (full_length); int max_keys = (mi_getint(page)-2) / (full_length);
n_dim = (keyinfo->keysegs-1) / 2; n_dim = keyinfo->keysegs / 2;
{ {
int coord_buf_size = n_dim * 2 * sizeof(double) * (max_keys + 1 + 4); int coord_buf_size = n_dim * 2 * sizeof(double) * (max_keys + 1 + 4);
......
...@@ -55,7 +55,7 @@ int run_test(const char *filename) ...@@ -55,7 +55,7 @@ int run_test(const char *filename)
int key_type=HA_KEYTYPE_DOUBLE; int key_type=HA_KEYTYPE_DOUBLE;
int key_length=8; int key_length=8;
int null_fields=0; int null_fields=0;
int nrecords=30; int nrecords=300;
int rec_length=0; int rec_length=0;
int uniques=0; int uniques=0;
int i; int i;
......
...@@ -111,7 +111,7 @@ int _create_index_by_sort(MI_SORT_PARAM *info,my_bool no_messages, ...@@ -111,7 +111,7 @@ int _create_index_by_sort(MI_SORT_PARAM *info,my_bool no_messages,
DBUG_ENTER("_create_index_by_sort"); DBUG_ENTER("_create_index_by_sort");
DBUG_PRINT("enter",("sort_length: %d", info->key_length)); DBUG_PRINT("enter",("sort_length: %d", info->key_length));
if (info->keyinfo->flag && HA_VAR_LENGTH_KEY) if (info->keyinfo->flag & HA_VAR_LENGTH_KEY)
{ {
info->write_keys=write_keys_varlen; info->write_keys=write_keys_varlen;
info->read_to_buffer=read_to_buffer_varlen; info->read_to_buffer=read_to_buffer_varlen;
...@@ -622,7 +622,7 @@ inline int my_var_write(MI_SORT_PARAM *info,IO_CACHE *to_file,char *bufs) ...@@ -622,7 +622,7 @@ inline int my_var_write(MI_SORT_PARAM *info,IO_CACHE *to_file,char *bufs)
{ {
int err; int err;
uint16 len = _mi_keylength(info->keyinfo,bufs); uint16 len = _mi_keylength(info->keyinfo,bufs);
if ((err= my_b_write(to_file,(byte*)&len,sizeof(len)))) if ((err= my_b_write(to_file,(byte*)&len,sizeof(len))))
return (err); return (err);
if ((err= my_b_write(to_file,(byte*)bufs,(uint) len))) if ((err= my_b_write(to_file,(byte*)bufs,(uint) len)))
...@@ -641,7 +641,7 @@ static int NEAR_F write_keys_varlen(MI_SORT_PARAM *info, register uchar **sort_k ...@@ -641,7 +641,7 @@ static int NEAR_F write_keys_varlen(MI_SORT_PARAM *info, register uchar **sort_k
qsort2((byte*) sort_keys,count,sizeof(byte*),(qsort2_cmp) info->key_cmp, qsort2((byte*) sort_keys,count,sizeof(byte*),(qsort2_cmp) info->key_cmp,
info); info);
if (!my_b_inited(tempfile) && if (!my_b_inited(tempfile) &&
open_cached_file(tempfile, my_tmpdir(info->tmpdir), "ST", open_cached_file(tempfile, my_tmpdir(info->tmpdir), "ST",
DISK_BUFFER_SIZE, info->sort_info->param->myf_rw)) DISK_BUFFER_SIZE, info->sort_info->param->myf_rw))
DBUG_RETURN(1); /* purecov: inspected */ DBUG_RETURN(1); /* purecov: inspected */
...@@ -650,7 +650,7 @@ static int NEAR_F write_keys_varlen(MI_SORT_PARAM *info, register uchar **sort_k ...@@ -650,7 +650,7 @@ static int NEAR_F write_keys_varlen(MI_SORT_PARAM *info, register uchar **sort_k
for (end=sort_keys+count ; sort_keys != end ; sort_keys++) for (end=sort_keys+count ; sort_keys != end ; sort_keys++)
{ {
if ((err= my_var_write(info,tempfile,*sort_keys))) if ((err= my_var_write(info,tempfile,*sort_keys)))
DBUG_RETURN(err); DBUG_RETURN(err);
} }
DBUG_RETURN(0); DBUG_RETURN(0);
} /* write_keys_varlen */ } /* write_keys_varlen */
...@@ -777,7 +777,7 @@ static uint NEAR_F read_to_buffer_varlen(IO_CACHE *fromfile, BUFFPEK *buffpek, ...@@ -777,7 +777,7 @@ static uint NEAR_F read_to_buffer_varlen(IO_CACHE *fromfile, BUFFPEK *buffpek,
uint16 length_of_key = 0; uint16 length_of_key = 0;
uint idx; uint idx;
uchar *buffp; uchar *buffp;
if ((count=(uint) min((ha_rows) buffpek->max_keys,buffpek->count))) if ((count=(uint) min((ha_rows) buffpek->max_keys,buffpek->count)))
{ {
buffp = buffpek->base; buffp = buffpek->base;
...@@ -786,11 +786,11 @@ static uint NEAR_F read_to_buffer_varlen(IO_CACHE *fromfile, BUFFPEK *buffpek, ...@@ -786,11 +786,11 @@ static uint NEAR_F read_to_buffer_varlen(IO_CACHE *fromfile, BUFFPEK *buffpek,
{ {
if (my_pread(fromfile->file,(byte*)&length_of_key,sizeof(length_of_key), if (my_pread(fromfile->file,(byte*)&length_of_key,sizeof(length_of_key),
buffpek->file_pos,MYF_RW)) buffpek->file_pos,MYF_RW))
return((uint) -1); return((uint) -1);
buffpek->file_pos+=sizeof(length_of_key); buffpek->file_pos+=sizeof(length_of_key);
if (my_pread(fromfile->file,(byte*) buffp,length_of_key, if (my_pread(fromfile->file,(byte*) buffp,length_of_key,
buffpek->file_pos,MYF_RW)) buffpek->file_pos,MYF_RW))
return((uint) -1); return((uint) -1);
buffpek->file_pos+=length_of_key; buffpek->file_pos+=length_of_key;
buffp = buffp + sort_length; buffp = buffp + sort_length;
} }
......
...@@ -4530,7 +4530,6 @@ void Field_geom::get_key_image(char *buff,uint length,CHARSET_INFO *cs, ...@@ -4530,7 +4530,6 @@ void Field_geom::get_key_image(char *buff,uint length,CHARSET_INFO *cs,
ulong blob_length=get_length(ptr); ulong blob_length=get_length(ptr);
char *blob; char *blob;
get_ptr(&blob); get_ptr(&blob);
memcpy(buff+2,blob,length);
MBR mbr; MBR mbr;
Geometry gobj; Geometry gobj;
......
...@@ -2293,6 +2293,7 @@ convert_search_mode_to_innobase( ...@@ -2293,6 +2293,7 @@ convert_search_mode_to_innobase(
case HA_READ_BEFORE_KEY: return(PAGE_CUR_L); case HA_READ_BEFORE_KEY: return(PAGE_CUR_L);
case HA_READ_PREFIX: return(PAGE_CUR_GE); case HA_READ_PREFIX: return(PAGE_CUR_GE);
case HA_READ_PREFIX_LAST: return(PAGE_CUR_LE); case HA_READ_PREFIX_LAST: return(PAGE_CUR_LE);
case HA_READ_PREFIX_LAST_OR_PREV:return(PAGE_CUR_LE);
/* In MySQL HA_READ_PREFIX and HA_READ_PREFIX_LAST always /* In MySQL HA_READ_PREFIX and HA_READ_PREFIX_LAST always
use a complete-field-prefix of a kay value as the search use a complete-field-prefix of a kay value as the search
tuple. I.e., it is not allowed that the last field would tuple. I.e., it is not allowed that the last field would
......
...@@ -1260,7 +1260,8 @@ void yyerror(const char *s) ...@@ -1260,7 +1260,8 @@ void yyerror(const char *s)
{ {
THD *thd=current_thd; THD *thd=current_thd;
char *yytext=(char*) thd->lex.tok_start; char *yytext=(char*) thd->lex.tok_start;
if (!strcmp(s,"parse error")) /* "parse error" changed into "syntax error" between bison 1.75 and 1.875 */
if (strcmp(s,"parse error") == 0 || strcmp(s,"syntax error") == 0)
s=ER(ER_SYNTAX_ERROR); s=ER(ER_SYNTAX_ERROR);
net_printf(thd,ER_PARSE_ERROR, s, yytext ? (char*) yytext : "", net_printf(thd,ER_PARSE_ERROR, s, yytext ? (char*) yytext : "",
thd->lex.yylineno); thd->lex.yylineno);
......
...@@ -2153,7 +2153,7 @@ check_quick_keys(PARAM *param,uint idx,SEL_ARG *key_tree, ...@@ -2153,7 +2153,7 @@ check_quick_keys(PARAM *param,uint idx,SEL_ARG *key_tree,
if (tmp_min_flag & GEOM_FLAG) if (tmp_min_flag & GEOM_FLAG)
{ {
tmp= param->table->file-> tmp= param->table->file->
records_in_range((int) keynr, (byte*)(param->min_key + 1), records_in_range((int) keynr, (byte*)(param->min_key),
min_key_length, min_key_length,
(ha_rkey_function)(tmp_min_flag ^ GEOM_FLAG), (ha_rkey_function)(tmp_min_flag ^ GEOM_FLAG),
(byte *)NullS, 0, HA_READ_KEY_EXACT); (byte *)NullS, 0, HA_READ_KEY_EXACT);
......
...@@ -705,14 +705,6 @@ int mysql_create_table(THD *thd,const char *db, const char *table_name, ...@@ -705,14 +705,6 @@ int mysql_create_table(THD *thd,const char *db, const char *table_name,
{ {
if (key->type == Key::FULLTEXT) if (key->type == Key::FULLTEXT)
column->length=1; /* ft-code ignores it anyway :-) */ column->length=1; /* ft-code ignores it anyway :-) */
else if (key->type == Key::SPATIAL)
{
/*
BAR: 4 is: (Xmin,Xmax,Ymin,Ymax), this is for 2D case
Lately we'll extend this code to support more dimensions
*/
column->length=4*sizeof(double);
}
else else
{ {
my_printf_error(ER_BLOB_KEY_WITHOUT_LENGTH, my_printf_error(ER_BLOB_KEY_WITHOUT_LENGTH,
...@@ -722,6 +714,17 @@ int mysql_create_table(THD *thd,const char *db, const char *table_name, ...@@ -722,6 +714,17 @@ int mysql_create_table(THD *thd,const char *db, const char *table_name,
} }
} }
} }
if (key->type == Key::SPATIAL)
{
if (!column->length )
{
/*
BAR: 4 is: (Xmin,Xmax,Ymin,Ymax), this is for 2D case
Lately we'll extend this code to support more dimensions
*/
column->length=4*sizeof(double);
}
}
if (!(sql_field->flags & NOT_NULL_FLAG)) if (!(sql_field->flags & NOT_NULL_FLAG))
{ {
if (key->type == Key::PRIMARY) if (key->type == Key::PRIMARY)
...@@ -757,6 +760,9 @@ int mysql_create_table(THD *thd,const char *db, const char *table_name, ...@@ -757,6 +760,9 @@ int mysql_create_table(THD *thd,const char *db, const char *table_name,
DBUG_RETURN(-1); DBUG_RETURN(-1);
} }
} }
else if (f_is_geom(sql_field->pack_flag))
{
}
else if (column->length > length || else if (column->length > length ||
((f_is_packed(sql_field->pack_flag) || ((f_is_packed(sql_field->pack_flag) ||
((file->table_flags() & HA_NO_PREFIX_CHAR_KEYS) && ((file->table_flags() & HA_NO_PREFIX_CHAR_KEYS) &&
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment