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