Commit 290d97a2 authored by unknown's avatar unknown

Merge mysql.com:/home/jonas/src/mysql-5.0

into mysql.com:/home/jonas/src/mysql-5.0-ndb


ndb/include/ndbapi/Ndb.hpp:
  Auto merged
ndb/src/ndbapi/Ndb.cpp:
  Auto merged
sql/ha_ndbcluster.cc:
  Auto merged
sql/sql_parse.cc:
  Auto merged
parents db722822 408d069e
......@@ -434,7 +434,7 @@ d date YES NULL
e varchar(1) NO
f datetime YES NULL
g time YES NULL
h varbinary(23) NO
h longblob NO
dd time YES NULL
select * from t2;
a b c d e f g h dd
......
......@@ -464,3 +464,11 @@ SELECT DISTINCT html,SUM(rout)/(SUM(rin)+1) as 'prod' FROM t1 GROUP BY rin;
html prod
1 0.0000
drop table t1;
create table t1 (id int, dsc varchar(50));
insert into t1 values (1, "line number one"), (2, "line number two"), (3, "line number three");
select distinct id, IFNULL(dsc, '-') from t1;
id IFNULL(dsc, '-')
1 line number one
2 line number two
3 line number three
drop table t1;
......@@ -40,3 +40,22 @@ p u o
5 5 5
drop table t1;
drop table t2;
create table t1 (p int not null primary key, u int not null) engine=ndb;
insert into t1 values (1,1),(2,2),(3,3);
create table t2 as
select t1.*
from t1 as t1, t1 as t2, t1 as t3, t1 as t4, t1 as t5, t1 as t6, t1 as t7, t1 as t8
where t1.u = t2.u
and t2.u = t3.u
and t3.u = t4.u
and t4.u = t5.u
and t5.u = t6.u
and t6.u = t7.u
and t7.u = t8.u;
select * from t2 order by 1;
p u
1 1
2 2
3 3
drop table t1;
drop table t2;
......@@ -672,3 +672,17 @@ select default(t30.s1) from t30;
end|
drop procedure bug10969|
drop table t1|
prepare stmt from "select 1";
create procedure p() deallocate prepare stmt;
ERROR 0A000: DEALLOCATE is not allowed in stored procedures
create function f() returns int begin deallocate prepare stmt;
ERROR 0A000: DEALLOCATE is not allowed in stored procedures
create procedure p() prepare stmt from "select 1";
ERROR 0A000: PREPARE is not allowed in stored procedures
create function f() returns int begin prepare stmt from "select 1";
ERROR 0A000: PREPARE is not allowed in stored procedures
create procedure p() execute stmt;
ERROR 0A000: EXECUTE is not allowed in stored procedures
create function f() returns int begin execute stmt;
ERROR 0A000: EXECUTE is not allowed in stored procedures
deallocate prepare stmt;
......@@ -40,3 +40,18 @@ Id User Host db Command Time State Info
unlock tables;
drop procedure bug9486;
drop table t1, t2;
drop procedure if exists bug11158;
create procedure bug11158() delete t1 from t1, t2 where t1.id = t2.id;
create table t1 (id int, j int);
insert into t1 values (1, 1), (2, 2);
create table t2 (id int);
insert into t2 values (1);
call bug11158();
select * from t1;
id j
2 2
lock tables t2 read;
call bug11158();
unlock tables;
drop procedure bug11158;
drop table t1, t2;
......@@ -896,6 +896,8 @@ create table t1( d1 decimal(18) unsigned, d2 decimal(20) unsigned, d3 decimal (2
insert into t1 values(1,-1,-1);
ERROR 22003: Out of range value adjusted for column 'd2' at row 1
drop table t1;
set sql_mode='';
set @sav_dpi= @@div_precision_increment;
set @@div_precision_increment=15;
create table t1 (col1 int, col2 decimal(30,25), col3 numeric(30,25));
insert into t1 values (1,0.0123456789012345678912345,0.0123456789012345678912345);
......@@ -909,3 +911,12 @@ select 77777777/7777777;
77777777/7777777
10.000000900000090
drop table t1;
set div_precision_increment= @sav_dpi;
create table t1 (a decimal(4,2));
insert into t1 values (0.00);
select * from t1 where a > -0.00;
a
select * from t1 where a = -0.00;
a
0.00
drop table t1;
......@@ -332,3 +332,11 @@ CREATE TABLE t1 (
INSERT INTO t1 VALUES ('1',1,0);
SELECT DISTINCT html,SUM(rout)/(SUM(rin)+1) as 'prod' FROM t1 GROUP BY rin;
drop table t1;
#
# Bug 9784 DISTINCT IFNULL truncates data
#
create table t1 (id int, dsc varchar(50));
insert into t1 values (1, "line number one"), (2, "line number two"), (3, "line number three");
select distinct id, IFNULL(dsc, '-') from t1;
drop table t1;
......@@ -37,3 +37,26 @@ drop table t1;
drop table t2;
# bug#5367
##########
###
# bug#11205
create table t1 (p int not null primary key, u int not null) engine=ndb;
insert into t1 values (1,1),(2,2),(3,3);
create table t2 as
select t1.*
from t1 as t1, t1 as t2, t1 as t3, t1 as t4, t1 as t5, t1 as t6, t1 as t7, t1 as t8
where t1.u = t2.u
and t2.u = t3.u
and t3.u = t4.u
and t4.u = t5.u
and t5.u = t6.u
and t6.u = t7.u
and t7.u = t8.u;
select * from t2 order by 1;
drop table t1;
drop table t2;
......@@ -965,3 +965,24 @@ drop procedure bug10969|
drop table t1|
delimiter ;|
#
# Bug#10975, #10605, #7115: Dynamic SQL by means of
# PREPARE/EXECUTE/DEALLOCATE is not supported yet.
# Check that an error message is returned.
#
prepare stmt from "select 1";
--error ER_SP_BADSTATEMENT
create procedure p() deallocate prepare stmt;
--error ER_SP_BADSTATEMENT
create function f() returns int begin deallocate prepare stmt;
--error ER_SP_BADSTATEMENT
create procedure p() prepare stmt from "select 1";
--error ER_SP_BADSTATEMENT
create function f() returns int begin prepare stmt from "select 1";
--error ER_SP_BADSTATEMENT
create procedure p() execute stmt;
--error ER_SP_BADSTATEMENT
create function f() returns int begin execute stmt;
deallocate prepare stmt;
......@@ -84,6 +84,32 @@ reap;
drop procedure bug9486;
drop table t1, t2;
#
# BUG#11158: Can't perform multi-delete in stored procedure
#
--disable_warnings
drop procedure if exists bug11158;
--enable_warnings
create procedure bug11158() delete t1 from t1, t2 where t1.id = t2.id;
create table t1 (id int, j int);
insert into t1 values (1, 1), (2, 2);
create table t2 (id int);
insert into t2 values (1);
# Procedure should work and cause proper effect (delete only first row)
call bug11158();
select * from t1;
# Also let us test that we obtain only read (and thus non exclusive) lock
# for table from which we are not going to delete rows.
connection con2root;
lock tables t2 read;
connection con1root;
call bug11158();
connection con2root;
unlock tables;
connection con1root;
# Clean-up
drop procedure bug11158;
drop table t1, t2;
#
# BUG#NNNN: New bug synopsis
......
......@@ -934,10 +934,12 @@ create table t1( d1 decimal(18) unsigned, d2 decimal(20) unsigned, d3 decimal (2
--error 1264
insert into t1 values(1,-1,-1);
drop table t1;
set sql_mode='';
#
# Bug #8425 (insufficient precision of the division)
#
set @sav_dpi= @@div_precision_increment;
set @@div_precision_increment=15;
create table t1 (col1 int, col2 decimal(30,25), col3 numeric(30,25));
insert into t1 values (1,0.0123456789012345678912345,0.0123456789012345678912345);
......@@ -945,4 +947,13 @@ select col2/9999999999 from t1 where col1=1;
select 9999999999/col2 from t1 where col1=1;
select 77777777/7777777;
drop table t1;
set div_precision_increment= @sav_dpi;
#
# Bug #10896 (0.00 > -0.00)
#
create table t1 (a decimal(4,2));
insert into t1 values (0.00);
select * from t1 where a > -0.00;
select * from t1 where a = -0.00;
drop table t1;
......@@ -1616,7 +1616,7 @@ private:
Uint32 theNoOfPreparedTransactions;
Uint32 theNoOfSentTransactions;
Uint32 theNoOfCompletedTransactions;
Uint32 theNoOfAllocatedTransactions;
Uint32 theRemainingStartTransactions;
Uint32 theMaxNoOfTransactions;
Uint32 theMinNoOfEventsToWakeUp;
......
......@@ -425,12 +425,20 @@ Ndb::startTransactionLocal(Uint32 aPriority, Uint32 nodeId)
DBUG_ENTER("Ndb::startTransactionLocal");
DBUG_PRINT("enter", ("nodeid: %d", nodeId));
if(unlikely(theRemainingStartTransactions == 0))
{
theError.code = 4006;
DBUG_RETURN(0);
}
NdbTransaction* tConnection;
Uint64 tFirstTransId = theFirstTransId;
tConnection = doConnect(nodeId);
if (tConnection == NULL) {
DBUG_RETURN(NULL);
}//if
theRemainingStartTransactions--;
NdbTransaction* tConNext = theTransactionList;
tConnection->init();
theTransactionList = tConnection; // into a transaction list.
......@@ -481,6 +489,7 @@ Ndb::closeTransaction(NdbTransaction* aConnection)
CHECK_STATUS_MACRO_VOID;
tCon = theTransactionList;
theRemainingStartTransactions++;
DBUG_PRINT("info",("close trans: 0x%x transid: 0x%llx",
aConnection, aConnection->getTransactionId()));
......
......@@ -89,15 +89,18 @@ int
NdbScanOperation::init(const NdbTableImpl* tab, NdbTransaction* myConnection)
{
m_transConnection = myConnection;
//NdbTransaction* aScanConnection = theNdb->startTransaction(myConnection);
//NdbConnection* aScanConnection = theNdb->startTransaction(myConnection);
theNdb->theRemainingStartTransactions++; // will be checked in hupp...
NdbTransaction* aScanConnection = theNdb->hupp(myConnection);
if (!aScanConnection){
theNdb->theRemainingStartTransactions--;
setErrorCodeAbort(theNdb->getNdbError().code);
return -1;
}
// NOTE! The hupped trans becomes the owner of the operation
if(NdbOperation::init(tab, aScanConnection) != 0){
theNdb->theRemainingStartTransactions--;
return -1;
}
......@@ -675,6 +678,7 @@ void NdbScanOperation::close(bool forceSend, bool releaseOp)
tCon->theScanningOp = 0;
theNdb->closeTransaction(tCon);
theNdb->theRemainingStartTransactions--;
DBUG_VOID_RETURN;
}
......
......@@ -107,12 +107,10 @@ Ndb::init(int aMaxNoOfTransactions)
goto error_handler;
}
tMaxNoOfTransactions = aMaxNoOfTransactions * 3;
if (tMaxNoOfTransactions > 1024) {
tMaxNoOfTransactions = 1024;
}//if
theMaxNoOfTransactions = tMaxNoOfTransactions;
tMaxNoOfTransactions = aMaxNoOfTransactions;
theMaxNoOfTransactions = tMaxNoOfTransactions;
theRemainingStartTransactions= tMaxNoOfTransactions;
thePreparedTransactionsArray = new NdbTransaction* [tMaxNoOfTransactions];
theSentTransactionsArray = new NdbTransaction* [tMaxNoOfTransactions];
theCompletedTransactionsArray = new NdbTransaction* [tMaxNoOfTransactions];
......
......@@ -59,7 +59,7 @@ void Ndb::setup(Ndb_cluster_connection *ndb_cluster_connection,
theNoOfPreparedTransactions= 0;
theNoOfSentTransactions= 0;
theNoOfCompletedTransactions= 0;
theNoOfAllocatedTransactions= 0;
theRemainingStartTransactions= 0;
theMaxNoOfTransactions= 0;
theMinNoOfEventsToWakeUp= 0;
theConIdleList= NULL;
......
......@@ -93,7 +93,6 @@ Ndb::createConIdleList(int aNrOfCon)
}
tNdbCon->Status(NdbTransaction::NotConnected);
}
theNoOfAllocatedTransactions = aNrOfCon;
return aNrOfCon;
}
......@@ -193,16 +192,10 @@ Ndb::getNdbCon()
{
NdbTransaction* tNdbCon;
if ( theConIdleList == NULL ) {
if (theNoOfAllocatedTransactions < theMaxNoOfTransactions) {
tNdbCon = new NdbTransaction(this);
if (tNdbCon == NULL) {
return NULL;
}//if
theNoOfAllocatedTransactions++;
} else {
ndbout << "theNoOfAllocatedTransactions = " << theNoOfAllocatedTransactions << " theMaxNoOfTransactions = " << theMaxNoOfTransactions << endl;
return NULL;
}//if
tNdbCon->next(NULL);
} else
{
......
......@@ -1269,6 +1269,101 @@ int runBug_11133(NDBT_Context* ctx, NDBT_Step* step){
return result;
}
int runScan_4006(NDBT_Context* ctx, NDBT_Step* step){
int result = NDBT_OK;
const Uint32 max= 5;
const NdbDictionary::Table* pTab = ctx->getTab();
Ndb* pNdb = new Ndb(&ctx->m_cluster_connection, "TEST_DB");
if (pNdb == NULL){
ndbout << "pNdb == NULL" << endl;
return NDBT_FAILED;
}
if (pNdb->init(max)){
ERR(pNdb->getNdbError());
delete pNdb;
return NDBT_FAILED;
}
NdbConnection* pCon = pNdb->startTransaction();
if (pCon == NULL){
pNdb->closeTransaction(pCon);
delete pNdb;
return NDBT_FAILED;
}
Uint32 i;
Vector<NdbScanOperation*> scans;
for(i = 0; i<10*max; i++)
{
NdbScanOperation* pOp = pCon->getNdbScanOperation(pTab->getName());
if (pOp == NULL){
ERR(pCon->getNdbError());
pNdb->closeTransaction(pCon);
delete pNdb;
return NDBT_FAILED;
}
if (pOp->readTuples() != 0){
pNdb->closeTransaction(pCon);
ERR(pOp->getNdbError());
delete pNdb;
return NDBT_FAILED;
}
scans.push_back(pOp);
}
// Dont' call any equal or setValues
// Execute should not work
int check = pCon->execute(NoCommit);
if (check == 0){
ndbout << "execute worked" << endl;
} else {
ERR(pCon->getNdbError());
}
for(i= 0; i<scans.size(); i++)
{
NdbScanOperation* pOp= scans[i];
while((check= pOp->nextResult()) == 0);
if(check != 1)
{
ERR(pOp->getNdbError());
pNdb->closeTransaction(pCon);
delete pNdb;
return NDBT_FAILED;
}
}
pNdb->closeTransaction(pCon);
Vector<NdbConnection*> cons;
for(i= 0; i<10*max; i++)
{
pCon= pNdb->startTransaction();
if(pCon)
cons.push_back(pCon);
else
break;
}
for(i= 0; i<cons.size(); i++)
{
cons[i]->close();
}
if(cons.size() != max)
{
result= NDBT_FAILED;
}
delete pNdb;
return result;
}
template class Vector<NdbScanOperation*>;
NDBT_TESTSUITE(testNdbApi);
......@@ -1351,6 +1446,12 @@ TESTCASE("Bug_11133",
INITIALIZER(runBug_11133);
FINALIZER(runClearTable);
}
TESTCASE("Scan_4006",
"Check that getNdbScanOperation does not get 4006\n"){
INITIALIZER(runLoadTable);
INITIALIZER(runScan_4006);
FINALIZER(runClearTable);
}
NDBT_TESTSUITE_END(testNdbApi);
int main(int argc, const char** argv){
......
......@@ -520,6 +520,10 @@ max-time: 500
cmd: testNdbApi
args: -n Bug_11133 T1
max-time: 500
cmd: testNdbApi
args: -n Scan_4006 T1
#max-time: 500
#cmd: testInterpreter
#args: T1
......
......@@ -13,7 +13,7 @@ save_args=$*
VERSION="ndb-autotest.sh version 1.04"
DATE=`date '+%Y-%m-%d'`
HOST=`hostname -s`
HOST=`hostname`
export DATE HOST
set -e
......@@ -330,8 +330,11 @@ start(){
tar cfz /tmp/res.$2.$$.tgz `basename $p2`/$DATE
scp /tmp/res.$2.$$.tgz \
$result_host:$result_path/res.$DATE.$HOST.$2.$$.tgz
if [ $? -eq 0 ]
then
rm -f /tmp/res.$2.$$.tgz
fi
fi
}
#########################################
......
......@@ -41,7 +41,7 @@ static const int parallelism= 0;
// Default value for max number of transactions
// createable against NDB from this handler
static const int max_transactions= 256;
static const int max_transactions= 2;
static const char *ha_ndb_ext=".ndb";
......
......@@ -1109,12 +1109,14 @@ void Item_func_between::print(String *str)
void
Item_func_ifnull::fix_length_and_dec()
{
agg_result_type(&hybrid_type, args, 2);
maybe_null=args[1]->maybe_null;
decimals= max(args[0]->decimals, args[1]->decimals);
max_length= (max(args[0]->max_length - args[0]->decimals,
args[1]->max_length - args[1]->decimals) +
decimals);
agg_result_type(&hybrid_type, args, 2);
max_length= (hybrid_type == DECIMAL_RESULT || hybrid_type == INT_RESULT) ?
(max(args[0]->max_length - args[0]->decimals,
args[1]->max_length - args[1]->decimals) + decimals) :
max(args[0]->max_length, args[1]->max_length);
switch (hybrid_type) {
case STRING_RESULT:
agg_arg_charsets(collation, args, arg_count, MY_COLL_CMP_CONV);
......@@ -1225,16 +1227,7 @@ Item_func_if::fix_length_and_dec()
{
maybe_null=args[1]->maybe_null || args[2]->maybe_null;
decimals= max(args[1]->decimals, args[2]->decimals);
if (decimals == NOT_FIXED_DEC)
{
max_length= max(args[1]->max_length, args[2]->max_length);
}
else
{
max_length= (max(args[1]->max_length - args[1]->decimals,
args[2]->max_length - args[2]->decimals) +
decimals);
}
enum Item_result arg1_type=args[1]->result_type();
enum Item_result arg2_type=args[2]->result_type();
bool null1=args[1]->const_item() && args[1]->null_value;
......@@ -1263,6 +1256,11 @@ Item_func_if::fix_length_and_dec()
collation.set(&my_charset_bin); // Number
}
}
max_length=
(cached_result_type == DECIMAL_RESULT || cached_result_type == INT_RESULT) ?
(max(args[1]->max_length - args[1]->decimals,
args[2]->max_length - args[2]->decimals) + decimals) :
max(args[1]->max_length, args[2]->max_length);
}
......
......@@ -290,6 +290,11 @@ int int2my_decimal(uint mask, longlong i, my_bool unsigned_flag, my_decimal *d)
inline
void my_decimal_neg(decimal_t *arg)
{
if (decimal_is_zero(arg))
{
arg->sign= 0;
return;
}
decimal_neg(arg);
}
......
......@@ -482,7 +482,7 @@ bool check_merge_table_access(THD *thd, char *db,
TABLE_LIST *table_list);
bool check_some_routine_access(THD *thd, const char *db, const char *name, bool is_proc);
bool multi_update_precheck(THD *thd, TABLE_LIST *tables);
bool multi_delete_precheck(THD *thd, TABLE_LIST *tables, uint *table_count);
bool multi_delete_precheck(THD *thd, TABLE_LIST *tables);
bool mysql_multi_update_prepare(THD *thd);
bool mysql_multi_delete_prepare(THD *thd);
bool mysql_insert_select_prepare(THD *thd);
......@@ -577,6 +577,7 @@ void mysql_init_query(THD *thd, uchar *buf, uint length);
bool mysql_new_select(LEX *lex, bool move_down);
void create_select_for_variable(const char *var_name);
void mysql_init_multi_delete(LEX *lex);
bool multi_delete_set_locks_and_link_aux_tables(LEX *lex);
void init_max_user_conn(void);
void init_update_queries(void);
void free_max_user_conn(void);
......
......@@ -42,7 +42,6 @@ static my_bool open_new_frm(const char *path, const char *alias,
uint db_stat, uint prgflag,
uint ha_open_flags, TABLE *outparam,
TABLE_LIST *table_desc, MEM_ROOT *mem_root);
static void relink_tables_for_multidelete(THD *thd);
extern "C" byte *table_cache_key(const byte *record,uint *length,
my_bool not_used __attribute__((unused)))
......@@ -2089,7 +2088,6 @@ bool open_and_lock_tables(THD *thd, TABLE_LIST *tables)
(thd->fill_derived_tables() &&
mysql_handle_derived(thd->lex, &mysql_derived_filling)))
DBUG_RETURN(TRUE); /* purecov: inspected */
relink_tables_for_multidelete(thd);
DBUG_RETURN(0);
}
......@@ -2119,36 +2117,10 @@ bool open_normal_and_derived_tables(THD *thd, TABLE_LIST *tables)
if (open_tables(thd, &tables, &counter) ||
mysql_handle_derived(thd->lex, &mysql_derived_prepare))
DBUG_RETURN(TRUE); /* purecov: inspected */
relink_tables_for_multidelete(thd); // Not really needed, but
DBUG_RETURN(0);
}
/*
Let us propagate pointers to open tables from global table list
to table lists for multi-delete
*/
static void relink_tables_for_multidelete(THD *thd)
{
if (thd->lex->all_selects_list->next_select_in_list())
{
for (SELECT_LEX *sl= thd->lex->all_selects_list;
sl;
sl= sl->next_select_in_list())
{
for (TABLE_LIST *cursor= (TABLE_LIST *) sl->table_list.first;
cursor;
cursor=cursor->next_local)
{
if (cursor->correspondent_table)
cursor->table= cursor->correspondent_table->table;
}
}
}
}
/*
Mark all real tables in the list as free for reuse.
......
......@@ -751,7 +751,12 @@ typedef struct st_lex
uint grant, grant_tot_col, which_columns;
uint fk_delete_opt, fk_update_opt, fk_match_option;
uint slave_thd_opt, start_transaction_opt;
uint table_count; /* used when usual update transformed in multiupdate */
/*
In LEX representing update which were transformed to multi-update
stores total number of tables. For LEX representing multi-delete
holds number of tables from which we will delete records.
*/
uint table_count;
uint8 describe;
uint8 derived_tables;
uint8 create_view_algorithm;
......
......@@ -3291,10 +3291,9 @@ mysql_execute_command(THD *thd)
DBUG_ASSERT(first_table == all_tables && first_table != 0);
TABLE_LIST *aux_tables=
(TABLE_LIST *)thd->lex->auxilliary_table_list.first;
uint table_count;
multi_delete *result;
if ((res= multi_delete_precheck(thd, all_tables, &table_count)))
if ((res= multi_delete_precheck(thd, all_tables)))
break;
/* condition will be TRUE on SP re-excuting */
......@@ -3311,7 +3310,7 @@ mysql_execute_command(THD *thd)
goto error;
if (!thd->is_fatal_error && (result= new multi_delete(thd,aux_tables,
table_count)))
lex->table_count)))
{
res= mysql_select(thd, &select_lex->ref_pointer_array,
select_lex->get_table_list(),
......@@ -6801,23 +6800,19 @@ bool multi_update_precheck(THD *thd, TABLE_LIST *tables)
multi_delete_precheck()
thd Thread handler
tables Global/local table list
table_count Pointer to table counter
RETURN VALUE
FALSE OK
TRUE error
*/
bool multi_delete_precheck(THD *thd, TABLE_LIST *tables, uint *table_count)
bool multi_delete_precheck(THD *thd, TABLE_LIST *tables)
{
SELECT_LEX *select_lex= &thd->lex->select_lex;
TABLE_LIST *aux_tables=
(TABLE_LIST *)thd->lex->auxilliary_table_list.first;
TABLE_LIST *target_tbl;
DBUG_ENTER("multi_delete_precheck");
*table_count= 0;
/* sql_yacc guarantees that tables and aux_tables are not zero */
DBUG_ASSERT(aux_tables != 0);
if (check_db_used(thd, tables) || check_db_used(thd,aux_tables) ||
......@@ -6830,9 +6825,35 @@ bool multi_delete_precheck(THD *thd, TABLE_LIST *tables, uint *table_count)
ER(ER_UPDATE_WITHOUT_KEY_IN_SAFE_MODE), MYF(0));
DBUG_RETURN(TRUE);
}
for (target_tbl= aux_tables; target_tbl; target_tbl= target_tbl->next_local)
DBUG_RETURN(FALSE);
}
/*
Link tables in auxilary table list of multi-delete with corresponding
elements in main table list, and set proper locks for them.
SYNOPSIS
multi_delete_set_locks_and_link_aux_tables()
lex - pointer to LEX representing multi-delete
RETURN VALUE
FALSE - success
TRUE - error
*/
bool multi_delete_set_locks_and_link_aux_tables(LEX *lex)
{
TABLE_LIST *tables= (TABLE_LIST*)lex->select_lex.table_list.first;
TABLE_LIST *target_tbl;
DBUG_ENTER("multi_delete_set_locks_and_link_aux_tables");
lex->table_count= 0;
for (target_tbl= (TABLE_LIST *)lex->auxilliary_table_list.first;
target_tbl; target_tbl= target_tbl->next_local)
{
(*table_count)++;
lex->table_count++;
/* All tables in aux_tables must be found in FROM PART */
TABLE_LIST *walk;
for (walk= tables; walk; walk= walk->next_local)
......@@ -6850,14 +6871,6 @@ bool multi_delete_precheck(THD *thd, TABLE_LIST *tables, uint *table_count)
}
walk->lock_type= target_tbl->lock_type;
target_tbl->correspondent_table= walk; // Remember corresponding table
/* in case of subselects, we need to set lock_type in
* corresponding table in list of all tables */
if (walk->correspondent_table)
{
target_tbl->correspondent_table= walk->correspondent_table;
walk->correspondent_table->lock_type= walk->lock_type;
}
}
DBUG_RETURN(FALSE);
}
......
......@@ -889,8 +889,8 @@ static bool insert_params_from_vars_with_log(Prepared_statement *stmt,
tables global/local table list
RETURN VALUE
FALSE OK
TRUE error
FALSE success
TRUE error, error message is set in THD
*/
static bool mysql_test_insert(Prepared_statement *stmt,
......@@ -905,11 +905,10 @@ static bool mysql_test_insert(Prepared_statement *stmt,
LEX *lex= stmt->lex;
List_iterator_fast<List_item> its(values_list);
List_item *values;
bool res;
DBUG_ENTER("mysql_test_insert");
if ((res= insert_precheck(thd, table_list)))
DBUG_RETURN(res);
if (insert_precheck(thd, table_list))
goto error;
/*
open temporary memory pool for temporary data allocated by derived
......@@ -920,10 +919,7 @@ static bool mysql_test_insert(Prepared_statement *stmt,
TL_WRITE_DELAYED as having two such locks can cause table corruption.
*/
if (open_normal_and_derived_tables(thd, table_list))
{
DBUG_RETURN(TRUE);
}
goto error;
if ((values= its++))
{
......@@ -937,17 +933,14 @@ static bool mysql_test_insert(Prepared_statement *stmt,
table_list->table->insert_values=(byte *)1;
}
if ((res= mysql_prepare_insert(thd, table_list, table_list->table,
fields, values, update_fields,
update_values, duplic,
&unused_conds, FALSE)))
if (mysql_prepare_insert(thd, table_list, table_list->table, fields,
values, update_fields, update_values, duplic,
&unused_conds, FALSE))
goto error;
value_count= values->elements;
its.rewind();
res= TRUE;
if (table_list->lock_type == TL_WRITE_DELAYED &&
!(table_list->table->file->table_flags() & HA_CAN_INSERT_DELAYED))
{
......@@ -968,12 +961,11 @@ static bool mysql_test_insert(Prepared_statement *stmt,
goto error;
}
}
DBUG_RETURN(FALSE);
res= FALSE;
error:
lex->unit.cleanup();
/* insert_values is cleared in open_table */
DBUG_RETURN(res);
DBUG_RETURN(TRUE);
}
......@@ -987,9 +979,10 @@ static bool mysql_test_insert(Prepared_statement *stmt,
RETURN VALUE
0 success
1 error, error message is set in THD
2 convert to multi_update
1 error
*/
static int mysql_test_update(Prepared_statement *stmt,
TABLE_LIST *table_list)
{
......@@ -1003,10 +996,11 @@ static int mysql_test_update(Prepared_statement *stmt,
DBUG_ENTER("mysql_test_update");
if (update_precheck(thd, table_list))
DBUG_RETURN(1);
goto error;
if (open_tables(thd, &table_list, &table_count))
goto error;
if (!open_tables(thd, &table_list, &table_count))
{
if (table_list->multitable_view)
{
DBUG_ASSERT(table_list->view != 0);
......@@ -1014,58 +1008,48 @@ static int mysql_test_update(Prepared_statement *stmt,
/* pass counter value */
thd->lex->table_count= table_count;
/* convert to multiupdate */
return 2;
DBUG_RETURN(2);
}
/*
thd->fill_derived_tables() is false here for sure (because it is
preparation of PS, so we even do not check it
preparation of PS, so we even do not check it).
*/
if (lock_tables(thd, table_list, table_count) ||
mysql_handle_derived(thd->lex, &mysql_derived_prepare))
DBUG_RETURN(1);
goto error;
#ifndef NO_EMBEDDED_ACCESS_CHECKS
/* TABLE_LIST contain right privilages request */
want_privilege= table_list->grant.want_privilege;
#endif
if (!(res= mysql_prepare_update(thd, table_list,
&select->where,
if (mysql_prepare_update(thd, table_list, &select->where,
select->order_list.elements,
(ORDER *) select->order_list.first)))
{
(ORDER *) select->order_list.first))
goto error;
#ifndef NO_EMBEDDED_ACCESS_CHECKS
table_list->grant.want_privilege=
table_list->table->grant.want_privilege=
want_privilege;
table_list->grant.want_privilege= want_privilege;
table_list->table->grant.want_privilege= want_privilege;
#endif
thd->lex->select_lex.no_wrap_view_item= 1;
if (setup_fields(thd, 0, table_list, select->item_list, 1, 0, 0))
{
res= 1;
thd->lex->select_lex.no_wrap_view_item= 0;
}
else
{
res= setup_fields(thd, 0, table_list, select->item_list, 1, 0, 0);
thd->lex->select_lex.no_wrap_view_item= 0;
if (res)
goto error;
#ifndef NO_EMBEDDED_ACCESS_CHECKS
/* Check values */
table_list->grant.want_privilege=
table_list->table->grant.want_privilege=
(SELECT_ACL & ~table_list->table->grant.privilege);
#endif
if (setup_fields(thd, 0, table_list,
stmt->lex->value_list, 0, 0, 0))
res= 1;
}
}
stmt->lex->unit.cleanup();
}
else
res= 1;
if (setup_fields(thd, 0, table_list, stmt->lex->value_list, 0, 0, 0))
goto error;
/* TODO: here we should send types of placeholders to the client. */
DBUG_RETURN(res);
DBUG_RETURN(0);
error:
DBUG_RETURN(1);
}
......@@ -1079,33 +1063,29 @@ static int mysql_test_update(Prepared_statement *stmt,
RETURN VALUE
FALSE success
TRUE error
TRUE error, error message is set in THD
*/
static int mysql_test_delete(Prepared_statement *stmt,
static bool mysql_test_delete(Prepared_statement *stmt,
TABLE_LIST *table_list)
{
THD *thd= stmt->thd;
LEX *lex= stmt->lex;
DBUG_ENTER("mysql_test_delete");
if (delete_precheck(thd, table_list))
DBUG_RETURN(TRUE);
if (delete_precheck(thd, table_list) ||
open_and_lock_tables(thd, table_list))
goto error;
if (!open_and_lock_tables(thd, table_list))
{
bool res;
if (!table_list->table)
{
my_error(ER_VIEW_DELETE_MERGE_VIEW, MYF(0),
table_list->view_db.str, table_list->view_name.str);
DBUG_RETURN(-1);
goto error;
}
res= mysql_prepare_delete(thd, table_list, &lex->select_lex.where);
lex->unit.cleanup();
DBUG_RETURN(res);
}
/* TODO: here we should send types of placeholders to the client. */
DBUG_RETURN(mysql_prepare_delete(thd, table_list, &lex->select_lex.where));
error:
DBUG_RETURN(TRUE);
}
......@@ -1125,13 +1105,12 @@ static int mysql_test_delete(Prepared_statement *stmt,
TRUE error, sent to client
*/
static int mysql_test_select(Prepared_statement *stmt,
static bool mysql_test_select(Prepared_statement *stmt,
TABLE_LIST *tables, bool text_protocol)
{
THD *thd= stmt->thd;
LEX *lex= stmt->lex;
SELECT_LEX_UNIT *unit= &lex->unit;
bool result;
DBUG_ENTER("mysql_test_select");
#ifndef NO_EMBEDDED_ACCESS_CHECKS
......@@ -1139,19 +1118,20 @@ static int mysql_test_select(Prepared_statement *stmt,
if (tables)
{
if (check_table_access(thd, privilege, tables,0))
DBUG_RETURN(TRUE);
goto error;
}
else if (check_access(thd, privilege, any_db,0,0,0))
DBUG_RETURN(TRUE);
goto error;
#endif
result= TRUE;
if (!lex->result && !(lex->result= new (stmt->mem_root) select_send))
goto err;
{
my_error(ER_OUTOFMEMORY, MYF(0), sizeof(select_send));
goto error;
}
if (open_and_lock_tables(thd, tables))
goto err;
goto error;
thd->used_tables= 0; // Updated by setup_fields
......@@ -1161,15 +1141,13 @@ static int mysql_test_select(Prepared_statement *stmt,
usual, and we pass 0 as setup_tables_done_option
*/
if (unit->prepare(thd, 0, 0, ""))
{
goto err_prep;
}
goto error;
if (!text_protocol)
{
if (lex->describe)
{
if (send_prep_stmt(stmt, 0) || thd->protocol->flush())
goto err_prep;
goto error;
}
else
{
......@@ -1179,7 +1157,7 @@ static int mysql_test_select(Prepared_statement *stmt,
/* Change columns if a procedure like analyse() */
if (unit->last_procedure &&
unit->last_procedure->change_columns(fields))
goto err_prep;
goto error;
/*
We can use lex->result as it should've been
......@@ -1188,15 +1166,12 @@ static int mysql_test_select(Prepared_statement *stmt,
if (send_prep_stmt(stmt, lex->result->field_count(fields)) ||
lex->result->send_fields(fields, Protocol::SEND_EOF) ||
thd->protocol->flush())
goto err_prep;
goto error;
}
}
result= FALSE; // ok
err_prep:
unit->cleanup();
err:
DBUG_RETURN(result);
DBUG_RETURN(FALSE);
error:
DBUG_RETURN(TRUE);
}
......@@ -1211,26 +1186,22 @@ static int mysql_test_select(Prepared_statement *stmt,
RETURN VALUE
FALSE success
TRUE error, sent to client
TRUE error, error message is set in THD
*/
static bool mysql_test_do_fields(Prepared_statement *stmt,
TABLE_LIST *tables,
List<Item> *values)
{
DBUG_ENTER("mysql_test_do_fields");
THD *thd= stmt->thd;
bool res;
DBUG_ENTER("mysql_test_do_fields");
if (tables && check_table_access(thd, SELECT_ACL, tables, 0))
DBUG_RETURN(TRUE);
if (open_and_lock_tables(thd, tables))
{
DBUG_RETURN(TRUE);
}
res= setup_fields(thd, 0, 0, *values, 0, 0, 0);
stmt->lex->unit.cleanup();
DBUG_RETURN(res);
DBUG_RETURN(setup_fields(thd, 0, 0, *values, 0, 0, 0));
}
......@@ -1247,6 +1218,7 @@ static bool mysql_test_do_fields(Prepared_statement *stmt,
FALSE success
TRUE error
*/
static bool mysql_test_set_fields(Prepared_statement *stmt,
TABLE_LIST *tables,
List<set_var_base> *var_list)
......@@ -1255,25 +1227,19 @@ static bool mysql_test_set_fields(Prepared_statement *stmt,
List_iterator_fast<set_var_base> it(*var_list);
THD *thd= stmt->thd;
set_var_base *var;
bool res;
if (tables && check_table_access(thd, SELECT_ACL, tables, 0))
DBUG_RETURN(TRUE);
if ((res= open_and_lock_tables(thd, tables)))
if (tables && check_table_access(thd, SELECT_ACL, tables, 0) ||
open_and_lock_tables(thd, tables))
goto error;
while ((var= it++))
{
if (var->light_check(thd))
{
stmt->lex->unit.cleanup();
res= TRUE;
goto error;
}
}
DBUG_RETURN(FALSE);
error:
stmt->lex->unit.cleanup();
DBUG_RETURN(res);
DBUG_RETURN(TRUE);
}
......@@ -1294,7 +1260,7 @@ static bool mysql_test_set_fields(Prepared_statement *stmt,
RETURN VALUE
FALSE success
TRUE error
TRUE error, error message is set in THD
*/
static bool select_like_stmt_test(Prepared_statement *stmt,
......@@ -1304,24 +1270,16 @@ static bool select_like_stmt_test(Prepared_statement *stmt,
DBUG_ENTER("select_like_stmt_test");
THD *thd= stmt->thd;
LEX *lex= stmt->lex;
bool res= FALSE;
if (specific_prepare && (res= (*specific_prepare)(thd)))
goto end;
if (specific_prepare && (*specific_prepare)(thd))
DBUG_RETURN(TRUE);
thd->used_tables= 0; // Updated by setup_fields
// JOIN::prepare calls
if (lex->unit.prepare(thd, 0, setup_tables_done_option, ""))
{
res= TRUE;
}
end:
lex->unit.cleanup();
DBUG_RETURN(res);
/* Calls JOIN::prepare */
DBUG_RETURN(lex->unit.prepare(thd, 0, setup_tables_done_option, ""));
}
/*
Check internal SELECT of the prepared command (with opening and
locking tables used).
......@@ -1369,25 +1327,26 @@ select_like_stmt_test_with_open_n_lock(Prepared_statement *stmt,
tables list of tables queries
RETURN VALUE
0 success
1 error, sent to client
-1 error, not sent to client
FALSE success
TRUE error, error message is set in THD
*/
static int mysql_test_create_table(Prepared_statement *stmt)
static bool mysql_test_create_table(Prepared_statement *stmt)
{
DBUG_ENTER("mysql_test_create_table");
THD *thd= stmt->thd;
LEX *lex= stmt->lex;
SELECT_LEX *select_lex= &lex->select_lex;
int res= 0;
bool res= FALSE;
/* Skip first table, which is the table we are creating */
bool link_to_local;
TABLE_LIST *create_table= lex->unlink_first_table(&link_to_local);
TABLE_LIST *tables= lex->query_tables;
if (!(res= create_table_precheck(thd, tables, create_table)) &&
select_lex->item_list.elements)
if (create_table_precheck(thd, tables, create_table))
DBUG_RETURN(TRUE);
if (select_lex->item_list.elements)
{
select_lex->resolve_mode= SELECT_LEX::SELECT_MODE;
res= select_like_stmt_test_with_open_n_lock(stmt, tables, 0, 0);
......@@ -1437,32 +1396,33 @@ static bool mysql_test_multiupdate(Prepared_statement *stmt,
RETURN VALUE
0 success
1 error, sent to client
-1 error, not sent to client
1 error, error message in THD is set.
*/
static int mysql_test_multidelete(Prepared_statement *stmt,
static bool mysql_test_multidelete(Prepared_statement *stmt,
TABLE_LIST *tables)
{
int res;
stmt->thd->lex->current_select= &stmt->thd->lex->select_lex;
if (add_item_to_list(stmt->thd, new Item_null()))
return -1;
{
my_error(ER_OUTOFMEMORY, MYF(0), 0);
goto error;
}
uint fake_counter;
if ((res= multi_delete_precheck(stmt->thd, tables, &fake_counter)))
return res;
if ((res= select_like_stmt_test_with_open_n_lock(stmt, tables,
if (multi_delete_precheck(stmt->thd, tables) ||
select_like_stmt_test_with_open_n_lock(stmt, tables,
&mysql_multi_delete_prepare,
OPTION_SETUP_TABLES_DONE)))
return res;
OPTION_SETUP_TABLES_DONE))
goto error;
if (!tables->table)
{
my_error(ER_VIEW_DELETE_MERGE_VIEW, MYF(0),
tables->view_db.str, tables->view_name.str);
return -1;
goto error;
}
return 0;
return FALSE;
error:
return TRUE;
}
......@@ -1520,8 +1480,8 @@ static int mysql_test_insert_select(Prepared_statement *stmt,
tables->table->insert_values=(byte *)1;
}
if ((res= insert_precheck(stmt->thd, tables)))
return res;
if (insert_precheck(stmt->thd, tables))
return 1;
/* store it, because mysql_insert_select_prepare_tester change it */
first_local_table= (TABLE_LIST *)lex->select_lex.table_list.first;
......@@ -1552,11 +1512,11 @@ static int mysql_test_insert_select(Prepared_statement *stmt,
by calling fix_fields.
RETURN VALUE
0 success
1 error, sent to client
FALSE success, statement metadata is sent to client
TRUE error, error message is set (but not sent)
*/
static int check_prepared_statement(Prepared_statement *stmt,
static bool check_prepared_statement(Prepared_statement *stmt,
bool text_protocol)
{
THD *thd= stmt->thd;
......@@ -1583,7 +1543,7 @@ static int check_prepared_statement(Prepared_statement *stmt,
case SQLCOM_UPDATE:
res= mysql_test_update(stmt, tables);
/* mysql_test_update return 2 if we need to switch to multi-update */
/* mysql_test_update returns 2 if we need to switch to multi-update */
if (res != 2)
break;
......@@ -1599,7 +1559,7 @@ static int check_prepared_statement(Prepared_statement *stmt,
if ((res= mysql_test_select(stmt, tables, text_protocol)))
goto error;
/* Statement and field info has already been sent */
DBUG_RETURN(0);
DBUG_RETURN(FALSE);
case SQLCOM_CREATE_TABLE:
res= mysql_test_create_table(stmt);
......@@ -1650,18 +1610,15 @@ static int check_prepared_statement(Prepared_statement *stmt,
break;
default:
/*
All other is not supported yet
*/
res= -1;
/* All other statements are not supported yet. */
my_message(ER_UNSUPPORTED_PS, ER(ER_UNSUPPORTED_PS), MYF(0));
goto error;
}
if (res == 0)
DBUG_RETURN(text_protocol? 0 : (send_prep_stmt(stmt, 0) ||
DBUG_RETURN(text_protocol? FALSE : (send_prep_stmt(stmt, 0) ||
thd->protocol->flush()));
error:
DBUG_RETURN(1);
DBUG_RETURN(TRUE);
}
/*
......@@ -1803,6 +1760,7 @@ bool mysql_stmt_prepare(THD *thd, char *packet, uint packet_length,
thd->lex->sphead= NULL;
}
lex_end(lex);
lex->unit.cleanup();
close_thread_tables(thd);
thd->restore_backup_statement(stmt, &thd->stmt_backup);
cleanup_items(stmt->free_list);
......
......@@ -919,6 +919,11 @@ deallocate:
yyerror(ER(ER_SYNTAX_ERROR));
YYABORT;
}
if (lex->sphead)
{
my_error(ER_SP_BADSTATEMENT, MYF(0), "DEALLOCATE");
YYABORT;
}
lex->sql_command= SQLCOM_DEALLOCATE_PREPARE;
lex->prepared_stmt_name= $3;
};
......@@ -939,6 +944,11 @@ prepare:
yyerror(ER(ER_SYNTAX_ERROR));
YYABORT;
}
if (lex->sphead)
{
my_error(ER_SP_BADSTATEMENT, MYF(0), "PREPARE");
YYABORT;
}
lex->sql_command= SQLCOM_PREPARE;
lex->prepared_stmt_name= $2;
};
......@@ -969,6 +979,11 @@ execute:
yyerror(ER(ER_SYNTAX_ERROR));
YYABORT;
}
if (lex->sphead)
{
my_error(ER_SP_BADSTATEMENT, MYF(0), "EXECUTE");
YYABORT;
}
lex->sql_command= SQLCOM_EXECUTE;
lex->prepared_stmt_name= $2;
}
......@@ -6132,10 +6147,17 @@ single_multi:
| table_wild_list
{ mysql_init_multi_delete(Lex); }
FROM join_table_list where_clause
{
if (multi_delete_set_locks_and_link_aux_tables(Lex))
YYABORT;
}
| FROM table_wild_list
{ mysql_init_multi_delete(Lex); }
USING join_table_list where_clause
{}
{
if (multi_delete_set_locks_and_link_aux_tables(Lex))
YYABORT;
}
;
table_wild_list:
......
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