Merge bk-internal:/home/bk/mysql-5.0
into serg.mylan:/usr/home/serg/Abk/mysql-5.0 mysql-test/r/join_outer.result: Auto merged mysql-test/t/join_outer.test: Auto merged sql/ha_innodb.cc: Auto merged sql/item_cmpfunc.h: Auto merged sql/mysql_priv.h: Auto merged sql/mysqld.cc: Auto merged
This commit is contained in:
commit
ebbee9d974
@ -457,6 +457,14 @@ ccarkner@nslinuxw10.bedford.progress.com|mysql-test/r/isolation.result|200103271
|
||||
ccarkner@nslinuxw10.bedford.progress.com|mysql-test/t/isolation.test|20010327145543|39049|6a39e4138dd4a456
|
||||
jani@hynda.mysql.fi|client/mysqlcheck|20010419221207|26716|363e3278166d84ec
|
||||
jcole@tetra.bedford.progress.com|BitKeeper/etc/logging_ok|20001004201211|30554
|
||||
jimw@mysql.com|mysql-test/t/ndb_alter_table.disabled|20050311230559|27526|411e026940e7a0aa
|
||||
jimw@mysql.com|mysql-test/t/ndb_alter_table.disabled|20050311230559|27526|411e026940e7a0aajimw@mysql.com|mysql-test/t/ndb_autodiscover2.disabled|20050311230559|22363|afa8e5b6e46a3ea1jimw@mysql.com|mysql-test/t/ndb_autodiscover.disabled|20050311230559|58101|dda20d04dddbb06jimw@mysql.com|mysql-test/t/ndb_cache_multi2.disabled|20050311230600|47901|84fed1a78c0d3e6djimw@mysql.com|mysql-test/t/ndb_cache_multi.disabled|20050311230600|18039|9657b6eff7deb27ajimw@mysql.com|mysql-test/t/ndb_multi.disabled|20050311230600|12240|2599367ad06100f6jimw@mysql.com|mysql-test/t/ndb_restore.disabled|20050311230600|30718|3c2453d6164b1a30jimw@mysql.com|mysql-test/t/ndb_alter_table.disabled|20050311230559|27526|411e026940e7a0aajimw@mysql.com|mysql-test/t/ndb_autodiscover2.disabled|20050311230559|22363|afa8e5b6e46a3ea1jimw@mysql.com|mysql-test/t/ndb_autodiscover.disabled|20050311230559|58101|dda20d04dddbb06jimw@mysql.com|mysql-test/t/ndb_cache_multi2.disabled|20050311230600|47901|84fed1a78c0d3e6djimw@mysql.com|mysql-test/t/ndb_cache_multi.disabled|20050311230600|18039|9657b6eff7deb27ajimw@mysql.com|mysql-test/t/ndb_multi.disabled|20050311230600|12240|2599367ad06100f6jimw@mysql.com|mysql-test/t/ndb_restore.disabled|20050311230600|30718|3c2453d6164b1a30magnus@neptunus.(none)|ndb/src/client/Makefile|20040414084436|02010|6c2778d2bf4954a2
|
||||
jimw@mysql.com|mysql-test/t/ndb_autodiscover.disabled|20050311230559|58101|dda20d04dddbb06
|
||||
jimw@mysql.com|mysql-test/t/ndb_autodiscover2.disabled|20050311230559|22363|afa8e5b6e46a3ea1
|
||||
jimw@mysql.com|mysql-test/t/ndb_cache_multi.disabled|20050311230600|18039|9657b6eff7deb27a
|
||||
jimw@mysql.com|mysql-test/t/ndb_cache_multi2.disabled|20050311230600|47901|84fed1a78c0d3e6d
|
||||
jimw@mysql.com|mysql-test/t/ndb_multi.disabled|20050311230600|12240|2599367ad06100f6
|
||||
jimw@mysql.com|mysql-test/t/ndb_restore.disabled|20050311230600|30718|3c2453d6164b1a30
|
||||
magnus@neptunus.(none)|ndb/src/client/Makefile|20040414084436|02010|6c2778d2bf4954a2
|
||||
magnus@neptunus.(none)|ndb/src/client/odbc/Extra.mk|20040414082358|47442|eabbb28986ca817d
|
||||
magnus@neptunus.(none)|ndb/src/client/odbc/Makefile|20040414084435|33394|9bc928a18aa88d66
|
||||
@ -1174,6 +1182,7 @@ mwagner@evoq.home.mwagner.org|mysql-test/xml/xsl/README|20001013051514|26509|cd4
|
||||
mwagner@evoq.home.mwagner.org|mysql-test/xml/xsl/mysqltest.xsl|20001013051514|27425|1b8f6ec4f1b5f634
|
||||
mwagner@work.mysql.com|mysql-test/r/3.23/sel000001.result|20001010091454|28284|383913ae4505ec86
|
||||
mwagner@work.mysql.com|mysql-test/r/3.23/sel000002.result|20001010091454|29230|d1787e6fd5dbc1cc
|
||||
ndb/src/client/Makefile
|
||||
nick@nick.leippe.com|mysql-test/r/rpl_empty_master_crash.result|20020531235552|47718|615f521be2132141
|
||||
nick@nick.leippe.com|mysql-test/t/rpl_empty_master_crash.test|20020531235552|52328|99464e737639ccc6
|
||||
sasha@mysql.sashanet.com|BitKeeper/etc/logging_ok|20000801000905|12967|5b7d847a2158554
|
||||
|
@ -2621,12 +2621,12 @@ fil_open_single_table_tablespace(
|
||||
fputs("!\n"
|
||||
"InnoDB: Have you moved InnoDB .ibd files around without using the\n"
|
||||
"InnoDB: commands DISCARD TABLESPACE and IMPORT TABLESPACE?\n"
|
||||
"InnoDB: It is also possible that this is a table created with\n"
|
||||
"InnoDB: CREATE TEMPORARY TABLE, and MySQL removed the .ibd file for this.\n"
|
||||
"InnoDB: It is also possible that this is a temporary table #sql...,\n"
|
||||
"InnoDB: and MySQL removed the .ibd file for this.\n"
|
||||
"InnoDB: Please refer to\n"
|
||||
"InnoDB:"
|
||||
" http://dev.mysql.com/doc/mysql/en/InnoDB_troubleshooting_datadict.html\n"
|
||||
"InnoDB: how to resolve the issue.\n", stderr);
|
||||
"InnoDB: for how to resolve the issue.\n", stderr);
|
||||
|
||||
mem_free(filepath);
|
||||
|
||||
@ -2666,7 +2666,7 @@ fil_open_single_table_tablespace(
|
||||
"InnoDB: Please refer to\n"
|
||||
"InnoDB:"
|
||||
" http://dev.mysql.com/doc/mysql/en/InnoDB_troubleshooting_datadict.html\n"
|
||||
"InnoDB: how to resolve the issue.\n", (ulong) space_id, (ulong) id);
|
||||
"InnoDB: for how to resolve the issue.\n", (ulong) space_id, (ulong) id);
|
||||
|
||||
ret = FALSE;
|
||||
|
||||
@ -3261,7 +3261,7 @@ fil_space_for_table_exists_in_mem(
|
||||
ut_print_filename(stderr, name);
|
||||
fprintf(stderr, "\n"
|
||||
"InnoDB: in InnoDB data dictionary has tablespace id %lu,\n"
|
||||
"InnoDB: but tablespace with that id does not exist. There is\n"
|
||||
"InnoDB: but a tablespace with that id does not exist. There is\n"
|
||||
"InnoDB: a tablespace of name %s and id %lu, though. Have\n"
|
||||
"InnoDB: you deleted or moved .ibd files?\n",
|
||||
(ulong) id, namespace->name,
|
||||
@ -3272,7 +3272,7 @@ fil_space_for_table_exists_in_mem(
|
||||
"InnoDB: Please refer to\n"
|
||||
"InnoDB:"
|
||||
" http://dev.mysql.com/doc/mysql/en/InnoDB_troubleshooting_datadict.html\n"
|
||||
"InnoDB: how to resolve the issue.\n", stderr);
|
||||
"InnoDB: for how to resolve the issue.\n", stderr);
|
||||
|
||||
mem_free(path);
|
||||
mutex_exit(&(system->mutex));
|
||||
@ -3286,7 +3286,7 @@ fil_space_for_table_exists_in_mem(
|
||||
ut_print_filename(stderr, name);
|
||||
fprintf(stderr, "\n"
|
||||
"InnoDB: in InnoDB data dictionary has tablespace id %lu,\n"
|
||||
"InnoDB: but tablespace with that id has name %s.\n"
|
||||
"InnoDB: but the tablespace with that id has name %s.\n"
|
||||
"InnoDB: Have you deleted or moved .ibd files?\n", (ulong) id, space->name);
|
||||
|
||||
if (namespace != NULL) {
|
||||
|
@ -369,6 +369,11 @@ struct trx_struct{
|
||||
XID xid; /* X/Open XA transaction
|
||||
identification to identify a
|
||||
transaction branch */
|
||||
ibool support_xa; /* normally we do the XA two-phase
|
||||
commit steps, but by setting this to
|
||||
FALSE, one can save CPU time and about
|
||||
150 bytes in the undo log size as then
|
||||
we skip XA steps */
|
||||
dulint no; /* transaction serialization number ==
|
||||
max trx id when the transaction is
|
||||
moved to COMMITTED_IN_MEMORY state */
|
||||
|
@ -3382,8 +3382,9 @@ row_rename_table_for_mysql(
|
||||
"InnoDB: data dictionary though MySQL is trying to rename the table.\n"
|
||||
"InnoDB: Have you copied the .frm file of the table to the\n"
|
||||
"InnoDB: MySQL database directory from another database?\n"
|
||||
"InnoDB: You can look for further help from section 15.1 of\n"
|
||||
"InnoDB: http://www.innodb.com/ibman.php\n", stderr);
|
||||
"InnoDB: You can look for further help from\n"
|
||||
"InnoDB: http://dev.mysql.com/doc/mysql/en/"
|
||||
"InnoDB_troubleshooting_datadict.html\n", stderr);
|
||||
goto funct_exit;
|
||||
}
|
||||
|
||||
@ -3395,8 +3396,9 @@ row_rename_table_for_mysql(
|
||||
ut_print_name(stderr, trx, old_name);
|
||||
fputs(
|
||||
" does not have an .ibd file in the database directory.\n"
|
||||
"InnoDB: You can look for further help from section 15.1 of\n"
|
||||
"InnoDB: http://www.innodb.com/ibman.php\n", stderr);
|
||||
"InnoDB: You can look for further help from\n"
|
||||
"InnoDB: http://dev.mysql.com/doc/mysql/en/"
|
||||
"InnoDB_troubleshooting_datadict.html\n", stderr);
|
||||
goto funct_exit;
|
||||
}
|
||||
|
||||
|
@ -441,16 +441,8 @@ loop:
|
||||
trx = UT_LIST_GET_NEXT(trx_list, trx);
|
||||
} else if (trx->conc_state == TRX_PREPARED) {
|
||||
|
||||
/* Roll back all prepared transactions if
|
||||
innobase_force_recovery > 0 in my.cnf */
|
||||
|
||||
if (srv_force_recovery > 0) {
|
||||
trx->conc_state = TRX_ACTIVE;
|
||||
break;
|
||||
} else {
|
||||
trx->sess = trx_dummy_sess;
|
||||
trx = UT_LIST_GET_NEXT(trx_list, trx);
|
||||
}
|
||||
trx->sess = trx_dummy_sess;
|
||||
trx = UT_LIST_GET_NEXT(trx_list, trx);
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
@ -461,7 +453,7 @@ loop:
|
||||
if (trx == NULL) {
|
||||
ut_print_timestamp(stderr);
|
||||
fprintf(stderr,
|
||||
" InnoDB: Rollback of uncommitted transactions completed\n");
|
||||
" InnoDB: Rollback of non-prepared transactions completed\n");
|
||||
|
||||
mem_heap_free(heap);
|
||||
|
||||
|
@ -93,6 +93,8 @@ trx_create(
|
||||
trx->id = ut_dulint_zero;
|
||||
trx->no = ut_dulint_max;
|
||||
|
||||
trx->support_xa = TRUE;
|
||||
|
||||
trx->check_foreigns = TRUE;
|
||||
trx->check_unique_secondary = TRUE;
|
||||
|
||||
@ -453,9 +455,15 @@ trx_lists_init_at_db_start(void)
|
||||
ut_dulint_get_high(trx->id),
|
||||
ut_dulint_get_low(trx->id));
|
||||
|
||||
trx->conc_state = TRX_ACTIVE;
|
||||
if (srv_force_recovery == 0) {
|
||||
|
||||
/* trx->conc_state = TRX_PREPARED;*/
|
||||
trx->conc_state = TRX_PREPARED;
|
||||
} else {
|
||||
fprintf(stderr,
|
||||
"InnoDB: Since innodb_force_recovery > 0, we will rollback it anyway.\n");
|
||||
|
||||
trx->conc_state = TRX_ACTIVE;
|
||||
}
|
||||
} else {
|
||||
trx->conc_state =
|
||||
TRX_COMMITTED_IN_MEMORY;
|
||||
@ -511,15 +519,20 @@ trx_lists_init_at_db_start(void)
|
||||
commit or abort decision from MySQL */
|
||||
|
||||
if (undo->state == TRX_UNDO_PREPARED) {
|
||||
fprintf(stderr,
|
||||
fprintf(stderr,
|
||||
"InnoDB: Transaction %lu %lu was in the XA prepared state.\n",
|
||||
ut_dulint_get_high(trx->id),
|
||||
ut_dulint_get_low(trx->id));
|
||||
ut_dulint_get_high(trx->id),
|
||||
ut_dulint_get_low(trx->id));
|
||||
|
||||
if (srv_force_recovery == 0) {
|
||||
|
||||
trx->conc_state = TRX_PREPARED;
|
||||
} else {
|
||||
fprintf(stderr,
|
||||
"InnoDB: Since innodb_force_recovery > 0, we will rollback it anyway.\n");
|
||||
|
||||
trx->conc_state = TRX_ACTIVE;
|
||||
|
||||
/* trx->conc_state =
|
||||
TRX_PREPARED; */
|
||||
}
|
||||
} else {
|
||||
trx->conc_state =
|
||||
TRX_COMMITTED_IN_MEMORY;
|
||||
@ -823,9 +836,6 @@ trx_commit_off_kernel(
|
||||
trx->read_view = NULL;
|
||||
}
|
||||
|
||||
/* fprintf(stderr, "Trx %lu commit finished\n",
|
||||
ut_dulint_get_low(trx->id)); */
|
||||
|
||||
if (must_flush_log) {
|
||||
|
||||
mutex_exit(&kernel_mutex);
|
||||
@ -869,14 +879,15 @@ trx_commit_off_kernel(
|
||||
/* Do nothing */
|
||||
} else if (srv_flush_log_at_trx_commit == 1) {
|
||||
if (srv_unix_file_flush_method == SRV_UNIX_NOSYNC) {
|
||||
/* Write the log but do not flush it to disk */
|
||||
/* Write the log but do not flush it to disk */
|
||||
|
||||
log_write_up_to(lsn, LOG_WAIT_ONE_GROUP, FALSE);
|
||||
log_write_up_to(lsn, LOG_WAIT_ONE_GROUP,
|
||||
FALSE);
|
||||
} else {
|
||||
/* Write the log to the log files AND flush
|
||||
them to disk */
|
||||
/* Write the log to the log files AND flush
|
||||
them to disk */
|
||||
|
||||
log_write_up_to(lsn, LOG_WAIT_ONE_GROUP, TRUE);
|
||||
log_write_up_to(lsn, LOG_WAIT_ONE_GROUP, TRUE);
|
||||
}
|
||||
} else if (srv_flush_log_at_trx_commit == 2) {
|
||||
|
||||
@ -1747,12 +1758,11 @@ Prepares a transaction. */
|
||||
|
||||
void
|
||||
trx_prepare_off_kernel(
|
||||
/*==================*/
|
||||
/*===================*/
|
||||
trx_t* trx) /* in: transaction */
|
||||
{
|
||||
page_t* update_hdr_page;
|
||||
trx_rseg_t* rseg;
|
||||
trx_undo_t* undo;
|
||||
ibool must_flush_log = FALSE;
|
||||
dulint lsn;
|
||||
mtr_t mtr;
|
||||
@ -1779,19 +1789,18 @@ trx_prepare_off_kernel(
|
||||
mutex_enter(&(rseg->mutex));
|
||||
|
||||
if (trx->insert_undo != NULL) {
|
||||
|
||||
/* It is not necessary to obtain trx->undo_mutex here
|
||||
because only a single OS thread is allowed to do the
|
||||
transaction prepare for this transaction. */
|
||||
|
||||
trx_undo_set_state_at_prepare(trx, trx->insert_undo,
|
||||
&mtr);
|
||||
}
|
||||
|
||||
undo = trx->update_undo;
|
||||
|
||||
if (undo) {
|
||||
/* It is not necessary to obtain trx->undo_mutex here
|
||||
because only a single OS thread is allowed to do the
|
||||
transaction prepare for this transaction. */
|
||||
|
||||
if (trx->update_undo) {
|
||||
update_hdr_page = trx_undo_set_state_at_prepare(trx,
|
||||
undo, &mtr);
|
||||
trx->update_undo, &mtr);
|
||||
}
|
||||
|
||||
mutex_exit(&(rseg->mutex));
|
||||
@ -1815,17 +1824,48 @@ trx_prepare_off_kernel(
|
||||
/*--------------------------------------*/
|
||||
|
||||
if (must_flush_log) {
|
||||
/* Depending on the my.cnf options, we may now write the log
|
||||
buffer to the log files, making the prepared state of the
|
||||
transaction durable if the OS does not crash. We may also
|
||||
flush the log files to disk, making the prepared state of the
|
||||
transaction durable also at an OS crash or a power outage.
|
||||
|
||||
The idea in InnoDB's group prepare is that a group of
|
||||
transactions gather behind a trx doing a physical disk write
|
||||
to log files, and when that physical write has been completed,
|
||||
one of those transactions does a write which prepares the whole
|
||||
group. Note that this group prepare will only bring benefit if
|
||||
there are > 2 users in the database. Then at least 2 users can
|
||||
gather behind one doing the physical log write to disk.
|
||||
|
||||
TODO: find out if MySQL holds some mutex when calling this.
|
||||
That would spoil our group prepare algorithm. */
|
||||
|
||||
mutex_exit(&kernel_mutex);
|
||||
|
||||
/* Write the log to the log files AND flush them to disk */
|
||||
|
||||
/*-------------------------------------*/
|
||||
if (srv_flush_log_at_trx_commit == 0) {
|
||||
/* Do nothing */
|
||||
} else if (srv_flush_log_at_trx_commit == 1) {
|
||||
if (srv_unix_file_flush_method == SRV_UNIX_NOSYNC) {
|
||||
/* Write the log but do not flush it to disk */
|
||||
|
||||
log_write_up_to(lsn, LOG_WAIT_ONE_GROUP, TRUE);
|
||||
log_write_up_to(lsn, LOG_WAIT_ONE_GROUP,
|
||||
FALSE);
|
||||
} else {
|
||||
/* Write the log to the log files AND flush
|
||||
them to disk */
|
||||
|
||||
log_write_up_to(lsn, LOG_WAIT_ONE_GROUP, TRUE);
|
||||
}
|
||||
} else if (srv_flush_log_at_trx_commit == 2) {
|
||||
|
||||
/* Write the log but do not flush it to disk */
|
||||
|
||||
log_write_up_to(lsn, LOG_WAIT_ONE_GROUP, FALSE);
|
||||
} else {
|
||||
ut_error;
|
||||
}
|
||||
|
||||
/*-------------------------------------*/
|
||||
|
||||
mutex_enter(&kernel_mutex);
|
||||
}
|
||||
}
|
||||
|
@ -596,7 +596,7 @@ trx_undo_read_xid(
|
||||
}
|
||||
|
||||
/*******************************************************************
|
||||
Adds the XA XID after an undo log old-style header. */
|
||||
Adds space for the XA XID after an undo log old-style header. */
|
||||
static
|
||||
void
|
||||
trx_undo_header_add_space_for_xid(
|
||||
@ -1488,6 +1488,7 @@ trx_undo_create(
|
||||
/*============*/
|
||||
/* out: undo log object, NULL if did not
|
||||
succeed: out of space */
|
||||
trx_t* trx, /* in: transaction */
|
||||
trx_rseg_t* rseg, /* in: rollback segment memory copy */
|
||||
ulint type, /* in: type of the log: TRX_UNDO_INSERT or
|
||||
TRX_UNDO_UPDATE */
|
||||
@ -1530,7 +1531,10 @@ trx_undo_create(
|
||||
|
||||
offset = trx_undo_header_create(undo_page, trx_id, mtr);
|
||||
|
||||
trx_undo_header_add_space_for_xid(undo_page, undo_page + offset, mtr);
|
||||
if (trx->support_xa) {
|
||||
trx_undo_header_add_space_for_xid(undo_page,
|
||||
undo_page + offset, mtr);
|
||||
}
|
||||
|
||||
undo = trx_undo_mem_create(rseg, id, type, trx_id, xid,
|
||||
page_no, offset);
|
||||
@ -1547,6 +1551,7 @@ trx_undo_reuse_cached(
|
||||
/*==================*/
|
||||
/* out: the undo log memory object, NULL if
|
||||
none cached */
|
||||
trx_t* trx, /* in: transaction */
|
||||
trx_rseg_t* rseg, /* in: rollback segment memory object */
|
||||
ulint type, /* in: type of the log: TRX_UNDO_INSERT or
|
||||
TRX_UNDO_UPDATE */
|
||||
@ -1597,16 +1602,22 @@ trx_undo_reuse_cached(
|
||||
|
||||
if (type == TRX_UNDO_INSERT) {
|
||||
offset = trx_undo_insert_header_reuse(undo_page, trx_id, mtr);
|
||||
trx_undo_header_add_space_for_xid(undo_page, undo_page + offset,
|
||||
mtr);
|
||||
|
||||
if (trx->support_xa) {
|
||||
trx_undo_header_add_space_for_xid(undo_page,
|
||||
undo_page + offset, mtr);
|
||||
}
|
||||
} else {
|
||||
ut_a(mach_read_from_2(undo_page + TRX_UNDO_PAGE_HDR
|
||||
+ TRX_UNDO_PAGE_TYPE)
|
||||
== TRX_UNDO_UPDATE);
|
||||
|
||||
offset = trx_undo_header_create(undo_page, trx_id, mtr);
|
||||
trx_undo_header_add_space_for_xid(undo_page, undo_page + offset,
|
||||
mtr);
|
||||
|
||||
if (trx->support_xa) {
|
||||
trx_undo_header_add_space_for_xid(undo_page,
|
||||
undo_page + offset, mtr);
|
||||
}
|
||||
}
|
||||
|
||||
trx_undo_mem_init_for_reuse(undo, trx_id, xid, offset);
|
||||
@ -1674,11 +1685,11 @@ trx_undo_assign_undo(
|
||||
#endif /* UNIV_SYNC_DEBUG */
|
||||
mutex_enter(&(rseg->mutex));
|
||||
|
||||
undo = trx_undo_reuse_cached(rseg, type, trx->id, &trx->xid, &mtr);
|
||||
|
||||
undo = trx_undo_reuse_cached(trx, rseg, type, trx->id, &trx->xid,
|
||||
&mtr);
|
||||
if (undo == NULL) {
|
||||
undo = trx_undo_create(rseg, type, trx->id, &trx->xid, &mtr);
|
||||
|
||||
undo = trx_undo_create(trx, rseg, type, trx->id, &trx->xid,
|
||||
&mtr);
|
||||
if (undo == NULL) {
|
||||
/* Did not succeed */
|
||||
|
||||
|
@ -896,3 +896,25 @@ a b a b
|
||||
2 2 2 2
|
||||
NULL NULL 3 3
|
||||
DROP TABLE t0,t1,t2,t3;
|
||||
CREATE TABLE t1 (a int PRIMARY KEY, b int);
|
||||
CREATE TABLE t2 (a int PRIMARY KEY, b int);
|
||||
INSERT INTO t1 VALUES (1,1), (2,1), (3,1), (4,2);
|
||||
INSERT INTO t2 VALUES (1,2), (2,2);
|
||||
SELECT * FROM t1 LEFT JOIN t2 ON t1.a=t2.a;
|
||||
a b a b
|
||||
1 1 1 2
|
||||
2 1 2 2
|
||||
3 1 NULL NULL
|
||||
4 2 NULL NULL
|
||||
SELECT * FROM t1 LEFT JOIN t2 ON t1.a=t2.a WHERE t1.b=1;
|
||||
a b a b
|
||||
1 1 1 2
|
||||
2 1 2 2
|
||||
3 1 NULL NULL
|
||||
SELECT * FROM t1 LEFT JOIN t2 ON t1.a=t2.a
|
||||
WHERE t1.b=1 XOR (NOT ISNULL(t2.a) AND t2.b=1);
|
||||
a b a b
|
||||
1 1 1 2
|
||||
2 1 2 2
|
||||
3 1 NULL NULL
|
||||
DROP TABLE t1,t2;
|
||||
|
@ -632,3 +632,22 @@ select * from t2 right join t1 on t2.a=t1.a;
|
||||
select straight_join * from t2 right join t1 on t2.a=t1.a;
|
||||
|
||||
DROP TABLE t0,t1,t2,t3;
|
||||
|
||||
#
|
||||
# Test for bug #9017: left join mistakingly converted to inner join
|
||||
#
|
||||
|
||||
CREATE TABLE t1 (a int PRIMARY KEY, b int);
|
||||
CREATE TABLE t2 (a int PRIMARY KEY, b int);
|
||||
|
||||
INSERT INTO t1 VALUES (1,1), (2,1), (3,1), (4,2);
|
||||
INSERT INTO t2 VALUES (1,2), (2,2);
|
||||
|
||||
SELECT * FROM t1 LEFT JOIN t2 ON t1.a=t2.a;
|
||||
SELECT * FROM t1 LEFT JOIN t2 ON t1.a=t2.a WHERE t1.b=1;
|
||||
SELECT * FROM t1 LEFT JOIN t2 ON t1.a=t2.a
|
||||
WHERE t1.b=1 XOR (NOT ISNULL(t2.a) AND t2.b=1);
|
||||
|
||||
DROP TABLE t1,t2;
|
||||
|
||||
|
||||
|
18
sql/field.cc
18
sql/field.cc
@ -7162,6 +7162,24 @@ void create_field::create_length_to_internal_length(void)
|
||||
}
|
||||
|
||||
|
||||
void create_field::init_for_tmp_table(enum_field_types sql_type_arg,
|
||||
uint32 length_arg, uint32 decimals,
|
||||
bool maybe_null, bool is_unsigned)
|
||||
{
|
||||
field_name= "";
|
||||
sql_type= sql_type_arg;
|
||||
length= length_arg;;
|
||||
unireg_check= Field::NONE;
|
||||
interval= 0;
|
||||
charset= &my_charset_bin;
|
||||
geom_type= Field::GEOM_GEOMETRY;
|
||||
pack_flag= (FIELDFLAG_NUMBER |
|
||||
((decimals & FIELDFLAG_MAX_DEC) << FIELDFLAG_DEC_SHIFT) |
|
||||
(maybe_null ? FIELDFLAG_MAYBE_NULL : 0) |
|
||||
(is_unsigned ? 0 : FIELDFLAG_DECIMAL));
|
||||
}
|
||||
|
||||
|
||||
enum_field_types get_blob_type_from_length(ulong length)
|
||||
{
|
||||
enum_field_types type;
|
||||
|
@ -1340,7 +1340,8 @@ public:
|
||||
Create field class for CREATE TABLE
|
||||
*/
|
||||
|
||||
class create_field :public Sql_alloc {
|
||||
class create_field :public Sql_alloc
|
||||
{
|
||||
public:
|
||||
const char *field_name;
|
||||
const char *change; // If done with alter table
|
||||
@ -1362,6 +1363,11 @@ public:
|
||||
create_field() :after(0) {}
|
||||
create_field(Field *field, Field *orig_field);
|
||||
void create_length_to_internal_length(void);
|
||||
|
||||
/* Init for a tmp table field. To be extended if need be. */
|
||||
void init_for_tmp_table(enum_field_types sql_type_arg,
|
||||
uint32 max_length, uint32 decimals,
|
||||
bool maybe_null, bool is_unsigned);
|
||||
};
|
||||
|
||||
|
||||
|
@ -692,6 +692,10 @@ check_trx_exists(
|
||||
trx->mysql_query_str = &(thd->query);
|
||||
trx->active_trans = 0;
|
||||
|
||||
/* Update the info whether we should skip XA steps that eat
|
||||
CPU time */
|
||||
trx->support_xa = (ibool)(thd->variables.innodb_support_xa);
|
||||
|
||||
thd->ha_data[innobase_hton.slot] = trx;
|
||||
} else {
|
||||
if (trx->magic_n != TRX_MAGIC_N) {
|
||||
@ -1436,6 +1440,9 @@ innobase_commit(
|
||||
|
||||
trx = check_trx_exists(thd);
|
||||
|
||||
/* Update the info whether we should skip XA steps that eat CPU time */
|
||||
trx->support_xa = (ibool)(thd->variables.innodb_support_xa);
|
||||
|
||||
/* Release a possible FIFO ticket and search latch. Since we will
|
||||
reserve the kernel mutex, we have to release the search system latch
|
||||
first to obey the latching order. */
|
||||
@ -1622,6 +1629,9 @@ innobase_rollback(
|
||||
|
||||
trx = check_trx_exists(thd);
|
||||
|
||||
/* Update the info whether we should skip XA steps that eat CPU time */
|
||||
trx->support_xa = (ibool)(thd->variables.innodb_support_xa);
|
||||
|
||||
/* Release a possible FIFO ticket and search latch. Since we will
|
||||
reserve the kernel mutex, we have to release the search system latch
|
||||
first to obey the latching order. */
|
||||
@ -6310,6 +6320,11 @@ innobase_xa_prepare(
|
||||
int error = 0;
|
||||
trx_t* trx;
|
||||
|
||||
if (!thd->variables.innodb_support_xa) {
|
||||
|
||||
return(0);
|
||||
}
|
||||
|
||||
trx = check_trx_exists(thd);
|
||||
|
||||
trx->xid=thd->transaction.xid;
|
||||
|
125
sql/item.cc
125
sql/item.cc
@ -33,6 +33,131 @@ static void mark_as_dependent(THD *thd,
|
||||
|
||||
const String my_null_string("NULL", 4, default_charset_info);
|
||||
|
||||
/****************************************************************************/
|
||||
|
||||
/* Hybrid_type_traits {_real} */
|
||||
|
||||
void Hybrid_type_traits::fix_length_and_dec(Item *item, Item *arg) const
|
||||
{
|
||||
item->decimals= NOT_FIXED_DEC;
|
||||
item->max_length= item->float_length(arg->decimals);
|
||||
}
|
||||
|
||||
|
||||
const Hybrid_type_traits *Hybrid_type_traits::instance()
|
||||
{
|
||||
const static Hybrid_type_traits real_traits;
|
||||
return &real_traits;
|
||||
}
|
||||
|
||||
|
||||
my_decimal *
|
||||
Hybrid_type_traits::val_decimal(Hybrid_type *val, my_decimal *to) const
|
||||
{
|
||||
double2my_decimal(E_DEC_FATAL_ERROR, val->real, val->dec_buf);
|
||||
return val->dec_buf;
|
||||
}
|
||||
|
||||
|
||||
String *
|
||||
Hybrid_type_traits::val_str(Hybrid_type *val, String *to, uint8 decimals) const
|
||||
{
|
||||
to->set(val->real, decimals, &my_charset_bin);
|
||||
return to;
|
||||
}
|
||||
|
||||
/* Hybrid_type_traits_decimal */
|
||||
|
||||
const Hybrid_type_traits_decimal *Hybrid_type_traits_decimal::instance()
|
||||
{
|
||||
const static Hybrid_type_traits_decimal decimal_traits;
|
||||
return &decimal_traits;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
Hybrid_type_traits_decimal::fix_length_and_dec(Item *item, Item *arg) const
|
||||
{
|
||||
item->decimals= arg->decimals;
|
||||
item->max_length= min(arg->max_length + DECIMAL_LONGLONG_DIGITS,
|
||||
DECIMAL_MAX_LENGTH);
|
||||
}
|
||||
|
||||
|
||||
void Hybrid_type_traits_decimal::set_zero(Hybrid_type *val) const
|
||||
{
|
||||
my_decimal_set_zero(&val->dec_buf[0]);
|
||||
val->used_dec_buf_no= 0;
|
||||
}
|
||||
|
||||
|
||||
void Hybrid_type_traits_decimal::add(Hybrid_type *val, Field *f) const
|
||||
{
|
||||
my_decimal_add(E_DEC_FATAL_ERROR,
|
||||
&val->dec_buf[val->used_dec_buf_no ^ 1],
|
||||
&val->dec_buf[val->used_dec_buf_no],
|
||||
f->val_decimal(&val->dec_buf[2]));
|
||||
val->used_dec_buf_no^= 1;
|
||||
}
|
||||
|
||||
|
||||
void Hybrid_type_traits_decimal::div(Hybrid_type *val, ulonglong u) const
|
||||
{
|
||||
int2my_decimal(E_DEC_FATAL_ERROR, u, TRUE, &val->dec_buf[2]);
|
||||
/* XXX: what is '4' for scale? */
|
||||
my_decimal_div(E_DEC_FATAL_ERROR,
|
||||
&val->dec_buf[val->used_dec_buf_no ^ 1],
|
||||
&val->dec_buf[val->used_dec_buf_no],
|
||||
&val->dec_buf[2], 4);
|
||||
val->used_dec_buf_no^= 1;
|
||||
}
|
||||
|
||||
|
||||
longlong
|
||||
Hybrid_type_traits_decimal::val_int(Hybrid_type *val, bool unsigned_flag) const
|
||||
{
|
||||
longlong result;
|
||||
my_decimal2int(E_DEC_FATAL_ERROR, &val->dec_buf[val->used_dec_buf_no],
|
||||
unsigned_flag, &result);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
double
|
||||
Hybrid_type_traits_decimal::val_real(Hybrid_type *val) const
|
||||
{
|
||||
my_decimal2double(E_DEC_FATAL_ERROR, &val->dec_buf[val->used_dec_buf_no],
|
||||
&val->real);
|
||||
return val->real;
|
||||
}
|
||||
|
||||
|
||||
String *
|
||||
Hybrid_type_traits_decimal::val_str(Hybrid_type *val, String *to,
|
||||
uint8 decimals) const
|
||||
{
|
||||
my_decimal_round(E_DEC_FATAL_ERROR, &val->dec_buf[val->used_dec_buf_no],
|
||||
decimals, FALSE, &val->dec_buf[2]);
|
||||
my_decimal2string(E_DEC_FATAL_ERROR, &val->dec_buf[2], 0, 0, 0, to);
|
||||
return to;
|
||||
}
|
||||
|
||||
/* Hybrid_type_traits_integer */
|
||||
|
||||
const Hybrid_type_traits_integer *Hybrid_type_traits_integer::instance()
|
||||
{
|
||||
const static Hybrid_type_traits_integer integer_traits;
|
||||
return &integer_traits;
|
||||
}
|
||||
|
||||
void
|
||||
Hybrid_type_traits_integer::fix_length_and_dec(Item *item, Item *arg) const
|
||||
{
|
||||
item->decimals= 0;
|
||||
item->max_length= 21;
|
||||
item->unsigned_flag= 0;
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
** Item functions
|
||||
*****************************************************************************/
|
||||
|
114
sql/item.h
114
sql/item.h
@ -106,6 +106,120 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/*************************************************************************/
|
||||
/*
|
||||
A framework to easily handle different return types for hybrid items
|
||||
(hybrid item is an item whose operand can be of any type, e.g. integer,
|
||||
real, decimal).
|
||||
*/
|
||||
|
||||
struct Hybrid_type_traits;
|
||||
|
||||
struct Hybrid_type
|
||||
{
|
||||
longlong integer;
|
||||
|
||||
double real;
|
||||
/*
|
||||
Use two decimal buffers interchangeably to speed up += operation
|
||||
which has no native support in decimal library.
|
||||
Hybrid_type+= arg is implemented as dec_buf[1]= dec_buf[0] + arg.
|
||||
The third decimal is used as a handy temporary storage.
|
||||
*/
|
||||
my_decimal dec_buf[3];
|
||||
int used_dec_buf_no;
|
||||
|
||||
/*
|
||||
Traits moved to a separate class to
|
||||
a) be able to easily change object traits in runtime
|
||||
b) they work as a differentiator for the union above
|
||||
*/
|
||||
const Hybrid_type_traits *traits;
|
||||
|
||||
Hybrid_type() {}
|
||||
/* XXX: add traits->copy() when needed */
|
||||
Hybrid_type(const Hybrid_type &rhs) :traits(rhs.traits) {}
|
||||
};
|
||||
|
||||
|
||||
/* Hybryd_type_traits interface + default implementation for REAL_RESULT */
|
||||
|
||||
struct Hybrid_type_traits
|
||||
{
|
||||
virtual Item_result type() const { return REAL_RESULT; }
|
||||
|
||||
virtual void
|
||||
fix_length_and_dec(Item *item, Item *arg) const;
|
||||
|
||||
/* Hybrid_type operations. */
|
||||
virtual void set_zero(Hybrid_type *val) const { val->real= 0.0; }
|
||||
virtual void add(Hybrid_type *val, Field *f) const
|
||||
{ val->real+= f->val_real(); }
|
||||
virtual void div(Hybrid_type *val, ulonglong u) const
|
||||
{ val->real/= ulonglong2double(u); }
|
||||
|
||||
virtual longlong val_int(Hybrid_type *val, bool unsigned_flag) const
|
||||
{ return (longlong) val->real; }
|
||||
virtual double val_real(Hybrid_type *val) const { return val->real; }
|
||||
virtual my_decimal *val_decimal(Hybrid_type *val, my_decimal *buf) const;
|
||||
virtual String *val_str(Hybrid_type *val, String *buf, uint8 decimals) const;
|
||||
static const Hybrid_type_traits *instance();
|
||||
};
|
||||
|
||||
|
||||
struct Hybrid_type_traits_decimal: public Hybrid_type_traits
|
||||
{
|
||||
virtual Item_result type() const { return DECIMAL_RESULT; }
|
||||
|
||||
virtual void
|
||||
fix_length_and_dec(Item *arg, Item *item) const;
|
||||
|
||||
/* Hybrid_type operations. */
|
||||
virtual void set_zero(Hybrid_type *val) const;
|
||||
virtual void add(Hybrid_type *val, Field *f) const;
|
||||
virtual void div(Hybrid_type *val, ulonglong u) const;
|
||||
|
||||
virtual longlong val_int(Hybrid_type *val, bool unsigned_flag) const;
|
||||
virtual double val_real(Hybrid_type *val) const;
|
||||
virtual my_decimal *val_decimal(Hybrid_type *val, my_decimal *buf) const
|
||||
{ return &val->dec_buf[val->used_dec_buf_no]; }
|
||||
virtual String *val_str(Hybrid_type *val, String *buf, uint8 decimals) const;
|
||||
static const Hybrid_type_traits_decimal *instance();
|
||||
};
|
||||
|
||||
|
||||
struct Hybrid_type_traits_integer: public Hybrid_type_traits
|
||||
{
|
||||
virtual Item_result type() const { return INT_RESULT; }
|
||||
|
||||
virtual void
|
||||
fix_length_and_dec(Item *arg, Item *item) const;
|
||||
|
||||
/* Hybrid_type operations. */
|
||||
virtual void set_zero(Hybrid_type *val) const
|
||||
{ val->integer= 0; }
|
||||
virtual void add(Hybrid_type *val, Field *f) const
|
||||
{ val->integer+= f->val_int(); }
|
||||
virtual void div(Hybrid_type *val, ulonglong u) const
|
||||
{ val->integer/= (longlong) u; }
|
||||
|
||||
virtual longlong val_int(Hybrid_type *val, bool unsigned_flag) const
|
||||
{ return val->integer; }
|
||||
virtual double val_real(Hybrid_type *val) const
|
||||
{ return (double) val->integer; }
|
||||
virtual my_decimal *val_decimal(Hybrid_type *val, my_decimal *buf) const
|
||||
{
|
||||
int2my_decimal(E_DEC_FATAL_ERROR, val->integer, 0, &val->dec_buf[2]);
|
||||
return &val->dec_buf[2];
|
||||
}
|
||||
virtual String *val_str(Hybrid_type *val, String *buf, uint8 decimals) const
|
||||
{ buf->set(val->integer, &my_charset_bin); return buf;}
|
||||
static const Hybrid_type_traits_integer *instance();
|
||||
};
|
||||
|
||||
/*************************************************************************/
|
||||
|
||||
typedef bool (Item::*Item_processor)(byte *arg);
|
||||
typedef Item* (Item::*Item_transformer) (byte *arg);
|
||||
|
||||
|
@ -1237,6 +1237,7 @@ public:
|
||||
enum Type type() const { return FUNC_ITEM; }
|
||||
longlong val_int();
|
||||
const char *func_name() const { return "xor"; }
|
||||
table_map not_null_tables() const { return and_tables_cache; }
|
||||
};
|
||||
|
||||
|
||||
|
366
sql/item_sum.cc
366
sql/item_sum.cc
@ -456,11 +456,30 @@ my_decimal *Item_sum_sum::val_decimal(my_decimal *val)
|
||||
return val_decimal_from_real(val);
|
||||
}
|
||||
|
||||
/***************************************************************************/
|
||||
|
||||
/* Item_sum_sum_distinct */
|
||||
C_MODE_START
|
||||
|
||||
Item_sum_sum_distinct::Item_sum_sum_distinct(Item *item)
|
||||
:Item_sum_sum(item), tree(0)
|
||||
/* Declarations for auxilary C-callbacks */
|
||||
|
||||
static int simple_raw_key_cmp(void* arg, const void* key1, const void* key2)
|
||||
{
|
||||
return memcmp(key1, key2, *(uint *) arg);
|
||||
}
|
||||
|
||||
|
||||
static int item_sum_distinct_walk(void *element, element_count num_of_dups,
|
||||
void *item)
|
||||
{
|
||||
return ((Item_sum_distinct*) (item))->unique_walk_function(element);
|
||||
}
|
||||
|
||||
C_MODE_END
|
||||
|
||||
/* Item_sum_distinct */
|
||||
|
||||
Item_sum_distinct::Item_sum_distinct(Item *item_arg)
|
||||
:Item_sum_num(item_arg), tree(0)
|
||||
{
|
||||
/*
|
||||
quick_group is an optimizer hint, which means that GROUP BY can be
|
||||
@ -472,239 +491,242 @@ Item_sum_sum_distinct::Item_sum_sum_distinct(Item *item)
|
||||
}
|
||||
|
||||
|
||||
Item_sum_sum_distinct::Item_sum_sum_distinct(THD *thd,
|
||||
Item_sum_sum_distinct *original)
|
||||
:Item_sum_sum(thd, original), tree(0), dec_bin_buff(original->dec_bin_buff)
|
||||
Item_sum_distinct::Item_sum_distinct(THD *thd, Item_sum_distinct *original)
|
||||
:Item_sum_num(thd, original), val(original->val), tree(0),
|
||||
table_field_type(original->table_field_type)
|
||||
{
|
||||
quick_group= 0;
|
||||
}
|
||||
|
||||
|
||||
void Item_sum_sum_distinct::fix_length_and_dec()
|
||||
/*
|
||||
Behaves like an Integer except to fix_length_and_dec().
|
||||
Additionally div() converts val with this traits to a val with true
|
||||
decimal traits along with conversion of integer value to decimal value.
|
||||
This is to speedup SUM/AVG(DISTINCT) evaluation for 8-32 bit integer
|
||||
values.
|
||||
*/
|
||||
|
||||
struct Hybrid_type_traits_fast_decimal: public
|
||||
Hybrid_type_traits_integer
|
||||
{
|
||||
Item_sum_sum::fix_length_and_dec();
|
||||
if (hybrid_type == DECIMAL_RESULT)
|
||||
virtual Item_result type() const { return DECIMAL_RESULT; }
|
||||
virtual void fix_length_and_dec(Item *item, Item *arg) const
|
||||
{ Hybrid_type_traits_decimal::instance()->fix_length_and_dec(item, arg); }
|
||||
|
||||
virtual void div(Hybrid_type *val, ulonglong u) const
|
||||
{
|
||||
dec_bin_buff= (byte *)
|
||||
sql_alloc(my_decimal_get_binary_size(args[0]->max_length,
|
||||
args[0]->decimals));
|
||||
int2my_decimal(E_DEC_FATAL_ERROR, val->integer, 0, val->dec_buf);
|
||||
val->used_dec_buf_no= 0;
|
||||
val->traits= Hybrid_type_traits_decimal::instance();
|
||||
val->traits->div(val, u);
|
||||
}
|
||||
static const Hybrid_type_traits_fast_decimal *instance()
|
||||
{
|
||||
static const Hybrid_type_traits_fast_decimal fast_decimal_traits;
|
||||
return &fast_decimal_traits;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
void Item_sum_distinct::fix_length_and_dec()
|
||||
{
|
||||
DBUG_ASSERT(args[0]->fixed);
|
||||
|
||||
table_field_type= args[0]->field_type();
|
||||
|
||||
/* Adjust tmp table type according to the chosen aggregation type */
|
||||
switch (args[0]->result_type()) {
|
||||
case STRING_RESULT:
|
||||
case REAL_RESULT:
|
||||
val.traits= Hybrid_type_traits::instance();
|
||||
if (table_field_type != MYSQL_TYPE_FLOAT)
|
||||
table_field_type= MYSQL_TYPE_DOUBLE;
|
||||
break;
|
||||
case INT_RESULT:
|
||||
/*
|
||||
Preserving int8, int16, int32 field types gives ~10% performance boost
|
||||
as the size of result tree becomes significantly smaller.
|
||||
Another speed up we gain by using longlong for intermediate
|
||||
calculations. The range of int64 is enough to hold sum 2^32 distinct
|
||||
integers each <= 2^32.
|
||||
*/
|
||||
if (table_field_type == MYSQL_TYPE_INT24 ||
|
||||
table_field_type >= MYSQL_TYPE_TINY &&
|
||||
table_field_type <= MYSQL_TYPE_LONG)
|
||||
{
|
||||
val.traits= Hybrid_type_traits_fast_decimal::instance();
|
||||
break;
|
||||
}
|
||||
table_field_type= MYSQL_TYPE_LONGLONG;
|
||||
/* fallthrough */
|
||||
case DECIMAL_RESULT:
|
||||
val.traits= Hybrid_type_traits_decimal::instance();
|
||||
if (table_field_type != MYSQL_TYPE_LONGLONG)
|
||||
table_field_type= MYSQL_TYPE_NEWDECIMAL;
|
||||
break;
|
||||
case ROW_RESULT:
|
||||
default:
|
||||
DBUG_ASSERT(0);
|
||||
}
|
||||
val.traits->fix_length_and_dec(this, args[0]);
|
||||
}
|
||||
|
||||
|
||||
Item *
|
||||
Item_sum_sum_distinct::copy_or_same(THD *thd)
|
||||
bool Item_sum_distinct::setup(THD *thd)
|
||||
{
|
||||
return new (thd->mem_root) Item_sum_sum_distinct(thd, this);
|
||||
}
|
||||
List<create_field> field_list;
|
||||
create_field field_def; /* field definition */
|
||||
|
||||
C_MODE_START
|
||||
|
||||
static int simple_raw_key_cmp(void* arg, const void* key1, const void* key2)
|
||||
{
|
||||
return memcmp(key1, key2, *(uint *) arg);
|
||||
}
|
||||
|
||||
C_MODE_END
|
||||
|
||||
|
||||
bool Item_sum_sum_distinct::setup(THD *thd)
|
||||
{
|
||||
DBUG_ENTER("Item_sum_sum_distinct::setup");
|
||||
SELECT_LEX *select_lex= thd->lex->current_select;
|
||||
/* what does it mean??? */
|
||||
if (select_lex->linkage == GLOBAL_OPTIONS_TYPE)
|
||||
DBUG_RETURN(1);
|
||||
DBUG_ENTER("Item_sum_distinct::setup");
|
||||
|
||||
DBUG_ASSERT(tree == 0); /* setup can not be called twice */
|
||||
|
||||
/*
|
||||
Uniques handles all unique elements in a tree until they can't fit in.
|
||||
Then thee tree is dumped to the temporary file.
|
||||
See class Unique for details.
|
||||
Virtual table and the tree are created anew on each re-execution of
|
||||
PS/SP. Hence all further allocations are performed in the runtime
|
||||
mem_root.
|
||||
*/
|
||||
if (field_list.push_back(&field_def))
|
||||
return TRUE;
|
||||
|
||||
null_value= maybe_null= 1;
|
||||
/*
|
||||
TODO: if underlying item result fits in 4 bytes we can take advantage
|
||||
of it and have tree of long/ulong. It gives 10% performance boost
|
||||
*/
|
||||
quick_group= 0;
|
||||
|
||||
DBUG_ASSERT(args[0]->fixed);
|
||||
|
||||
field_def.init_for_tmp_table(table_field_type, args[0]->max_length,
|
||||
args[0]->decimals, args[0]->maybe_null,
|
||||
args[0]->unsigned_flag);
|
||||
|
||||
if (! (table= create_virtual_tmp_table(thd, field_list)))
|
||||
return TRUE;
|
||||
|
||||
/* XXX: check that the case of CHAR(0) works OK */
|
||||
tree_key_length= table->s->reclength - table->s->null_bytes;
|
||||
|
||||
/*
|
||||
It's safe to use key_length here as even if we do copy_or_same()
|
||||
the new item will just share the old items key_length, which will not
|
||||
change or disappear during the life time of this item.
|
||||
Unique handles all unique elements in a tree until they can't fit
|
||||
in. Then the tree is dumped to the temporary file. We can use
|
||||
simple_raw_key_cmp because the table contains numbers only; decimals
|
||||
are converted to binary representation as well.
|
||||
*/
|
||||
key_length= ((hybrid_type == DECIMAL_RESULT) ?
|
||||
my_decimal_get_binary_size(args[0]->max_length,
|
||||
args[0]->decimals) :
|
||||
sizeof(double));
|
||||
tree= new Unique(simple_raw_key_cmp, &key_length, key_length,
|
||||
tree= new Unique(simple_raw_key_cmp, &tree_key_length, tree_key_length,
|
||||
thd->variables.max_heap_table_size);
|
||||
DBUG_PRINT("info", ("tree 0x%lx, key length %d", (ulong)tree,
|
||||
key_length));
|
||||
|
||||
DBUG_RETURN(tree == 0);
|
||||
}
|
||||
|
||||
void Item_sum_sum_distinct::clear()
|
||||
|
||||
bool Item_sum_distinct::add()
|
||||
{
|
||||
DBUG_ENTER("Item_sum_sum_distinct::clear");
|
||||
args[0]->save_in_field(table->field[0], FALSE);
|
||||
if (!table->field[0]->is_null())
|
||||
{
|
||||
DBUG_ASSERT(tree);
|
||||
null_value= 0;
|
||||
/*
|
||||
'0' values are also stored in the tree. This doesn't matter
|
||||
for SUM(DISTINCT), but is important for AVG(DISTINCT)
|
||||
*/
|
||||
return tree->unique_add(table->field[0]->ptr);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
bool Item_sum_distinct::unique_walk_function(void *element)
|
||||
{
|
||||
memcpy(table->field[0]->ptr, element, tree_key_length);
|
||||
++count;
|
||||
val.traits->add(&val, table->field[0]);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void Item_sum_distinct::clear()
|
||||
{
|
||||
DBUG_ENTER("Item_sum_distinct::clear");
|
||||
DBUG_ASSERT(tree != 0); /* we always have a tree */
|
||||
null_value= 1;
|
||||
null_value= 1;
|
||||
tree->reset();
|
||||
DBUG_VOID_RETURN;
|
||||
}
|
||||
|
||||
void Item_sum_sum_distinct::cleanup()
|
||||
void Item_sum_distinct::cleanup()
|
||||
{
|
||||
Item_sum_num::cleanup();
|
||||
delete tree;
|
||||
tree= 0;
|
||||
table= 0;
|
||||
}
|
||||
|
||||
|
||||
bool Item_sum_sum_distinct::add()
|
||||
Item_sum_distinct::~Item_sum_distinct()
|
||||
{
|
||||
DBUG_ENTER("Item_sum_sum_distinct::add");
|
||||
if (hybrid_type == DECIMAL_RESULT)
|
||||
{
|
||||
my_decimal value, *val= args[0]->val_decimal(&value);
|
||||
if (!args[0]->null_value)
|
||||
{
|
||||
DBUG_ASSERT(tree != 0);
|
||||
null_value= 0;
|
||||
my_decimal2binary(E_DEC_FATAL_ERROR, val, (char *) dec_bin_buff,
|
||||
args[0]->max_length, args[0]->decimals);
|
||||
DBUG_RETURN(tree->unique_add(dec_bin_buff));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* args[0]->val() may reset args[0]->null_value */
|
||||
double val= args[0]->val_real();
|
||||
if (!args[0]->null_value)
|
||||
{
|
||||
DBUG_ASSERT(tree != 0);
|
||||
null_value= 0;
|
||||
DBUG_PRINT("info", ("real: %lg, tree 0x%lx", val, (ulong)tree));
|
||||
if (val)
|
||||
DBUG_RETURN(tree->unique_add(&val));
|
||||
}
|
||||
else
|
||||
DBUG_PRINT("info", ("real: NULL"));
|
||||
}
|
||||
DBUG_RETURN(0);
|
||||
delete tree;
|
||||
/* no need to free the table */
|
||||
}
|
||||
|
||||
|
||||
void Item_sum_sum_distinct::add_real(double val)
|
||||
void Item_sum_distinct::calculate_val_and_count()
|
||||
{
|
||||
DBUG_ENTER("Item_sum_sum_distinct::add_real");
|
||||
sum+= val;
|
||||
DBUG_PRINT("info", ("sum %lg, val %lg", sum, val));
|
||||
DBUG_VOID_RETURN;
|
||||
}
|
||||
|
||||
|
||||
void Item_sum_sum_distinct::add_decimal(byte *val)
|
||||
{
|
||||
binary2my_decimal(E_DEC_FATAL_ERROR, (char *) val, &tmp_dec,
|
||||
args[0]->max_length, args[0]->decimals);
|
||||
my_decimal_add(E_DEC_FATAL_ERROR, dec_buffs + (curr_dec_buff^1),
|
||||
&tmp_dec, dec_buffs + curr_dec_buff);
|
||||
curr_dec_buff^= 1;
|
||||
}
|
||||
|
||||
C_MODE_START
|
||||
|
||||
static int sum_sum_distinct_real(void *element, element_count num_of_dups,
|
||||
void *item_sum_sum_distinct)
|
||||
{
|
||||
((Item_sum_sum_distinct *)
|
||||
(item_sum_sum_distinct))->add_real(* (double *) element);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int sum_sum_distinct_decimal(void *element, element_count num_of_dups,
|
||||
void *item_sum_sum_distinct)
|
||||
{
|
||||
((Item_sum_sum_distinct *)
|
||||
(item_sum_sum_distinct))->add_decimal((byte *)element);
|
||||
return 0;
|
||||
}
|
||||
|
||||
C_MODE_END
|
||||
|
||||
|
||||
double Item_sum_sum_distinct::val_real()
|
||||
{
|
||||
DBUG_ENTER("Item_sum_sum_distinct::val");
|
||||
count= 0;
|
||||
val.traits->set_zero(&val);
|
||||
/*
|
||||
We don't have a tree only if 'setup()' hasn't been called;
|
||||
this is the case of sql_select.cc:return_zero_rows.
|
||||
*/
|
||||
if (hybrid_type == DECIMAL_RESULT)
|
||||
if (tree)
|
||||
{
|
||||
/* Item_sum_sum_distinct::val_decimal do not use argument */
|
||||
my_decimal *val= val_decimal(0);
|
||||
if (!null_value)
|
||||
my_decimal2double(E_DEC_FATAL_ERROR, val, &sum);
|
||||
table->field[0]->set_notnull();
|
||||
tree->walk(item_sum_distinct_walk, (void*) this);
|
||||
}
|
||||
else
|
||||
{
|
||||
sum= 0.0;
|
||||
DBUG_PRINT("info", ("tree 0x%lx", (ulong)tree));
|
||||
if (tree)
|
||||
tree->walk(sum_sum_distinct_real, (void *) this);
|
||||
}
|
||||
DBUG_RETURN(sum);
|
||||
}
|
||||
|
||||
|
||||
my_decimal *Item_sum_sum_distinct::val_decimal(my_decimal *fake)
|
||||
double Item_sum_distinct::val_real()
|
||||
{
|
||||
if (hybrid_type == DECIMAL_RESULT)
|
||||
{
|
||||
my_decimal_set_zero(dec_buffs);
|
||||
curr_dec_buff= 0;
|
||||
if (tree)
|
||||
tree->walk(sum_sum_distinct_decimal, (void *)this);
|
||||
}
|
||||
else
|
||||
{
|
||||
double real= val_real();
|
||||
curr_dec_buff= 0;
|
||||
double2my_decimal(E_DEC_FATAL_ERROR, real, dec_buffs);
|
||||
}
|
||||
return(dec_buffs + curr_dec_buff);
|
||||
calculate_val_and_count();
|
||||
return val.traits->val_real(&val);
|
||||
}
|
||||
|
||||
|
||||
longlong Item_sum_sum_distinct::val_int()
|
||||
my_decimal *Item_sum_distinct::val_decimal(my_decimal *to)
|
||||
{
|
||||
longlong result;
|
||||
if (hybrid_type == DECIMAL_RESULT)
|
||||
{
|
||||
/* Item_sum_sum_distinct::val_decimal do not use argument */
|
||||
my_decimal *val= val_decimal(0);
|
||||
if (!null_value)
|
||||
my_decimal2int(E_DEC_FATAL_ERROR, val, unsigned_flag, &result);
|
||||
}
|
||||
else
|
||||
result= (longlong) val_real();
|
||||
return result;
|
||||
calculate_val_and_count();
|
||||
if (null_value)
|
||||
return 0;
|
||||
return val.traits->val_decimal(&val, to);
|
||||
}
|
||||
|
||||
|
||||
String *Item_sum_sum_distinct::val_str(String *str)
|
||||
longlong Item_sum_distinct::val_int()
|
||||
{
|
||||
DBUG_ASSERT(fixed == 1);
|
||||
if (hybrid_type == DECIMAL_RESULT)
|
||||
return val_string_from_decimal(str);
|
||||
return val_string_from_real(str);
|
||||
calculate_val_and_count();
|
||||
return val.traits->val_int(&val, unsigned_flag);
|
||||
}
|
||||
|
||||
|
||||
/* end of Item_sum_sum_distinct */
|
||||
String *Item_sum_distinct::val_str(String *str)
|
||||
{
|
||||
calculate_val_and_count();
|
||||
if (null_value)
|
||||
return 0;
|
||||
return val.traits->val_str(&val, str, decimals);
|
||||
}
|
||||
|
||||
/* end of Item_sum_distinct */
|
||||
|
||||
/* Item_sum_avg_distinct */
|
||||
|
||||
void
|
||||
Item_sum_avg_distinct::calculate_val_and_count()
|
||||
{
|
||||
Item_sum_distinct::calculate_val_and_count();
|
||||
if (count)
|
||||
val.traits->div(&val, count);
|
||||
}
|
||||
|
||||
|
||||
Item *Item_sum_count::copy_or_same(THD* thd)
|
||||
{
|
||||
|
@ -30,8 +30,8 @@ class Item_sum :public Item_result_field
|
||||
public:
|
||||
enum Sumfunctype
|
||||
{ COUNT_FUNC, COUNT_DISTINCT_FUNC, SUM_FUNC, SUM_DISTINCT_FUNC, AVG_FUNC,
|
||||
MIN_FUNC, MAX_FUNC, UNIQUE_USERS_FUNC, STD_FUNC, VARIANCE_FUNC,
|
||||
SUM_BIT_FUNC, UDF_SUM_FUNC, GROUP_CONCAT_FUNC
|
||||
AVG_DISTINCT_FUNC, MIN_FUNC, MAX_FUNC, UNIQUE_USERS_FUNC, STD_FUNC,
|
||||
VARIANCE_FUNC, SUM_BIT_FUNC, UDF_SUM_FUNC, GROUP_CONCAT_FUNC
|
||||
};
|
||||
|
||||
Item **args, *tmp_args[2];
|
||||
@ -68,6 +68,9 @@ public:
|
||||
a temporary table. Similar to reset(), but must also store value in
|
||||
result_field. Like reset() it is supposed to reset start value to
|
||||
default.
|
||||
This set of methods (reult_field(), reset_field, update_field()) of
|
||||
Item_sum is used only if quick_group is not null. Otherwise
|
||||
copy_or_same() is used to obtain a copy of this item.
|
||||
*/
|
||||
virtual void reset_field()=0;
|
||||
/*
|
||||
@ -161,26 +164,28 @@ public:
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
Item_sum_sum_distinct - SELECT SUM(DISTINCT expr) FROM ...
|
||||
support. See also: MySQL manual, chapter 'Adding New Functions To MySQL'
|
||||
and comments in item_sum.cc.
|
||||
*/
|
||||
|
||||
/* Common class for SUM(DISTINCT), AVG(DISTINCT) */
|
||||
|
||||
class Unique;
|
||||
|
||||
class Item_sum_sum_distinct :public Item_sum_sum
|
||||
class Item_sum_distinct :public Item_sum_num
|
||||
{
|
||||
protected:
|
||||
/* storage for the summation result */
|
||||
ulonglong count;
|
||||
Hybrid_type val;
|
||||
/* storage for unique elements */
|
||||
Unique *tree;
|
||||
byte *dec_bin_buff;
|
||||
my_decimal tmp_dec;
|
||||
uint key_length;
|
||||
private:
|
||||
Item_sum_sum_distinct(THD *thd, Item_sum_sum_distinct *item);
|
||||
TABLE *table;
|
||||
enum enum_field_types table_field_type;
|
||||
uint tree_key_length;
|
||||
protected:
|
||||
Item_sum_distinct(THD *thd, Item_sum_distinct *item);
|
||||
public:
|
||||
Item_sum_sum_distinct(Item *item_par);
|
||||
~Item_sum_sum_distinct() {}
|
||||
|
||||
Item_sum_distinct(Item *item_par);
|
||||
~Item_sum_distinct();
|
||||
|
||||
bool setup(THD *thd);
|
||||
void clear();
|
||||
void cleanup();
|
||||
@ -190,15 +195,54 @@ public:
|
||||
longlong val_int();
|
||||
String *val_str(String *str);
|
||||
|
||||
void add_real(double val);
|
||||
void add_decimal(byte *val);
|
||||
/* XXX: does it need make_unique? */
|
||||
|
||||
enum Sumfunctype sum_func () const { return SUM_DISTINCT_FUNC; }
|
||||
void reset_field() {} // not used
|
||||
void update_field() {} // not used
|
||||
const char *func_name() const { return "sum_distinct"; }
|
||||
Item *copy_or_same(THD* thd);
|
||||
virtual void no_rows_in_result() {}
|
||||
void fix_length_and_dec();
|
||||
enum Item_result result_type () const { return val.traits->type(); }
|
||||
virtual void calculate_val_and_count();
|
||||
virtual bool unique_walk_function(void *elem);
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
Item_sum_sum_distinct - implementation of SUM(DISTINCT expr).
|
||||
See also: MySQL manual, chapter 'Adding New Functions To MySQL'
|
||||
and comments in item_sum.cc.
|
||||
*/
|
||||
|
||||
class Item_sum_sum_distinct :public Item_sum_distinct
|
||||
{
|
||||
private:
|
||||
Item_sum_sum_distinct(THD *thd, Item_sum_sum_distinct *item)
|
||||
:Item_sum_distinct(thd, item) {}
|
||||
public:
|
||||
Item_sum_sum_distinct(Item *item_arg) :Item_sum_distinct(item_arg) {}
|
||||
|
||||
enum Sumfunctype sum_func () const { return SUM_DISTINCT_FUNC; }
|
||||
const char *func_name() const { return "sum_distinct"; }
|
||||
Item *copy_or_same(THD* thd) { return new Item_sum_sum_distinct(thd, this); }
|
||||
};
|
||||
|
||||
|
||||
/* Item_sum_avg_distinct - SELECT AVG(DISTINCT expr) FROM ... */
|
||||
|
||||
class Item_sum_avg_distinct: public Item_sum_distinct
|
||||
{
|
||||
private:
|
||||
Item_sum_avg_distinct(THD *thd, Item_sum_avg_distinct *original)
|
||||
:Item_sum_distinct(thd, original) {}
|
||||
public:
|
||||
Item_sum_avg_distinct(Item *item_arg) : Item_sum_distinct(item_arg) {}
|
||||
|
||||
virtual void calculate_val_and_count();
|
||||
enum Sumfunctype sum_func () const { return AVG_DISTINCT_FUNC; }
|
||||
const char *func_name() const { return "avg_distinct"; }
|
||||
Item *copy_or_same(THD* thd) { return new Item_sum_avg_distinct(thd, this); }
|
||||
};
|
||||
|
||||
|
||||
|
@ -821,7 +821,7 @@ MYSQL_ERROR *push_warning(THD *thd, MYSQL_ERROR::enum_warning_level level, uint
|
||||
const char *msg);
|
||||
void push_warning_printf(THD *thd, MYSQL_ERROR::enum_warning_level level,
|
||||
uint code, const char *format, ...);
|
||||
void mysql_reset_errors(THD *thd);
|
||||
void mysql_reset_errors(THD *thd, bool force= false);
|
||||
bool mysqld_show_warnings(THD *thd, ulong levels_to_show);
|
||||
|
||||
/* sql_handler.cc */
|
||||
|
@ -4216,6 +4216,7 @@ enum options_mysqld
|
||||
OPT_INNODB_STATUS_FILE,
|
||||
OPT_INNODB_MAX_DIRTY_PAGES_PCT,
|
||||
OPT_INNODB_TABLE_LOCKS,
|
||||
OPT_INNODB_SUPPORT_XA,
|
||||
OPT_INNODB_OPEN_FILES,
|
||||
OPT_INNODB_AUTOEXTEND_INCREMENT,
|
||||
OPT_INNODB_SYNC_SPIN_LOOPS,
|
||||
@ -4519,6 +4520,11 @@ Disable with --skip-innodb-doublewrite.", (gptr*) &innobase_use_doublewrite,
|
||||
(gptr*) &global_system_variables.innodb_table_locks,
|
||||
(gptr*) &global_system_variables.innodb_table_locks,
|
||||
0, GET_BOOL, OPT_ARG, 1, 0, 0, 0, 0, 0},
|
||||
{"innodb_support_xa", OPT_INNODB_SUPPORT_XA,
|
||||
"Enable InnoDB support for the XA two-phase commit",
|
||||
(gptr*) &global_system_variables.innodb_support_xa,
|
||||
(gptr*) &global_system_variables.innodb_support_xa,
|
||||
0, GET_BOOL, OPT_ARG, 1, 0, 0, 0, 0, 0},
|
||||
#endif /* End HAVE_INNOBASE_DB */
|
||||
{"isam", OPT_ISAM, "Enable ISAM (if this version of MySQL supports it). \
|
||||
Disable with --skip-isam.",
|
||||
|
@ -392,6 +392,8 @@ sys_var_long_ptr sys_innodb_max_purge_lag("innodb_max_purge_lag",
|
||||
&srv_max_purge_lag);
|
||||
sys_var_thd_bool sys_innodb_table_locks("innodb_table_locks",
|
||||
&SV::innodb_table_locks);
|
||||
sys_var_thd_bool sys_innodb_support_xa("innodb_support_xa",
|
||||
&SV::innodb_support_xa);
|
||||
sys_var_long_ptr sys_innodb_autoextend_increment("innodb_autoextend_increment",
|
||||
&srv_auto_extend_increment);
|
||||
sys_var_long_ptr sys_innodb_sync_spin_loops("innodb_sync_spin_loops",
|
||||
@ -689,6 +691,7 @@ sys_var *sys_variables[]=
|
||||
&sys_innodb_max_dirty_pages_pct,
|
||||
&sys_innodb_max_purge_lag,
|
||||
&sys_innodb_table_locks,
|
||||
&sys_innodb_support_xa,
|
||||
&sys_innodb_max_purge_lag,
|
||||
&sys_innodb_autoextend_increment,
|
||||
&sys_innodb_sync_spin_loops,
|
||||
@ -810,6 +813,7 @@ struct show_var_st init_vars[]= {
|
||||
{"innodb_open_files", (char*) &innobase_open_files, SHOW_LONG },
|
||||
{sys_innodb_sync_spin_loops.name, (char*) &sys_innodb_sync_spin_loops, SHOW_SYS},
|
||||
{sys_innodb_table_locks.name, (char*) &sys_innodb_table_locks, SHOW_SYS},
|
||||
{sys_innodb_support_xa.name, (char*) &sys_innodb_support_xa, SHOW_SYS},
|
||||
{sys_innodb_thread_concurrency.name, (char*) &sys_innodb_thread_concurrency, SHOW_SYS},
|
||||
{sys_innodb_thread_sleep_delay.name, (char*) &sys_innodb_thread_sleep_delay, SHOW_SYS},
|
||||
#endif
|
||||
|
@ -1606,7 +1606,8 @@ static int open_unireg_entry(THD *thd, TABLE *entry, const char *db,
|
||||
if (ha_create_table_from_engine(thd, db, name, TRUE) != 0)
|
||||
goto err;
|
||||
|
||||
thd->clear_error(); // Clear error message
|
||||
mysql_reset_errors(thd, true); // Clear warnings
|
||||
thd->clear_error(); // Clear error message
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -578,6 +578,7 @@ struct system_variables
|
||||
#endif /* HAVE_REPLICATION */
|
||||
#ifdef HAVE_INNOBASE_DB
|
||||
my_bool innodb_table_locks;
|
||||
my_bool innodb_support_xa;
|
||||
#endif /* HAVE_INNOBASE_DB */
|
||||
#ifdef HAVE_NDBCLUSTER_DB
|
||||
ulong ndb_autoincrement_prefetch_sz;
|
||||
|
@ -64,6 +64,7 @@ void MYSQL_ERROR::set_msg(THD *thd, const char *msg_arg)
|
||||
SYNOPSIS
|
||||
mysql_reset_errors()
|
||||
thd Thread handle
|
||||
force Reset warnings even if it has been done before
|
||||
|
||||
IMPLEMENTATION
|
||||
Don't reset warnings if this has already been called for this query.
|
||||
@ -71,14 +72,15 @@ void MYSQL_ERROR::set_msg(THD *thd, const char *msg_arg)
|
||||
in which case push_warnings() has already called this function.
|
||||
*/
|
||||
|
||||
void mysql_reset_errors(THD *thd)
|
||||
void mysql_reset_errors(THD *thd, bool force)
|
||||
{
|
||||
DBUG_ENTER("mysql_reset_errors");
|
||||
if (thd->query_id != thd->warn_id)
|
||||
if (thd->query_id != thd->warn_id || force)
|
||||
{
|
||||
thd->warn_id= thd->query_id;
|
||||
free_root(&thd->warn_root,MYF(0));
|
||||
bzero((char*) thd->warn_count, sizeof(thd->warn_count));
|
||||
if (force) thd->total_warn_count= 0;
|
||||
thd->warn_list.empty();
|
||||
thd->row_count= 1; // by default point to row 1
|
||||
}
|
||||
|
@ -8359,6 +8359,117 @@ create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List<Item> &fields,
|
||||
}
|
||||
|
||||
|
||||
/****************************************************************************/
|
||||
|
||||
/*
|
||||
Create a reduced TABLE object with properly set up Field list from a
|
||||
list of field definitions.
|
||||
|
||||
SYNOPSIS
|
||||
create_virtual_tmp_table()
|
||||
thd connection handle
|
||||
field_list list of column definitions
|
||||
|
||||
DESCRIPTION
|
||||
The created table doesn't have a table handler assotiated with
|
||||
it, has no keys, no group/distinct, no copy_funcs array.
|
||||
The sole purpose of this TABLE object is to use the power of Field
|
||||
class to read/write data to/from table->record[0]. Then one can store
|
||||
the record in any container (RB tree, hash, etc).
|
||||
The table is created in THD mem_root, so are the table's fields.
|
||||
Consequently, if you don't BLOB fields, you don't need to free it.
|
||||
|
||||
RETURN
|
||||
0 if out of memory, TABLE object in case of success
|
||||
*/
|
||||
|
||||
TABLE *create_virtual_tmp_table(THD *thd, List<create_field> &field_list)
|
||||
{
|
||||
uint field_count= field_list.elements;
|
||||
Field **field;
|
||||
create_field *cdef; /* column definition */
|
||||
uint record_length= 0;
|
||||
uint null_count= 0; /* number of columns which may be null */
|
||||
uint null_pack_length; /* NULL representation array length */
|
||||
TABLE_SHARE *s;
|
||||
/* Create the table and list of all fields */
|
||||
TABLE *table= (TABLE*) thd->calloc(sizeof(*table));
|
||||
field= (Field**) thd->alloc((field_count + 1) * sizeof(Field*));
|
||||
if (!table || !field)
|
||||
return 0;
|
||||
|
||||
table->field= field;
|
||||
table->s= s= &table->share_not_to_be_used;
|
||||
s->fields= field_count;
|
||||
|
||||
/* Create all fields and calculate the total length of record */
|
||||
List_iterator_fast<create_field> it(field_list);
|
||||
while ((cdef= it++))
|
||||
{
|
||||
*field= make_field(0, cdef->length,
|
||||
(uchar*) (f_maybe_null(cdef->pack_flag) ? "" : 0),
|
||||
f_maybe_null(cdef->pack_flag) ? 1 : 0,
|
||||
cdef->pack_flag, cdef->sql_type, cdef->charset,
|
||||
cdef->geom_type, cdef->unireg_check,
|
||||
cdef->interval, cdef->field_name, table);
|
||||
if (!*field)
|
||||
goto error;
|
||||
record_length+= (**field).pack_length();
|
||||
if (! ((**field).flags & NOT_NULL_FLAG))
|
||||
++null_count;
|
||||
++field;
|
||||
}
|
||||
*field= NULL; /* mark the end of the list */
|
||||
|
||||
null_pack_length= (null_count + 7)/8;
|
||||
s->reclength= record_length + null_pack_length;
|
||||
s->rec_buff_length= ALIGN_SIZE(s->reclength + 1);
|
||||
table->record[0]= (byte*) thd->alloc(s->rec_buff_length);
|
||||
if (!table->record[0])
|
||||
goto error;
|
||||
|
||||
if (null_pack_length)
|
||||
{
|
||||
table->null_flags= (uchar*) table->record[0];
|
||||
s->null_fields= null_count;
|
||||
s->null_bytes= null_pack_length;
|
||||
}
|
||||
|
||||
table->in_use= thd; /* field->reset() may access table->in_use */
|
||||
{
|
||||
/* Set up field pointers */
|
||||
byte *null_pos= table->record[0];
|
||||
byte *field_pos= null_pos + s->null_bytes;
|
||||
uint null_bit= 1;
|
||||
|
||||
for (field= table->field; *field; ++field)
|
||||
{
|
||||
Field *cur_field= *field;
|
||||
if ((cur_field->flags & NOT_NULL_FLAG))
|
||||
cur_field->move_field((char*) field_pos);
|
||||
else
|
||||
{
|
||||
cur_field->move_field((char*) field_pos, (uchar*) null_pos, null_bit);
|
||||
null_bit<<= 1;
|
||||
if (null_bit == (1 << 8))
|
||||
{
|
||||
++null_pos;
|
||||
null_bit= 1;
|
||||
}
|
||||
}
|
||||
cur_field->reset();
|
||||
|
||||
field_pos+= cur_field->pack_length();
|
||||
}
|
||||
}
|
||||
return table;
|
||||
error:
|
||||
for (field= table->field; *field; ++field)
|
||||
delete *field; /* just invokes field destructor */
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static bool open_tmp_table(TABLE *table)
|
||||
{
|
||||
int error;
|
||||
|
@ -387,6 +387,7 @@ TABLE *create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List<Item> &fields,
|
||||
ORDER *group, bool distinct, bool save_sum_fields,
|
||||
ulong select_options, ha_rows rows_limit,
|
||||
char* alias);
|
||||
TABLE *create_virtual_tmp_table(THD *thd, List<create_field> &field_list);
|
||||
void free_tmp_table(THD *thd, TABLE *entry);
|
||||
void count_field_types(TMP_TABLE_PARAM *param, List<Item> &fields,
|
||||
bool reset_with_sum_func);
|
||||
|
@ -4754,6 +4754,8 @@ udf_expr:
|
||||
sum_expr:
|
||||
AVG_SYM '(' in_sum_expr ')'
|
||||
{ $$=new Item_sum_avg($3); }
|
||||
| AVG_SYM '(' DISTINCT in_sum_expr ')'
|
||||
{ $$=new Item_sum_avg_distinct($4); }
|
||||
| BIT_AND '(' in_sum_expr ')'
|
||||
{ $$=new Item_sum_and($3); }
|
||||
| BIT_OR '(' in_sum_expr ')'
|
||||
|
Loading…
x
Reference in New Issue
Block a user