Merge bk-internal:/home/bk/mysql-5.1
into mysql.com:/home/jimw/my/mysql-5.1-clean
This commit is contained in:
commit
282855e90b
@ -3056,12 +3056,6 @@ static int run_query_normal(MYSQL* mysql, struct st_query* q, int flags)
|
||||
goto end;
|
||||
}
|
||||
|
||||
if (handle_no_error(q))
|
||||
{
|
||||
error= 1;
|
||||
goto end;
|
||||
}
|
||||
|
||||
if (!disable_result_log)
|
||||
{
|
||||
ulong affected_rows; /* Ok to be undef if 'disable_info' is set */
|
||||
@ -3106,12 +3100,9 @@ static int run_query_normal(MYSQL* mysql, struct st_query* q, int flags)
|
||||
MYSQL_RES *warn_res=0;
|
||||
uint count= mysql_warning_count(mysql);
|
||||
if (!mysql_real_query(mysql, "SHOW WARNINGS", 13))
|
||||
{
|
||||
warn_res= mysql_store_result(mysql);
|
||||
}
|
||||
if (!warn_res)
|
||||
verbose_msg("Warning count is %u but didn't get any warnings",
|
||||
count);
|
||||
die("Warning count is %u but didn't get any warnings", count);
|
||||
else
|
||||
{
|
||||
dynstr_append_mem(ds, "Warnings:\n", 10);
|
||||
@ -3142,15 +3133,28 @@ static int run_query_normal(MYSQL* mysql, struct st_query* q, int flags)
|
||||
}
|
||||
else if (q->record_file[0])
|
||||
{
|
||||
error = check_result(ds, q->record_file, q->require_file);
|
||||
error= check_result(ds, q->record_file, q->require_file);
|
||||
}
|
||||
if (res)
|
||||
mysql_free_result(res);
|
||||
last_result= 0;
|
||||
counter++;
|
||||
} while (!(err= mysql_next_result(mysql)));
|
||||
if (err >= 1)
|
||||
mysql_error(mysql);
|
||||
if (err > 0)
|
||||
{
|
||||
/* We got an error from mysql_next_result, maybe expected */
|
||||
if (handle_error(query, q, mysql_errno(mysql), mysql_error(mysql),
|
||||
mysql_sqlstate(mysql), ds))
|
||||
error= 1;
|
||||
goto end;
|
||||
}
|
||||
|
||||
// If we come here the query is both executed and read successfully
|
||||
if (handle_no_error(q))
|
||||
{
|
||||
error= 1;
|
||||
goto end;
|
||||
}
|
||||
|
||||
end:
|
||||
free_replace();
|
||||
@ -3203,8 +3207,7 @@ static int handle_error(const char *query, struct st_query *q,
|
||||
abort_not_supported_test();
|
||||
|
||||
if (q->abort_on_error)
|
||||
die("query '%s' failed: %d: %s", query,
|
||||
err_errno, err_error);
|
||||
die("query '%s' failed: %d: %s", query, err_errno, err_error);
|
||||
|
||||
for (i= 0 ; (uint) i < q->expected_errors ; i++)
|
||||
{
|
||||
@ -3243,13 +3246,11 @@ static int handle_error(const char *query, struct st_query *q,
|
||||
if (i)
|
||||
{
|
||||
if (q->expected_errno[0].type == ERR_ERRNO)
|
||||
verbose_msg("query '%s' failed with wrong errno %d instead of %d...",
|
||||
q->query, err_errno,
|
||||
q->expected_errno[0].code.errnum);
|
||||
die("query '%s' failed with wrong errno %d instead of %d...",
|
||||
q->query, err_errno, q->expected_errno[0].code.errnum);
|
||||
else
|
||||
verbose_msg("query '%s' failed with wrong sqlstate %s instead of %s...",
|
||||
q->query, err_sqlstate,
|
||||
q->expected_errno[0].code.sqlstate);
|
||||
die("query '%s' failed with wrong sqlstate %s instead of %s...",
|
||||
q->query, err_sqlstate, q->expected_errno[0].code.sqlstate);
|
||||
DBUG_RETURN(1);
|
||||
}
|
||||
|
||||
@ -3283,16 +3284,16 @@ static int handle_no_error(struct st_query *q)
|
||||
q->expected_errno[0].code.errnum != 0)
|
||||
{
|
||||
/* Error code we wanted was != 0, i.e. not an expected success */
|
||||
verbose_msg("query '%s' succeeded - should have failed with errno %d...",
|
||||
q->query, q->expected_errno[0].code.errnum);
|
||||
die("query '%s' succeeded - should have failed with errno %d...",
|
||||
q->query, q->expected_errno[0].code.errnum);
|
||||
DBUG_RETURN(1);
|
||||
}
|
||||
else if (q->expected_errno[0].type == ERR_SQLSTATE &&
|
||||
strcmp(q->expected_errno[0].code.sqlstate,"00000") != 0)
|
||||
{
|
||||
/* SQLSTATE we wanted was != "00000", i.e. not an expected success */
|
||||
verbose_msg("query '%s' succeeded - should have failed with sqlstate %s...",
|
||||
q->query, q->expected_errno[0].code.sqlstate);
|
||||
die("query '%s' succeeded - should have failed with sqlstate %s...",
|
||||
q->query, q->expected_errno[0].code.sqlstate);
|
||||
DBUG_RETURN(1);
|
||||
}
|
||||
|
||||
@ -3312,7 +3313,7 @@ static int run_query_stmt(MYSQL *mysql, struct st_query *q, int flags)
|
||||
{
|
||||
int error= 0; /* Function return code if "goto end;" */
|
||||
int err; /* Temporary storage of return code from calls */
|
||||
int query_len, got_error_on_execute;
|
||||
int query_len;
|
||||
ulonglong num_rows;
|
||||
char *query;
|
||||
MYSQL_RES *res= NULL; /* Note that here 'res' is meta data result set */
|
||||
@ -3328,7 +3329,7 @@ static int run_query_stmt(MYSQL *mysql, struct st_query *q, int flags)
|
||||
*/
|
||||
if (!(stmt= mysql_stmt_init(mysql)))
|
||||
die("unable init stmt structure");
|
||||
|
||||
|
||||
if (q->type != Q_EVAL)
|
||||
{
|
||||
query= q->query;
|
||||
@ -3369,30 +3370,21 @@ static int run_query_stmt(MYSQL *mysql, struct st_query *q, int flags)
|
||||
|
||||
if (err != 0)
|
||||
{
|
||||
if (q->abort_on_error)
|
||||
{
|
||||
die("query '%s' failed: %d: %s", query,
|
||||
mysql_stmt_errno(stmt), mysql_stmt_error(stmt));
|
||||
}
|
||||
else
|
||||
{
|
||||
/*
|
||||
Preparing is part of normal execution and some errors may be expected
|
||||
*/
|
||||
error= handle_error(query, q, mysql_stmt_errno(stmt),
|
||||
mysql_stmt_error(stmt), mysql_stmt_sqlstate(stmt),
|
||||
ds);
|
||||
goto end;
|
||||
}
|
||||
/*
|
||||
Preparing is part of normal execution and some errors may be expected
|
||||
*/
|
||||
if (handle_error(query, q, mysql_stmt_errno(stmt),
|
||||
mysql_stmt_error(stmt), mysql_stmt_sqlstate(stmt), ds))
|
||||
error= 1;
|
||||
goto end;
|
||||
}
|
||||
|
||||
/* We may have got warnings already, collect them if any */
|
||||
/* FIXME we only want this if the statement succeeds I think */
|
||||
if (!disable_ps_warnings)
|
||||
run_query_stmt_handle_warnings(mysql, ds);
|
||||
|
||||
/*
|
||||
No need to call mysql_stmt_bind_param() because we have no
|
||||
No need to call mysql_stmt_bind_param() because we have no
|
||||
parameter markers.
|
||||
|
||||
To optimize performance we use a global 'stmt' that is initiated
|
||||
@ -3401,24 +3393,13 @@ static int run_query_stmt(MYSQL *mysql, struct st_query *q, int flags)
|
||||
prepared statement.
|
||||
*/
|
||||
|
||||
if ((got_error_on_execute= mysql_stmt_execute(stmt)) != 0) /* 0 == Success */
|
||||
if (mysql_stmt_execute(stmt) != 0) /* 0 == Success */
|
||||
{
|
||||
if (q->abort_on_error)
|
||||
{
|
||||
/* We got an error, unexpected */
|
||||
die("unable to execute statement '%s': "
|
||||
"%s (mysql_stmt_errno=%d returned=%d)",
|
||||
query, mysql_stmt_error(stmt),
|
||||
mysql_stmt_errno(stmt), got_error_on_execute);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* We got an error, maybe expected */
|
||||
error= handle_error(query, q, mysql_stmt_errno(stmt),
|
||||
mysql_stmt_error(stmt), mysql_stmt_sqlstate(stmt),
|
||||
ds);
|
||||
goto end;
|
||||
}
|
||||
/* We got an error, maybe expected */
|
||||
if (handle_error(query, q, mysql_stmt_errno(stmt),
|
||||
mysql_stmt_error(stmt), mysql_stmt_sqlstate(stmt), ds))
|
||||
error= 1;
|
||||
goto end;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -3428,11 +3409,10 @@ static int run_query_stmt(MYSQL *mysql, struct st_query *q, int flags)
|
||||
*/
|
||||
{
|
||||
my_bool one= 1;
|
||||
if (mysql_stmt_attr_set(stmt, STMT_ATTR_UPDATE_MAX_LENGTH,
|
||||
(void*) &one) != 0)
|
||||
if ((err= mysql_stmt_attr_set(stmt, STMT_ATTR_UPDATE_MAX_LENGTH,
|
||||
(void*) &one)) != 0)
|
||||
die("unable to set stmt attribute "
|
||||
"'STMT_ATTR_UPDATE_MAX_LENGTH': %s (returned=%d)",
|
||||
query, err);
|
||||
"'STMT_ATTR_UPDATE_MAX_LENGTH' err: %d", err);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -3441,22 +3421,11 @@ static int run_query_stmt(MYSQL *mysql, struct st_query *q, int flags)
|
||||
*/
|
||||
if ((err= mysql_stmt_store_result(stmt)) != 0)
|
||||
{
|
||||
if (q->abort_on_error)
|
||||
{
|
||||
/* We got an error, unexpected */
|
||||
die("unable to execute statement '%s': "
|
||||
"%s (mysql_stmt_errno=%d returned=%d)",
|
||||
query, mysql_stmt_error(stmt),
|
||||
mysql_stmt_errno(stmt), got_error_on_execute);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* We got an error, maybe expected */
|
||||
error= handle_error(query, q, mysql_stmt_errno(stmt),
|
||||
mysql_stmt_error(stmt), mysql_stmt_sqlstate(stmt),
|
||||
ds);
|
||||
goto end;
|
||||
}
|
||||
/* We got an error, maybe expected */
|
||||
if(handle_error(query, q, mysql_stmt_errno(stmt),
|
||||
mysql_stmt_error(stmt), mysql_stmt_sqlstate(stmt), ds))
|
||||
error = 1;
|
||||
goto end;
|
||||
}
|
||||
|
||||
/* If we got here the statement was both executed and read succeesfully */
|
||||
@ -3480,8 +3449,6 @@ static int run_query_stmt(MYSQL *mysql, struct st_query *q, int flags)
|
||||
MYSQL_FIELD *field= mysql_fetch_fields(res);
|
||||
uint num_fields= mysql_num_fields(res);
|
||||
|
||||
/* FIXME check error from the above? */
|
||||
|
||||
if (display_metadata)
|
||||
run_query_display_metadata(field, num_fields, ds);
|
||||
|
||||
@ -3634,9 +3601,6 @@ static int run_query_stmt(MYSQL *mysql, struct st_query *q, int flags)
|
||||
mysql_free_result(res); /* Free normal result set with meta data */
|
||||
last_result= 0; /* FIXME have no idea what this is about... */
|
||||
|
||||
if (err >= 1)
|
||||
mysql_error(mysql); /* FIXME strange, has no effect... */
|
||||
|
||||
end:
|
||||
free_replace();
|
||||
last_result=0;
|
||||
@ -3727,8 +3691,8 @@ static void run_query_stmt_handle_warnings(MYSQL *mysql, DYNAMIC_STRING *ds)
|
||||
{
|
||||
MYSQL_RES *warn_res= mysql_store_result(mysql);
|
||||
if (!warn_res)
|
||||
verbose_msg("Warning count is %u but didn't get any warnings",
|
||||
count);
|
||||
die("Warning count is %u but didn't get any warnings",
|
||||
count);
|
||||
else
|
||||
{
|
||||
dynstr_append_mem(ds, "Warnings:\n", 10);
|
||||
|
@ -134,7 +134,6 @@ select 1146 as "after_!errno_masked_error" ;
|
||||
after_!errno_masked_error
|
||||
1146
|
||||
mysqltest: At line 1: query 'select 3 from t1' failed with wrong errno 1146 instead of 1000...
|
||||
mysqltest: At line 1: query 'select 3 from t1' failed with wrong errno 1146 instead of 1000...
|
||||
garbage ;
|
||||
ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'garbage' at line 1
|
||||
select 1064 as "after_--enable_abort_on_error" ;
|
||||
@ -143,7 +142,6 @@ after_--enable_abort_on_error
|
||||
select 3 from t1 ;
|
||||
ERROR 42S02: Table 'test.t1' doesn't exist
|
||||
mysqltest: At line 1: query 'select 3 from t1' failed with wrong errno 1146 instead of 1064...
|
||||
mysqltest: At line 1: query 'select 3 from t1' failed: 1146: Table 'test.t1' doesn't exist
|
||||
hello
|
||||
hello
|
||||
;;;;;;;;
|
||||
|
@ -1057,42 +1057,64 @@ create table t1 (s1 int)//
|
||||
create procedure f1 () begin
|
||||
select sql_cache * from t1;
|
||||
select sql_cache * from t1;
|
||||
select sql_cache * from t1;
|
||||
end;//
|
||||
create procedure f2 () begin
|
||||
select sql_cache * from t1 where s1=1;
|
||||
select sql_cache * from t1;
|
||||
end;//
|
||||
create procedure f3 () begin
|
||||
select sql_cache * from t1;
|
||||
select sql_cache * from t1 where s1=1;
|
||||
end;//
|
||||
create procedure f4 () begin
|
||||
select sql_cache * from t1;
|
||||
select sql_cache * from t1 where s1=1;
|
||||
select sql_cache * from t1;
|
||||
select sql_cache * from t1 where s1=1;
|
||||
select sql_cache * from t1 where s1=1;
|
||||
end;//
|
||||
call f1();
|
||||
s1
|
||||
show status like "Qcache_queries_in_cache";
|
||||
Variable_name Value
|
||||
Qcache_queries_in_cache 1
|
||||
show status like "Qcache_inserts";
|
||||
Variable_name Value
|
||||
Qcache_inserts 1
|
||||
show status like "Qcache_hits";
|
||||
Variable_name Value
|
||||
Qcache_hits 1
|
||||
call f1();
|
||||
s1
|
||||
s1
|
||||
show status like "Qcache_queries_in_cache";
|
||||
Variable_name Value
|
||||
Qcache_queries_in_cache 1
|
||||
Qcache_queries_in_cache 3
|
||||
show status like "Qcache_inserts";
|
||||
Variable_name Value
|
||||
Qcache_inserts 1
|
||||
Qcache_inserts 3
|
||||
show status like "Qcache_hits";
|
||||
Variable_name Value
|
||||
Qcache_hits 0
|
||||
call f1();
|
||||
s1
|
||||
s1
|
||||
s1
|
||||
show status like "Qcache_queries_in_cache";
|
||||
Variable_name Value
|
||||
Qcache_queries_in_cache 3
|
||||
show status like "Qcache_inserts";
|
||||
Variable_name Value
|
||||
Qcache_inserts 3
|
||||
show status like "Qcache_hits";
|
||||
Variable_name Value
|
||||
Qcache_hits 3
|
||||
call f1();
|
||||
s1
|
||||
s1
|
||||
s1
|
||||
select sql_cache * from t1;
|
||||
s1
|
||||
show status like "Qcache_queries_in_cache";
|
||||
Variable_name Value
|
||||
Qcache_queries_in_cache 2
|
||||
Qcache_queries_in_cache 4
|
||||
show status like "Qcache_inserts";
|
||||
Variable_name Value
|
||||
Qcache_inserts 2
|
||||
Qcache_inserts 4
|
||||
show status like "Qcache_hits";
|
||||
Variable_name Value
|
||||
Qcache_hits 5
|
||||
Qcache_hits 6
|
||||
insert into t1 values (1);
|
||||
select sql_cache * from t1;
|
||||
s1
|
||||
@ -1102,28 +1124,150 @@ Variable_name Value
|
||||
Qcache_queries_in_cache 1
|
||||
show status like "Qcache_inserts";
|
||||
Variable_name Value
|
||||
Qcache_inserts 3
|
||||
Qcache_inserts 5
|
||||
show status like "Qcache_hits";
|
||||
Variable_name Value
|
||||
Qcache_hits 5
|
||||
Qcache_hits 6
|
||||
call f1();
|
||||
s1
|
||||
1
|
||||
s1
|
||||
1
|
||||
s1
|
||||
1
|
||||
call f1();
|
||||
s1
|
||||
1
|
||||
s1
|
||||
1
|
||||
s1
|
||||
1
|
||||
select sql_cache * from t1;
|
||||
s1
|
||||
1
|
||||
show status like "Qcache_queries_in_cache";
|
||||
Variable_name Value
|
||||
Qcache_queries_in_cache 2
|
||||
Qcache_queries_in_cache 4
|
||||
show status like "Qcache_inserts";
|
||||
Variable_name Value
|
||||
Qcache_inserts 4
|
||||
Qcache_inserts 8
|
||||
show status like "Qcache_hits";
|
||||
Variable_name Value
|
||||
Qcache_hits 9
|
||||
Qcache_hits 10
|
||||
flush query cache;
|
||||
reset query cache;
|
||||
flush status;
|
||||
select sql_cache * from t1;
|
||||
s1
|
||||
1
|
||||
select sql_cache * from t1 where s1=1;
|
||||
s1
|
||||
1
|
||||
call f1();
|
||||
s1
|
||||
1
|
||||
s1
|
||||
1
|
||||
s1
|
||||
1
|
||||
call f2();
|
||||
s1
|
||||
1
|
||||
s1
|
||||
1
|
||||
call f3();
|
||||
s1
|
||||
1
|
||||
s1
|
||||
1
|
||||
call f4();
|
||||
s1
|
||||
1
|
||||
s1
|
||||
1
|
||||
s1
|
||||
1
|
||||
s1
|
||||
1
|
||||
s1
|
||||
1
|
||||
call f4();
|
||||
s1
|
||||
1
|
||||
s1
|
||||
1
|
||||
s1
|
||||
1
|
||||
s1
|
||||
1
|
||||
s1
|
||||
1
|
||||
call f3();
|
||||
s1
|
||||
1
|
||||
s1
|
||||
1
|
||||
call f2();
|
||||
s1
|
||||
1
|
||||
s1
|
||||
1
|
||||
select sql_cache * from t1 where s1=1;
|
||||
s1
|
||||
1
|
||||
insert into t1 values (2);
|
||||
call f1();
|
||||
s1
|
||||
1
|
||||
2
|
||||
s1
|
||||
1
|
||||
2
|
||||
s1
|
||||
1
|
||||
2
|
||||
select sql_cache * from t1 where s1=1;
|
||||
s1
|
||||
1
|
||||
select sql_cache * from t1;
|
||||
s1
|
||||
1
|
||||
2
|
||||
call f1();
|
||||
s1
|
||||
1
|
||||
2
|
||||
s1
|
||||
1
|
||||
2
|
||||
s1
|
||||
1
|
||||
2
|
||||
call f3();
|
||||
s1
|
||||
1
|
||||
2
|
||||
s1
|
||||
1
|
||||
call f3();
|
||||
s1
|
||||
1
|
||||
2
|
||||
s1
|
||||
1
|
||||
call f1();
|
||||
s1
|
||||
1
|
||||
2
|
||||
s1
|
||||
1
|
||||
2
|
||||
s1
|
||||
1
|
||||
2
|
||||
drop procedure f1;
|
||||
drop procedure f2;
|
||||
drop procedure f3;
|
||||
drop procedure f4;
|
||||
drop table t1;
|
||||
set GLOBAL query_cache_size=0;
|
||||
|
@ -692,6 +692,7 @@ END P1|
|
||||
call SP001();
|
||||
TEMP_SUM
|
||||
0
|
||||
ERROR 24000: Cursor is not open
|
||||
drop procedure SP001;
|
||||
drop table t1, t2;
|
||||
drop function if exists bug11394|
|
||||
|
@ -776,6 +776,7 @@ delimiter ;//
|
||||
|
||||
#
|
||||
# query in QC from normal execution and SP (BUG#6897)
|
||||
# improved to also test BUG#3583 and BUG#12990
|
||||
#
|
||||
flush query cache;
|
||||
reset query cache;
|
||||
@ -785,6 +786,22 @@ create table t1 (s1 int)//
|
||||
create procedure f1 () begin
|
||||
select sql_cache * from t1;
|
||||
select sql_cache * from t1;
|
||||
select sql_cache * from t1;
|
||||
end;//
|
||||
create procedure f2 () begin
|
||||
select sql_cache * from t1 where s1=1;
|
||||
select sql_cache * from t1;
|
||||
end;//
|
||||
create procedure f3 () begin
|
||||
select sql_cache * from t1;
|
||||
select sql_cache * from t1 where s1=1;
|
||||
end;//
|
||||
create procedure f4 () begin
|
||||
select sql_cache * from t1;
|
||||
select sql_cache * from t1 where s1=1;
|
||||
select sql_cache * from t1;
|
||||
select sql_cache * from t1 where s1=1;
|
||||
select sql_cache * from t1 where s1=1;
|
||||
end;//
|
||||
delimiter ;//
|
||||
call f1();
|
||||
@ -811,7 +828,32 @@ select sql_cache * from t1;
|
||||
show status like "Qcache_queries_in_cache";
|
||||
show status like "Qcache_inserts";
|
||||
show status like "Qcache_hits";
|
||||
flush query cache;
|
||||
reset query cache;
|
||||
flush status;
|
||||
select sql_cache * from t1;
|
||||
select sql_cache * from t1 where s1=1;
|
||||
call f1();
|
||||
call f2();
|
||||
call f3();
|
||||
call f4();
|
||||
call f4();
|
||||
call f3();
|
||||
call f2();
|
||||
select sql_cache * from t1 where s1=1;
|
||||
insert into t1 values (2);
|
||||
call f1();
|
||||
select sql_cache * from t1 where s1=1;
|
||||
select sql_cache * from t1;
|
||||
call f1();
|
||||
call f3();
|
||||
call f3();
|
||||
call f1();
|
||||
|
||||
drop procedure f1;
|
||||
drop procedure f2;
|
||||
drop procedure f3;
|
||||
drop procedure f4;
|
||||
drop table t1;
|
||||
set GLOBAL query_cache_size=0;
|
||||
|
||||
|
@ -991,6 +991,7 @@ P1: BEGIN
|
||||
SELECT 'end of proc';
|
||||
END P1|
|
||||
delimiter ;|
|
||||
--error 1326
|
||||
call SP001();
|
||||
drop procedure SP001;
|
||||
drop table t1, t2;
|
||||
@ -1187,7 +1188,30 @@ delimiter ;|
|
||||
create trigger bug12712
|
||||
before insert on t1 for each row set session autocommit = 0;
|
||||
|
||||
|
||||
#
|
||||
# BUG#9367: Stored procedures: client hang after "show warnings"
|
||||
#
|
||||
--disable_parsing
|
||||
--disable_warnings
|
||||
drop procedure if exists bug9367;
|
||||
--enable_warnings
|
||||
create table t1 (s1 int);
|
||||
select s1 from t1;
|
||||
delimiter |;
|
||||
create procedure bug9367()
|
||||
begin
|
||||
declare v int;
|
||||
declare c cursor for select s1 from t1;
|
||||
open c;
|
||||
show warnings;
|
||||
fetch c into v;
|
||||
select v;
|
||||
end|
|
||||
delimiter ;|
|
||||
call bug9367();
|
||||
drop procedure bug9367;
|
||||
drop table t1;
|
||||
--enable_parsing
|
||||
#
|
||||
# BUG#NNNN: New bug synopsis
|
||||
#
|
||||
|
@ -17,18 +17,22 @@
|
||||
/*
|
||||
Make sure to look at ha_tina.h for more details.
|
||||
|
||||
First off, this is a play thing for me, there are a number of things wrong with it:
|
||||
*) It was designed for csv and therefor its performance is highly questionable.
|
||||
*) Indexes have not been implemented. This is because the files can be traded in
|
||||
and out of the table directory without having to worry about rebuilding anything.
|
||||
*) NULLs and "" are treated equally (like a spreadsheet).
|
||||
*) There was in the beginning no point to anyone seeing this other then me, so there
|
||||
is a good chance that I haven't quite documented it well.
|
||||
*) Less design, more "make it work"
|
||||
First off, this is a play thing for me, there are a number of things
|
||||
wrong with it:
|
||||
*) It was designed for csv and therefore its performance is highly
|
||||
questionable.
|
||||
*) Indexes have not been implemented. This is because the files can
|
||||
be traded in and out of the table directory without having to worry
|
||||
about rebuilding anything.
|
||||
*) NULLs and "" are treated equally (like a spreadsheet).
|
||||
*) There was in the beginning no point to anyone seeing this other
|
||||
then me, so there is a good chance that I haven't quite documented
|
||||
it well.
|
||||
*) Less design, more "make it work"
|
||||
|
||||
Now there are a few cool things with it:
|
||||
*) Errors can result in corrupted data files.
|
||||
*) Data files can be read by spreadsheets directly.
|
||||
Now there are a few cool things with it:
|
||||
*) Errors can result in corrupted data files.
|
||||
*) Data files can be read by spreadsheets directly.
|
||||
|
||||
TODO:
|
||||
*) Move to a block system for larger files
|
||||
@ -78,7 +82,7 @@ static handlerton tina_hton= {
|
||||
** TINA tables
|
||||
*****************************************************************************/
|
||||
|
||||
/*
|
||||
/*
|
||||
Used for sorting chains.
|
||||
*/
|
||||
int sort_set (tina_set *a, tina_set *b)
|
||||
@ -106,7 +110,7 @@ int get_mmap(TINA_SHARE *share, int write)
|
||||
if (my_fstat(share->data_file, &share->file_stat, MYF(MY_WME)) == -1)
|
||||
DBUG_RETURN(1);
|
||||
|
||||
if (share->file_stat.st_size)
|
||||
if (share->file_stat.st_size)
|
||||
{
|
||||
if (write)
|
||||
share->mapped_file= (byte *)my_mmap(NULL, share->file_stat.st_size,
|
||||
@ -116,7 +120,7 @@ int get_mmap(TINA_SHARE *share, int write)
|
||||
share->mapped_file= (byte *)my_mmap(NULL, share->file_stat.st_size,
|
||||
PROT_READ, MAP_PRIVATE,
|
||||
share->data_file, 0);
|
||||
if ((share->mapped_file ==(caddr_t)-1))
|
||||
if ((share->mapped_file ==(caddr_t)-1))
|
||||
{
|
||||
/*
|
||||
Bad idea you think? See the problem is that nothing actually checks
|
||||
@ -129,7 +133,7 @@ int get_mmap(TINA_SHARE *share, int write)
|
||||
DBUG_RETURN(1);
|
||||
}
|
||||
}
|
||||
else
|
||||
else
|
||||
share->mapped_file= NULL;
|
||||
|
||||
DBUG_RETURN(0);
|
||||
@ -167,17 +171,18 @@ static TINA_SHARE *get_share(const char *table_name, TABLE *table)
|
||||
if (!my_multi_malloc(MYF(MY_WME | MY_ZEROFILL),
|
||||
&share, sizeof(*share),
|
||||
&tmp_name, length+1,
|
||||
NullS))
|
||||
NullS))
|
||||
{
|
||||
pthread_mutex_unlock(&tina_mutex);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
share->use_count=0;
|
||||
share->table_name_length=length;
|
||||
share->table_name=tmp_name;
|
||||
strmov(share->table_name,table_name);
|
||||
fn_format(data_file_name, table_name, "", ".CSV",MY_REPLACE_EXT|MY_UNPACK_FILENAME);
|
||||
share->use_count= 0;
|
||||
share->table_name_length= length;
|
||||
share->table_name= tmp_name;
|
||||
strmov(share->table_name, table_name);
|
||||
fn_format(data_file_name, table_name, "", ".CSV",
|
||||
MY_REPLACE_EXT|MY_UNPACK_FILENAME);
|
||||
if (my_hash_insert(&tina_open_tables, (byte*) share))
|
||||
goto error;
|
||||
thr_lock_init(&share->lock);
|
||||
@ -186,11 +191,14 @@ static TINA_SHARE *get_share(const char *table_name, TABLE *table)
|
||||
if ((share->data_file= my_open(data_file_name, O_RDWR, MYF(0))) == -1)
|
||||
goto error2;
|
||||
|
||||
/* We only use share->data_file for writing, so we scan to the end to append */
|
||||
/*
|
||||
We only use share->data_file for writing, so we scan to
|
||||
the end to append
|
||||
*/
|
||||
if (my_seek(share->data_file, 0, SEEK_END, MYF(0)) == MY_FILEPOS_ERROR)
|
||||
goto error2;
|
||||
|
||||
share->mapped_file= NULL; // We don't know the state since we just allocated it
|
||||
share->mapped_file= NULL; // We don't know the state as we just allocated it
|
||||
if (get_mmap(share, 0) > 0)
|
||||
goto error3;
|
||||
}
|
||||
@ -212,7 +220,7 @@ error:
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
/*
|
||||
Free lock controls.
|
||||
*/
|
||||
static int free_share(TINA_SHARE *share)
|
||||
@ -222,7 +230,7 @@ static int free_share(TINA_SHARE *share)
|
||||
int result_code= 0;
|
||||
if (!--share->use_count){
|
||||
/* Drop the mapped file */
|
||||
if (share->mapped_file)
|
||||
if (share->mapped_file)
|
||||
my_munmap(share->mapped_file, share->file_stat.st_size);
|
||||
result_code= my_close(share->data_file,MYF(0));
|
||||
hash_delete(&tina_open_tables, (byte*) share);
|
||||
@ -236,13 +244,13 @@ static int free_share(TINA_SHARE *share)
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
/*
|
||||
Finds the end of a line.
|
||||
Currently only supports files written on a UNIX OS.
|
||||
*/
|
||||
byte * find_eoln(byte *data, off_t begin, off_t end)
|
||||
byte * find_eoln(byte *data, off_t begin, off_t end)
|
||||
{
|
||||
for (off_t x= begin; x < end; x++)
|
||||
for (off_t x= begin; x < end; x++)
|
||||
if (data[x] == '\n')
|
||||
return data + x;
|
||||
|
||||
@ -256,7 +264,8 @@ ha_tina::ha_tina(TABLE *table_arg)
|
||||
These definitions are found in hanler.h
|
||||
These are not probably completely right.
|
||||
*/
|
||||
current_position(0), next_position(0), chain_alloced(0), chain_size(DEFAULT_CHAIN_LENGTH)
|
||||
current_position(0), next_position(0), chain_alloced(0),
|
||||
chain_size(DEFAULT_CHAIN_LENGTH)
|
||||
{
|
||||
/* Set our original buffers from pre-allocated memory */
|
||||
buffer.set(byte_buffer, IO_SIZE, system_charset_info);
|
||||
@ -266,7 +275,7 @@ ha_tina::ha_tina(TABLE *table_arg)
|
||||
/*
|
||||
Encode a buffer into the quoted format.
|
||||
*/
|
||||
int ha_tina::encode_quote(byte *buf)
|
||||
int ha_tina::encode_quote(byte *buf)
|
||||
{
|
||||
char attribute_buffer[1024];
|
||||
String attribute(attribute_buffer, sizeof(attribute_buffer), &my_charset_bin);
|
||||
@ -324,13 +333,15 @@ int ha_tina::encode_quote(byte *buf)
|
||||
}
|
||||
|
||||
/*
|
||||
chain_append() adds delete positions to the chain that we use to keep track of space.
|
||||
chain_append() adds delete positions to the chain that we use to keep
|
||||
track of space. Then the chain will be used to cleanup "holes", occured
|
||||
due to deletes and updates.
|
||||
*/
|
||||
int ha_tina::chain_append()
|
||||
{
|
||||
if ( chain_ptr != chain && (chain_ptr -1)->end == current_position)
|
||||
(chain_ptr -1)->end= next_position;
|
||||
else
|
||||
else
|
||||
{
|
||||
/* We set up for the next position */
|
||||
if ((off_t)(chain_ptr - chain) == (chain_size -1))
|
||||
@ -340,12 +351,14 @@ int ha_tina::chain_append()
|
||||
if (chain_alloced)
|
||||
{
|
||||
/* Must cast since my_malloc unlike malloc doesn't have a void ptr */
|
||||
if ((chain= (tina_set *)my_realloc((gptr)chain,chain_size,MYF(MY_WME))) == NULL)
|
||||
if ((chain= (tina_set *) my_realloc((gptr)chain,
|
||||
chain_size, MYF(MY_WME))) == NULL)
|
||||
return -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
tina_set *ptr= (tina_set *)my_malloc(chain_size * sizeof(tina_set),MYF(MY_WME));
|
||||
tina_set *ptr= (tina_set *) my_malloc(chain_size * sizeof(tina_set),
|
||||
MYF(MY_WME));
|
||||
memcpy(ptr, chain, DEFAULT_CHAIN_LENGTH * sizeof(tina_set));
|
||||
chain= ptr;
|
||||
chain_alloced++;
|
||||
@ -361,7 +374,7 @@ int ha_tina::chain_append()
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
/*
|
||||
Scans for a row.
|
||||
*/
|
||||
int ha_tina::find_current_row(byte *buf)
|
||||
@ -371,7 +384,8 @@ int ha_tina::find_current_row(byte *buf)
|
||||
DBUG_ENTER("ha_tina::find_current_row");
|
||||
|
||||
/* EOF should be counted as new line */
|
||||
if ((end_ptr= find_eoln(share->mapped_file, current_position, share->file_stat.st_size)) == 0)
|
||||
if ((end_ptr= find_eoln(share->mapped_file, current_position,
|
||||
share->file_stat.st_size)) == 0)
|
||||
DBUG_RETURN(HA_ERR_END_OF_FILE);
|
||||
|
||||
for (Field **field=table->field ; *field ; field++)
|
||||
@ -380,14 +394,15 @@ int ha_tina::find_current_row(byte *buf)
|
||||
mapped_ptr++; // Increment past the first quote
|
||||
for(;mapped_ptr != end_ptr; mapped_ptr++)
|
||||
{
|
||||
//Need to convert line feeds!
|
||||
if (*mapped_ptr == '"' &&
|
||||
(((mapped_ptr[1] == ',') && (mapped_ptr[2] == '"')) || (mapped_ptr == end_ptr -1 )))
|
||||
// Need to convert line feeds!
|
||||
if (*mapped_ptr == '"' &&
|
||||
(((mapped_ptr[1] == ',') && (mapped_ptr[2] == '"')) ||
|
||||
(mapped_ptr == end_ptr -1 )))
|
||||
{
|
||||
mapped_ptr += 2; // Move past the , and the "
|
||||
break;
|
||||
}
|
||||
if (*mapped_ptr == '\\' && mapped_ptr != (end_ptr - 1))
|
||||
}
|
||||
if (*mapped_ptr == '\\' && mapped_ptr != (end_ptr - 1))
|
||||
{
|
||||
mapped_ptr++;
|
||||
if (*mapped_ptr == 'r')
|
||||
@ -401,7 +416,7 @@ int ha_tina::find_current_row(byte *buf)
|
||||
buffer.append('\\');
|
||||
buffer.append(*mapped_ptr);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
buffer.append(*mapped_ptr);
|
||||
}
|
||||
@ -429,7 +444,7 @@ const char **ha_tina::bas_ext() const
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
/*
|
||||
Open a database file. Keep in mind that tables are caches, so
|
||||
this will not be called for every request. Any sort of positions
|
||||
that need to be reset should be kept in the ::extra() call.
|
||||
@ -457,7 +472,7 @@ int ha_tina::close(void)
|
||||
DBUG_RETURN(free_share(share));
|
||||
}
|
||||
|
||||
/*
|
||||
/*
|
||||
This is an INSERT. At the moment this handler just seeks to the end
|
||||
of the file and appends the data. In an error case it really should
|
||||
just truncate to the original position (this is not done yet).
|
||||
@ -477,22 +492,22 @@ int ha_tina::write_row(byte * buf)
|
||||
if (my_write(share->data_file, buffer.ptr(), size, MYF(MY_WME | MY_NABP)))
|
||||
DBUG_RETURN(-1);
|
||||
|
||||
/*
|
||||
Ok, this is means that we will be doing potentially bad things
|
||||
/*
|
||||
Ok, this is means that we will be doing potentially bad things
|
||||
during a bulk insert on some OS'es. What we need is a cleanup
|
||||
call for ::write_row that would let us fix up everything after the bulk
|
||||
insert. The archive handler does this with an extra mutx call, which
|
||||
might be a solution for this.
|
||||
*/
|
||||
if (get_mmap(share, 0) > 0)
|
||||
if (get_mmap(share, 0) > 0)
|
||||
DBUG_RETURN(-1);
|
||||
DBUG_RETURN(0);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
/*
|
||||
This is called for an update.
|
||||
Make sure you put in code to increment the auto increment, also
|
||||
Make sure you put in code to increment the auto increment, also
|
||||
update any timestamp data. Currently auto increment is not being
|
||||
fixed since autoincrements have yet to be added to this table handler.
|
||||
This will be called in a table scan right before the previous ::rnd_next()
|
||||
@ -520,18 +535,20 @@ int ha_tina::update_row(const byte * old_data, byte * new_data)
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Deletes a row. First the database will find the row, and then call this method.
|
||||
In the case of a table scan, the previous call to this will be the ::rnd_next()
|
||||
that found this row.
|
||||
The exception to this is an ORDER BY. This will cause the table handler to walk
|
||||
the table noting the positions of all rows that match a query. The table will
|
||||
then be deleted/positioned based on the ORDER (so RANDOM, DESC, ASC).
|
||||
/*
|
||||
Deletes a row. First the database will find the row, and then call this
|
||||
method. In the case of a table scan, the previous call to this will be
|
||||
the ::rnd_next() that found this row.
|
||||
The exception to this is an ORDER BY. This will cause the table handler
|
||||
to walk the table noting the positions of all rows that match a query.
|
||||
The table will then be deleted/positioned based on the ORDER (so RANDOM,
|
||||
DESC, ASC).
|
||||
*/
|
||||
int ha_tina::delete_row(const byte * buf)
|
||||
{
|
||||
DBUG_ENTER("ha_tina::delete_row");
|
||||
statistic_increment(table->in_use->status_var.ha_delete_count,&LOCK_status);
|
||||
statistic_increment(table->in_use->status_var.ha_delete_count,
|
||||
&LOCK_status);
|
||||
|
||||
if (chain_append())
|
||||
DBUG_RETURN(-1);
|
||||
@ -542,7 +559,7 @@ int ha_tina::delete_row(const byte * buf)
|
||||
}
|
||||
|
||||
/*
|
||||
Fill buf with value from key. Simply this is used for a single index read
|
||||
Fill buf with value from key. Simply this is used for a single index read
|
||||
with a key.
|
||||
*/
|
||||
int ha_tina::index_read(byte * buf, const byte * key,
|
||||
@ -556,7 +573,7 @@ int ha_tina::index_read(byte * buf, const byte * key,
|
||||
}
|
||||
|
||||
/*
|
||||
Fill buf with value from key. Simply this is used for a single index read
|
||||
Fill buf with value from key. Simply this is used for a single index read
|
||||
with a key.
|
||||
Whatever the current key is we will use it. This is what will be in "index".
|
||||
*/
|
||||
@ -613,8 +630,8 @@ int ha_tina::index_last(byte * buf)
|
||||
DBUG_RETURN(HA_ADMIN_NOT_IMPLEMENTED);
|
||||
}
|
||||
|
||||
/*
|
||||
All table scans call this first.
|
||||
/*
|
||||
All table scans call this first.
|
||||
The order of a table scan is:
|
||||
|
||||
ha_tina::store_lock
|
||||
@ -638,8 +655,8 @@ int ha_tina::index_last(byte * buf)
|
||||
ha_tina::extra
|
||||
ENUM HA_EXTRA_RESET Reset database to after open
|
||||
|
||||
Each call to ::rnd_next() represents a row returned in the can. When no more
|
||||
rows can be returned, rnd_next() returns a value of HA_ERR_END_OF_FILE.
|
||||
Each call to ::rnd_next() represents a row returned in the can. When no more
|
||||
rows can be returned, rnd_next() returns a value of HA_ERR_END_OF_FILE.
|
||||
The ::info() call is just for the optimizer.
|
||||
|
||||
*/
|
||||
@ -653,22 +670,26 @@ int ha_tina::rnd_init(bool scan)
|
||||
chain_ptr= chain;
|
||||
#ifdef HAVE_MADVISE
|
||||
if (scan)
|
||||
(void)madvise(share->mapped_file,share->file_stat.st_size,MADV_SEQUENTIAL);
|
||||
(void) madvise(share->mapped_file, share->file_stat.st_size,
|
||||
MADV_SEQUENTIAL);
|
||||
#endif
|
||||
|
||||
DBUG_RETURN(0);
|
||||
}
|
||||
|
||||
/*
|
||||
::rnd_next() does all the heavy lifting for a table scan. You will need to populate *buf
|
||||
with the correct field data. You can walk the field to determine at what position you
|
||||
should store the data (take a look at how ::find_current_row() works). The structure
|
||||
is something like:
|
||||
::rnd_next() does all the heavy lifting for a table scan. You will need to
|
||||
populate *buf with the correct field data. You can walk the field to
|
||||
determine at what position you should store the data (take a look at how
|
||||
::find_current_row() works). The structure is something like:
|
||||
0Foo Dog Friend
|
||||
The first offset is for the first attribute. All space before that is reserved for null count.
|
||||
Basically this works as a mask for which rows are nulled (compared to just empty).
|
||||
This table handler doesn't do nulls and does not know the difference between NULL and "". This
|
||||
is ok since this table handler is for spreadsheets and they don't know about them either :)
|
||||
The first offset is for the first attribute. All space before that is
|
||||
reserved for null count.
|
||||
Basically this works as a mask for which rows are nulled (compared to just
|
||||
empty).
|
||||
This table handler doesn't do nulls and does not know the difference between
|
||||
NULL and "". This is ok since this table handler is for spreadsheets and
|
||||
they don't know about them either :)
|
||||
*/
|
||||
int ha_tina::rnd_next(byte *buf)
|
||||
{
|
||||
@ -678,9 +699,9 @@ int ha_tina::rnd_next(byte *buf)
|
||||
&LOCK_status);
|
||||
|
||||
current_position= next_position;
|
||||
if (!share->mapped_file)
|
||||
if (!share->mapped_file)
|
||||
DBUG_RETURN(HA_ERR_END_OF_FILE);
|
||||
if (HA_ERR_END_OF_FILE == find_current_row(buf) )
|
||||
if (HA_ERR_END_OF_FILE == find_current_row(buf) )
|
||||
DBUG_RETURN(HA_ERR_END_OF_FILE);
|
||||
|
||||
records++;
|
||||
@ -689,11 +710,11 @@ int ha_tina::rnd_next(byte *buf)
|
||||
|
||||
/*
|
||||
In the case of an order by rows will need to be sorted.
|
||||
::position() is called after each call to ::rnd_next(),
|
||||
::position() is called after each call to ::rnd_next(),
|
||||
the data it stores is to a byte array. You can store this
|
||||
data via my_store_ptr(). ref_length is a variable defined to the
|
||||
class that is the sizeof() of position being stored. In our case
|
||||
its just a position. Look at the bdb code if you want to see a case
|
||||
data via my_store_ptr(). ref_length is a variable defined to the
|
||||
class that is the sizeof() of position being stored. In our case
|
||||
its just a position. Look at the bdb code if you want to see a case
|
||||
where something other then a number is stored.
|
||||
*/
|
||||
void ha_tina::position(const byte *record)
|
||||
@ -704,8 +725,8 @@ void ha_tina::position(const byte *record)
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Used to fetch a row from a posiion stored with ::position().
|
||||
/*
|
||||
Used to fetch a row from a posiion stored with ::position().
|
||||
my_get_ptr() retrieves the data for you.
|
||||
*/
|
||||
|
||||
@ -727,7 +748,7 @@ void ha_tina::info(uint flag)
|
||||
{
|
||||
DBUG_ENTER("ha_tina::info");
|
||||
/* This is a lie, but you don't want the optimizer to see zero or 1 */
|
||||
if (records < 2)
|
||||
if (records < 2)
|
||||
records= 2;
|
||||
DBUG_VOID_RETURN;
|
||||
}
|
||||
@ -743,7 +764,7 @@ int ha_tina::extra(enum ha_extra_function operation)
|
||||
DBUG_RETURN(0);
|
||||
}
|
||||
|
||||
/*
|
||||
/*
|
||||
This is no longer used.
|
||||
*/
|
||||
int ha_tina::reset(void)
|
||||
@ -755,8 +776,10 @@ int ha_tina::reset(void)
|
||||
|
||||
|
||||
/*
|
||||
Called after deletes, inserts, and updates. This is where we clean up all of
|
||||
the dead space we have collected while writing the file.
|
||||
Called after each table scan. In particular after deletes,
|
||||
and updates. In the last case we employ chain of deleted
|
||||
slots to clean up all of the dead space we have collected while
|
||||
performing deletes/updates.
|
||||
*/
|
||||
int ha_tina::rnd_end()
|
||||
{
|
||||
@ -768,11 +791,11 @@ int ha_tina::rnd_end()
|
||||
tina_set *ptr;
|
||||
off_t length;
|
||||
|
||||
/*
|
||||
/*
|
||||
Setting up writable map, this will contain all of the data after the
|
||||
get_mmap call that we have added to the file.
|
||||
*/
|
||||
if (get_mmap(share, 1) > 0)
|
||||
if (get_mmap(share, 1) > 0)
|
||||
DBUG_RETURN(-1);
|
||||
length= share->file_stat.st_size;
|
||||
|
||||
@ -781,7 +804,8 @@ int ha_tina::rnd_end()
|
||||
It also sorts so that we move the final blocks to the
|
||||
beginning so that we move the smallest amount of data possible.
|
||||
*/
|
||||
qsort(chain, (size_t)(chain_ptr - chain), sizeof(tina_set), (qsort_cmp)sort_set);
|
||||
qsort(chain, (size_t)(chain_ptr - chain), sizeof(tina_set),
|
||||
(qsort_cmp)sort_set);
|
||||
for (ptr= chain; ptr < chain_ptr; ptr++)
|
||||
{
|
||||
/* We peek a head to see if this is the last chain */
|
||||
@ -789,7 +813,8 @@ int ha_tina::rnd_end()
|
||||
memmove(share->mapped_file + ptr->begin, share->mapped_file + ptr->end,
|
||||
length - (size_t)ptr->end);
|
||||
else
|
||||
memmove((caddr_t)share->mapped_file + ptr->begin, (caddr_t)share->mapped_file + ptr->end,
|
||||
memmove((caddr_t)share->mapped_file + ptr->begin,
|
||||
(caddr_t)share->mapped_file + ptr->end,
|
||||
(size_t)((ptr++)->begin - ptr->end));
|
||||
length= length - (size_t)(ptr->end - ptr->begin);
|
||||
}
|
||||
@ -803,15 +828,15 @@ int ha_tina::rnd_end()
|
||||
|
||||
/* We set it to null so that get_mmap() won't try to unmap it */
|
||||
share->mapped_file= NULL;
|
||||
if (get_mmap(share, 0) > 0)
|
||||
if (get_mmap(share, 0) > 0)
|
||||
DBUG_RETURN(-1);
|
||||
}
|
||||
|
||||
DBUG_RETURN(0);
|
||||
}
|
||||
|
||||
/*
|
||||
Truncate table and others of its ilk call this.
|
||||
/*
|
||||
Truncate table and others of its ilk call this.
|
||||
*/
|
||||
int ha_tina::delete_all_rows()
|
||||
{
|
||||
@ -819,7 +844,7 @@ int ha_tina::delete_all_rows()
|
||||
|
||||
int rc= my_chsize(share->data_file, 0, 0, MYF(MY_WME));
|
||||
|
||||
if (get_mmap(share, 0) > 0)
|
||||
if (get_mmap(share, 0) > 0)
|
||||
DBUG_RETURN(-1);
|
||||
|
||||
DBUG_RETURN(rc);
|
||||
@ -834,7 +859,7 @@ int ha_tina::external_lock(THD *thd, int lock_type)
|
||||
DBUG_RETURN(0); // No external locking
|
||||
}
|
||||
|
||||
/*
|
||||
/*
|
||||
Called by the database to lock the table. Keep in mind that this
|
||||
is an internal lock.
|
||||
*/
|
||||
@ -848,33 +873,32 @@ THR_LOCK_DATA **ha_tina::store_lock(THD *thd,
|
||||
return to;
|
||||
}
|
||||
|
||||
/*
|
||||
/*
|
||||
Range optimizer calls this.
|
||||
I need to update the information on this.
|
||||
*/
|
||||
ha_rows ha_tina::records_in_range(int inx,
|
||||
const byte *start_key,uint start_key_len,
|
||||
enum ha_rkey_function start_search_flag,
|
||||
const byte *end_key,uint end_key_len,
|
||||
enum ha_rkey_function end_search_flag)
|
||||
ha_rows ha_tina::records_in_range(uint inx, key_range *min_key,
|
||||
key_range *max_key)
|
||||
{
|
||||
DBUG_ENTER("ha_tina::records_in_range ");
|
||||
DBUG_RETURN(records); // Good guess
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
/*
|
||||
Create a table. You do not want to leave the table open after a call to
|
||||
this (the database will call ::open() if it needs to).
|
||||
*/
|
||||
|
||||
int ha_tina::create(const char *name, TABLE *table_arg, HA_CREATE_INFO *create_info)
|
||||
int ha_tina::create(const char *name, TABLE *table_arg,
|
||||
HA_CREATE_INFO *create_info)
|
||||
{
|
||||
char name_buff[FN_REFLEN];
|
||||
File create_file;
|
||||
DBUG_ENTER("ha_tina::create");
|
||||
|
||||
if ((create_file= my_create(fn_format(name_buff,name,"",".CSV",MY_REPLACE_EXT|MY_UNPACK_FILENAME),0,
|
||||
if ((create_file= my_create(fn_format(name_buff, name, "", ".CSV",
|
||||
MY_REPLACE_EXT|MY_UNPACK_FILENAME),0,
|
||||
O_RDWR | O_TRUNC,MYF(MY_WME))) < 0)
|
||||
DBUG_RETURN(-1);
|
||||
|
||||
|
@ -43,6 +43,11 @@ class ha_tina: public handler
|
||||
off_t next_position; /* Next position in the file scan */
|
||||
byte byte_buffer[IO_SIZE];
|
||||
String buffer;
|
||||
/*
|
||||
The chain contains "holes" in the file, occured because of
|
||||
deletes/updates. It is used in rnd_end() to get rid of them
|
||||
in the end of the query.
|
||||
*/
|
||||
tina_set chain_buffer[DEFAULT_CHAIN_LENGTH];
|
||||
tina_set *chain;
|
||||
tina_set *chain_ptr;
|
||||
@ -78,7 +83,11 @@ public:
|
||||
*/
|
||||
virtual double scan_time() { return (double) (records+deleted) / 20.0+10; }
|
||||
/* The next method will never be called */
|
||||
virtual double read_time(ha_rows rows) { DBUG_ASSERT(0); return((double) rows / 20.0+1); }
|
||||
virtual double read_time(uint index, uint ranges, ha_rows rows)
|
||||
{
|
||||
DBUG_ASSERT(0);
|
||||
return((double) rows / 20.0+1);
|
||||
}
|
||||
virtual bool fast_key_read() { return 1;}
|
||||
/*
|
||||
TODO: return actual upper bound of number of records in the table.
|
||||
@ -110,10 +119,8 @@ public:
|
||||
int reset(void);
|
||||
int external_lock(THD *thd, int lock_type);
|
||||
int delete_all_rows(void);
|
||||
ha_rows records_in_range(int inx, const byte *start_key,uint start_key_len,
|
||||
enum ha_rkey_function start_search_flag,
|
||||
const byte *end_key,uint end_key_len,
|
||||
enum ha_rkey_function end_search_flag);
|
||||
ha_rows records_in_range(uint inx, key_range *min_key,
|
||||
key_range *max_key);
|
||||
// int delete_table(const char *from);
|
||||
// int rename_table(const char * from, const char * to);
|
||||
int create(const char *name, TABLE *form, HA_CREATE_INFO *create_info);
|
||||
|
@ -544,6 +544,7 @@ struct Query_cache_query_flags
|
||||
unsigned int client_long_flag:1;
|
||||
unsigned int client_protocol_41:1;
|
||||
unsigned int more_results_exists:1;
|
||||
unsigned int pkt_nr;
|
||||
uint character_set_client_num;
|
||||
uint character_set_results_num;
|
||||
uint collation_connection_num;
|
||||
|
@ -801,6 +801,7 @@ void Query_cache::store_query(THD *thd, TABLE_LIST *tables_used)
|
||||
CLIENT_PROTOCOL_41);
|
||||
flags.more_results_exists= test(thd->server_status &
|
||||
SERVER_MORE_RESULTS_EXISTS);
|
||||
flags.pkt_nr= net->pkt_nr;
|
||||
flags.character_set_client_num=
|
||||
thd->variables.character_set_client->number;
|
||||
flags.character_set_results_num=
|
||||
@ -814,12 +815,13 @@ void Query_cache::store_query(THD *thd, TABLE_LIST *tables_used)
|
||||
flags.sql_mode= thd->variables.sql_mode;
|
||||
flags.max_sort_length= thd->variables.max_sort_length;
|
||||
flags.group_concat_max_len= thd->variables.group_concat_max_len;
|
||||
DBUG_PRINT("qcache", ("long %d, 4.1: %d, more results %d, \
|
||||
DBUG_PRINT("qcache", ("long %d, 4.1: %d, more results %d, pkt_nr: %d, \
|
||||
CS client: %u, CS result: %u, CS conn: %u, limit: %lu, TZ: 0x%lx, \
|
||||
sql mode: 0x%lx, sort len: %lu, conncat len: %lu",
|
||||
(int)flags.client_long_flag,
|
||||
(int)flags.client_protocol_41,
|
||||
(int)flags.more_results_exists,
|
||||
flags.pkt_nr,
|
||||
flags.character_set_client_num,
|
||||
flags.character_set_results_num,
|
||||
flags.collation_connection_num,
|
||||
@ -1019,6 +1021,7 @@ Query_cache::send_result_to_client(THD *thd, char *sql, uint query_length)
|
||||
CLIENT_PROTOCOL_41);
|
||||
flags.more_results_exists= test(thd->server_status &
|
||||
SERVER_MORE_RESULTS_EXISTS);
|
||||
flags.pkt_nr= thd->net.pkt_nr;
|
||||
flags.character_set_client_num= thd->variables.character_set_client->number;
|
||||
flags.character_set_results_num=
|
||||
(thd->variables.character_set_results ?
|
||||
@ -1030,12 +1033,13 @@ Query_cache::send_result_to_client(THD *thd, char *sql, uint query_length)
|
||||
flags.sql_mode= thd->variables.sql_mode;
|
||||
flags.max_sort_length= thd->variables.max_sort_length;
|
||||
flags.group_concat_max_len= thd->variables.group_concat_max_len;
|
||||
DBUG_PRINT("qcache", ("long %d, 4.1: %d, more results %d, \
|
||||
DBUG_PRINT("qcache", ("long %d, 4.1: %d, more results %d, pkt_nr: %d, \
|
||||
CS client: %u, CS result: %u, CS conn: %u, limit: %lu, TZ: 0x%lx, \
|
||||
sql mode: 0x%lx, sort len: %lu, conncat len: %lu",
|
||||
(int)flags.client_long_flag,
|
||||
(int)flags.client_protocol_41,
|
||||
(int)flags.more_results_exists,
|
||||
flags.pkt_nr,
|
||||
flags.character_set_client_num,
|
||||
flags.character_set_results_num,
|
||||
flags.collation_connection_num,
|
||||
|
@ -440,7 +440,8 @@ bool mysql_create_db(THD *thd, char *db, HA_CREATE_INFO *create_info,
|
||||
push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_NOTE,
|
||||
ER_DB_CREATE_EXISTS, ER(ER_DB_CREATE_EXISTS), db);
|
||||
error= 0;
|
||||
send_ok(thd);
|
||||
if (!silent)
|
||||
send_ok(thd);
|
||||
goto exit;
|
||||
}
|
||||
else
|
||||
|
Loading…
x
Reference in New Issue
Block a user