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:
unknown 2005-03-14 14:47:51 +01:00
commit ebbee9d974
26 changed files with 833 additions and 260 deletions

View File

@ -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

View File

@ -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) {

View File

@ -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 */

View File

@ -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;
}

View File

@ -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);

View File

@ -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);
}
}

View File

@ -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 */

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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);
};

View File

@ -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;

View File

@ -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
*****************************************************************************/

View File

@ -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);

View File

@ -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; }
};

View File

@ -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)
{

View File

@ -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); }
};

View File

@ -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 */

View File

@ -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.",

View File

@ -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

View File

@ -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;
}

View File

@ -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;

View File

@ -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
}

View File

@ -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;

View File

@ -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);

View File

@ -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 ')'