branches/zip: Merge revisions 265:459 from trunk.

This commit is contained in:
marko 2006-04-12 09:32:17 +00:00
parent cb6a8cc100
commit 450bbd7c3b
82 changed files with 4836 additions and 2831 deletions

View file

@ -76,7 +76,7 @@ EXTRA_DIST = include/btr0btr.h include/btr0btr.ic include/btr0cur.h include/btr
include/univ.i include/usr0sess.h include/usr0sess.ic include/usr0types.h \
include/ut0byte.h include/ut0byte.ic include/ut0dbg.h include/ut0lst.h \
include/ut0mem.h include/ut0mem.ic include/ut0rnd.h include/ut0rnd.ic \
include/ut0sort.h include/ut0ut.h include/ut0ut.ic
include/ut0sort.h include/ut0ut.h include/ut0ut.ic include/ut0vec.h include/ut0vec.ic
# Don't update the files from bitkeeper
%::SCCS/s.%

View file

@ -137,7 +137,7 @@ btr_root_get(
root = btr_page_get(space, root_page_no, RW_X_LATCH, mtr);
ut_a((ibool)!!page_is_comp(root) ==
dict_table_is_comp(UT_LIST_GET_FIRST(tree->tree_indexes)->table));
dict_table_is_comp(tree->tree_index->table));
return(root);
}
@ -251,7 +251,7 @@ btr_page_create(
ulint level, /* in: the B-tree level of the page */
mtr_t* mtr) /* in: mtr */
{
dict_index_t* index = UT_LIST_GET_FIRST(tree->tree_indexes);
dict_index_t* index = tree->tree_index;
ut_ad(mtr_memo_contains(mtr, buf_block_align(page),
MTR_MEMO_PAGE_X_FIX));
@ -587,7 +587,7 @@ btr_page_get_father_for_rec(
tuple = dict_tree_build_node_ptr(tree, user_rec, 0, heap,
btr_page_get_level(page, mtr));
index = UT_LIST_GET_FIRST(tree->tree_indexes);
index = tree->tree_index;
/* In the following, we choose just any index from the tree as the
first parameter for btr_cur_search_to_nth_level. */
@ -1155,8 +1155,7 @@ btr_root_raise_and_insert(
/* fprintf(stderr, "Root raise new page no %lu\n",
buf_frame_get_page_no(new_page)); */
ibuf_reset_free_bits(UT_LIST_GET_FIRST(tree->tree_indexes),
new_page);
ibuf_reset_free_bits(tree->tree_index, new_page);
/* Reposition the cursor to the child node */
page_cur_search(new_page, cursor->index, tuple,
PAGE_CUR_LE, page_cursor);
@ -1497,7 +1496,7 @@ btr_insert_on_non_leaf_level(
/* In the following, choose just any index from the tree as the
first parameter for btr_cur_search_to_nth_level. */
btr_cur_search_to_nth_level(UT_LIST_GET_FIRST(tree->tree_indexes),
btr_cur_search_to_nth_level(tree->tree_index,
level, tuple, PAGE_CUR_LE, BTR_CONT_MODIFY_TREE,
&cursor, 0, mtr);
@ -1569,7 +1568,7 @@ btr_attach_half_pages(
btr_node_ptr_set_child_page_no(node_ptr,
buf_block_get_page_zip(buf_block_align(node_ptr)),
rec_get_offsets(node_ptr,
UT_LIST_GET_FIRST(tree->tree_indexes),
tree->tree_index,
NULL, ULINT_UNDEFINED, &heap),
lower_page_no, mtr);
mem_heap_empty(heap);
@ -1887,8 +1886,8 @@ insert_failed:
buf_frame_get_page_no(left_page),
buf_frame_get_page_no(right_page)); */
ut_ad(page_validate(left_page, UT_LIST_GET_FIRST(tree->tree_indexes)));
ut_ad(page_validate(right_page, UT_LIST_GET_FIRST(tree->tree_indexes)));
ut_ad(page_validate(left_page, tree->tree_index));
ut_ad(page_validate(right_page, tree->tree_index));
mem_heap_free(heap);
return(rec);
@ -2039,8 +2038,7 @@ btr_node_ptr_delete(
node_ptr = btr_page_get_father_node_ptr(tree, page, mtr);
btr_cur_position(UT_LIST_GET_FIRST(tree->tree_indexes), node_ptr,
&cursor);
btr_cur_position(tree->tree_index, node_ptr, &cursor);
compressed = btr_cur_pessimistic_delete(&err, TRUE, &cursor, FALSE,
mtr);
ut_a(err == DB_SUCCESS);
@ -2078,7 +2076,7 @@ btr_lift_page_up(
father_page_zip = buf_block_get_page_zip(buf_block_align(father_page));
page_level = btr_page_get_level(page, mtr);
index = UT_LIST_GET_FIRST(tree->tree_indexes);
index = tree->tree_index;
btr_search_drop_page_hash_index(page);
@ -2328,7 +2326,7 @@ btr_discard_only_page_on_level(
== dict_tree_get_page(tree))) {
/* The father is the root page */
dict_index_t* index = UT_LIST_GET_FIRST(tree->tree_indexes);
dict_index_t* index = tree->tree_index;
btr_page_empty(father_page,
buf_block_get_page_zip(buf_block_align(father_page)),
@ -2599,7 +2597,7 @@ btr_check_node_ptr(
ut_a(cmp_dtuple_rec(node_ptr_tuple, node_ptr,
rec_get_offsets(node_ptr,
dict_tree_find_index(tree, node_ptr),
tree->tree_index,
NULL, ULINT_UNDEFINED, &heap)) == 0);
mem_heap_free(heap);
@ -2844,7 +2842,7 @@ btr_validate_level(
space = buf_frame_get_space_id(page);
index = UT_LIST_GET_FIRST(tree->tree_indexes);
index = tree->tree_index;
while (level != btr_page_get_level(page, &mtr)) {
#ifdef UNIV_DEBUG

View file

@ -1738,7 +1738,7 @@ btr_cur_optimistic_update(
new_entry = row_rec_to_index_entry(ROW_COPY_DATA, index, rec, heap);
row_upd_index_replace_new_col_vals_index_pos(new_entry, index, update,
NULL);
FALSE, NULL);
old_rec_size = rec_offs_size(offsets);
new_rec_size = rec_get_converted_size(index, new_entry);
@ -1991,7 +1991,7 @@ btr_cur_pessimistic_update(
new_entry = row_rec_to_index_entry(ROW_COPY_DATA, index, rec, heap);
row_upd_index_replace_new_col_vals_index_pos(new_entry, index, update,
heap);
FALSE, heap);
if (!(flags & BTR_KEEP_SYS_FLAG)) {
row_upd_index_entry_sys_field(new_entry, index, DATA_ROLL_PTR,
roll_ptr);
@ -2067,11 +2067,11 @@ btr_cur_pessimistic_update(
ut_a(rec || optim_err != DB_UNDERFLOW);
if (rec) {
lock_rec_restore_from_page_infimum(rec, page);
offsets = rec_get_offsets(rec, index, offsets,
ULINT_UNDEFINED, &heap);
lock_rec_restore_from_page_infimum(rec, page);
if (!rec_get_deleted_flag(rec, rec_offs_comp(offsets))) {
/* The new inserted record owns its possible externally
stored fields */
@ -3480,7 +3480,10 @@ btr_store_big_rec_extern_fields(
dict_index_t* index, /* in: index of rec; the index tree
MUST be X-latched */
rec_t* rec, /* in/out: record */
const ulint* offsets, /* in: rec_get_offsets(rec, index) */
const ulint* offsets, /* in: rec_get_offsets(rec, index);
the "external storage" flags in offsets
will not correspond to rec when
this function returns */
big_rec_t* big_rec_vec, /* in: vector containing fields
to be stored externally */
mtr_t* local_mtr __attribute__((unused))) /* in: mtr

View file

@ -158,7 +158,7 @@ btr_pcur_copy_stored_position(
mem_free(pcur_receive->old_rec_buf);
}
ut_memcpy((byte*)pcur_receive, (byte*)pcur_donate, sizeof(btr_pcur_t));
ut_memcpy(pcur_receive, pcur_donate, sizeof(btr_pcur_t));
if (pcur_donate->old_rec_buf) {
@ -208,7 +208,7 @@ btr_pcur_restore_position(
if (UNIV_UNLIKELY(cursor->old_stored != BTR_PCUR_OLD_STORED)
|| UNIV_UNLIKELY(cursor->pos_state != BTR_PCUR_WAS_POSITIONED
&& cursor->pos_state != BTR_PCUR_IS_POSITIONED)) {
ut_print_buf(stderr, (const byte*)cursor, sizeof(btr_pcur_t));
ut_print_buf(stderr, cursor, sizeof(btr_pcur_t));
if (cursor->trx_if_known) {
trx_print(stderr, cursor->trx_if_known, 0);
}
@ -259,10 +259,7 @@ btr_pcur_restore_position(
cursor->latch_mode = latch_mode;
#ifdef UNIV_DEBUG
rec = btr_pcur_get_rec(cursor);
index = dict_tree_find_index(
btr_cur_get_tree(
btr_pcur_get_btr_cur(cursor)),
rec);
index = btr_pcur_get_btr_cur(cursor)->index;
heap = mem_heap_create(256);
offsets1 = rec_get_offsets(cursor->old_rec,

View file

@ -24,8 +24,8 @@ ulint btr_search_this_is_zero = 0; /* A dummy variable to fool the
#ifdef UNIV_SEARCH_PERF_STAT
ulint btr_search_n_succ = 0;
#endif /* UNIV_SEARCH_PERF_STAT */
ulint btr_search_n_hash_fail = 0;
#endif /* UNIV_SEARCH_PERF_STAT */
byte btr_sea_pad1[64]; /* padding to prevent other memory update
hotspots from residing on the same memory
@ -169,10 +169,12 @@ btr_search_info_create(
info->last_hash_succ = FALSE;
#ifdef UNIV_SEARCH_PERF_STAT
info->n_hash_succ = 0;
info->n_hash_fail = 0;
info->n_patt_succ = 0;
info->n_searches = 0;
#endif /* UNIV_SEARCH_PERF_STAT */
/* Set some sensible values */
info->n_fields = 1;
@ -484,7 +486,9 @@ btr_search_info_update_slow(
if (cursor->flag == BTR_CUR_HASH_FAIL) {
/* Update the hash node reference, if appropriate */
#ifdef UNIV_SEARCH_PERF_STAT
btr_search_n_hash_fail++;
#endif /* UNIV_SEARCH_PERF_STAT */
rw_lock_x_lock(&btr_search_latch);
@ -869,11 +873,11 @@ failure_unlock:
rw_lock_s_unlock(&btr_search_latch);
}
failure:
info->n_hash_fail++;
cursor->flag = BTR_CUR_HASH_FAIL;
#ifdef UNIV_SEARCH_PERF_STAT
info->n_hash_fail++;
if (info->n_hash_succ > 0) {
info->n_hash_succ--;
}
@ -1604,12 +1608,13 @@ btr_search_validate(void)
mem_heap_t* heap = NULL;
ulint offsets_[REC_OFFS_NORMAL_SIZE];
ulint* offsets = offsets_;
*offsets_ = (sizeof offsets_) / sizeof *offsets_;
/* How many cells to check before temporarily releasing
btr_search_latch. */
ulint chunk_size = 10000;
*offsets_ = (sizeof offsets_) / sizeof *offsets_;
rw_lock_x_lock(&btr_search_latch);
cell_count = hash_get_n_cells(btr_search_sys->hash_index);

View file

@ -120,7 +120,7 @@ buf_flush_ready_for_replace(
fprintf(stderr,
" InnoDB: Error: buffer block state %lu in the LRU list!\n",
(ulong)block->state);
ut_print_buf(stderr, (byte*)block, sizeof(buf_block_t));
ut_print_buf(stderr, block, sizeof(buf_block_t));
return(FALSE);
}

View file

@ -294,14 +294,14 @@ buf_LRU_try_free_flushed_blocks(void)
}
/**********************************************************************
Returns TRUE if less than 15 % of the buffer pool is available. This can be
Returns TRUE if less than 25 % of the buffer pool is available. This can be
used in heuristics to prevent huge transactions eating up the whole buffer
pool for their locks. */
ibool
buf_LRU_buf_pool_running_out(void)
/*==============================*/
/* out: TRUE if less than 15 % of buffer pool
/* out: TRUE if less than 25 % of buffer pool
left */
{
ibool ret = FALSE;
@ -309,7 +309,7 @@ buf_LRU_buf_pool_running_out(void)
mutex_enter(&(buf_pool->mutex));
if (!recv_recovery_on && UT_LIST_GET_LEN(buf_pool->free)
+ UT_LIST_GET_LEN(buf_pool->LRU) < buf_pool->max_size / 7) {
+ UT_LIST_GET_LEN(buf_pool->LRU) < buf_pool->max_size / 4) {
ret = TRUE;
}
@ -340,11 +340,11 @@ loop:
mutex_enter(&(buf_pool->mutex));
if (!recv_recovery_on && UT_LIST_GET_LEN(buf_pool->free)
+ UT_LIST_GET_LEN(buf_pool->LRU) < buf_pool->max_size / 10) {
+ UT_LIST_GET_LEN(buf_pool->LRU) < buf_pool->max_size / 20) {
ut_print_timestamp(stderr);
fprintf(stderr,
" InnoDB: ERROR: over 9 / 10 of the buffer pool is occupied by\n"
" InnoDB: ERROR: over 95 percent of the buffer pool is occupied by\n"
"InnoDB: lock heaps or the adaptive hash index! Check that your\n"
"InnoDB: transactions do not set too many row locks.\n"
"InnoDB: Your buffer pool size is %lu MB. Maybe you should make\n"
@ -356,17 +356,17 @@ loop:
ut_error;
} else if (!recv_recovery_on && UT_LIST_GET_LEN(buf_pool->free)
+ UT_LIST_GET_LEN(buf_pool->LRU) < buf_pool->max_size / 5) {
+ UT_LIST_GET_LEN(buf_pool->LRU) < buf_pool->max_size / 3) {
if (!buf_lru_switched_on_innodb_mon) {
/* Over 80 % of the buffer pool is occupied by lock
/* Over 67 % of the buffer pool is occupied by lock
heaps or the adaptive hash index. This may be a memory
leak! */
ut_print_timestamp(stderr);
fprintf(stderr,
" InnoDB: WARNING: over 4 / 5 of the buffer pool is occupied by\n"
" InnoDB: WARNING: over 67 percent of the buffer pool is occupied by\n"
"InnoDB: lock heaps or the adaptive hash index! Check that your\n"
"InnoDB: transactions do not set too many row locks.\n"
"InnoDB: Your buffer pool size is %lu MB. Maybe you should make\n"
@ -881,10 +881,10 @@ buf_LRU_block_remove_hashed_page(
if (buf_page_hash_get(block->space, block->offset)) {
fprintf(stderr,
"InnoDB: From hash table we find block %p of %lu %lu which is not %p\n",
buf_page_hash_get(block->space, block->offset),
(void*) buf_page_hash_get(block->space, block->offset),
(ulong) buf_page_hash_get(block->space, block->offset)->space,
(ulong) buf_page_hash_get(block->space, block->offset)->offset,
block);
(void*) block);
}
#ifdef UNIV_DEBUG

35
cmakelists.txt Normal file
View file

@ -0,0 +1,35 @@
#SET(CMAKE_CXX_FLAGS_DEBUG "-DSAFEMALLOC -DSAFE_MUTEX")
#SET(CMAKE_C_FLAGS_DEBUG "-DSAFEMALLOC -DSAFE_MUTEX")
ADD_DEFINITIONS(-DMYSQL_SERVER -D_WIN32 -DWIN32 -D_LIB)
INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}/include include)
ADD_LIBRARY(innobase btr/btr0btr.c btr/btr0cur.c btr/btr0pcur.c btr/btr0sea.c
buf/buf0buf.c buf/buf0flu.c buf/buf0lru.c buf/buf0rea.c
data/data0data.c data/data0type.c
dict/dict0boot.c dict/dict0crea.c dict/dict0dict.c dict/dict0load.c dict/dict0mem.c
dyn/dyn0dyn.c
eval/eval0eval.c eval/eval0proc.c
fil/fil0fil.c
fsp/fsp0fsp.c
fut/fut0fut.c fut/fut0lst.c
ha/ha0ha.c ha/hash0hash.c
ibuf/ibuf0ibuf.c
pars/lexyy.c pars/pars0grm.c pars/pars0opt.c pars/pars0pars.c pars/pars0sym.c
lock/lock0lock.c
log/log0log.c log/log0recv.c
mach/mach0data.c
mem/mem0mem.c mem/mem0pool.c
mtr/mtr0log.c mtr/mtr0mtr.c
os/os0file.c os/os0proc.c os/os0sync.c os/os0thread.c
page/page0cur.c page/page0page.c
que/que0que.c
read/read0read.c
rem/rem0cmp.c rem/rem0rec.c
row/row0ins.c row/row0mysql.c row/row0purge.c row/row0row.c row/row0sel.c row/row0uins.c
row/row0umod.c row/row0undo.c row/row0upd.c row/row0vers.c
srv/srv0que.c srv/srv0srv.c srv/srv0start.c
sync/sync0arr.c sync/sync0rw.c sync/sync0sync.c
thr/thr0loc.c
trx/trx0purge.c trx/trx0rec.c trx/trx0roll.c trx/trx0rseg.c trx/trx0sys.c trx/trx0trx.c trx/trx0undo.c
usr/usr0sess.c
ut/ut0byte.c ut/ut0dbg.c ut/ut0mem.c ut/ut0rnd.c ut/ut0ut.c ut/ut0vec.c)

View file

@ -89,6 +89,25 @@ else
CXXFLAGS="$OPTIMIZE_CXXFLAGS -DDBUG_OFF $CXXFLAGS -DDEBUG_OFF"
fi
# NOTE: The flags below are disabled by default since we can't easily get
# rid of the "string over 509 characters in length" warnings, and thus can't
# add -Werror. But it's a good idea to enable these for a test compile
# before shipping a new snapshot to MySQL to catch errors that could make
# the compile fail on non-C99 compilers.
# If using gcc, disallow usage of C99 features to avoid accidentally
# introducing problems on compilers that only implement C89.
#if test "$ac_cv_prog_gcc" = "yes"
#then
# CFLAGS="$CFLAGS -std=c89 -ansi -pedantic -Wno-long-long"
#fi
# If using gcc, add some extra warning flags.
if test "$ac_cv_prog_gcc" = "yes"
then
CFLAGS="$CFLAGS -Werror-implicit-function-declaration"
fi
case "$target_os" in
lin*)
CFLAGS="$CFLAGS -DUNIV_LINUX";;

View file

@ -431,6 +431,22 @@ dfield_print_also_hex(
}
}
/*****************************************************************
Print a dfield value using ut_print_buf. */
void
dfield_print_raw(
/*=============*/
FILE* f, /* in: output stream */
dfield_t* dfield) /* in: dfield */
{
if (dfield->len != UNIV_SQL_NULL) {
ut_print_buf(f, dfield->data, dfield->len);
} else {
fputs(" SQL NULL", f);
}
}
/**************************************************************
The following function prints the contents of a tuple. */
@ -440,7 +456,6 @@ dtuple_print(
FILE* f, /* in: output stream */
dtuple_t* tuple) /* in: tuple */
{
dfield_t* field;
ulint n_fields;
ulint i;
@ -451,13 +466,7 @@ dtuple_print(
for (i = 0; i < n_fields; i++) {
fprintf(f, " %lu:", (ulong) i);
field = dtuple_get_nth_field(tuple, i);
if (field->len != UNIV_SQL_NULL) {
ut_print_buf(f, field->data, field->len);
} else {
fputs(" SQL NULL", f);
}
dfield_print_raw(f, dtuple_get_nth_field(tuple, i));
putc(';', f);
}

View file

@ -216,20 +216,43 @@ dtype_print(
mtype = type->mtype;
prtype = type->prtype;
if (mtype == DATA_VARCHAR) {
switch (mtype) {
case DATA_VARCHAR:
fputs("DATA_VARCHAR", stderr);
} else if (mtype == DATA_CHAR) {
break;
case DATA_CHAR:
fputs("DATA_CHAR", stderr);
} else if (mtype == DATA_BINARY) {
break;
case DATA_BINARY:
fputs("DATA_BINARY", stderr);
} else if (mtype == DATA_INT) {
break;
case DATA_FIXBINARY:
fputs("DATA_FIXBINARY", stderr);
break;
case DATA_BLOB:
fputs("DATA_BLOB", stderr);
break;
case DATA_INT:
fputs("DATA_INT", stderr);
} else if (mtype == DATA_MYSQL) {
break;
case DATA_MYSQL:
fputs("DATA_MYSQL", stderr);
} else if (mtype == DATA_SYS) {
break;
case DATA_SYS:
fputs("DATA_SYS", stderr);
} else {
break;
default:
fprintf(stderr, "type %lu", (ulong) mtype);
break;
}
len = type->len;
@ -254,6 +277,18 @@ dtype_print(
} else {
fprintf(stderr, "prtype %lu", (ulong) prtype);
}
} else {
if (prtype & DATA_UNSIGNED) {
fputs(" DATA_UNSIGNED", stderr);
}
if (prtype & DATA_BINARY_TYPE) {
fputs(" DATA_BINARY_TYPE", stderr);
}
if (prtype & DATA_NOT_NULL) {
fputs(" DATA_NOT_NULL", stderr);
}
}
fprintf(stderr, " len %lu prec %lu", (ulong) len, (ulong) type->prec);

View file

@ -24,6 +24,7 @@ Created 1/8/1996 Heikki Tuuri
#include "pars0pars.h"
#include "trx0roll.h"
#include "usr0sess.h"
#include "ut0vec.h"
/*********************************************************************
Based on a table object, this function builds the entry to be inserted
@ -81,7 +82,7 @@ dict_create_sys_tables_tuple(
dfield = dtuple_get_nth_field(entry, 4);
ptr = mem_heap_alloc(heap, 8);
mach_write_to_8(ptr, table->mix_id);
memset(ptr, 0, 8);
dfield_set_data(dfield, ptr, 8);
/* 7: MIX_LEN --------------------------*/
@ -89,19 +90,13 @@ dict_create_sys_tables_tuple(
dfield = dtuple_get_nth_field(entry, 5);
ptr = mem_heap_alloc(heap, 4);
mach_write_to_4(ptr, table->mix_len);
memset(ptr, 0, 4);
dfield_set_data(dfield, ptr, 4);
/* 8: CLUSTER_NAME ---------------------*/
dfield = dtuple_get_nth_field(entry, 6);
dfield_set_data(dfield, NULL, UNIV_SQL_NULL); /* not supported */
if (table->type == DICT_TABLE_CLUSTER_MEMBER) {
dfield_set_data(dfield, table->cluster_name,
ut_strlen(table->cluster_name));
ut_error; /* Oracle-style clusters are not supported yet */
} else {
dfield_set_data(dfield, NULL, UNIV_SQL_NULL);
}
/* 9: SPACE ----------------------------*/
dfield = dtuple_get_nth_field(entry, 7);
@ -207,7 +202,6 @@ dict_build_table_def_step(
tab_node_t* node) /* in: table create node */
{
dict_table_t* table;
dict_table_t* cluster_table;
dtuple_t* row;
ulint error;
const char* path_or_name;
@ -235,23 +229,6 @@ dict_build_table_def_step(
return(DB_TOO_BIG_RECORD);
}
if (table->type == DICT_TABLE_CLUSTER_MEMBER) {
cluster_table = dict_table_get_low(table->cluster_name);
if (cluster_table == NULL) {
return(DB_CLUSTER_NOT_FOUND);
}
/* Inherit space and mix len from the cluster */
table->space = cluster_table->space;
table->mix_len = cluster_table->mix_len;
table->mix_id = dict_hdr_get_new_id(DICT_HDR_MIX_ID);
}
if (srv_file_per_table) {
/* We create a new single-table tablespace for the table.
We initially let it be 4 pages:
@ -614,15 +591,6 @@ dict_create_index_tree_step(
sys_indexes = dict_sys->sys_indexes;
if (dict_index_is_clust(index)
&& table->type == DICT_TABLE_CLUSTER_MEMBER) {
/* Do not create a new index tree: entries are put to the
cluster tree */
return(DB_SUCCESS);
}
/* Run a mini-transaction in which the index tree is allocated for
the index and its root address is written to the index entry in
sys_indexes */
@ -1239,7 +1207,7 @@ dict_create_or_check_foreign_constraint_tables(void)
"COMMIT WORK;\n"
"END;\n";
graph = pars_sql(str);
graph = pars_sql(NULL, str);
ut_a(graph);
@ -1287,138 +1255,27 @@ dict_create_or_check_foreign_constraint_tables(void)
return(error);
}
/************************************************************************
Adds foreign key definitions to data dictionary tables in the database. We
look at table->foreign_list, and also generate names to constraints that were
not named by the user. A generated constraint has a name of the format
databasename/tablename_ibfk_<number>, where the numbers start from 1, and are
given locally for this table, that is, the number is not global, as in the
old format constraints < 4.0.18 it used to be. */
/********************************************************************
Evaluate the given SQL statement. */
ulint
dict_create_add_foreigns_to_dictionary(
/*===================================*/
dict_foreign_eval_sql(
/*==================*/
/* out: error code or DB_SUCCESS */
ulint start_id,/* in: if we are actually doing ALTER TABLE
ADD CONSTRAINT, we want to generate constraint
numbers which are bigger than in the table so
far; we number the constraints from
start_id + 1 up; start_id should be set to 0 if
we are creating a new table, or if the table
so far has no constraints for which the name
was generated here */
pars_info_t* info, /* in: info struct, or NULL */
const char* sql, /* in: SQL string to evaluate */
dict_table_t* table, /* in: table */
dict_foreign_t* foreign,/* in: foreign */
trx_t* trx) /* in: transaction */
{
dict_foreign_t* foreign;
que_thr_t* thr;
que_t* graph;
ulint number = start_id + 1;
ulint len;
ulint error;
FILE* ef = dict_foreign_err_file;
ulint i;
char* sql;
char* sqlend;
/* This procedure builds an InnoDB stored procedure which will insert
the necessary rows into SYS_FOREIGN and SYS_FOREIGN_COLS. */
static const char str1[] = "PROCEDURE ADD_FOREIGN_DEFS_PROC () IS\n"
"BEGIN\n"
"INSERT INTO SYS_FOREIGN VALUES(";
static const char str2[] = ");\n";
static const char str3[] =
"INSERT INTO SYS_FOREIGN_COLS VALUES(";
static const char str4[] =
"COMMIT WORK;\n"
"END;\n";
#ifdef UNIV_SYNC_DEBUG
ut_ad(mutex_own(&(dict_sys->mutex)));
#endif /* UNIV_SYNC_DEBUG */
if (NULL == dict_table_get_low("SYS_FOREIGN")) {
fprintf(stderr,
"InnoDB: table SYS_FOREIGN not found from internal data dictionary\n");
return(DB_ERROR);
}
foreign = UT_LIST_GET_FIRST(table->foreign_list);
loop:
if (foreign == NULL) {
return(DB_SUCCESS);
}
if (foreign->id == NULL) {
/* Generate a new constraint id */
ulint namelen = strlen(table->name);
char* id = mem_heap_alloc(foreign->heap, namelen + 20);
/* no overflow if number < 1e13 */
sprintf(id, "%s_ibfk_%lu", table->name, (ulong) number++);
foreign->id = id;
}
len = (sizeof str1) + (sizeof str2) + (sizeof str4) - 3
+ 9/* ' and , chars */ + 10/* 32-bit integer */
+ ut_strlenq(foreign->id, '\'') * (foreign->n_fields + 1)
+ ut_strlenq(table->name, '\'')
+ ut_strlenq(foreign->referenced_table_name, '\'');
for (i = 0; i < foreign->n_fields; i++) {
len += 9/* ' and , chars */ + 10/* 32-bit integer */
+ (sizeof str3) + (sizeof str2) - 2
+ ut_strlenq(foreign->foreign_col_names[i], '\'')
+ ut_strlenq(foreign->referenced_col_names[i], '\'');
}
sql = sqlend = mem_alloc(len + 1);
/* INSERT INTO SYS_FOREIGN VALUES(...); */
memcpy(sqlend, str1, (sizeof str1) - 1);
sqlend += (sizeof str1) - 1;
*sqlend++ = '\'';
sqlend = ut_strcpyq(sqlend, '\'', foreign->id);
*sqlend++ = '\'', *sqlend++ = ',', *sqlend++ = '\'';
sqlend = ut_strcpyq(sqlend, '\'', table->name);
*sqlend++ = '\'', *sqlend++ = ',', *sqlend++ = '\'';
sqlend = ut_strcpyq(sqlend, '\'', foreign->referenced_table_name);
*sqlend++ = '\'', *sqlend++ = ',';
sqlend += sprintf(sqlend, "%010lu",
foreign->n_fields + (foreign->type << 24));
memcpy(sqlend, str2, (sizeof str2) - 1);
sqlend += (sizeof str2) - 1;
for (i = 0; i < foreign->n_fields; i++) {
/* INSERT INTO SYS_FOREIGN_COLS VALUES(...); */
memcpy(sqlend, str3, (sizeof str3) - 1);
sqlend += (sizeof str3) - 1;
*sqlend++ = '\'';
sqlend = ut_strcpyq(sqlend, '\'', foreign->id);
*sqlend++ = '\''; *sqlend++ = ',';
sqlend += sprintf(sqlend, "%010lu", (ulong) i);
*sqlend++ = ','; *sqlend++ = '\'';
sqlend = ut_strcpyq(sqlend, '\'',
foreign->foreign_col_names[i]);
*sqlend++ = '\''; *sqlend++ = ','; *sqlend++ = '\'';
sqlend = ut_strcpyq(sqlend, '\'',
foreign->referenced_col_names[i]);
*sqlend++ = '\'';
memcpy(sqlend, str2, (sizeof str2) - 1);
sqlend += (sizeof str2) - 1;
}
memcpy(sqlend, str4, sizeof str4);
sqlend += sizeof str4;
ut_a(sqlend == sql + len + 1);
graph = pars_sql(sql);
graph = pars_sql(info, sql);
ut_a(graph);
mem_free(sql);
graph->trx = trx;
trx->graph = NULL;
@ -1476,7 +1333,163 @@ loop:
return(error);
}
foreign = UT_LIST_GET_NEXT(foreign_list, foreign);
goto loop;
return(DB_SUCCESS);
}
/************************************************************************
Add a single foreign key field definition to the data dictionary tables in
the database. */
static
ulint
dict_create_add_foreign_field_to_dictionary(
/*========================================*/
/* out: error code or DB_SUCCESS */
ulint field_nr, /* in: foreign field number */
dict_table_t* table, /* in: table */
dict_foreign_t* foreign, /* in: foreign */
trx_t* trx) /* in: transaction */
{
pars_info_t* info = pars_info_create();
pars_info_add_str_literal(info, "id", foreign->id);
pars_info_add_int4_literal(info, "pos", field_nr);
pars_info_add_str_literal(info, "for_col_name",
foreign->foreign_col_names[field_nr]);
pars_info_add_str_literal(info, "ref_col_name",
foreign->referenced_col_names[field_nr]);
return dict_foreign_eval_sql(info,
"PROCEDURE P () IS\n"
"BEGIN\n"
"INSERT INTO SYS_FOREIGN_COLS VALUES"
"(:id, :pos, :for_col_name, :ref_col_name);\n"
"END;\n"
, table, foreign, trx);
}
/************************************************************************
Add a single foreign key definition to the data dictionary tables in the
database. We also generate names to constraints that were not named by the
user. A generated constraint has a name of the format
databasename/tablename_ibfk_<number>, where the numbers start from 1, and
are given locally for this table, that is, the number is not global, as in
the old format constraints < 4.0.18 it used to be. */
static
ulint
dict_create_add_foreign_to_dictionary(
/*==================================*/
/* out: error code or DB_SUCCESS */
ulint* id_nr, /* in/out: number to use in id generation;
incremented if used */
dict_table_t* table, /* in: table */
dict_foreign_t* foreign,/* in: foreign */
trx_t* trx) /* in: transaction */
{
ulint error;
ulint i;
pars_info_t* info = pars_info_create();
if (foreign->id == NULL) {
/* Generate a new constraint id */
ulint namelen = strlen(table->name);
char* id = mem_heap_alloc(foreign->heap, namelen + 20);
/* no overflow if number < 1e13 */
sprintf(id, "%s_ibfk_%lu", table->name, (ulong) (*id_nr)++);
foreign->id = id;
}
pars_info_add_str_literal(info, "id", foreign->id);
pars_info_add_str_literal(info, "for_name", table->name);
pars_info_add_str_literal(info, "ref_name",
foreign->referenced_table_name);
pars_info_add_int4_literal(info, "n_cols",
foreign->n_fields + (foreign->type << 24));
error = dict_foreign_eval_sql(info,
"PROCEDURE P () IS\n"
"BEGIN\n"
"INSERT INTO SYS_FOREIGN VALUES"
"(:id, :for_name, :ref_name, :n_cols);\n"
"END;\n"
, table, foreign, trx);
if (error != DB_SUCCESS) {
return(error);
}
for (i = 0; i < foreign->n_fields; i++) {
error = dict_create_add_foreign_field_to_dictionary(i,
table, foreign, trx);
if (error != DB_SUCCESS) {
return(error);
}
}
error = dict_foreign_eval_sql(NULL,
"PROCEDURE P () IS\n"
"BEGIN\n"
"COMMIT WORK;\n"
"END;\n"
, table, foreign, trx);
return(error);
}
/************************************************************************
Adds foreign key definitions to data dictionary tables in the database. */
ulint
dict_create_add_foreigns_to_dictionary(
/*===================================*/
/* out: error code or DB_SUCCESS */
ulint start_id,/* in: if we are actually doing ALTER TABLE
ADD CONSTRAINT, we want to generate constraint
numbers which are bigger than in the table so
far; we number the constraints from
start_id + 1 up; start_id should be set to 0 if
we are creating a new table, or if the table
so far has no constraints for which the name
was generated here */
dict_table_t* table, /* in: table */
trx_t* trx) /* in: transaction */
{
dict_foreign_t* foreign;
ulint number = start_id + 1;
ulint error;
#ifdef UNIV_SYNC_DEBUG
ut_ad(mutex_own(&(dict_sys->mutex)));
#endif /* UNIV_SYNC_DEBUG */
if (NULL == dict_table_get_low("SYS_FOREIGN")) {
fprintf(stderr,
"InnoDB: table SYS_FOREIGN not found from internal data dictionary\n");
return(DB_ERROR);
}
for (foreign = UT_LIST_GET_FIRST(table->foreign_list);
foreign;
foreign = UT_LIST_GET_NEXT(foreign_list, foreign)) {
error = dict_create_add_foreign_to_dictionary(&number,
table, foreign, trx);
if (error != DB_SUCCESS) {
return(error);
}
}
return(DB_SUCCESS);
}

View file

@ -649,6 +649,19 @@ dict_table_get_nth_col_pos(
n));
}
/************************************************************************
Check whether the table uses the compact page format. */
ibool
dict_table_is_comp_noninline(
/*=========================*/
/* out: TRUE if table uses the
compact page format */
const dict_table_t* table) /* in: table */
{
return(dict_table_is_comp(table));
}
/************************************************************************
Checks if a column is in the ordering columns of the clustered index of a
table. Column prefixes are treated like whole columns. */
@ -862,13 +875,6 @@ dict_table_add_to_cache(
ut_a(table2 == NULL);
}
if (table->type == DICT_TABLE_CLUSTER_MEMBER) {
table->mix_id_len = mach_dulint_get_compressed_size(
table->mix_id);
mach_dulint_write_compressed(table->mix_id_buf, table->mix_id);
}
/* Add the columns to the column hash table */
for (i = 0; i < table->n_cols; i++) {
dict_col_add_to_cache(table, dict_table_get_nth_col(table, i));
@ -1243,15 +1249,13 @@ dict_table_remove_from_cache(
/* Remove table from LRU list of tables */
UT_LIST_REMOVE(table_LRU, dict_sys->table_LRU, table);
mutex_free(&(table->autoinc_mutex));
size = mem_heap_get_size(table->heap);
ut_ad(dict_sys->size >= size);
dict_sys->size -= size;
mem_heap_free(table->heap);
dict_mem_table_free(table);
}
/**************************************************************************
@ -1372,6 +1376,38 @@ dict_col_reposition_in_cache(
HASH_INSERT(dict_col_t, hash, dict_sys->col_hash, fold, col);
}
/********************************************************************
If the given column name is reserved for InnoDB system columns, return
TRUE. */
ibool
dict_col_name_is_reserved(
/*======================*/
/* out: TRUE if name is reserved */
const char* name) /* in: column name */
{
/* This check reminds that if a new system column is added to
the program, it should be dealt with here. */
#if DATA_N_SYS_COLS != 4
#error "DATA_N_SYS_COLS != 4"
#endif
static const char* reserved_names[] = {
"DB_ROW_ID", "DB_TRX_ID", "DB_ROLL_PTR", "DB_MIX_ID"
};
ulint i;
for (i = 0; i < UT_ARR_SIZE(reserved_names); i++) {
if (strcmp(name, reserved_names[i]) == 0) {
return(TRUE);
}
}
return(FALSE);
}
/**************************************************************************
Adds an index to the dictionary cache. */
@ -1386,7 +1422,6 @@ dict_index_add_to_cache(
{
dict_index_t* new_index;
dict_tree_t* tree;
dict_table_t* cluster;
dict_field_t* field;
ulint n_ord;
ibool success;
@ -1460,21 +1495,11 @@ dict_index_add_to_cache(
dict_field_get_col(field)->ord_part++;
}
if (table->type == DICT_TABLE_CLUSTER_MEMBER) {
/* The index tree is found from the cluster object */
/* Create an index tree memory object for the index */
tree = dict_tree_create(new_index, page_no);
ut_ad(tree);
cluster = dict_table_get_low(table->cluster_name);
tree = dict_index_get_tree(
UT_LIST_GET_FIRST(cluster->indexes));
new_index->tree = tree;
} else {
/* Create an index tree memory object for the index */
tree = dict_tree_create(new_index, page_no);
ut_ad(tree);
new_index->tree = tree;
}
new_index->tree = tree;
if (!UNIV_UNLIKELY(new_index->type & DICT_UNIVERSAL)) {
@ -1492,7 +1517,7 @@ dict_index_add_to_cache(
}
/* Add the index to the list of indexes stored in the tree */
UT_LIST_ADD_LAST(tree_indexes, tree->tree_indexes, new_index);
tree->tree_index = new_index;
/* If the dictionary cache grows too big, trim the table LRU list */
@ -1524,7 +1549,7 @@ dict_index_remove_from_cache(
ut_ad(mutex_own(&(dict_sys->mutex)));
#endif /* UNIV_SYNC_DEBUG */
ut_ad(UT_LIST_GET_LEN((index->tree)->tree_indexes) == 1);
ut_ad(index->tree->tree_index);
dict_tree_free(index->tree);
/* Decrement the ord_part counts in columns which are ordering */
@ -1545,7 +1570,7 @@ dict_index_remove_from_cache(
dict_sys->size -= size;
mem_heap_free(index->heap);
dict_mem_index_free(index);
}
/***********************************************************************
@ -1741,22 +1766,10 @@ dict_index_build_internal_clust(
new_index->id = index->id;
if (table->type != DICT_TABLE_ORDINARY) {
/* The index is mixed: copy common key prefix fields */
ut_a(table->type == DICT_TABLE_ORDINARY);
dict_index_copy(new_index, index, 0, table->mix_len);
/* Add the mix id column */
dict_index_add_col(new_index,
dict_table_get_sys_col(table, DATA_MIX_ID), 0);
/* Copy the rest of fields */
dict_index_copy(new_index, index, table->mix_len,
index->n_fields);
} else {
/* Copy the fields of index */
dict_index_copy(new_index, index, 0, index->n_fields);
}
/* Copy the fields of index */
dict_index_copy(new_index, index, 0, index->n_fields);
if (UNIV_UNLIKELY(index->type & DICT_UNIVERSAL)) {
/* No fixed number of fields determines an entry uniquely */
@ -3651,7 +3664,7 @@ dict_tree_create(
tree->id = index->id;
UT_LIST_INIT(tree->tree_indexes);
tree->tree_index = NULL;
tree->magic_n = DICT_TREE_MAGIC_N;
@ -3677,135 +3690,7 @@ dict_tree_free(
mem_free(tree);
}
/**************************************************************************
In an index tree, finds the index corresponding to a record in the tree. */
UNIV_INLINE
dict_index_t*
dict_tree_find_index_low(
/*=====================*/
/* out: index */
dict_tree_t* tree, /* in: index tree */
rec_t* rec) /* in: record for which to find correct
index */
{
dict_index_t* index;
dict_table_t* table;
dulint mix_id;
ulint len;
index = UT_LIST_GET_FIRST(tree->tree_indexes);
ut_ad(index);
table = index->table;
if (dict_index_is_clust(index)
&& UNIV_UNLIKELY(table->type != DICT_TABLE_ORDINARY)) {
/* Get the mix id of the record */
ut_a(!dict_table_is_comp(table));
mix_id = mach_dulint_read_compressed(
rec_get_nth_field_old(rec, table->mix_len, &len));
while (ut_dulint_cmp(table->mix_id, mix_id) != 0) {
index = UT_LIST_GET_NEXT(tree_indexes, index);
table = index->table;
ut_ad(index);
}
}
return(index);
}
/**************************************************************************
In an index tree, finds the index corresponding to a record in the tree. */
dict_index_t*
dict_tree_find_index(
/*=================*/
/* out: index */
dict_tree_t* tree, /* in: index tree */
rec_t* rec) /* in: record for which to find correct
index */
{
dict_index_t* index;
index = dict_tree_find_index_low(tree, rec);
return(index);
}
/**************************************************************************
In an index tree, finds the index corresponding to a dtuple which is used
in a search to a tree. */
dict_index_t*
dict_tree_find_index_for_tuple(
/*===========================*/
/* out: index; NULL if the tuple does not
contain the mix id field in a mixed tree */
dict_tree_t* tree, /* in: index tree */
dtuple_t* tuple) /* in: tuple for which to find index */
{
dict_index_t* index;
dict_table_t* table;
dulint mix_id;
ut_ad(dtuple_check_typed(tuple));
if (UT_LIST_GET_LEN(tree->tree_indexes) == 1) {
return(UT_LIST_GET_FIRST(tree->tree_indexes));
}
index = UT_LIST_GET_FIRST(tree->tree_indexes);
ut_ad(index);
table = index->table;
if (dtuple_get_n_fields(tuple) <= table->mix_len) {
return(NULL);
}
/* Get the mix id of the record */
mix_id = mach_dulint_read_compressed(
dfield_get_data(
dtuple_get_nth_field(tuple, table->mix_len)));
while (ut_dulint_cmp(table->mix_id, mix_id) != 0) {
index = UT_LIST_GET_NEXT(tree_indexes, index);
table = index->table;
ut_ad(index);
}
return(index);
}
/***********************************************************************
Checks if a table which is a mixed cluster member owns a record. */
ibool
dict_is_mixed_table_rec(
/*====================*/
/* out: TRUE if the record belongs to this
table */
dict_table_t* table, /* in: table in a mixed cluster */
rec_t* rec) /* in: user record in the clustered index */
{
byte* mix_id_field;
ulint len;
ut_ad(!dict_table_is_comp(table));
mix_id_field = rec_get_nth_field_old(rec,
table->mix_len, &len);
return(len == table->mix_id_len
&& !ut_memcmp(table->mix_id_buf, mix_id_field, len));
}
#ifdef UNIV_DEBUG
/**************************************************************************
Checks that a tuple has n_fields_cmp value in a sensible range, so that
no comparison can occur with the page number field in a node pointer. */
@ -3817,19 +3702,14 @@ dict_tree_check_search_tuple(
dict_tree_t* tree, /* in: index tree */
dtuple_t* tuple) /* in: tuple used in a search */
{
dict_index_t* index;
index = dict_tree_find_index_for_tuple(tree, tuple);
if (index == NULL) {
return(TRUE);
}
dict_index_t* index = tree->tree_index;
ut_a(index);
ut_a(dtuple_get_n_fields_cmp(tuple)
<= dict_index_get_n_unique_in_tree(index));
return(TRUE);
}
#endif /* UNIV_DEBUG */
/**************************************************************************
Builds a node pointer out of a physical record and a page number. */
@ -3852,7 +3732,7 @@ dict_tree_build_node_ptr(
byte* buf;
ulint n_unique;
ind = dict_tree_find_index_low(tree, rec);
ind = tree->tree_index;
if (UNIV_UNLIKELY(tree->type & DICT_UNIVERSAL)) {
/* In a universal index tree, we take the whole record as
@ -3920,7 +3800,7 @@ dict_tree_copy_rec_order_prefix(
ulint n;
UNIV_PREFETCH_R(rec);
index = dict_tree_find_index_low(tree, rec);
index = tree->tree_index;
if (UNIV_UNLIKELY(tree->type & DICT_UNIVERSAL)) {
ut_a(!dict_table_is_comp(index->table));
@ -3948,7 +3828,7 @@ dict_tree_build_data_tuple(
dtuple_t* tuple;
dict_index_t* ind;
ind = dict_tree_find_index_low(tree, rec);
ind = tree->tree_index;
ut_ad(dict_table_is_comp(ind->table)
|| n_fields <= rec_get_n_fields_old(rec));
@ -4106,6 +3986,18 @@ dict_update_statistics(
dict_update_statistics_low(table, FALSE);
}
/**************************************************************************
A noninlined version of dict_table_get_low. */
dict_table_t*
dict_table_get_low_noninlined(
/*==========================*/
/* out: table, NULL if not found */
const char* table_name) /* in: table name */
{
return(dict_table_get_low(table_name));
}
/**************************************************************************
Prints info of a foreign key constraint. */
static
@ -4275,7 +4167,7 @@ dict_index_print_low(
}
fprintf(stderr,
" INDEX: name %s, id %lu %lu, fields %lu/%lu, type %lu\n"
" INDEX: name %s, id %lu %lu, fields %lu/%lu, uniq %lu, type %lu\n"
" root page %lu, appr.key vals %lu,"
" leaf pages %lu, size pages %lu\n"
" FIELDS: ",
@ -4283,7 +4175,9 @@ dict_index_print_low(
(ulong) ut_dulint_get_high(tree->id),
(ulong) ut_dulint_get_low(tree->id),
(ulong) index->n_user_defined_cols,
(ulong) index->n_fields, (ulong) index->type,
(ulong) index->n_fields,
(ulong) index->n_uniq,
(ulong) index->type,
(ulong) tree->page,
(ulong) n_vals,
(ulong) index->stat_n_leaf_pages,

View file

@ -849,35 +849,11 @@ dict_load_table(
field = rec_get_nth_field_old(rec, 5, &len);
table->type = mach_read_from_4(field);
if (table->type == DICT_TABLE_CLUSTER_MEMBER) {
ut_error;
#if 0 /* clustered tables have not been implemented yet */
field = rec_get_nth_field_old(rec, 6, &len);
table->mix_id = mach_read_from_8(field);
field = rec_get_nth_field_old(rec, 8, &len);
table->cluster_name = mem_heap_strdupl(heap, (char*) field, len);
#endif
}
if ((table->type == DICT_TABLE_CLUSTER)
|| (table->type == DICT_TABLE_CLUSTER_MEMBER)) {
field = rec_get_nth_field_old(rec, 7, &len);
ut_a(len == 4);
table->mix_len = mach_read_from_4(field);
}
ut_a(table->type == DICT_TABLE_ORDINARY);
btr_pcur_close(&pcur);
mtr_commit(&mtr);
if (table->type == DICT_TABLE_CLUSTER_MEMBER) {
/* Load the cluster table definition if not yet in
memory cache */
dict_table_get_low(table->cluster_name);
}
dict_load_columns(table, heap);
dict_table_add_to_cache(table);

View file

@ -66,9 +66,6 @@ dict_mem_table_create(
table->cached = FALSE;
table->mix_id = ut_dulint_zero;
table->mix_len = 0;
table->cols = mem_heap_alloc(heap, (n_cols + DATA_N_SYS_COLS)
* sizeof(dict_col_t));
UT_LIST_INIT(table->indexes);
@ -97,42 +94,19 @@ dict_mem_table_create(
return(table);
}
/**************************************************************************
Creates a cluster memory object. */
dict_table_t*
dict_mem_cluster_create(
/*====================*/
/* out, own: cluster object */
const char* name, /* in: cluster name */
ulint space, /* in: space where the clustered indexes
of the member tables are placed */
ulint n_cols, /* in: number of columns */
ulint mix_len)/* in: length of the common key prefix in the
cluster */
{
dict_table_t* cluster;
/* Clustered tables cannot work with the compact record format. */
cluster = dict_mem_table_create(name, space, n_cols, 0);
cluster->type = DICT_TABLE_CLUSTER;
cluster->mix_len = mix_len;
return(cluster);
}
/**************************************************************************
Declares a non-published table as a member in a cluster. */
/********************************************************************
Free a table memory object. */
void
dict_mem_table_make_cluster_member(
/*===============================*/
dict_table_t* table, /* in: non-published table */
const char* cluster_name) /* in: cluster name */
dict_mem_table_free(
/*================*/
dict_table_t* table) /* in: table */
{
table->type = DICT_TABLE_CLUSTER_MEMBER;
table->cluster_name = cluster_name;
ut_ad(table);
ut_ad(table->magic_n == DICT_TABLE_MAGIC_N);
mutex_free(&(table->autoinc_mutex));
mem_heap_free(table->heap);
}
/**************************************************************************
@ -286,5 +260,8 @@ dict_mem_index_free(
/*================*/
dict_index_t* index) /* in: index */
{
ut_ad(index);
ut_ad(index->magic_n == DICT_INDEX_MAGIC_N);
mem_heap_free(index->heap);
}

View file

@ -212,6 +212,38 @@ for_step(
return(thr);
}
/**************************************************************************
Performs an execution step of an exit statement node. */
que_thr_t*
exit_step(
/*======*/
/* out: query thread to run next or NULL */
que_thr_t* thr) /* in: query thread */
{
exit_node_t* node;
que_node_t* loop_node;
ut_ad(thr);
node = thr->run_node;
ut_ad(que_node_get_type(node) == QUE_NODE_EXIT);
/* Loops exit by setting thr->run_node as the loop node's parent, so
find our containing loop node and get its parent. */
loop_node = que_node_get_containing_loop_node(node);
/* If someone uses an EXIT statement outside of a loop, this will
trigger. */
ut_a(loop_node);
thr->run_node = que_node_get_parent(loop_node);
return(thr);
}
/**************************************************************************
Performs an execution step of a return-statement node. */

View file

@ -132,6 +132,7 @@ extern "C" {
#include "../storage/innobase/include/sync0sync.h"
#include "../storage/innobase/include/fil0fil.h"
#include "../storage/innobase/include/trx0xa.h"
#include "../storage/innobase/include/thr0loc.h"
}
#define HA_INNOBASE_ROWS_IN_TABLE 10000 /* to get optimization right */
@ -231,7 +232,13 @@ handlerton innobase_hton = {
innobase_start_trx_and_assign_read_view, /* Start Consistent Snapshot */
innobase_flush_logs, /* Flush logs */
innobase_show_status, /* Show status */
HTON_NO_FLAGS
NULL, /* Partition flags */
NULL, /* Alter table flags */
NULL, /* alter_tablespace */
NULL, /* Fill FILES table */
HTON_NO_FLAGS,
NULL, /* binlog_func */
NULL /* binlog_log_query */
};
@ -533,11 +540,18 @@ convert_error_code_to_mysql(
return(HA_ERR_NO_SAVEPOINT);
} else if (error == (int) DB_LOCK_TABLE_FULL) {
/* Since we rolled back the whole transaction, we must
tell it also to MySQL so that MySQL knows to empty the
cached binlog for this transaction */
return(HA_ERR_LOCK_TABLE_FULL);
} else {
return(-1); // Unknown error
}
if (thd) {
ha_rollback(thd);
}
return(HA_ERR_LOCK_TABLE_FULL);
} else {
return(-1); // Unknown error
}
}
/*****************************************************************
@ -792,7 +806,7 @@ check_trx_exists(
thd->ha_data[innobase_hton.slot] = trx;
} else {
if (trx->magic_n != TRX_MAGIC_N) {
mem_analyze_corruption((byte*)trx);
mem_analyze_corruption(trx);
ut_a(0);
}
@ -1000,7 +1014,6 @@ innobase_query_caching_of_table_permitted(
mutex_enter_noninline(&kernel_mutex);
trx_print(stderr, trx, 1024);
mutex_exit_noninline(&kernel_mutex);
ut_error;
}
innobase_release_stat_resources(trx);
@ -2286,6 +2299,7 @@ innobase_close_connection(
innobase_rollback_trx(trx);
thr_local_free(trx->mysql_thread_id);
trx_free_for_mysql(trx);
return(0);
@ -2306,7 +2320,7 @@ ha_innobase::get_row_type() const
row_prebuilt_t* prebuilt = (row_prebuilt_t*) innobase_prebuilt;
if (prebuilt && prebuilt->table) {
if (dict_table_is_comp(prebuilt->table)) {
if (dict_table_is_comp_noninline(prebuilt->table)) {
return(ROW_TYPE_COMPACT);
} else {
return(ROW_TYPE_REDUNDANT);
@ -3699,7 +3713,8 @@ calc_row_difference(
TRUE,
new_mysql_row_col,
col_pack_len,
dict_table_is_comp(prebuilt->table));
dict_table_is_comp_noninline(
prebuilt->table));
ufield->new_val.data = dfield.data;
ufield->new_val.len = dfield.len;
} else {
@ -3859,9 +3874,17 @@ ha_innobase::unlock_row(void)
ut_error;
}
/* Consistent read does not take any locks, thus there is
nothing to unlock. */
if (prebuilt->select_lock_type == LOCK_NONE) {
DBUG_VOID_RETURN;
}
switch (prebuilt->row_read_type) {
case ROW_READ_WITH_LOCKS:
if (!srv_locks_unsafe_for_binlog) {
if (!srv_locks_unsafe_for_binlog
|| prebuilt->trx->isolation_level == TRX_ISO_READ_COMMITTED) {
break;
}
/* fall through */
@ -3893,7 +3916,13 @@ ha_innobase::try_semi_consistent_read(bool yes)
{
row_prebuilt_t* prebuilt = (row_prebuilt_t*) innobase_prebuilt;
if (yes && srv_locks_unsafe_for_binlog) {
/* Row read type is set to semi consistent read if this was
requested by the MySQL and either innodb_locks_unsafe_for_binlog
option is used or this session is using READ COMMITTED isolation
level. */
if (yes && (srv_locks_unsafe_for_binlog
|| prebuilt->trx->isolation_level == TRX_ISO_READ_COMMITTED)) {
prebuilt->row_read_type = ROW_READ_TRY_SEMI_CONSISTENT;
} else {
prebuilt->row_read_type = ROW_READ_WITH_LOCKS;
@ -5794,7 +5823,7 @@ ha_innobase::analyze(
}
/**************************************************************************
This is mapped to "ALTER TABLE tablename TYPE=InnoDB", which rebuilds
This is mapped to "ALTER TABLE tablename ENGINE=InnoDB", which rebuilds
the table in MySQL. */
int
@ -6376,12 +6405,6 @@ ha_innobase::external_lock(
trx->n_mysql_tables_in_use++;
prebuilt->mysql_has_locked = TRUE;
if (trx->n_mysql_tables_in_use == 1) {
trx->isolation_level = innobase_map_isolation_level(
(enum_tx_isolation)
thd->variables.tx_isolation);
}
if (trx->isolation_level == TRX_ISO_SERIALIZABLE
&& prebuilt->select_lock_type == LOCK_NONE
&& (thd->options
@ -6855,11 +6878,22 @@ ha_innobase::store_lock(
TL_IGNORE */
{
row_prebuilt_t* prebuilt = (row_prebuilt_t*) innobase_prebuilt;
trx_t* trx = prebuilt->trx;
/* NOTE: MySQL can call this function with lock 'type' TL_IGNORE!
Be careful to ignore TL_IGNORE if we are going to do something with
only 'real' locks! */
/* If no MySQL tables is use we need to set isolation level
of the transaction. */
if (lock_type != TL_IGNORE
&& trx->n_mysql_tables_in_use == 0) {
trx->isolation_level = innobase_map_isolation_level(
(enum_tx_isolation)
thd->variables.tx_isolation);
}
if ((lock_type == TL_READ && thd->in_lock_tables) ||
(lock_type == TL_READ_HIGH_PRIORITY && thd->in_lock_tables) ||
lock_type == TL_READ_WITH_SHARED_LOCKS ||
@ -6884,18 +6918,26 @@ ha_innobase::store_lock(
unexpected if an obsolete consistent read view would be
used. */
if (srv_locks_unsafe_for_binlog &&
prebuilt->trx->isolation_level != TRX_ISO_SERIALIZABLE &&
(lock_type == TL_READ || lock_type == TL_READ_NO_INSERT) &&
(thd->lex->sql_command == SQLCOM_INSERT_SELECT ||
thd->lex->sql_command == SQLCOM_UPDATE)) {
ulint isolation_level;
/* In case we have innobase_locks_unsafe_for_binlog
option set and isolation level of the transaction
isolation_level = trx->isolation_level;
if ((srv_locks_unsafe_for_binlog
|| isolation_level == TRX_ISO_READ_COMMITTED)
&& isolation_level != TRX_ISO_SERIALIZABLE
&& (lock_type == TL_READ || lock_type == TL_READ_NO_INSERT)
&& (thd->lex->sql_command == SQLCOM_INSERT_SELECT
|| thd->lex->sql_command == SQLCOM_UPDATE
|| thd->lex->sql_command == SQLCOM_CREATE_TABLE)) {
/* If we either have innobase_locks_unsafe_for_binlog
option set or this session is using READ COMMITTED
isolation level and isolation level of the transaction
is not set to serializable and MySQL is doing
INSERT INTO...SELECT or UPDATE ... = (SELECT ...)
without FOR UPDATE or IN SHARE MODE in select, then
we use consistent read for select. */
INSERT INTO...SELECT or UPDATE ... = (SELECT ...) or
CREATE ... SELECT... without FOR UPDATE or
IN SHARE MODE in select, then we use consistent
read for select. */
prebuilt->select_lock_type = LOCK_NONE;
prebuilt->stored_select_lock_type = LOCK_NONE;
@ -6949,17 +6991,18 @@ ha_innobase::store_lock(
< TL_WRITE_CONCURRENT_INSERT.
We especially allow multiple writers if MySQL is at the
start of a stored procedure call (SQLCOM_CALL)
(MySQL does have thd->in_lock_tables TRUE there). */
start of a stored procedure call (SQLCOM_CALL) or a
stored function call (MySQL does have thd->in_lock_tables
TRUE there). */
if ((lock_type >= TL_WRITE_CONCURRENT_INSERT
&& lock_type <= TL_WRITE)
&& (!thd->in_lock_tables
|| thd->lex->sql_command == SQLCOM_CALL)
&& !thd->tablespace_op
&& thd->lex->sql_command != SQLCOM_TRUNCATE
&& thd->lex->sql_command != SQLCOM_OPTIMIZE
&& thd->lex->sql_command != SQLCOM_CREATE_TABLE) {
&& lock_type <= TL_WRITE)
&& !(thd->in_lock_tables
&& thd->lex->sql_command == SQLCOM_LOCK_TABLES)
&& !thd->tablespace_op
&& thd->lex->sql_command != SQLCOM_TRUNCATE
&& thd->lex->sql_command != SQLCOM_OPTIMIZE
&& thd->lex->sql_command != SQLCOM_CREATE_TABLE) {
lock_type = TL_WRITE_ALLOW_WRITE;
}

View file

@ -1170,9 +1170,9 @@ ibuf_dummy_index_free(
dict_index_t* index) /* in: dummy index */
{
dict_table_t* table = index->table;
mem_heap_free(index->heap);
mutex_free(&(table->autoinc_mutex));
mem_heap_free(table->heap);
dict_mem_index_free(index);
dict_mem_table_free(table);
}
/*************************************************************************

View file

@ -459,7 +459,10 @@ btr_store_big_rec_extern_fields(
dict_index_t* index, /* in: index of rec; the index tree
MUST be X-latched */
rec_t* rec, /* in: record */
const ulint* offsets, /* in: rec_get_offsets(rec, index) */
const ulint* offsets, /* in: rec_get_offsets(rec, index);
the "external storage" flags in offsets
will not correspond to rec when
this function returns */
big_rec_t* big_rec_vec, /* in: vector containing fields
to be stored externally */
mtr_t* local_mtr); /* in: mtr containing the latch to

View file

@ -180,12 +180,14 @@ struct btr_search_struct{
the same prefix should be indexed in the
hash index */
/*----------------------*/
#ifdef UNIV_SEARCH_PERF_STAT
ulint n_hash_succ; /* number of successful hash searches thus
far */
ulint n_hash_fail; /* number of failed hash searches */
ulint n_patt_succ; /* number of successful pattern searches thus
far */
ulint n_searches; /* number of searches */
#endif /* UNIV_SEARCH_PERF_STAT */
};
#define BTR_SEARCH_MAGIC_N 1112765
@ -218,8 +220,8 @@ extern rw_lock_t* btr_search_latch_temp;
#ifdef UNIV_SEARCH_PERF_STAT
extern ulint btr_search_n_succ;
#endif /* UNIV_SEARCH_PERF_STAT */
extern ulint btr_search_n_hash_fail;
#endif /* UNIV_SEARCH_PERF_STAT */
/* After change in n_fields or n_bytes in info, this many rounds are waited
before starting the hash analysis again: this is to save CPU time when there

View file

@ -26,14 +26,14 @@ void
buf_LRU_try_free_flushed_blocks(void);
/*==================================*/
/**********************************************************************
Returns TRUE if less than 15 % of the buffer pool is available. This can be
Returns TRUE if less than 25 % of the buffer pool is available. This can be
used in heuristics to prevent huge transactions eating up the whole buffer
pool for their locks. */
ibool
buf_LRU_buf_pool_running_out(void);
/*==============================*/
/* out: TRUE if less than 15 % of buffer pool
/* out: TRUE if less than 25 % of buffer pool
left */
/*#######################################################################

View file

@ -320,6 +320,14 @@ void
dfield_print_also_hex(
/*==================*/
dfield_t* dfield); /* in: dfield */
/*****************************************************************
Print a dfield value using ut_print_buf. */
void
dfield_print_raw(
/*=============*/
FILE* f, /* in: output stream */
dfield_t* dfield); /* in: dfield */
/**************************************************************
The following function prints the contents of a tuple. */

View file

@ -100,6 +100,15 @@ ulint
dict_col_get_clust_pos(
/*===================*/
dict_col_t* col);
/********************************************************************
If the given column name is reserved for InnoDB system columns, return
TRUE. */
ibool
dict_col_name_is_reserved(
/*======================*/
/* out: TRUE if name is reserved */
const char* name); /* in: column name */
/************************************************************************
Initializes the autoinc counter. It is not an error to initialize an already
initialized counter. */
@ -321,6 +330,14 @@ dict_table_get_low(
/* out: table, NULL if not found */
const char* table_name); /* in: table name */
/**************************************************************************
A noninlined version of dict_table_get_low. */
dict_table_t*
dict_table_get_low_noninlined(
/*==========================*/
/* out: table, NULL if not found */
const char* table_name); /* in: table name */
/**************************************************************************
Returns an index object. */
UNIV_INLINE
dict_index_t*
@ -507,6 +524,15 @@ dict_table_is_comp(
compact page format */
const dict_table_t* table); /* in: table */
/************************************************************************
Check whether the table uses the compact page format. */
ibool
dict_table_is_comp_noninline(
/*=========================*/
/* out: TRUE if table uses the
compact page format */
const dict_table_t* table); /* in: table */
/************************************************************************
Check whether the table uses the compressed compact page format. */
UNIV_INLINE
ibool
@ -745,33 +771,6 @@ dict_tree_free(
/**************************************************************************
In an index tree, finds the index corresponding to a record in the tree. */
dict_index_t*
dict_tree_find_index(
/*=================*/
/* out: index */
dict_tree_t* tree, /* in: index tree */
rec_t* rec); /* in: record for which to find correct index */
/**************************************************************************
In an index tree, finds the index corresponding to a dtuple which is used
in a search to a tree. */
dict_index_t*
dict_tree_find_index_for_tuple(
/*===========================*/
/* out: index; NULL if the tuple does not
contain the mix id field in a mixed tree */
dict_tree_t* tree, /* in: index tree */
dtuple_t* tuple); /* in: tuple for which to find index */
/***********************************************************************
Checks if a table which is a mixed cluster member owns a record. */
ibool
dict_is_mixed_table_rec(
/*====================*/
/* out: TRUE if the record belongs to this
table */
dict_table_t* table, /* in: table in a mixed cluster */
rec_t* rec); /* in: user record in the clustered index */
/**************************************************************************
Returns an index object if it is found in the dictionary cache.
Assumes that dict_sys->mutex is already being held. */
@ -789,6 +788,7 @@ dict_index_get_if_in_cache(
/*=======================*/
/* out: index, NULL if not found */
dulint index_id); /* in: index id */
#ifdef UNIV_DEBUG
/**************************************************************************
Checks that a tuple has n_fields_cmp value in a sensible range, so that
no comparison can occur with the page number field in a node pointer. */
@ -799,6 +799,7 @@ dict_tree_check_search_tuple(
/* out: TRUE if ok */
dict_tree_t* tree, /* in: index tree */
dtuple_t* tuple); /* in: tuple used in a search */
#endif /* UNIV_DEBUG */
/**************************************************************************
Builds a node pointer out of a physical record and a page number. */

View file

@ -108,7 +108,6 @@ dict_table_get_n_user_cols(
{
ut_ad(table);
ut_ad(table->magic_n == DICT_TABLE_MAGIC_N);
ut_ad(table->cached);
return(table->n_cols - DATA_N_SYS_COLS);
}
@ -142,7 +141,6 @@ dict_table_get_n_cols(
{
ut_ad(table);
ut_ad(table->magic_n == DICT_TABLE_MAGIC_N);
ut_ad(table->cached);
return(table->n_cols);
}

View file

@ -35,9 +35,11 @@ combination of types */
/* Types for a table object */
#define DICT_TABLE_ORDINARY 1
#if 0 /* not implemented */
#define DICT_TABLE_CLUSTER_MEMBER 2
#define DICT_TABLE_CLUSTER 3 /* this means that the table is
really a cluster definition */
#endif
/* Table flags */
#define DICT_TF_COMPACT 1 /* compact page format */
@ -57,29 +59,13 @@ dict_mem_table_create(
a member of a cluster */
ulint n_cols, /* in: number of columns */
ulint flags); /* in: table flags */
/**************************************************************************
Creates a cluster memory object. */
dict_cluster_t*
dict_mem_cluster_create(
/*====================*/
/* out, own: cluster object (where the
type dict_cluster_t == dict_table_t) */
const char* name, /* in: cluster name */
ulint space, /* in: space where the clustered
indexes of the member tables are
placed */
ulint n_cols, /* in: number of columns */
ulint mix_len); /* in: length of the common key prefix
in the cluster */
/**************************************************************************
Declares a non-published table as a member in a cluster. */
/********************************************************************
Free a table memory object. */
void
dict_mem_table_make_cluster_member(
/*===============================*/
dict_table_t* table, /* in: non-published table */
const char* cluster_name); /* in: cluster name */
dict_mem_table_free(
/*================*/
dict_table_t* table); /* in: table */
/**************************************************************************
Adds a column definition to a table. */
@ -177,9 +163,7 @@ struct dict_field_struct{
/* Data structure for an index tree */
struct dict_tree_struct{
ulint type; /* tree type */
dulint id; /* id of the index stored in the tree, in the
case of a mixed index, the id of the clustered
index of the cluster table */
dulint id; /* id of the index stored in the tree */
ulint space; /* space of index tree */
ulint page; /* index tree root page number */
byte pad[64];/* Padding to prevent other memory hotspots on
@ -190,13 +174,8 @@ struct dict_tree_struct{
struct has been memoryfixed (by mini-
transactions wanting to access the index
tree) */
UT_LIST_BASE_NODE_T(dict_index_t)
tree_indexes; /* list of indexes stored in the
index tree: if the tree is not of the
mixed type there is only one index in
the list; if the tree is of the mixed
type, the first index in the list is the
index of the cluster which owns the tree */
dict_index_t* tree_index; /* the index stored in the
index tree */
ulint magic_n;/* magic number */
};
@ -302,7 +281,7 @@ a foreign key constraint is enforced, therefore RESTRICT just means no flag */
/* Data structure for a database table */
struct dict_table_struct{
dulint id; /* id of the table or cluster */
dulint id; /* id of the table */
ulint type; /* DICT_TABLE_ORDINARY, ... */
ulint flags; /* DICT_TF_COMPACT, ... */
mem_heap_t* heap; /* memory heap */
@ -372,17 +351,6 @@ struct dict_table_struct{
UT_LIST_BASE_NODE_T(lock_t)
locks; /* list of locks on the table */
/*----------------------*/
dulint mix_id; /* if the table is a member in a cluster,
this is its mix id */
ulint mix_len;/* if the table is a cluster or a member
this is the common key prefix lenght */
ulint mix_id_len;/* mix id length in a compressed form */
byte mix_id_buf[12];
/* mix id of a mixed table written in
a compressed form */
const char* cluster_name; /* if the table is a member in a
cluster, this is the name of the cluster */
/*----------------------*/
ibool does_not_fit_in_memory;
/* this field is used to specify in simulations
tables which are so big that disk should be

View file

@ -63,6 +63,14 @@ proc_eval_step(
/* out: query thread to run next or NULL */
que_thr_t* thr); /* in: query thread */
/**************************************************************************
Performs an execution step of an exit statement node. */
que_thr_t*
exit_step(
/*======*/
/* out: query thread to run next or NULL */
que_thr_t* thr); /* in: query thread */
/**************************************************************************
Performs an execution step of a return-statement node. */
que_thr_t*

View file

@ -222,6 +222,32 @@ do {\
mem_heap_free_top(hash_get_heap(TABLE, fold111), sizeof(TYPE));\
} while (0)
/********************************************************************
Move all hash table entries from OLD_TABLE to NEW_TABLE.*/
#define HASH_MIGRATE(OLD_TABLE, NEW_TABLE, NODE_TYPE, PTR_NAME, FOLD_FUNC) \
do {\
ulint i2222;\
ulint cell_count2222;\
\
cell_count2222 = hash_get_n_cells(OLD_TABLE);\
\
for (i2222 = 0; i2222 < cell_count2222; i2222++) {\
NODE_TYPE* node2222 = HASH_GET_FIRST((OLD_TABLE), i2222);\
\
while (node2222) {\
NODE_TYPE* next2222 = node2222->PTR_NAME;\
ulint fold2222 = FOLD_FUNC(node2222);\
\
HASH_INSERT(NODE_TYPE, PTR_NAME, (NEW_TABLE),\
fold2222, node2222);\
\
node2222 = next2222;\
}\
}\
} while (0)
/****************************************************************
Gets the mutex index for a fold value in a hash table. */
UNIV_INLINE

View file

@ -595,6 +595,15 @@ ibool
lock_validate(void);
/*===============*/
/* out: TRUE if ok */
/*************************************************************************
Return approximate number or record locks (bits set in the bitmap) for
this transaction. Since delete-marked records ma ybe removed, the
record count will not be precise. */
ulint
lock_number_of_rows_locked(
/*=======================*/
trx_t* trx); /* in: transaction */
/* The lock system */
extern lock_sys_t* lock_sys;

View file

@ -114,7 +114,7 @@ the neighborhood of a given pointer. */
void
mem_analyze_corruption(
/*===================*/
byte* ptr); /* in: pointer to place of possible corruption */
void* ptr); /* in: pointer to place of possible corruption */
/*********************************************************************
Prints information of dynamic memory usage and currently allocated memory
heaps or buffers. Can only be used in the debug version. */

View file

@ -193,19 +193,6 @@ page_rec_is_comp(
/* out: nonzero if in compact format */
const rec_t* rec) /* in: record */
{
#ifdef UNIV_RELEASE_NOT_YET_STABLE
if (UNIV_UNLIKELY((ulint)rec < (ulint)(buf_pool->frame_zero))
|| UNIV_UNLIKELY((ulint)rec >= (ulint)(buf_pool->high_end))) {
ut_print_timestamp(stderr);
fprintf(stderr,
"InnoDB: Error: trying to read a stray page rec %p\n"
"InnoDB: buf pool start is at %p, end at %p\n",
rec, buf_pool->frame_zero,
buf_pool->high_end);
ut_error;
}
#endif
return(page_is_comp(ut_align_down((rec_t*) rec, UNIV_PAGE_SIZE)));
}

View file

@ -32,177 +32,187 @@
PARS_INT_LIT = 258,
PARS_FLOAT_LIT = 259,
PARS_STR_LIT = 260,
PARS_NULL_LIT = 261,
PARS_ID_TOKEN = 262,
PARS_AND_TOKEN = 263,
PARS_OR_TOKEN = 264,
PARS_NOT_TOKEN = 265,
PARS_GE_TOKEN = 266,
PARS_LE_TOKEN = 267,
PARS_NE_TOKEN = 268,
PARS_PROCEDURE_TOKEN = 269,
PARS_IN_TOKEN = 270,
PARS_OUT_TOKEN = 271,
PARS_BINARY_TOKEN = 272,
PARS_BLOB_TOKEN = 273,
PARS_INT_TOKEN = 274,
PARS_INTEGER_TOKEN = 275,
PARS_FLOAT_TOKEN = 276,
PARS_CHAR_TOKEN = 277,
PARS_IS_TOKEN = 278,
PARS_BEGIN_TOKEN = 279,
PARS_END_TOKEN = 280,
PARS_IF_TOKEN = 281,
PARS_THEN_TOKEN = 282,
PARS_ELSE_TOKEN = 283,
PARS_ELSIF_TOKEN = 284,
PARS_LOOP_TOKEN = 285,
PARS_WHILE_TOKEN = 286,
PARS_RETURN_TOKEN = 287,
PARS_SELECT_TOKEN = 288,
PARS_SUM_TOKEN = 289,
PARS_COUNT_TOKEN = 290,
PARS_DISTINCT_TOKEN = 291,
PARS_FROM_TOKEN = 292,
PARS_WHERE_TOKEN = 293,
PARS_FOR_TOKEN = 294,
PARS_DDOT_TOKEN = 295,
PARS_CONSISTENT_TOKEN = 296,
PARS_READ_TOKEN = 297,
PARS_ORDER_TOKEN = 298,
PARS_BY_TOKEN = 299,
PARS_ASC_TOKEN = 300,
PARS_DESC_TOKEN = 301,
PARS_INSERT_TOKEN = 302,
PARS_INTO_TOKEN = 303,
PARS_VALUES_TOKEN = 304,
PARS_UPDATE_TOKEN = 305,
PARS_SET_TOKEN = 306,
PARS_DELETE_TOKEN = 307,
PARS_CURRENT_TOKEN = 308,
PARS_OF_TOKEN = 309,
PARS_CREATE_TOKEN = 310,
PARS_TABLE_TOKEN = 311,
PARS_INDEX_TOKEN = 312,
PARS_UNIQUE_TOKEN = 313,
PARS_CLUSTERED_TOKEN = 314,
PARS_DOES_NOT_FIT_IN_MEM_TOKEN = 315,
PARS_ON_TOKEN = 316,
PARS_ASSIGN_TOKEN = 317,
PARS_DECLARE_TOKEN = 318,
PARS_CURSOR_TOKEN = 319,
PARS_SQL_TOKEN = 320,
PARS_OPEN_TOKEN = 321,
PARS_FETCH_TOKEN = 322,
PARS_CLOSE_TOKEN = 323,
PARS_NOTFOUND_TOKEN = 324,
PARS_TO_CHAR_TOKEN = 325,
PARS_TO_NUMBER_TOKEN = 326,
PARS_TO_BINARY_TOKEN = 327,
PARS_BINARY_TO_NUMBER_TOKEN = 328,
PARS_SUBSTR_TOKEN = 329,
PARS_REPLSTR_TOKEN = 330,
PARS_CONCAT_TOKEN = 331,
PARS_INSTR_TOKEN = 332,
PARS_LENGTH_TOKEN = 333,
PARS_SYSDATE_TOKEN = 334,
PARS_PRINTF_TOKEN = 335,
PARS_ASSERT_TOKEN = 336,
PARS_RND_TOKEN = 337,
PARS_RND_STR_TOKEN = 338,
PARS_ROW_PRINTF_TOKEN = 339,
PARS_COMMIT_TOKEN = 340,
PARS_ROLLBACK_TOKEN = 341,
PARS_WORK_TOKEN = 342,
NEG = 343
PARS_FIXBINARY_LIT = 261,
PARS_BLOB_LIT = 262,
PARS_NULL_LIT = 263,
PARS_ID_TOKEN = 264,
PARS_AND_TOKEN = 265,
PARS_OR_TOKEN = 266,
PARS_NOT_TOKEN = 267,
PARS_GE_TOKEN = 268,
PARS_LE_TOKEN = 269,
PARS_NE_TOKEN = 270,
PARS_PROCEDURE_TOKEN = 271,
PARS_IN_TOKEN = 272,
PARS_OUT_TOKEN = 273,
PARS_BINARY_TOKEN = 274,
PARS_BLOB_TOKEN = 275,
PARS_INT_TOKEN = 276,
PARS_INTEGER_TOKEN = 277,
PARS_FLOAT_TOKEN = 278,
PARS_CHAR_TOKEN = 279,
PARS_IS_TOKEN = 280,
PARS_BEGIN_TOKEN = 281,
PARS_END_TOKEN = 282,
PARS_IF_TOKEN = 283,
PARS_THEN_TOKEN = 284,
PARS_ELSE_TOKEN = 285,
PARS_ELSIF_TOKEN = 286,
PARS_LOOP_TOKEN = 287,
PARS_WHILE_TOKEN = 288,
PARS_RETURN_TOKEN = 289,
PARS_SELECT_TOKEN = 290,
PARS_SUM_TOKEN = 291,
PARS_COUNT_TOKEN = 292,
PARS_DISTINCT_TOKEN = 293,
PARS_FROM_TOKEN = 294,
PARS_WHERE_TOKEN = 295,
PARS_FOR_TOKEN = 296,
PARS_DDOT_TOKEN = 297,
PARS_CONSISTENT_TOKEN = 298,
PARS_READ_TOKEN = 299,
PARS_ORDER_TOKEN = 300,
PARS_BY_TOKEN = 301,
PARS_ASC_TOKEN = 302,
PARS_DESC_TOKEN = 303,
PARS_INSERT_TOKEN = 304,
PARS_INTO_TOKEN = 305,
PARS_VALUES_TOKEN = 306,
PARS_UPDATE_TOKEN = 307,
PARS_SET_TOKEN = 308,
PARS_DELETE_TOKEN = 309,
PARS_CURRENT_TOKEN = 310,
PARS_OF_TOKEN = 311,
PARS_CREATE_TOKEN = 312,
PARS_TABLE_TOKEN = 313,
PARS_INDEX_TOKEN = 314,
PARS_UNIQUE_TOKEN = 315,
PARS_CLUSTERED_TOKEN = 316,
PARS_DOES_NOT_FIT_IN_MEM_TOKEN = 317,
PARS_ON_TOKEN = 318,
PARS_ASSIGN_TOKEN = 319,
PARS_DECLARE_TOKEN = 320,
PARS_CURSOR_TOKEN = 321,
PARS_SQL_TOKEN = 322,
PARS_OPEN_TOKEN = 323,
PARS_FETCH_TOKEN = 324,
PARS_CLOSE_TOKEN = 325,
PARS_NOTFOUND_TOKEN = 326,
PARS_TO_CHAR_TOKEN = 327,
PARS_TO_NUMBER_TOKEN = 328,
PARS_TO_BINARY_TOKEN = 329,
PARS_BINARY_TO_NUMBER_TOKEN = 330,
PARS_SUBSTR_TOKEN = 331,
PARS_REPLSTR_TOKEN = 332,
PARS_CONCAT_TOKEN = 333,
PARS_INSTR_TOKEN = 334,
PARS_LENGTH_TOKEN = 335,
PARS_SYSDATE_TOKEN = 336,
PARS_PRINTF_TOKEN = 337,
PARS_ASSERT_TOKEN = 338,
PARS_RND_TOKEN = 339,
PARS_RND_STR_TOKEN = 340,
PARS_ROW_PRINTF_TOKEN = 341,
PARS_COMMIT_TOKEN = 342,
PARS_ROLLBACK_TOKEN = 343,
PARS_WORK_TOKEN = 344,
PARS_UNSIGNED_TOKEN = 345,
PARS_EXIT_TOKEN = 346,
PARS_FUNCTION_TOKEN = 347,
NEG = 348
};
#endif
#define PARS_INT_LIT 258
#define PARS_FLOAT_LIT 259
#define PARS_STR_LIT 260
#define PARS_NULL_LIT 261
#define PARS_ID_TOKEN 262
#define PARS_AND_TOKEN 263
#define PARS_OR_TOKEN 264
#define PARS_NOT_TOKEN 265
#define PARS_GE_TOKEN 266
#define PARS_LE_TOKEN 267
#define PARS_NE_TOKEN 268
#define PARS_PROCEDURE_TOKEN 269
#define PARS_IN_TOKEN 270
#define PARS_OUT_TOKEN 271
#define PARS_BINARY_TOKEN 272
#define PARS_BLOB_TOKEN 273
#define PARS_INT_TOKEN 274
#define PARS_INTEGER_TOKEN 275
#define PARS_FLOAT_TOKEN 276
#define PARS_CHAR_TOKEN 277
#define PARS_IS_TOKEN 278
#define PARS_BEGIN_TOKEN 279
#define PARS_END_TOKEN 280
#define PARS_IF_TOKEN 281
#define PARS_THEN_TOKEN 282
#define PARS_ELSE_TOKEN 283
#define PARS_ELSIF_TOKEN 284
#define PARS_LOOP_TOKEN 285
#define PARS_WHILE_TOKEN 286
#define PARS_RETURN_TOKEN 287
#define PARS_SELECT_TOKEN 288
#define PARS_SUM_TOKEN 289
#define PARS_COUNT_TOKEN 290
#define PARS_DISTINCT_TOKEN 291
#define PARS_FROM_TOKEN 292
#define PARS_WHERE_TOKEN 293
#define PARS_FOR_TOKEN 294
#define PARS_DDOT_TOKEN 295
#define PARS_CONSISTENT_TOKEN 296
#define PARS_READ_TOKEN 297
#define PARS_ORDER_TOKEN 298
#define PARS_BY_TOKEN 299
#define PARS_ASC_TOKEN 300
#define PARS_DESC_TOKEN 301
#define PARS_INSERT_TOKEN 302
#define PARS_INTO_TOKEN 303
#define PARS_VALUES_TOKEN 304
#define PARS_UPDATE_TOKEN 305
#define PARS_SET_TOKEN 306
#define PARS_DELETE_TOKEN 307
#define PARS_CURRENT_TOKEN 308
#define PARS_OF_TOKEN 309
#define PARS_CREATE_TOKEN 310
#define PARS_TABLE_TOKEN 311
#define PARS_INDEX_TOKEN 312
#define PARS_UNIQUE_TOKEN 313
#define PARS_CLUSTERED_TOKEN 314
#define PARS_DOES_NOT_FIT_IN_MEM_TOKEN 315
#define PARS_ON_TOKEN 316
#define PARS_ASSIGN_TOKEN 317
#define PARS_DECLARE_TOKEN 318
#define PARS_CURSOR_TOKEN 319
#define PARS_SQL_TOKEN 320
#define PARS_OPEN_TOKEN 321
#define PARS_FETCH_TOKEN 322
#define PARS_CLOSE_TOKEN 323
#define PARS_NOTFOUND_TOKEN 324
#define PARS_TO_CHAR_TOKEN 325
#define PARS_TO_NUMBER_TOKEN 326
#define PARS_TO_BINARY_TOKEN 327
#define PARS_BINARY_TO_NUMBER_TOKEN 328
#define PARS_SUBSTR_TOKEN 329
#define PARS_REPLSTR_TOKEN 330
#define PARS_CONCAT_TOKEN 331
#define PARS_INSTR_TOKEN 332
#define PARS_LENGTH_TOKEN 333
#define PARS_SYSDATE_TOKEN 334
#define PARS_PRINTF_TOKEN 335
#define PARS_ASSERT_TOKEN 336
#define PARS_RND_TOKEN 337
#define PARS_RND_STR_TOKEN 338
#define PARS_ROW_PRINTF_TOKEN 339
#define PARS_COMMIT_TOKEN 340
#define PARS_ROLLBACK_TOKEN 341
#define PARS_WORK_TOKEN 342
#define NEG 343
#define PARS_FIXBINARY_LIT 261
#define PARS_BLOB_LIT 262
#define PARS_NULL_LIT 263
#define PARS_ID_TOKEN 264
#define PARS_AND_TOKEN 265
#define PARS_OR_TOKEN 266
#define PARS_NOT_TOKEN 267
#define PARS_GE_TOKEN 268
#define PARS_LE_TOKEN 269
#define PARS_NE_TOKEN 270
#define PARS_PROCEDURE_TOKEN 271
#define PARS_IN_TOKEN 272
#define PARS_OUT_TOKEN 273
#define PARS_BINARY_TOKEN 274
#define PARS_BLOB_TOKEN 275
#define PARS_INT_TOKEN 276
#define PARS_INTEGER_TOKEN 277
#define PARS_FLOAT_TOKEN 278
#define PARS_CHAR_TOKEN 279
#define PARS_IS_TOKEN 280
#define PARS_BEGIN_TOKEN 281
#define PARS_END_TOKEN 282
#define PARS_IF_TOKEN 283
#define PARS_THEN_TOKEN 284
#define PARS_ELSE_TOKEN 285
#define PARS_ELSIF_TOKEN 286
#define PARS_LOOP_TOKEN 287
#define PARS_WHILE_TOKEN 288
#define PARS_RETURN_TOKEN 289
#define PARS_SELECT_TOKEN 290
#define PARS_SUM_TOKEN 291
#define PARS_COUNT_TOKEN 292
#define PARS_DISTINCT_TOKEN 293
#define PARS_FROM_TOKEN 294
#define PARS_WHERE_TOKEN 295
#define PARS_FOR_TOKEN 296
#define PARS_DDOT_TOKEN 297
#define PARS_CONSISTENT_TOKEN 298
#define PARS_READ_TOKEN 299
#define PARS_ORDER_TOKEN 300
#define PARS_BY_TOKEN 301
#define PARS_ASC_TOKEN 302
#define PARS_DESC_TOKEN 303
#define PARS_INSERT_TOKEN 304
#define PARS_INTO_TOKEN 305
#define PARS_VALUES_TOKEN 306
#define PARS_UPDATE_TOKEN 307
#define PARS_SET_TOKEN 308
#define PARS_DELETE_TOKEN 309
#define PARS_CURRENT_TOKEN 310
#define PARS_OF_TOKEN 311
#define PARS_CREATE_TOKEN 312
#define PARS_TABLE_TOKEN 313
#define PARS_INDEX_TOKEN 314
#define PARS_UNIQUE_TOKEN 315
#define PARS_CLUSTERED_TOKEN 316
#define PARS_DOES_NOT_FIT_IN_MEM_TOKEN 317
#define PARS_ON_TOKEN 318
#define PARS_ASSIGN_TOKEN 319
#define PARS_DECLARE_TOKEN 320
#define PARS_CURSOR_TOKEN 321
#define PARS_SQL_TOKEN 322
#define PARS_OPEN_TOKEN 323
#define PARS_FETCH_TOKEN 324
#define PARS_CLOSE_TOKEN 325
#define PARS_NOTFOUND_TOKEN 326
#define PARS_TO_CHAR_TOKEN 327
#define PARS_TO_NUMBER_TOKEN 328
#define PARS_TO_BINARY_TOKEN 329
#define PARS_BINARY_TO_NUMBER_TOKEN 330
#define PARS_SUBSTR_TOKEN 331
#define PARS_REPLSTR_TOKEN 332
#define PARS_CONCAT_TOKEN 333
#define PARS_INSTR_TOKEN 334
#define PARS_LENGTH_TOKEN 335
#define PARS_SYSDATE_TOKEN 336
#define PARS_PRINTF_TOKEN 337
#define PARS_ASSERT_TOKEN 338
#define PARS_RND_TOKEN 339
#define PARS_RND_STR_TOKEN 340
#define PARS_ROW_PRINTF_TOKEN 341
#define PARS_COMMIT_TOKEN 342
#define PARS_ROLLBACK_TOKEN 343
#define PARS_WORK_TOKEN 344
#define PARS_UNSIGNED_TOKEN 345
#define PARS_EXIT_TOKEN 346
#define PARS_FUNCTION_TOKEN 347
#define NEG 348

View file

@ -15,6 +15,13 @@ Created 11/19/1996 Heikki Tuuri
#include "pars0types.h"
#include "row0types.h"
#include "trx0types.h"
#include "ut0vec.h"
/* Type of the user functions. The first argument is always InnoDB-supplied
and varies in type, while 'user_arg' is a user-supplied argument. The
meaning of the return type also varies. See the individual use cases, e.g.
the FETCH statement, for details on them. */
typedef void* (*pars_user_func_cb_t)(void* arg, void* user_arg);
extern int yydebug;
@ -77,6 +84,7 @@ que_t*
pars_sql(
/*=====*/
/* out, own: the query graph */
pars_info_t* info, /* in: extra information, or NULL */
const char* str); /* in: SQL string */
/*****************************************************************
Retrieves characters to the lexical analyzer. */
@ -157,6 +165,15 @@ pars_cursor_declaration(
table */
sel_node_t* select_node); /* in: select node */
/*************************************************************************
Parses a function declaration. */
que_node_t*
pars_function_declaration(
/*======================*/
/* out: sym_node */
sym_node_t* sym_node); /* in: function id node in the symbol
table */
/*************************************************************************
Parses a select statement. */
sel_node_t*
@ -269,6 +286,13 @@ pars_while_statement(
que_node_t* cond, /* in: while-condition */
que_node_t* stat_list); /* in: statement list */
/*************************************************************************
Parses an exit statement. */
exit_node_t*
pars_exit_statement(void);
/*=====================*/
/* out: exit statement node */
/*************************************************************************
Parses a return-statement. */
return_node_t*
@ -294,14 +318,16 @@ pars_assignment_statement(
sym_node_t* var, /* in: variable to assign */
que_node_t* val); /* in: value to assign */
/*************************************************************************
Parses a fetch statement. */
Parses a fetch statement. into_list or user_func (but not both) must be
non-NULL. */
fetch_node_t*
pars_fetch_statement(
/*=================*/
/* out: fetch statement node */
sym_node_t* cursor, /* in: cursor node */
sym_node_t* into_list); /* in: variables to set */
sym_node_t* into_list, /* in: variables to set, or NULL */
sym_node_t* user_func); /* in: user function name, or NULL */
/*************************************************************************
Parses an open or close cursor statement. */
@ -345,6 +371,8 @@ pars_column_def(
pars_res_word_t* type, /* in: data type */
sym_node_t* len, /* in: length of column, or
NULL */
void* is_unsigned, /* in: if not NULL, column
is of type UNSIGNED. */
void* is_not_null); /* in: if not NULL, column
is of type NOT NULL. */
/*************************************************************************
@ -418,6 +446,126 @@ pars_complete_graph_for_exec(
trx_t* trx, /* in: transaction handle */
mem_heap_t* heap); /* in: memory heap from which allocated */
/********************************************************************
Create parser info struct.*/
pars_info_t*
pars_info_create(void);
/*==================*/
/* out, own: info struct */
/********************************************************************
Free info struct and everything it contains.*/
void
pars_info_free(
/*===========*/
pars_info_t* info); /* in: info struct */
/********************************************************************
Add bound literal. */
void
pars_info_add_literal(
/*==================*/
pars_info_t* info, /* in: info struct */
const char* name, /* in: name */
const void* address, /* in: address */
ulint length, /* in: length of data */
ulint type, /* in: type, e.g. DATA_FIXBINARY */
ulint prtype); /* in: precise type, e.g.
DATA_UNSIGNED */
/********************************************************************
Equivalent to pars_info_add_literal(info, name, str, strlen(str),
DATA_VARCHAR, DATA_ENGLISH). */
void
pars_info_add_str_literal(
/*======================*/
pars_info_t* info, /* in: info struct */
const char* name, /* in: name */
const char* str); /* in: string */
/********************************************************************
Equivalent to:
char buf[4];
mach_write_to_4(buf, val);
pars_info_add_literal(info, name, buf, 4, DATA_INT, 0);
except that the buffer is dynamically allocated from the info struct's
heap. */
void
pars_info_add_int4_literal(
/*=======================*/
pars_info_t* info, /* in: info struct */
const char* name, /* in: name */
lint val); /* in: value */
/********************************************************************
Add user function. */
void
pars_info_add_function(
/*===================*/
pars_info_t* info, /* in: info struct */
const char* name, /* in: function name */
pars_user_func_cb_t func, /* in: function address */
void* arg); /* in: user-supplied argument */
/********************************************************************
Get user function with the given name.*/
pars_user_func_t*
pars_info_get_user_func(
/*====================*/
/* out: user func, or NULL if not
found */
pars_info_t* info, /* in: info struct */
const char* name); /* in: function name to find*/
/********************************************************************
Get bound literal with the given name.*/
pars_bound_lit_t*
pars_info_get_bound_lit(
/*====================*/
/* out: bound literal, or NULL if
not found */
pars_info_t* info, /* in: info struct */
const char* name); /* in: bound literal name to find */
/* Extra information supplied for pars_sql(). */
struct pars_info_struct {
mem_heap_t* heap; /* our own memory heap */
ib_vector_t* funcs; /* user functions, or NUll
(pars_user_func_t*) */
ib_vector_t* bound_lits; /* bound literals, or NULL
(pars_bound_lit_t*) */
ibool graph_owns_us; /* if TRUE (which is the default),
que_graph_free() will free us */
};
/* User-supplied function and argument. */
struct pars_user_func_struct {
const char* name; /* function name */
pars_user_func_cb_t func; /* function address */
void* arg; /* user-supplied argument */
};
/* Bound literal. */
struct pars_bound_lit_struct {
const char* name; /* name */
const void* address; /* address */
ulint length; /* length of data */
ulint type; /* type, e.g. DATA_FIXBINARY */
ulint prtype; /* precise type, e.g. DATA_UNSIGNED */
};
/* Struct used to denote a reserved word in a parsing tree */
struct pars_res_word_struct{
@ -498,6 +646,11 @@ struct for_node_struct{
que_node_t* stat_list; /* statement list */
};
/* exit statement node */
struct exit_node_struct{
que_common_t common; /* type: QUE_NODE_EXIT */
};
/* return-statement node */
struct return_node_struct{
que_common_t common; /* type: QUE_NODE_RETURN */

View file

@ -54,6 +54,16 @@ sym_tab_add_str_lit(
it */
ulint len); /* in: string length */
/**********************************************************************
Add a bound literal to a symbol table. */
sym_node_t*
sym_tab_add_bound_lit(
/*==================*/
/* out: symbol table node */
sym_tab_t* sym_tab, /* in: symbol table */
const char* name, /* in: name of bound literal */
ulint* lit_type); /* out: type of literal (PARS_*_LIT) */
/**********************************************************************
Adds an SQL null literal to a symbol table. */
sym_node_t*
@ -83,6 +93,19 @@ struct sym_node_struct{
been allocated from dynamic memory and it should be freed when the
symbol table is discarded */
/* 'alias' and 'indirection' are almost the same, but not quite.
'alias' always points to the primary instance of the variable, while
'indirection' does the same only if we should use the primary
instance's values for the node's data. This is usually the case, but
when initializing a cursor (e.g., "DECLARE CURSOR c IS SELECT * FROM
t WHERE id = x;"), we copy the values from the primary instance to
the cursor's instance so that they are fixed for the duration of the
cursor, and set 'indirection' to NULL. If we did not, the value of
'x' could change between fetches and things would break horribly.
TODO: It would be cleaner to make 'indirection' a boolean field and
always use 'alias' to refer to the primary node. */
sym_node_t* indirection; /* pointer to
another symbol table
node which contains
@ -158,6 +181,7 @@ struct sym_tab_struct{
/* position of the next character in
sql_string to give to the lexical
analyzer */
pars_info_t* info; /* extra information, or NULL */
sym_node_list_t sym_list;
/* list of symbol nodes in the symbol
table */
@ -180,6 +204,7 @@ struct sym_tab_struct{
#define SYM_CURSOR 96 /* named cursor */
#define SYM_PROCEDURE_NAME 97 /* stored procedure name */
#define SYM_INDEX 98 /* database index name */
#define SYM_FUNCTION 99 /* user function name */
#ifndef UNIV_NONINL
#include "pars0sym.ic"

View file

@ -9,6 +9,9 @@ Created 1/11/1998 Heikki Tuuri
#ifndef pars0types_h
#define pars0types_h
typedef struct pars_info_struct pars_info_t;
typedef struct pars_user_func_struct pars_user_func_t;
typedef struct pars_bound_lit_struct pars_bound_lit_t;
typedef struct sym_node_struct sym_node_t;
typedef struct sym_tab_struct sym_tab_t;
typedef struct pars_res_word_struct pars_res_word_t;
@ -19,6 +22,7 @@ typedef struct elsif_node_struct elsif_node_t;
typedef struct if_node_struct if_node_t;
typedef struct while_node_struct while_node_t;
typedef struct for_node_struct for_node_t;
typedef struct exit_node_struct exit_node_t;
typedef struct return_node_struct return_node_t;
typedef struct assign_node_struct assign_node_t;
typedef struct col_assign_node_struct col_assign_node_t;

View file

@ -277,6 +277,15 @@ que_node_get_parent(
/*================*/
/* out: parent node or NULL */
que_node_t* node); /* in: node */
/********************************************************************
Get the first containing loop node (e.g. while_node_t or for_node_t) for the
given node, or NULL if the node is not within a loop. */
que_node_t*
que_node_get_containing_loop_node(
/*==============================*/
/* out: containing loop node, or NULL. */
que_node_t* node); /* in: node */
/*************************************************************************
Catenates a query graph node to a list of them, possible empty list. */
UNIV_INLINE
@ -388,6 +397,7 @@ struct que_fork_struct{
sym_tab_t* sym_tab; /* symbol table of the query,
generated by the parser, or NULL
if the graph was created 'by hand' */
pars_info_t* info; /* in: info struct, or NULL */
/* The following cur_... fields are relevant only in a select graph */
ulint cur_end; /* QUE_CUR_NOT_DEFINED, QUE_CUR_START,
@ -469,6 +479,7 @@ struct que_fork_struct{
#define QUE_NODE_ROW_PRINTF 29
#define QUE_NODE_ELSIF 30
#define QUE_NODE_CALL 31
#define QUE_NODE_EXIT 32
/* Query thread states */
#define QUE_THR_RUNNING 1

View file

@ -244,7 +244,8 @@ row_update_for_mysql(
row_prebuilt_t* prebuilt); /* in: prebuilt struct in MySQL
handle */
/*************************************************************************
This can only be used when srv_locks_unsafe_for_binlog is TRUE. Before
This can only be used when srv_locks_unsafe_for_binlog is TRUE or
session is using a READ COMMITTED isolation level. Before
calling this function we must use trx_reset_new_rec_lock_info() and
trx_register_new_rec_lock() to store the information which new record locks
really were set. This function removes a newly set lock under prebuilt->pcur,

View file

@ -78,6 +78,26 @@ fetch_step(
/*=======*/
/* out: query thread to run next or NULL */
que_thr_t* thr); /* in: query thread */
/********************************************************************
Sample callback function for fetch that prints each row.*/
void*
row_fetch_print(
/*============*/
/* out: always returns non-NULL */
void* row, /* in: sel_node_t* */
void* user_arg); /* in: not used */
/********************************************************************
Callback function for fetch that stores an unsigned 4 byte integer to the
location pointed. The column's type must be DATA_INT, DATA_UNSIGNED, length
= 4. */
void*
row_fetch_store_uint4(
/*==================*/
/* out: always returns NULL */
void* row, /* in: sel_node_t* */
void* user_arg); /* in: data pointer */
/***************************************************************
Prints a row in a select result. */
@ -204,8 +224,6 @@ struct plan_struct{
ulint first_prefetched;/* index of the first cached row in
select buffer arrays for each column */
ibool no_prefetch; /* no prefetch for this table */
ibool mixed_index; /* TRUE if index is a clustered index
in a mixed cluster */
sym_node_list_t columns; /* symbol table nodes for the columns
to retrieve from the table */
UT_LIST_BASE_NODE_T(func_node_t)
@ -311,6 +329,20 @@ struct fetch_node_struct{
que_common_t common; /* type: QUE_NODE_FETCH */
sel_node_t* cursor_def; /* cursor definition */
sym_node_t* into_list; /* variables to set */
pars_user_func_t*
func; /* User callback function or NULL.
The first argument to the function
is a sel_node_t*, containing the
results of the SELECT operation for
one row. If the function returns
NULL, it is not interested in
further rows and the cursor is
modified so (cursor % NOTFOUND) is
true. If it returns not-NULL,
continue normally. See
row_fetch_print() for an example
(and a useful debugging tool). */
};
/* Open or close cursor statement node */

View file

@ -189,6 +189,10 @@ row_upd_index_replace_new_col_vals_index_pos(
upd_t* update, /* in: an update vector built for the index so
that the field number in an upd_field is the
index position */
ibool order_only,
/* in: if TRUE, limit the replacement to
ordering fields of index; note that this
does not work for non-clustered indexes. */
mem_heap_t* heap); /* in: memory heap to which we allocate and
copy the new values, set this as NULL if you
do not want allocation */

View file

@ -544,7 +544,9 @@ struct trx_struct{
the transaction; note that it is also
in the lock list trx_locks */
dict_index_t* new_rec_locks[2];/* these are normally NULL; if
srv_locks_unsafe_for_binlog is TRUE,
srv_locks_unsafe_for_binlog is TRUE
or session is using READ COMMITTED
isolation level,
in a cursor search, if we set a new
record lock on an index, this is set
to point to the index; this is

View file

@ -40,7 +40,9 @@ if we are compiling on Windows. */
#undef VERSION
/* Include the header file generated by GNU autoconf */
#ifndef __WIN__
#include "../ib_config.h"
#endif
#ifdef HAVE_SCHED_H
#include <sched.h>
@ -80,10 +82,6 @@ memory is read outside the allocated blocks. */
/* Make a non-inline debug version */
/* You can remove this define when the release is stable. This define adds
some consistency checks to code. They use a little CPU time. */
#define UNIV_RELEASE_NOT_YET_STABLE
#define UNIV_DEBUG
/*
#define UNIV_MEM_DEBUG
@ -127,7 +125,7 @@ by one. */
#ifdef __WIN__
#define UNIV_INLINE __inline
#else
#define UNIV_INLINE static inline
#define UNIV_INLINE static __inline__
#endif
#else
@ -177,6 +175,16 @@ management to ensure correct alignment for doubles etc. */
/* Note that inside MySQL 'byte' is defined as char on Linux! */
#define byte unsigned char
/* Define an unsigned integer type that is exactly 32 bits. */
#if SIZEOF_INT == 4
typedef unsigned int ib_uint32_t;
#elif SIZEOF_LONG == 4
typedef unsigned long ib_uint32_t;
#else
#error "Neither int or long is 4 bytes"
#endif
/* Another basic type we use is unsigned long integer which should be equal to
the word size of the machine, that is on a 32-bit platform 32 bits, and on a
64-bit platform 64 bits. We also give the printf format for the type as a
@ -204,9 +212,6 @@ typedef longlong ib_longlong;
#endif
#endif
/* The following type should be at least a 64-bit floating point number */
typedef double utfloat;
/* The 'undefined' value for a ulint */
#define ULINT_UNDEFINED ((ulint)(-1))

View file

@ -181,6 +181,30 @@ ut_memcpyq(
const char* src, /* in: string to be quoted */
ulint len); /* in: length of src */
/**************************************************************************
Return the number of times s2 occurs in s1. Overlapping instances of s2
are only counted once. */
ulint
ut_strcount(
/*========*/
/* out: the number of times s2 occurs in s1 */
const char* s1, /* in: string to search in */
const char* s2); /* in: string to search for */
/**************************************************************************
Replace every occurrence of s1 in str with s2. Overlapping instances of s1
are only replaced once. */
char *
ut_strreplace(
/*==========*/
/* out, own: modified string, must be
freed with mem_free() */
const char* str, /* in: string to operate on */
const char* s1, /* in: string to replace */
const char* s2); /* in: string to replace s1 with */
#ifndef UNIV_NONINL
#include "ut0mem.ic"
#endif

View file

@ -202,7 +202,7 @@ void
ut_print_buf(
/*=========*/
FILE* file, /* in: file where to print */
const byte* buf, /* in: memory buffer */
const void* buf, /* in: memory buffer */
ulint len); /* in: length of the buffer */
/**************************************************************************

73
include/ut0vec.h Normal file
View file

@ -0,0 +1,73 @@
#ifndef IB_VECTOR_H
#define IB_VECTOR_H
#include "univ.i"
#include "mem0mem.h"
typedef struct ib_vector_struct ib_vector_t;
/* An automatically resizing vector datatype with the following properties:
-Contains void* items.
-The items are owned by the caller.
-All memory allocation is done through a heap owned by the caller, who is
responsible for freeing it when done with the vector.
-When the vector is resized, the old memory area is left allocated since it
uses the same heap as the new memory area, so this is best used for
relatively small or short-lived uses.
*/
/********************************************************************
Create a new vector with the given initial size. */
ib_vector_t*
ib_vector_create(
/*=============*/
/* out: vector */
mem_heap_t* heap, /* in: heap */
ulint size); /* in: initial size */
/********************************************************************
Push a new element to the vector, increasing its size if necessary. */
void
ib_vector_push(
/*===========*/
ib_vector_t* vec, /* in: vector */
void* elem); /* in: data element */
/********************************************************************
Get the number of elements in the vector. */
UNIV_INLINE
ulint
ib_vector_size(
/*===========*/
/* out: number of elements in vector */
ib_vector_t* vec); /* in: vector */
/********************************************************************
Get the n'th element. */
UNIV_INLINE
void*
ib_vector_get(
/*==========*/
/* out: n'th element */
ib_vector_t* vec, /* in: vector */
ulint n); /* in: element index to get */
/* See comment at beginning of file. */
struct ib_vector_struct {
mem_heap_t* heap; /* heap */
void** data; /* data elements */
ulint used; /* number of elements currently used */
ulint total; /* number of elements allocated */
};
#ifndef UNIV_NONINL
#include "ut0vec.ic"
#endif
#endif

26
include/ut0vec.ic Normal file
View file

@ -0,0 +1,26 @@
/********************************************************************
Get number of elements in vector. */
UNIV_INLINE
ulint
ib_vector_size(
/*===========*/
/* out: number of elements in vector */
ib_vector_t* vec) /* in: vector */
{
return(vec->used);
}
/********************************************************************
Get n'th element. */
UNIV_INLINE
void*
ib_vector_get(
/*==========*/
/* out: n'th element */
ib_vector_t* vec, /* in: vector */
ulint n) /* in: element index to get */
{
ut_a(n < vec->used);
return(vec->data[n]);
}

View file

@ -1701,6 +1701,40 @@ lock_sec_rec_some_has_impl_off_kernel(
return(row_vers_impl_x_locked_off_kernel(rec, index, offsets));
}
/*************************************************************************
Return approximate number or record locks (bits set in the bitmap) for
this transaction. Since delete-marked records may be removed, the
record count will not be precise. */
ulint
lock_number_of_rows_locked(
/*=======================*/
trx_t* trx) /* in: transaction */
{
lock_t* lock;
ulint n_records = 0;
ulint n_bits;
ulint n_bit;
lock = UT_LIST_GET_FIRST(trx->trx_locks);
while (lock) {
if (lock_get_type(lock) == LOCK_REC) {
n_bits = lock_rec_get_n_bits(lock);
for (n_bit = 0; n_bit < n_bits; n_bit++) {
if (lock_rec_get_nth_bit(lock, n_bit)) {
n_records++;
}
}
}
lock = UT_LIST_GET_NEXT(trx_locks, lock);
}
return (n_records);
}
/*============== RECORD LOCK CREATION AND QUEUE MANAGEMENT =============*/
/*************************************************************************
@ -2012,7 +2046,8 @@ lock_rec_lock_fast(
if (!impl) {
lock_rec_create(mode, rec, heap_no, index, trx);
if (srv_locks_unsafe_for_binlog) {
if (srv_locks_unsafe_for_binlog
|| trx->isolation_level == TRX_ISO_READ_COMMITTED) {
trx_register_new_rec_lock(trx, index);
}
}
@ -2038,7 +2073,8 @@ lock_rec_lock_fast(
if (!lock_rec_get_nth_bit(lock, heap_no)) {
lock_rec_set_nth_bit(lock, heap_no);
if (srv_locks_unsafe_for_binlog) {
if (srv_locks_unsafe_for_binlog
|| trx->isolation_level == TRX_ISO_READ_COMMITTED) {
trx_register_new_rec_lock(trx, index);
}
}
@ -2099,7 +2135,8 @@ lock_rec_lock_slow(
err = lock_rec_enqueue_waiting(mode, rec, index, thr);
if (srv_locks_unsafe_for_binlog) {
if (srv_locks_unsafe_for_binlog
|| trx->isolation_level == TRX_ISO_READ_COMMITTED) {
trx_register_new_rec_lock(trx, index);
}
} else {
@ -2108,7 +2145,8 @@ lock_rec_lock_slow(
lock_rec_add_to_queue(LOCK_REC | mode, rec, heap_no,
index, trx);
if (srv_locks_unsafe_for_binlog) {
if (srv_locks_unsafe_for_binlog
|| trx->isolation_level == TRX_ISO_READ_COMMITTED) {
trx_register_new_rec_lock(trx, index);
}
}
@ -2469,15 +2507,18 @@ lock_rec_inherit_to_gap(
lock = lock_rec_get_first(rec, heap_no);
/* If srv_locks_unsafe_for_binlog is TRUE, we do not want locks set
/* If srv_locks_unsafe_for_binlog is TRUE or session is using
READ COMMITTED isolation level, we do not want locks set
by an UPDATE or a DELETE to be inherited as gap type locks. But we
DO want S-locks set by a consistency constraint to be inherited also
then. */
while (lock != NULL) {
if (!lock_rec_get_insert_intention(lock)
&& !(srv_locks_unsafe_for_binlog
&& lock_get_mode(lock) == LOCK_X)) {
&& !((srv_locks_unsafe_for_binlog
|| lock->trx->isolation_level ==
TRX_ISO_READ_COMMITTED)
&& lock_get_mode(lock) == LOCK_X)) {
lock_rec_add_to_queue(LOCK_REC | lock_get_mode(lock)
| LOCK_GAP,
@ -4404,6 +4445,10 @@ loop:
(ulong) ut_dulint_get_low(trx->read_view->up_limit_id));
}
fprintf(file,
"Trx has approximately %lu row locks\n",
(ulong) lock_number_of_rows_locked(trx));
if (trx->que_state == TRX_QUE_LOCK_WAIT) {
fprintf(file,
"------- TRX HAS BEEN WAITING %lu SEC FOR THIS LOCK TO BE GRANTED:\n",
@ -5280,3 +5325,4 @@ lock_clust_rec_read_check_and_lock_alt(
}
return(ret);
}

View file

@ -917,9 +917,9 @@ recv_parse_or_apply_log_rec_body(
ut_ad(!page || ptr);
if (index) {
dict_table_t* table = index->table;
mem_heap_free(index->heap);
mutex_free(&(table->autoinc_mutex));
mem_heap_free(table->heap);
dict_mem_index_free(index);
dict_mem_table_free(table);
}
return(ptr);

View file

@ -445,7 +445,7 @@ mem_heap_validate_or_print(
&& (mem_block_get_len(block) > UNIV_PAGE_SIZE)) {
fprintf(stderr,
"InnoDB: Error: mem block %p length %lu > UNIV_PAGE_SIZE\n", block,
"InnoDB: Error: mem block %p length %lu > UNIV_PAGE_SIZE\n", (void*) block,
(ulong) mem_block_get_len(block));
/* error */
@ -733,18 +733,18 @@ the neighborhood of a given pointer. */
void
mem_analyze_corruption(
/*===================*/
byte* ptr) /* in: pointer to place of possible corruption */
void* ptr) /* in: pointer to place of possible corruption */
{
byte* p;
ulint i;
ulint dist;
fputs("InnoDB: Apparent memory corruption: mem dump ", stderr);
ut_print_buf(stderr, ptr - 250, 500);
ut_print_buf(stderr, (byte*)ptr - 250, 500);
fputs("\nInnoDB: Scanning backward trying to find previous allocated mem blocks\n", stderr);
p = ptr;
p = (byte*)ptr;
dist = 0;
for (i = 0; i < 10; i++) {
@ -781,7 +781,7 @@ mem_analyze_corruption(
fprintf(stderr,
"InnoDB: Scanning forward trying to find next allocated mem blocks\n");
p = ptr;
p = (byte*)ptr;
dist = 0;
for (i = 0; i < 10; i++) {

View file

@ -141,7 +141,7 @@ mem_heap_create_block(
|| (type == MEM_HEAP_BUFFER + MEM_HEAP_BTR_SEARCH));
if (heap && heap->magic_n != MEM_BLOCK_MAGIC_N) {
mem_analyze_corruption((byte*)heap);
mem_analyze_corruption(heap);
}
/* In dynamic allocation, calculate the size: block header + data. */
@ -286,7 +286,7 @@ mem_heap_block_free(
ibool init_block;
if (block->magic_n != MEM_BLOCK_MAGIC_N) {
mem_analyze_corruption((byte*)block);
mem_analyze_corruption(block);
}
UT_LIST_REMOVE(list, heap->base, block);
@ -361,7 +361,7 @@ mem_validate_all_blocks(void)
while (block) {
if (block->magic_n != MEM_BLOCK_MAGIC_N) {
mem_analyze_corruption((byte*)block);
mem_analyze_corruption(block);
}
block = UT_LIST_GET_NEXT(mem_block_list, block);

View file

@ -294,7 +294,7 @@ mem_pool_fill_free_list(
}
if (UT_LIST_GET_LEN(pool->free_list[i + 1]) == 0) {
mem_analyze_corruption((byte*)area);
mem_analyze_corruption(area);
ut_error;
}
@ -363,7 +363,7 @@ mem_area_alloc(
"InnoDB: element is not marked free!\n",
(ulong) n);
mem_analyze_corruption((byte*)area);
mem_analyze_corruption(area);
/* Try to analyze a strange assertion failure reported at
mysql@lists.mysql.com where the free bit IS 1 in the
@ -382,7 +382,7 @@ mem_area_alloc(
"InnoDB: Error: Removing element from mem pool free list %lu\n"
"InnoDB: though the list length is 0!\n",
(ulong) n);
mem_analyze_corruption((byte*)area);
mem_analyze_corruption(area);
ut_error;
}
@ -475,7 +475,7 @@ mem_area_free(
"InnoDB: Error: Freeing element to mem pool free list though the\n"
"InnoDB: element is marked free!\n");
mem_analyze_corruption((byte*)area);
mem_analyze_corruption(area);
ut_error;
}
@ -486,7 +486,7 @@ mem_area_free(
"InnoDB: Error: Mem area size is 0. Possibly a memory overrun of the\n"
"InnoDB: previous allocated area!\n");
mem_analyze_corruption((byte*)area);
mem_analyze_corruption(area);
ut_error;
}
@ -502,7 +502,7 @@ mem_area_free(
"InnoDB: Error: Memory area size %lu, next area size %lu not a power of 2!\n"
"InnoDB: Possibly a memory overrun of the buffer being freed here.\n",
(ulong) size, (ulong) next_size);
mem_analyze_corruption((byte*)area);
mem_analyze_corruption(area);
ut_error;
}

View file

@ -1 +1 @@
--binlog_cache_size=32768
--binlog_cache_size=32768 --innodb_lock_wait_timeout=1

View file

@ -856,7 +856,7 @@ create table t1 (a char(20), index (a(5))) engine=innodb;
show create table t1;
Table Create Table
t1 CREATE TABLE `t1` (
`a` char(20) default NULL,
`a` char(20) DEFAULT NULL,
KEY `a` (`a`(5))
) ENGINE=InnoDB DEFAULT CHARSET=latin1
drop table t1;
@ -1295,22 +1295,14 @@ insert into t2 (a) select b from t1;
insert into t1 (a) select b from t2;
insert into t2 (a) select b from t1;
insert into t1 (a) select b from t2;
insert into t2 (a) select b from t1;
insert into t1 (a) select b from t2;
insert into t2 (a) select b from t1;
insert into t1 (a) select b from t2;
insert into t2 (a) select b from t1;
insert into t1 (a) select b from t2;
insert into t2 (a) select b from t1;
insert into t1 (a) select b from t2;
select count(*) from t1;
count(*)
29267
explain select * from t1 where c between 1 and 10000;
623
explain select * from t1 where c between 1 and 2500;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 range c c 5 NULL # Using where
update t1 set c=a;
explain select * from t1 where c between 1 and 10000;
explain select * from t1 where c between 1 and 2500;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 ALL c NULL NULL NULL # Using where
drop table t1,t2;
@ -1587,7 +1579,7 @@ create table t2 (id int(11) not null auto_increment, id2 int(11) not null, const
show create table t2;
Table Create Table
t2 CREATE TABLE `t2` (
`id` int(11) NOT NULL auto_increment,
`id` int(11) NOT NULL AUTO_INCREMENT,
`id2` int(11) NOT NULL,
PRIMARY KEY (`id`),
KEY `id` (`id`,`id2`),
@ -1598,7 +1590,7 @@ create table t2 (id int(11) not null auto_increment, id2 int(11) not null, const
show create table t2;
Table Create Table
t2 CREATE TABLE `t2` (
`id` int(11) NOT NULL auto_increment,
`id` int(11) NOT NULL AUTO_INCREMENT,
`id2` int(11) NOT NULL,
KEY `t1_id_fk` (`id`),
CONSTRAINT `t1_id_fk` FOREIGN KEY (`id`) REFERENCES `t1` (`id`)
@ -1607,7 +1599,7 @@ alter table t2 add index id_test (id), add index id_test2 (id,id2);
show create table t2;
Table Create Table
t2 CREATE TABLE `t2` (
`id` int(11) NOT NULL auto_increment,
`id` int(11) NOT NULL AUTO_INCREMENT,
`id2` int(11) NOT NULL,
KEY `id_test` (`id`),
KEY `id_test2` (`id`,`id2`),
@ -1620,8 +1612,8 @@ create table t2 (a int auto_increment primary key, b int, index(b), foreign key
show create table t2;
Table Create Table
t2 CREATE TABLE `t2` (
`a` int(11) NOT NULL auto_increment,
`b` int(11) default NULL,
`a` int(11) NOT NULL AUTO_INCREMENT,
`b` int(11) DEFAULT NULL,
PRIMARY KEY (`a`),
UNIQUE KEY `b_2` (`b`),
KEY `b` (`b`),
@ -1632,8 +1624,8 @@ create table t2 (a int auto_increment primary key, b int, foreign key (b) refere
show create table t2;
Table Create Table
t2 CREATE TABLE `t2` (
`a` int(11) NOT NULL auto_increment,
`b` int(11) default NULL,
`a` int(11) NOT NULL AUTO_INCREMENT,
`b` int(11) DEFAULT NULL,
PRIMARY KEY (`a`),
UNIQUE KEY `b` (`b`),
CONSTRAINT `t2_ibfk_1` FOREIGN KEY (`b`) REFERENCES `t1` (`id`),
@ -1843,40 +1835,40 @@ concat('*',v,'*',c,'*',t,'*')
show create table t1;
Table Create Table
t1 CREATE TABLE `t1` (
`v` varchar(10) default NULL,
`c` char(10) default NULL,
`v` varchar(10) DEFAULT NULL,
`c` char(10) DEFAULT NULL,
`t` text
) ENGINE=InnoDB DEFAULT CHARSET=latin1
create table t2 like t1;
show create table t2;
Table Create Table
t2 CREATE TABLE `t2` (
`v` varchar(10) default NULL,
`c` char(10) default NULL,
`v` varchar(10) DEFAULT NULL,
`c` char(10) DEFAULT NULL,
`t` text
) ENGINE=InnoDB DEFAULT CHARSET=latin1
create table t3 select * from t1;
show create table t3;
Table Create Table
t3 CREATE TABLE `t3` (
`v` varchar(10) default NULL,
`c` char(10) default NULL,
`v` varchar(10) DEFAULT NULL,
`c` char(10) DEFAULT NULL,
`t` text
) ENGINE=InnoDB DEFAULT CHARSET=latin1
alter table t1 modify c varchar(10);
show create table t1;
Table Create Table
t1 CREATE TABLE `t1` (
`v` varchar(10) default NULL,
`c` varchar(10) default NULL,
`v` varchar(10) DEFAULT NULL,
`c` varchar(10) DEFAULT NULL,
`t` text
) ENGINE=InnoDB DEFAULT CHARSET=latin1
alter table t1 modify v char(10);
show create table t1;
Table Create Table
t1 CREATE TABLE `t1` (
`v` char(10) default NULL,
`c` varchar(10) default NULL,
`v` char(10) DEFAULT NULL,
`c` varchar(10) DEFAULT NULL,
`t` text
) ENGINE=InnoDB DEFAULT CHARSET=latin1
alter table t1 modify t varchar(10);
@ -1885,9 +1877,9 @@ Note 1265 Data truncated for column 't' at row 2
show create table t1;
Table Create Table
t1 CREATE TABLE `t1` (
`v` char(10) default NULL,
`c` varchar(10) default NULL,
`t` varchar(10) default NULL
`v` char(10) DEFAULT NULL,
`c` varchar(10) DEFAULT NULL,
`t` varchar(10) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=latin1
select concat('*',v,'*',c,'*',t,'*') from t1;
concat('*',v,'*',c,'*',t,'*')
@ -1898,8 +1890,8 @@ create table t1 (v varchar(10), c char(10), t text, key(v), key(c), key(t(10)));
show create table t1;
Table Create Table
t1 CREATE TABLE `t1` (
`v` varchar(10) default NULL,
`c` char(10) default NULL,
`v` varchar(10) DEFAULT NULL,
`c` char(10) DEFAULT NULL,
`t` text,
KEY `v` (`v`),
KEY `c` (`c`),
@ -2117,8 +2109,8 @@ alter table t1 modify v varchar(300), drop key v, drop key v_2, add key v (v);
show create table t1;
Table Create Table
t1 CREATE TABLE `t1` (
`v` varchar(300) default NULL,
`c` char(10) default NULL,
`v` varchar(300) DEFAULT NULL,
`c` char(10) DEFAULT NULL,
`t` text,
KEY `c` (`c`),
KEY `t` (`t`(10)),
@ -2197,8 +2189,8 @@ alter table t1 drop key v, add key v (v(30));
show create table t1;
Table Create Table
t1 CREATE TABLE `t1` (
`v` varchar(300) default NULL,
`c` char(10) default NULL,
`v` varchar(300) DEFAULT NULL,
`c` char(10) DEFAULT NULL,
`t` text,
KEY `c` (`c`),
KEY `t` (`t`(10)),
@ -2277,8 +2269,8 @@ alter table t1 modify v varchar(600), drop key v, add key v (v);
show create table t1;
Table Create Table
t1 CREATE TABLE `t1` (
`v` varchar(600) default NULL,
`c` char(10) default NULL,
`v` varchar(600) DEFAULT NULL,
`c` char(10) DEFAULT NULL,
`t` text,
KEY `c` (`c`),
KEY `t` (`t`(10)),
@ -2355,8 +2347,8 @@ create table t1 (v varchar(10), c char(10), t text, key(v(5)), key(c(5)), key(t(
show create table t1;
Table Create Table
t1 CREATE TABLE `t1` (
`v` varchar(10) default NULL,
`c` char(10) default NULL,
`v` varchar(10) DEFAULT NULL,
`c` char(10) DEFAULT NULL,
`t` text,
KEY `v` (`v`(5)),
KEY `c` (`c`(5)),
@ -2367,15 +2359,15 @@ create table t1 (v char(10) character set utf8);
show create table t1;
Table Create Table
t1 CREATE TABLE `t1` (
`v` char(10) character set utf8 default NULL
`v` char(10) CHARACTER SET utf8 DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=latin1
drop table t1;
create table t1 (v varchar(10), c char(10)) row_format=fixed;
show create table t1;
Table Create Table
t1 CREATE TABLE `t1` (
`v` varchar(10) default NULL,
`c` char(10) default NULL
`v` varchar(10) DEFAULT NULL,
`c` char(10) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=latin1 ROW_FORMAT=FIXED
insert into t1 values('a','a'),('a ','a ');
select concat('*',v,'*',c,'*') from t1;
@ -2417,7 +2409,7 @@ Note 1246 Converting column 'v' from VARCHAR to TEXT
show create table t1;
Table Create Table
t1 CREATE TABLE `t1` (
`v` mediumtext character set utf8
`v` mediumtext CHARACTER SET utf8
) ENGINE=InnoDB DEFAULT CHARSET=latin1
drop table t1;
set storage_engine=MyISAM;
@ -2544,8 +2536,8 @@ character set = latin1 engine = innodb;
show create table t9;
Table Create Table
t9 CREATE TABLE `t9` (
`col1` varchar(512) default NULL,
`col2` varchar(512) default NULL,
`col1` varchar(512) DEFAULT NULL,
`col2` varchar(512) DEFAULT NULL,
KEY `col1` (`col1`,`col2`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1
drop table t1, t2, t3, t4, t5, t6, t7, t8, t9;
@ -2568,7 +2560,7 @@ Warning 1071 Specified key was too long; max key length is 767 bytes
show create table t1;
Table Create Table
t1 CREATE TABLE `t1` (
`col1` varchar(768) default NULL,
`col1` varchar(768) DEFAULT NULL,
KEY `col1` (`col1`(767))
) ENGINE=InnoDB DEFAULT CHARSET=latin1
drop table t1, t2, t3, t4;
@ -2635,25 +2627,6 @@ checksum table t1;
Table Checksum
test.t1 2050879373
drop table t1;
create table t1 (col1 integer primary key, col2 integer) engine=innodb;
insert t1 values (1,100);
create function f1 () returns integer begin
declare var1 int;
select col2 into var1 from t1 where col1=1 for update;
return var1;
end|
start transaction;
select f1();
f1()
100
update t1 set col2=0 where col1=1;
select * from t1;
col1 col2
1 100
rollback;
rollback;
drop table t1;
drop function f1;
create table t1 (
a int, b char(10), c char(10), filler char(10), primary key(a, b(2)), unique key (a, c(2))
) character set utf8 engine = innodb;
@ -3151,7 +3124,7 @@ ALTER TABLE t2 DROP FOREIGN KEY t2_ibfk_0;
SHOW CREATE TABLE t2;
Table Create Table
t2 CREATE TABLE `t2` (
`a` int(11) default NULL,
`a` int(11) DEFAULT NULL,
KEY `t2_ibfk_0` (`a`),
CONSTRAINT `t2_ibfk_0` FOREIGN KEY (`a`) REFERENCES `t1` (`a`),
CONSTRAINT `t2_ibfk_1` FOREIGN KEY (`a`) REFERENCES `t1` (`a`)
@ -3233,3 +3206,132 @@ UPDATE t1 SET field1 = 'other' WHERE field2 = 'somevalu';
ERROR 23000: Upholding foreign key constraints for table 't1', entry 'other-somevalu', key 1 would lead to a duplicate entry
DROP TABLE t2;
DROP TABLE t1;
create table t1 (id int not null, f_id int not null, f int not null,
primary key(f_id, id)) engine=innodb;
create table t2 (id int not null,s_id int not null,s varchar(200),
primary key(id)) engine=innodb;
INSERT INTO t1 VALUES (8, 1, 3);
INSERT INTO t1 VALUES (1, 2, 1);
INSERT INTO t2 VALUES (1, 0, '');
INSERT INTO t2 VALUES (8, 1, '');
commit;
DELETE ml.* FROM t1 AS ml LEFT JOIN t2 AS mm ON (mm.id=ml.id)
WHERE mm.id IS NULL;
select ml.* from t1 as ml left join t2 as mm on (mm.id=ml.id)
where mm.id is null lock in share mode;
id f_id f
drop table t1,t2;
create table t1(a int not null, b int, primary key(a)) engine=innodb;
insert into t1 values(1,1),(2,2),(3,1),(4,2),(5,1),(6,2),(7,3);
commit;
set autocommit = 0;
SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED;
update t1 set b = 5 where b = 1;
set autocommit = 0;
SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED;
select * from t1 where a = 7 and b = 3 for update;
a b
7 3
commit;
commit;
drop table t1;
create table t1(a int not null, b int, primary key(a)) engine=innodb;
insert into t1 values(1,1),(2,2),(3,1),(4,2),(5,1),(6,2);
commit;
set autocommit = 0;
select * from t1 lock in share mode;
a b
1 1
2 2
3 1
4 2
5 1
6 2
update t1 set b = 5 where b = 1;
set autocommit = 0;
select * from t1 where a = 2 and b = 2 for update;
ERROR HY000: Lock wait timeout exceeded; try restarting transaction
commit;
commit;
drop table t1;
create table t1(a int not null, b int, primary key(a)) engine=innodb;
insert into t1 values (1,2),(5,3),(4,2);
create table t2(d int not null, e int, primary key(d)) engine=innodb;
insert into t2 values (8,6),(12,1),(3,1);
commit;
set autocommit = 0;
select * from t2 for update;
d e
3 1
8 6
12 1
set autocommit = 0;
SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED;
insert into t1 select * from t2;
update t1 set b = (select e from t2 where a = d);
create table t3(d int not null, e int, primary key(d)) engine=innodb
select * from t2;
commit;
commit;
drop table t1, t2, t3;
create table t1(a int not null, b int, primary key(a)) engine=innodb;
insert into t1 values (1,2),(5,3),(4,2);
create table t2(a int not null, b int, primary key(a)) engine=innodb;
insert into t2 values (8,6),(12,1),(3,1);
create table t3(d int not null, b int, primary key(d)) engine=innodb;
insert into t3 values (8,6),(12,1),(3,1);
create table t5(a int not null, b int, primary key(a)) engine=innodb;
insert into t5 values (1,2),(5,3),(4,2);
create table t6(d int not null, e int, primary key(d)) engine=innodb;
insert into t6 values (8,6),(12,1),(3,1);
create table t8(a int not null, b int, primary key(a)) engine=innodb;
insert into t8 values (1,2),(5,3),(4,2);
create table t9(d int not null, e int, primary key(d)) engine=innodb;
insert into t9 values (8,6),(12,1),(3,1);
commit;
set autocommit = 0;
select * from t2 for update;
a b
3 1
8 6
12 1
set autocommit = 0;
SET SESSION TRANSACTION ISOLATION LEVEL SERIALIZABLE;
insert into t1 select * from t2;
set autocommit = 0;
SET SESSION TRANSACTION ISOLATION LEVEL SERIALIZABLE;
update t3 set b = (select b from t2 where a = d);
set autocommit = 0;
SET SESSION TRANSACTION ISOLATION LEVEL SERIALIZABLE;
create table t4(a int not null, b int, primary key(a)) engine=innodb select * from t2;
set autocommit = 0;
SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED;
insert into t5 (select * from t2 lock in share mode);
set autocommit = 0;
SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED;
update t6 set e = (select b from t2 where a = d lock in share mode);
set autocommit = 0;
SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED;
create table t7(a int not null, b int, primary key(a)) engine=innodb select * from t2 lock in share mode;
set autocommit = 0;
SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED;
insert into t8 (select * from t2 for update);
set autocommit = 0;
SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED;
update t9 set e = (select b from t2 where a = d for update);
set autocommit = 0;
SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED;
create table t10(a int not null, b int, primary key(a)) engine=innodb select * from t2 for update;
ERROR HY000: Lock wait timeout exceeded; try restarting transaction
ERROR HY000: Lock wait timeout exceeded; try restarting transaction
ERROR HY000: Lock wait timeout exceeded; try restarting transaction
ERROR HY000: Lock wait timeout exceeded; try restarting transaction
ERROR HY000: Lock wait timeout exceeded; try restarting transaction
ERROR HY000: Lock wait timeout exceeded; try restarting transaction
ERROR HY000: Lock wait timeout exceeded; try restarting transaction
ERROR HY000: Lock wait timeout exceeded; try restarting transaction
ERROR HY000: Lock wait timeout exceeded; try restarting transaction
commit;
drop table t1, t2, t3, t5, t6, t8, t9;
CREATE TABLE t1 (DB_ROW_ID int) engine=innodb;
ERROR HY000: Can't create table 'test.t1' (errno: -1)

View file

@ -891,20 +891,12 @@ insert into t2 (a) select b from t1;
insert into t1 (a) select b from t2;
insert into t2 (a) select b from t1;
insert into t1 (a) select b from t2;
insert into t2 (a) select b from t1;
insert into t1 (a) select b from t2;
insert into t2 (a) select b from t1;
insert into t1 (a) select b from t2;
insert into t2 (a) select b from t1;
insert into t1 (a) select b from t2;
insert into t2 (a) select b from t1;
insert into t1 (a) select b from t2;
select count(*) from t1;
--replace_column 9 #
explain select * from t1 where c between 1 and 10000;
explain select * from t1 where c between 1 and 2500;
update t1 set c=a;
--replace_column 9 #
explain select * from t1 where c between 1 and 10000;
explain select * from t1 where c between 1 and 2500;
drop table t1,t2;
#
@ -1576,33 +1568,7 @@ connection a;
checksum table t1;
drop table t1;
#
# BUG#11238 - in prelocking mode SELECT .. FOR UPDATE is changed to
# non-blocking SELECT
#
create table t1 (col1 integer primary key, col2 integer) engine=innodb;
insert t1 values (1,100);
delimiter |;
create function f1 () returns integer begin
declare var1 int;
select col2 into var1 from t1 where col1=1 for update;
return var1;
end|
delimiter ;|
start transaction;
select f1();
connection b;
send update t1 set col2=0 where col1=1;
connection default;
select * from t1;
connection a;
rollback;
connection b;
reap;
rollback;
connection default;
drop table t1;
drop function f1;
disconnect a;
disconnect b;
@ -1745,6 +1711,7 @@ commit;
set foreign_key_checks=0;
create table t2 (a int primary key, b int, foreign key (b) references t1(a)) engine = innodb;
--replace_result $MYSQLTEST_VARDIR . master-data/ ''
-- error 1005
create table t1(a char(10) primary key, b varchar(20)) engine = innodb;
set foreign_key_checks=1;
@ -1755,6 +1722,7 @@ drop table t2;
set foreign_key_checks=0;
create table t1(a varchar(10) primary key) engine = innodb DEFAULT CHARSET=latin1;
--replace_result $MYSQLTEST_VARDIR . master-data/ ''
-- error 1005
create table t2 (a varchar(10), foreign key (a) references t1(a)) engine = innodb DEFAULT CHARSET=utf8;
set foreign_key_checks=1;
@ -1784,6 +1752,7 @@ drop table t2,t1;
set foreign_key_checks=0;
create table t2 (a varchar(10), foreign key (a) references t1(a)) engine = innodb DEFAULT CHARSET=latin1;
create table t3(a varchar(10) primary key) engine = innodb DEFAULT CHARSET=utf8;
--replace_result $MYSQLTEST_VARDIR . master-data/ ''
-- error 1025
rename table t3 to t1;
set foreign_key_checks=1;
@ -2136,3 +2105,257 @@ UPDATE t1 SET field1 = 'other' WHERE field2 = 'somevalu';
DROP TABLE t2;
DROP TABLE t1;
create table t1 (id int not null, f_id int not null, f int not null,
primary key(f_id, id)) engine=innodb;
create table t2 (id int not null,s_id int not null,s varchar(200),
primary key(id)) engine=innodb;
INSERT INTO t1 VALUES (8, 1, 3);
INSERT INTO t1 VALUES (1, 2, 1);
INSERT INTO t2 VALUES (1, 0, '');
INSERT INTO t2 VALUES (8, 1, '');
commit;
DELETE ml.* FROM t1 AS ml LEFT JOIN t2 AS mm ON (mm.id=ml.id)
WHERE mm.id IS NULL;
select ml.* from t1 as ml left join t2 as mm on (mm.id=ml.id)
where mm.id is null lock in share mode;
drop table t1,t2;
#
# Test case where X-locks on unused rows should be released in a
# update (because READ COMMITTED isolation level)
#
connect (a,localhost,root,,);
connect (b,localhost,root,,);
connection a;
create table t1(a int not null, b int, primary key(a)) engine=innodb;
insert into t1 values(1,1),(2,2),(3,1),(4,2),(5,1),(6,2),(7,3);
commit;
set autocommit = 0;
SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED;
update t1 set b = 5 where b = 1;
connection b;
set autocommit = 0;
SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED;
#
# X-lock to record (7,3) should be released in a update
#
select * from t1 where a = 7 and b = 3 for update;
connection a;
commit;
connection b;
commit;
drop table t1;
connection default;
disconnect a;
disconnect b;
#
# Test case where no locks should be released (because we are not
# using READ COMMITTED isolation level)
#
connect (a,localhost,root,,);
connect (b,localhost,root,,);
connection a;
create table t1(a int not null, b int, primary key(a)) engine=innodb;
insert into t1 values(1,1),(2,2),(3,1),(4,2),(5,1),(6,2);
commit;
set autocommit = 0;
select * from t1 lock in share mode;
update t1 set b = 5 where b = 1;
connection b;
set autocommit = 0;
#
# S-lock to records (2,2),(4,2), and (6,2) should not be released in a update
#
--error 1205
select * from t1 where a = 2 and b = 2 for update;
#
# X-lock to record (1,1),(3,1),(5,1) should not be released in a update
#
--error 1205
connection a;
commit;
connection b;
commit;
connection default;
disconnect a;
disconnect b;
drop table t1;
#
# Consistent read should be used in following selects
#
# 1) INSERT INTO ... SELECT
# 2) UPDATE ... = ( SELECT ...)
# 3) CREATE ... SELECT
connect (a,localhost,root,,);
connect (b,localhost,root,,);
connection a;
create table t1(a int not null, b int, primary key(a)) engine=innodb;
insert into t1 values (1,2),(5,3),(4,2);
create table t2(d int not null, e int, primary key(d)) engine=innodb;
insert into t2 values (8,6),(12,1),(3,1);
commit;
set autocommit = 0;
select * from t2 for update;
connection b;
set autocommit = 0;
SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED;
insert into t1 select * from t2;
update t1 set b = (select e from t2 where a = d);
create table t3(d int not null, e int, primary key(d)) engine=innodb
select * from t2;
commit;
connection a;
commit;
connection default;
disconnect a;
disconnect b;
drop table t1, t2, t3;
#
# Consistent read should not be used if
#
# (a) isolation level is serializable OR
# (b) select ... lock in share mode OR
# (c) select ... for update
#
# in following queries:
#
# 1) INSERT INTO ... SELECT
# 2) UPDATE ... = ( SELECT ...)
# 3) CREATE ... SELECT
connect (a,localhost,root,,);
connect (b,localhost,root,,);
connect (c,localhost,root,,);
connect (d,localhost,root,,);
connect (e,localhost,root,,);
connect (f,localhost,root,,);
connect (g,localhost,root,,);
connect (h,localhost,root,,);
connect (i,localhost,root,,);
connect (j,localhost,root,,);
connection a;
create table t1(a int not null, b int, primary key(a)) engine=innodb;
insert into t1 values (1,2),(5,3),(4,2);
create table t2(a int not null, b int, primary key(a)) engine=innodb;
insert into t2 values (8,6),(12,1),(3,1);
create table t3(d int not null, b int, primary key(d)) engine=innodb;
insert into t3 values (8,6),(12,1),(3,1);
create table t5(a int not null, b int, primary key(a)) engine=innodb;
insert into t5 values (1,2),(5,3),(4,2);
create table t6(d int not null, e int, primary key(d)) engine=innodb;
insert into t6 values (8,6),(12,1),(3,1);
create table t8(a int not null, b int, primary key(a)) engine=innodb;
insert into t8 values (1,2),(5,3),(4,2);
create table t9(d int not null, e int, primary key(d)) engine=innodb;
insert into t9 values (8,6),(12,1),(3,1);
commit;
set autocommit = 0;
select * from t2 for update;
connection b;
set autocommit = 0;
SET SESSION TRANSACTION ISOLATION LEVEL SERIALIZABLE;
--send
insert into t1 select * from t2;
connection c;
set autocommit = 0;
SET SESSION TRANSACTION ISOLATION LEVEL SERIALIZABLE;
--send
update t3 set b = (select b from t2 where a = d);
connection d;
set autocommit = 0;
SET SESSION TRANSACTION ISOLATION LEVEL SERIALIZABLE;
--send
create table t4(a int not null, b int, primary key(a)) engine=innodb select * from t2;
connection e;
set autocommit = 0;
SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED;
--send
insert into t5 (select * from t2 lock in share mode);
connection f;
set autocommit = 0;
SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED;
--send
update t6 set e = (select b from t2 where a = d lock in share mode);
connection g;
set autocommit = 0;
SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED;
--send
create table t7(a int not null, b int, primary key(a)) engine=innodb select * from t2 lock in share mode;
connection h;
set autocommit = 0;
SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED;
--send
insert into t8 (select * from t2 for update);
connection i;
set autocommit = 0;
SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED;
--send
update t9 set e = (select b from t2 where a = d for update);
connection j;
set autocommit = 0;
SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED;
--send
create table t10(a int not null, b int, primary key(a)) engine=innodb select * from t2 for update;
connection b;
--error 1205
reap;
connection c;
--error 1205
reap;
connection d;
--error 1205
reap;
connection e;
--error 1205
reap;
connection f;
--error 1205
reap;
connection g;
--error 1205
reap;
connection h;
--error 1205
reap;
connection i;
--error 1205
reap;
connection j;
--error 1205
reap;
connection a;
commit;
connection default;
disconnect a;
disconnect b;
disconnect c;
disconnect d;
disconnect e;
disconnect f;
disconnect g;
disconnect h;
disconnect i;
disconnect j;
drop table t1, t2, t3, t5, t6, t8, t9;
# bug 18934, "InnoDB crashes when table uses column names like DB_ROW_ID"
--error 1005
CREATE TABLE t1 (DB_ROW_ID int) engine=innodb;

View file

@ -1,50 +1,51 @@
SET storage_engine=innodb;
DROP TABLE IF EXISTS t1, gis_point, gis_line, gis_polygon, gis_multi_point, gis_multi_line, gis_multi_polygon, gis_geometrycollection, gis_geometry;
CREATE TABLE gis_point (fid INTEGER, g POINT);
CREATE TABLE gis_line (fid INTEGER, g LINESTRING);
CREATE TABLE gis_polygon (fid INTEGER, g POLYGON);
CREATE TABLE gis_multi_point (fid INTEGER, g MULTIPOINT);
CREATE TABLE gis_multi_line (fid INTEGER, g MULTILINESTRING);
CREATE TABLE gis_multi_polygon (fid INTEGER, g MULTIPOLYGON);
CREATE TABLE gis_geometrycollection (fid INTEGER, g GEOMETRYCOLLECTION);
CREATE TABLE gis_geometry (fid INTEGER, g GEOMETRY);
CREATE TABLE gis_point (fid INTEGER PRIMARY KEY AUTO_INCREMENT, g POINT);
CREATE TABLE gis_line (fid INTEGER PRIMARY KEY AUTO_INCREMENT, g LINESTRING);
CREATE TABLE gis_polygon (fid INTEGER PRIMARY KEY AUTO_INCREMENT, g POLYGON);
CREATE TABLE gis_multi_point (fid INTEGER PRIMARY KEY AUTO_INCREMENT, g MULTIPOINT);
CREATE TABLE gis_multi_line (fid INTEGER PRIMARY KEY AUTO_INCREMENT, g MULTILINESTRING);
CREATE TABLE gis_multi_polygon (fid INTEGER PRIMARY KEY AUTO_INCREMENT, g MULTIPOLYGON);
CREATE TABLE gis_geometrycollection (fid INTEGER PRIMARY KEY AUTO_INCREMENT, g GEOMETRYCOLLECTION);
CREATE TABLE gis_geometry (fid INTEGER PRIMARY KEY AUTO_INCREMENT, g GEOMETRY);
SHOW CREATE TABLE gis_point;
Table Create Table
gis_point CREATE TABLE `gis_point` (
`fid` int(11) default NULL,
`g` point default NULL
`fid` int(11) NOT NULL AUTO_INCREMENT,
`g` point DEFAULT NULL,
PRIMARY KEY (`fid`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1
SHOW FIELDS FROM gis_point;
Field Type Null Key Default Extra
fid int(11) YES NULL
fid int(11) NO PRI NULL auto_increment
g point YES NULL
SHOW FIELDS FROM gis_line;
Field Type Null Key Default Extra
fid int(11) YES NULL
fid int(11) NO PRI NULL auto_increment
g linestring YES NULL
SHOW FIELDS FROM gis_polygon;
Field Type Null Key Default Extra
fid int(11) YES NULL
fid int(11) NO PRI NULL auto_increment
g polygon YES NULL
SHOW FIELDS FROM gis_multi_point;
Field Type Null Key Default Extra
fid int(11) YES NULL
fid int(11) NO PRI NULL auto_increment
g multipoint YES NULL
SHOW FIELDS FROM gis_multi_line;
Field Type Null Key Default Extra
fid int(11) YES NULL
fid int(11) NO PRI NULL auto_increment
g multilinestring YES NULL
SHOW FIELDS FROM gis_multi_polygon;
Field Type Null Key Default Extra
fid int(11) YES NULL
fid int(11) NO PRI NULL auto_increment
g multipolygon YES NULL
SHOW FIELDS FROM gis_geometrycollection;
Field Type Null Key Default Extra
fid int(11) YES NULL
fid int(11) NO PRI NULL auto_increment
g geometrycollection YES NULL
SHOW FIELDS FROM gis_geometry;
Field Type Null Key Default Extra
fid int(11) YES NULL
fid int(11) NO PRI NULL auto_increment
g geometry YES NULL
INSERT INTO gis_point VALUES
(101, PointFromText('POINT(10 10)')),
@ -407,6 +408,7 @@ Warnings:
Note 1003 select `test`.`g1`.`fid` AS `first`,`test`.`g2`.`fid` AS `second`,within(`test`.`g1`.`g`,`test`.`g2`.`g`) AS `w`,contains(`test`.`g1`.`g`,`test`.`g2`.`g`) AS `c`,overlaps(`test`.`g1`.`g`,`test`.`g2`.`g`) AS `o`,equals(`test`.`g1`.`g`,`test`.`g2`.`g`) AS `e`,disjoint(`test`.`g1`.`g`,`test`.`g2`.`g`) AS `d`,touches(`test`.`g1`.`g`,`test`.`g2`.`g`) AS `t`,intersects(`test`.`g1`.`g`,`test`.`g2`.`g`) AS `i`,crosses(`test`.`g1`.`g`,`test`.`g2`.`g`) AS `r` from `test`.`gis_geometrycollection` `g1` join `test`.`gis_geometrycollection` `g2` order by `test`.`g1`.`fid`,`test`.`g2`.`fid`
DROP TABLE gis_point, gis_line, gis_polygon, gis_multi_point, gis_multi_line, gis_multi_polygon, gis_geometrycollection, gis_geometry;
CREATE TABLE t1 (
a INTEGER PRIMARY KEY AUTO_INCREMENT,
gp point,
ln linestring,
pg polygon,
@ -418,6 +420,7 @@ gm geometry
);
SHOW FIELDS FROM t1;
Field Type Null Key Default Extra
a int(11) NO PRI NULL auto_increment
gp point YES NULL
ln linestring YES NULL
pg polygon YES NULL
@ -429,6 +432,7 @@ gm geometry YES NULL
ALTER TABLE t1 ADD fid INT;
SHOW FIELDS FROM t1;
Field Type Null Key Default Extra
a int(11) NO PRI NULL auto_increment
gp point YES NULL
ln linestring YES NULL
pg polygon YES NULL
@ -439,20 +443,20 @@ gc geometrycollection YES NULL
gm geometry YES NULL
fid int(11) YES NULL
DROP TABLE t1;
create table t1 (a geometry not null);
insert into t1 values (GeomFromText('Point(1 2)'));
insert into t1 values ('Garbage');
create table t1 (pk integer primary key auto_increment, a geometry not null);
insert into t1 (a) values (GeomFromText('Point(1 2)'));
insert into t1 (a) values ('Garbage');
ERROR 22003: Cannot get geometry object from data you send to the GEOMETRY field
insert IGNORE into t1 values ('Garbage');
insert IGNORE into t1 (a) values ('Garbage');
ERROR 22003: Cannot get geometry object from data you send to the GEOMETRY field
drop table t1;
create table t1 (fl geometry);
insert into t1 values (1);
create table t1 (pk integer primary key auto_increment, fl geometry);
insert into t1 (fl) values (1);
ERROR 22003: Cannot get geometry object from data you send to the GEOMETRY field
insert into t1 values (1.11);
insert into t1 (fl) values (1.11);
ERROR 22003: Cannot get geometry object from data you send to the GEOMETRY field
insert into t1 values ("qwerty");
insert into t1 (fl) values ("qwerty");
ERROR 22003: Cannot get geometry object from data you send to the GEOMETRY field
insert into t1 values (pointfromtext('point(1,1)'));
insert into t1 (fl) values (pointfromtext('point(1,1)'));
ERROR 22003: Cannot get geometry object from data you send to the GEOMETRY field
drop table t1;

View file

@ -1 +1 @@
--innodb_locks_unsafe_for_binlog=true
--innodb_locks_unsafe_for_binlog=true --innodb_lock_wait_timeout=1

View file

@ -15,7 +15,7 @@ where mm.id is null lock in share mode;
id f_id f
drop table t1,t2;
create table t1(a int not null, b int, primary key(a)) engine=innodb;
insert into t1 values(1,1),(2,2),(3,1),(4,2),(5,1),(6,2);
insert into t1 values(1,1),(2,2),(3,1),(4,2),(5,1),(6,2),(7,3);
commit;
set autocommit = 0;
select * from t1 lock in share mode;
@ -26,6 +26,7 @@ a b
4 2
5 1
6 2
7 3
update t1 set b = 5 where b = 1;
set autocommit = 0;
select * from t1 where a = 2 and b = 2 for update;
@ -33,3 +34,87 @@ ERROR HY000: Lock wait timeout exceeded; try restarting transaction
commit;
commit;
drop table t1;
create table t1(a int not null, b int, primary key(a)) engine=innodb;
insert into t1 values(1,1),(2,2),(3,1),(4,2),(5,1),(6,2),(7,3);
commit;
set autocommit = 0;
update t1 set b = 5 where b = 1;
set autocommit = 0;
select * from t1 where a = 7 and b = 3 for update;
a b
7 3
commit;
commit;
drop table t1;
create table t1(a int not null, b int, primary key(a)) engine=innodb;
insert into t1 values (1,2),(5,3),(4,2);
create table t2(d int not null, e int, primary key(d)) engine=innodb;
insert into t2 values (8,6),(12,1),(3,1);
commit;
set autocommit = 0;
select * from t2 for update;
d e
3 1
8 6
12 1
set autocommit = 0;
insert into t1 select * from t2;
update t1 set b = (select e from t2 where a = d);
create table t3(d int not null, e int, primary key(d)) engine=innodb
select * from t2;
commit;
commit;
drop table t1, t2, t3;
create table t1(a int not null, b int, primary key(a)) engine=innodb;
insert into t1 values (1,2),(5,3),(4,2);
create table t2(a int not null, b int, primary key(a)) engine=innodb;
insert into t2 values (8,6),(12,1),(3,1);
create table t3(d int not null, b int, primary key(d)) engine=innodb;
insert into t3 values (8,6),(12,1),(3,1);
create table t5(a int not null, b int, primary key(a)) engine=innodb;
insert into t5 values (1,2),(5,3),(4,2);
create table t6(d int not null, e int, primary key(d)) engine=innodb;
insert into t6 values (8,6),(12,1),(3,1);
create table t8(a int not null, b int, primary key(a)) engine=innodb;
insert into t8 values (1,2),(5,3),(4,2);
create table t9(d int not null, e int, primary key(d)) engine=innodb;
insert into t9 values (8,6),(12,1),(3,1);
commit;
set autocommit = 0;
select * from t2 for update;
a b
3 1
8 6
12 1
set autocommit = 0;
SET SESSION TRANSACTION ISOLATION LEVEL SERIALIZABLE;
insert into t1 select * from t2;
set autocommit = 0;
SET SESSION TRANSACTION ISOLATION LEVEL SERIALIZABLE;
update t3 set b = (select b from t2 where a = d);
set autocommit = 0;
SET SESSION TRANSACTION ISOLATION LEVEL SERIALIZABLE;
create table t4(a int not null, b int, primary key(a)) engine=innodb select * from t2;
set autocommit = 0;
insert into t5 (select * from t2 lock in share mode);
set autocommit = 0;
update t6 set e = (select b from t2 where a = d lock in share mode);
set autocommit = 0;
create table t7(a int not null, b int, primary key(a)) engine=innodb select * from t2 lock in share mode;
set autocommit = 0;
insert into t8 (select * from t2 for update);
set autocommit = 0;
update t9 set e = (select b from t2 where a = d for update);
set autocommit = 0;
create table t10(a int not null, b int, primary key(a)) engine=innodb select * from t2 for update;
ERROR HY000: Lock wait timeout exceeded; try restarting transaction
ERROR HY000: Lock wait timeout exceeded; try restarting transaction
ERROR HY000: Lock wait timeout exceeded; try restarting transaction
ERROR HY000: Lock wait timeout exceeded; try restarting transaction
ERROR HY000: Lock wait timeout exceeded; try restarting transaction
ERROR HY000: Lock wait timeout exceeded; try restarting transaction
ERROR HY000: Lock wait timeout exceeded; try restarting transaction
ERROR HY000: Lock wait timeout exceeded; try restarting transaction
ERROR HY000: Lock wait timeout exceeded; try restarting transaction
commit;
drop table t1, t2, t3, t5, t6, t8, t9;

View file

@ -1,7 +1,9 @@
-- source include/have_innodb.inc
#
# Note that these tests uses a innodb_locks_unsafe_for_binlog option.
#
# Note that these tests uses options
# innodb_locks_unsafe_for_binlog = true
# innodb_lock_timeout = 5
#
# Test cases for a bug #15650
#
@ -33,7 +35,7 @@ connect (a,localhost,root,,);
connect (b,localhost,root,,);
connection a;
create table t1(a int not null, b int, primary key(a)) engine=innodb;
insert into t1 values(1,1),(2,2),(3,1),(4,2),(5,1),(6,2);
insert into t1 values(1,1),(2,2),(3,1),(4,2),(5,1),(6,2),(7,3);
commit;
set autocommit = 0;
select * from t1 lock in share mode;
@ -50,6 +52,197 @@ commit;
connection b;
commit;
drop table t1;
connection default;
disconnect a;
disconnect b;
#
# unlock row test
#
connect (a,localhost,root,,);
connect (b,localhost,root,,);
connection a;
create table t1(a int not null, b int, primary key(a)) engine=innodb;
insert into t1 values(1,1),(2,2),(3,1),(4,2),(5,1),(6,2),(7,3);
commit;
set autocommit = 0;
update t1 set b = 5 where b = 1;
connection b;
set autocommit = 0;
#
# X-lock to record (7,3) should be released in a update
#
select * from t1 where a = 7 and b = 3 for update;
commit;
connection a;
commit;
drop table t1;
connection default;
disconnect a;
disconnect b;
#
# Consistent read should be used in following selects
#
# 1) INSERT INTO ... SELECT
# 2) UPDATE ... = ( SELECT ...)
# 3) CREATE ... SELECT
connect (a,localhost,root,,);
connect (b,localhost,root,,);
connection a;
create table t1(a int not null, b int, primary key(a)) engine=innodb;
insert into t1 values (1,2),(5,3),(4,2);
create table t2(d int not null, e int, primary key(d)) engine=innodb;
insert into t2 values (8,6),(12,1),(3,1);
commit;
set autocommit = 0;
select * from t2 for update;
connection b;
set autocommit = 0;
insert into t1 select * from t2;
update t1 set b = (select e from t2 where a = d);
create table t3(d int not null, e int, primary key(d)) engine=innodb
select * from t2;
commit;
connection a;
commit;
connection default;
disconnect a;
disconnect b;
drop table t1, t2, t3;
#
# Consistent read should not be used if
#
# (a) isolation level is serializable OR
# (b) select ... lock in share mode OR
# (c) select ... for update
#
# in following queries:
#
# 1) INSERT INTO ... SELECT
# 2) UPDATE ... = ( SELECT ...)
# 3) CREATE ... SELECT
connect (a,localhost,root,,);
connect (b,localhost,root,,);
connect (c,localhost,root,,);
connect (d,localhost,root,,);
connect (e,localhost,root,,);
connect (f,localhost,root,,);
connect (g,localhost,root,,);
connect (h,localhost,root,,);
connect (i,localhost,root,,);
connect (j,localhost,root,,);
connection a;
create table t1(a int not null, b int, primary key(a)) engine=innodb;
insert into t1 values (1,2),(5,3),(4,2);
create table t2(a int not null, b int, primary key(a)) engine=innodb;
insert into t2 values (8,6),(12,1),(3,1);
create table t3(d int not null, b int, primary key(d)) engine=innodb;
insert into t3 values (8,6),(12,1),(3,1);
create table t5(a int not null, b int, primary key(a)) engine=innodb;
insert into t5 values (1,2),(5,3),(4,2);
create table t6(d int not null, e int, primary key(d)) engine=innodb;
insert into t6 values (8,6),(12,1),(3,1);
create table t8(a int not null, b int, primary key(a)) engine=innodb;
insert into t8 values (1,2),(5,3),(4,2);
create table t9(d int not null, e int, primary key(d)) engine=innodb;
insert into t9 values (8,6),(12,1),(3,1);
commit;
set autocommit = 0;
select * from t2 for update;
connection b;
set autocommit = 0;
SET SESSION TRANSACTION ISOLATION LEVEL SERIALIZABLE;
--send
insert into t1 select * from t2;
connection c;
set autocommit = 0;
SET SESSION TRANSACTION ISOLATION LEVEL SERIALIZABLE;
--send
update t3 set b = (select b from t2 where a = d);
connection d;
set autocommit = 0;
SET SESSION TRANSACTION ISOLATION LEVEL SERIALIZABLE;
--send
create table t4(a int not null, b int, primary key(a)) engine=innodb select * from t2;
connection e;
set autocommit = 0;
--send
insert into t5 (select * from t2 lock in share mode);
connection f;
set autocommit = 0;
--send
update t6 set e = (select b from t2 where a = d lock in share mode);
connection g;
set autocommit = 0;
--send
create table t7(a int not null, b int, primary key(a)) engine=innodb select * from t2 lock in share mode;
connection h;
set autocommit = 0;
--send
insert into t8 (select * from t2 for update);
connection i;
set autocommit = 0;
--send
update t9 set e = (select b from t2 where a = d for update);
connection j;
set autocommit = 0;
--send
create table t10(a int not null, b int, primary key(a)) engine=innodb select * from t2 for update;
connection b;
--error 1205
reap;
connection c;
--error 1205
reap;
connection d;
--error 1205
reap;
connection e;
--error 1205
reap;
connection f;
--error 1205
reap;
connection g;
--error 1205
reap;
connection h;
--error 1205
reap;
connection i;
--error 1205
reap;
connection j;
--error 1205
reap;
connection a;
commit;
connection default;
disconnect a;
disconnect b;
disconnect c;
disconnect d;
disconnect e;
disconnect f;
disconnect g;
disconnect h;
disconnect i;
disconnect j;
drop table t1, t2, t3, t5, t6, t8, t9;

View file

@ -641,9 +641,8 @@ os_fast_mutex_free(
" InnoDB: error: return value %lu when calling\n"
"InnoDB: pthread_mutex_destroy().\n", (ulint)ret);
fprintf(stderr,
"InnoDB: Byte contents of the pthread mutex at %p:\n", fast_mutex);
ut_print_buf(stderr, (const byte*)fast_mutex,
sizeof(os_fast_mutex_t));
"InnoDB: Byte contents of the pthread mutex at %p:\n", (void*) fast_mutex);
ut_print_buf(stderr, fast_mutex, sizeof(os_fast_mutex_t));
fprintf(stderr, "\n");
}
#endif

File diff suppressed because it is too large Load diff

20
pars/make_flex.sh Executable file
View file

@ -0,0 +1,20 @@
#!/bin/bash
#
# generate lexer files from flex input files.
set -eu
TMPFILE=_flex_tmp.c
OUTFILE=lexyy.c
flex -o $TMPFILE pars0lex.l
# AIX needs its includes done in a certain order, so include "univ.i" first
# to be sure we get it right.
echo '#include "univ.i"' > $OUTFILE
# flex assigns a pointer to an int in one place without a cast, resulting in
# a warning on Win64. this adds the cast.
sed -e 's/int offset = (yy_c_buf_p) - (yytext_ptr);/int offset = (int)((yy_c_buf_p) - (yytext_ptr));/;' < $TMPFILE >> $OUTFILE
rm $TMPFILE

File diff suppressed because it is too large Load diff

View file

@ -32,177 +32,187 @@
PARS_INT_LIT = 258,
PARS_FLOAT_LIT = 259,
PARS_STR_LIT = 260,
PARS_NULL_LIT = 261,
PARS_ID_TOKEN = 262,
PARS_AND_TOKEN = 263,
PARS_OR_TOKEN = 264,
PARS_NOT_TOKEN = 265,
PARS_GE_TOKEN = 266,
PARS_LE_TOKEN = 267,
PARS_NE_TOKEN = 268,
PARS_PROCEDURE_TOKEN = 269,
PARS_IN_TOKEN = 270,
PARS_OUT_TOKEN = 271,
PARS_BINARY_TOKEN = 272,
PARS_BLOB_TOKEN = 273,
PARS_INT_TOKEN = 274,
PARS_INTEGER_TOKEN = 275,
PARS_FLOAT_TOKEN = 276,
PARS_CHAR_TOKEN = 277,
PARS_IS_TOKEN = 278,
PARS_BEGIN_TOKEN = 279,
PARS_END_TOKEN = 280,
PARS_IF_TOKEN = 281,
PARS_THEN_TOKEN = 282,
PARS_ELSE_TOKEN = 283,
PARS_ELSIF_TOKEN = 284,
PARS_LOOP_TOKEN = 285,
PARS_WHILE_TOKEN = 286,
PARS_RETURN_TOKEN = 287,
PARS_SELECT_TOKEN = 288,
PARS_SUM_TOKEN = 289,
PARS_COUNT_TOKEN = 290,
PARS_DISTINCT_TOKEN = 291,
PARS_FROM_TOKEN = 292,
PARS_WHERE_TOKEN = 293,
PARS_FOR_TOKEN = 294,
PARS_DDOT_TOKEN = 295,
PARS_CONSISTENT_TOKEN = 296,
PARS_READ_TOKEN = 297,
PARS_ORDER_TOKEN = 298,
PARS_BY_TOKEN = 299,
PARS_ASC_TOKEN = 300,
PARS_DESC_TOKEN = 301,
PARS_INSERT_TOKEN = 302,
PARS_INTO_TOKEN = 303,
PARS_VALUES_TOKEN = 304,
PARS_UPDATE_TOKEN = 305,
PARS_SET_TOKEN = 306,
PARS_DELETE_TOKEN = 307,
PARS_CURRENT_TOKEN = 308,
PARS_OF_TOKEN = 309,
PARS_CREATE_TOKEN = 310,
PARS_TABLE_TOKEN = 311,
PARS_INDEX_TOKEN = 312,
PARS_UNIQUE_TOKEN = 313,
PARS_CLUSTERED_TOKEN = 314,
PARS_DOES_NOT_FIT_IN_MEM_TOKEN = 315,
PARS_ON_TOKEN = 316,
PARS_ASSIGN_TOKEN = 317,
PARS_DECLARE_TOKEN = 318,
PARS_CURSOR_TOKEN = 319,
PARS_SQL_TOKEN = 320,
PARS_OPEN_TOKEN = 321,
PARS_FETCH_TOKEN = 322,
PARS_CLOSE_TOKEN = 323,
PARS_NOTFOUND_TOKEN = 324,
PARS_TO_CHAR_TOKEN = 325,
PARS_TO_NUMBER_TOKEN = 326,
PARS_TO_BINARY_TOKEN = 327,
PARS_BINARY_TO_NUMBER_TOKEN = 328,
PARS_SUBSTR_TOKEN = 329,
PARS_REPLSTR_TOKEN = 330,
PARS_CONCAT_TOKEN = 331,
PARS_INSTR_TOKEN = 332,
PARS_LENGTH_TOKEN = 333,
PARS_SYSDATE_TOKEN = 334,
PARS_PRINTF_TOKEN = 335,
PARS_ASSERT_TOKEN = 336,
PARS_RND_TOKEN = 337,
PARS_RND_STR_TOKEN = 338,
PARS_ROW_PRINTF_TOKEN = 339,
PARS_COMMIT_TOKEN = 340,
PARS_ROLLBACK_TOKEN = 341,
PARS_WORK_TOKEN = 342,
NEG = 343
PARS_FIXBINARY_LIT = 261,
PARS_BLOB_LIT = 262,
PARS_NULL_LIT = 263,
PARS_ID_TOKEN = 264,
PARS_AND_TOKEN = 265,
PARS_OR_TOKEN = 266,
PARS_NOT_TOKEN = 267,
PARS_GE_TOKEN = 268,
PARS_LE_TOKEN = 269,
PARS_NE_TOKEN = 270,
PARS_PROCEDURE_TOKEN = 271,
PARS_IN_TOKEN = 272,
PARS_OUT_TOKEN = 273,
PARS_BINARY_TOKEN = 274,
PARS_BLOB_TOKEN = 275,
PARS_INT_TOKEN = 276,
PARS_INTEGER_TOKEN = 277,
PARS_FLOAT_TOKEN = 278,
PARS_CHAR_TOKEN = 279,
PARS_IS_TOKEN = 280,
PARS_BEGIN_TOKEN = 281,
PARS_END_TOKEN = 282,
PARS_IF_TOKEN = 283,
PARS_THEN_TOKEN = 284,
PARS_ELSE_TOKEN = 285,
PARS_ELSIF_TOKEN = 286,
PARS_LOOP_TOKEN = 287,
PARS_WHILE_TOKEN = 288,
PARS_RETURN_TOKEN = 289,
PARS_SELECT_TOKEN = 290,
PARS_SUM_TOKEN = 291,
PARS_COUNT_TOKEN = 292,
PARS_DISTINCT_TOKEN = 293,
PARS_FROM_TOKEN = 294,
PARS_WHERE_TOKEN = 295,
PARS_FOR_TOKEN = 296,
PARS_DDOT_TOKEN = 297,
PARS_CONSISTENT_TOKEN = 298,
PARS_READ_TOKEN = 299,
PARS_ORDER_TOKEN = 300,
PARS_BY_TOKEN = 301,
PARS_ASC_TOKEN = 302,
PARS_DESC_TOKEN = 303,
PARS_INSERT_TOKEN = 304,
PARS_INTO_TOKEN = 305,
PARS_VALUES_TOKEN = 306,
PARS_UPDATE_TOKEN = 307,
PARS_SET_TOKEN = 308,
PARS_DELETE_TOKEN = 309,
PARS_CURRENT_TOKEN = 310,
PARS_OF_TOKEN = 311,
PARS_CREATE_TOKEN = 312,
PARS_TABLE_TOKEN = 313,
PARS_INDEX_TOKEN = 314,
PARS_UNIQUE_TOKEN = 315,
PARS_CLUSTERED_TOKEN = 316,
PARS_DOES_NOT_FIT_IN_MEM_TOKEN = 317,
PARS_ON_TOKEN = 318,
PARS_ASSIGN_TOKEN = 319,
PARS_DECLARE_TOKEN = 320,
PARS_CURSOR_TOKEN = 321,
PARS_SQL_TOKEN = 322,
PARS_OPEN_TOKEN = 323,
PARS_FETCH_TOKEN = 324,
PARS_CLOSE_TOKEN = 325,
PARS_NOTFOUND_TOKEN = 326,
PARS_TO_CHAR_TOKEN = 327,
PARS_TO_NUMBER_TOKEN = 328,
PARS_TO_BINARY_TOKEN = 329,
PARS_BINARY_TO_NUMBER_TOKEN = 330,
PARS_SUBSTR_TOKEN = 331,
PARS_REPLSTR_TOKEN = 332,
PARS_CONCAT_TOKEN = 333,
PARS_INSTR_TOKEN = 334,
PARS_LENGTH_TOKEN = 335,
PARS_SYSDATE_TOKEN = 336,
PARS_PRINTF_TOKEN = 337,
PARS_ASSERT_TOKEN = 338,
PARS_RND_TOKEN = 339,
PARS_RND_STR_TOKEN = 340,
PARS_ROW_PRINTF_TOKEN = 341,
PARS_COMMIT_TOKEN = 342,
PARS_ROLLBACK_TOKEN = 343,
PARS_WORK_TOKEN = 344,
PARS_UNSIGNED_TOKEN = 345,
PARS_EXIT_TOKEN = 346,
PARS_FUNCTION_TOKEN = 347,
NEG = 348
};
#endif
#define PARS_INT_LIT 258
#define PARS_FLOAT_LIT 259
#define PARS_STR_LIT 260
#define PARS_NULL_LIT 261
#define PARS_ID_TOKEN 262
#define PARS_AND_TOKEN 263
#define PARS_OR_TOKEN 264
#define PARS_NOT_TOKEN 265
#define PARS_GE_TOKEN 266
#define PARS_LE_TOKEN 267
#define PARS_NE_TOKEN 268
#define PARS_PROCEDURE_TOKEN 269
#define PARS_IN_TOKEN 270
#define PARS_OUT_TOKEN 271
#define PARS_BINARY_TOKEN 272
#define PARS_BLOB_TOKEN 273
#define PARS_INT_TOKEN 274
#define PARS_INTEGER_TOKEN 275
#define PARS_FLOAT_TOKEN 276
#define PARS_CHAR_TOKEN 277
#define PARS_IS_TOKEN 278
#define PARS_BEGIN_TOKEN 279
#define PARS_END_TOKEN 280
#define PARS_IF_TOKEN 281
#define PARS_THEN_TOKEN 282
#define PARS_ELSE_TOKEN 283
#define PARS_ELSIF_TOKEN 284
#define PARS_LOOP_TOKEN 285
#define PARS_WHILE_TOKEN 286
#define PARS_RETURN_TOKEN 287
#define PARS_SELECT_TOKEN 288
#define PARS_SUM_TOKEN 289
#define PARS_COUNT_TOKEN 290
#define PARS_DISTINCT_TOKEN 291
#define PARS_FROM_TOKEN 292
#define PARS_WHERE_TOKEN 293
#define PARS_FOR_TOKEN 294
#define PARS_DDOT_TOKEN 295
#define PARS_CONSISTENT_TOKEN 296
#define PARS_READ_TOKEN 297
#define PARS_ORDER_TOKEN 298
#define PARS_BY_TOKEN 299
#define PARS_ASC_TOKEN 300
#define PARS_DESC_TOKEN 301
#define PARS_INSERT_TOKEN 302
#define PARS_INTO_TOKEN 303
#define PARS_VALUES_TOKEN 304
#define PARS_UPDATE_TOKEN 305
#define PARS_SET_TOKEN 306
#define PARS_DELETE_TOKEN 307
#define PARS_CURRENT_TOKEN 308
#define PARS_OF_TOKEN 309
#define PARS_CREATE_TOKEN 310
#define PARS_TABLE_TOKEN 311
#define PARS_INDEX_TOKEN 312
#define PARS_UNIQUE_TOKEN 313
#define PARS_CLUSTERED_TOKEN 314
#define PARS_DOES_NOT_FIT_IN_MEM_TOKEN 315
#define PARS_ON_TOKEN 316
#define PARS_ASSIGN_TOKEN 317
#define PARS_DECLARE_TOKEN 318
#define PARS_CURSOR_TOKEN 319
#define PARS_SQL_TOKEN 320
#define PARS_OPEN_TOKEN 321
#define PARS_FETCH_TOKEN 322
#define PARS_CLOSE_TOKEN 323
#define PARS_NOTFOUND_TOKEN 324
#define PARS_TO_CHAR_TOKEN 325
#define PARS_TO_NUMBER_TOKEN 326
#define PARS_TO_BINARY_TOKEN 327
#define PARS_BINARY_TO_NUMBER_TOKEN 328
#define PARS_SUBSTR_TOKEN 329
#define PARS_REPLSTR_TOKEN 330
#define PARS_CONCAT_TOKEN 331
#define PARS_INSTR_TOKEN 332
#define PARS_LENGTH_TOKEN 333
#define PARS_SYSDATE_TOKEN 334
#define PARS_PRINTF_TOKEN 335
#define PARS_ASSERT_TOKEN 336
#define PARS_RND_TOKEN 337
#define PARS_RND_STR_TOKEN 338
#define PARS_ROW_PRINTF_TOKEN 339
#define PARS_COMMIT_TOKEN 340
#define PARS_ROLLBACK_TOKEN 341
#define PARS_WORK_TOKEN 342
#define NEG 343
#define PARS_FIXBINARY_LIT 261
#define PARS_BLOB_LIT 262
#define PARS_NULL_LIT 263
#define PARS_ID_TOKEN 264
#define PARS_AND_TOKEN 265
#define PARS_OR_TOKEN 266
#define PARS_NOT_TOKEN 267
#define PARS_GE_TOKEN 268
#define PARS_LE_TOKEN 269
#define PARS_NE_TOKEN 270
#define PARS_PROCEDURE_TOKEN 271
#define PARS_IN_TOKEN 272
#define PARS_OUT_TOKEN 273
#define PARS_BINARY_TOKEN 274
#define PARS_BLOB_TOKEN 275
#define PARS_INT_TOKEN 276
#define PARS_INTEGER_TOKEN 277
#define PARS_FLOAT_TOKEN 278
#define PARS_CHAR_TOKEN 279
#define PARS_IS_TOKEN 280
#define PARS_BEGIN_TOKEN 281
#define PARS_END_TOKEN 282
#define PARS_IF_TOKEN 283
#define PARS_THEN_TOKEN 284
#define PARS_ELSE_TOKEN 285
#define PARS_ELSIF_TOKEN 286
#define PARS_LOOP_TOKEN 287
#define PARS_WHILE_TOKEN 288
#define PARS_RETURN_TOKEN 289
#define PARS_SELECT_TOKEN 290
#define PARS_SUM_TOKEN 291
#define PARS_COUNT_TOKEN 292
#define PARS_DISTINCT_TOKEN 293
#define PARS_FROM_TOKEN 294
#define PARS_WHERE_TOKEN 295
#define PARS_FOR_TOKEN 296
#define PARS_DDOT_TOKEN 297
#define PARS_CONSISTENT_TOKEN 298
#define PARS_READ_TOKEN 299
#define PARS_ORDER_TOKEN 300
#define PARS_BY_TOKEN 301
#define PARS_ASC_TOKEN 302
#define PARS_DESC_TOKEN 303
#define PARS_INSERT_TOKEN 304
#define PARS_INTO_TOKEN 305
#define PARS_VALUES_TOKEN 306
#define PARS_UPDATE_TOKEN 307
#define PARS_SET_TOKEN 308
#define PARS_DELETE_TOKEN 309
#define PARS_CURRENT_TOKEN 310
#define PARS_OF_TOKEN 311
#define PARS_CREATE_TOKEN 312
#define PARS_TABLE_TOKEN 313
#define PARS_INDEX_TOKEN 314
#define PARS_UNIQUE_TOKEN 315
#define PARS_CLUSTERED_TOKEN 316
#define PARS_DOES_NOT_FIT_IN_MEM_TOKEN 317
#define PARS_ON_TOKEN 318
#define PARS_ASSIGN_TOKEN 319
#define PARS_DECLARE_TOKEN 320
#define PARS_CURSOR_TOKEN 321
#define PARS_SQL_TOKEN 322
#define PARS_OPEN_TOKEN 323
#define PARS_FETCH_TOKEN 324
#define PARS_CLOSE_TOKEN 325
#define PARS_NOTFOUND_TOKEN 326
#define PARS_TO_CHAR_TOKEN 327
#define PARS_TO_NUMBER_TOKEN 328
#define PARS_TO_BINARY_TOKEN 329
#define PARS_BINARY_TO_NUMBER_TOKEN 330
#define PARS_SUBSTR_TOKEN 331
#define PARS_REPLSTR_TOKEN 332
#define PARS_CONCAT_TOKEN 333
#define PARS_INSTR_TOKEN 334
#define PARS_LENGTH_TOKEN 335
#define PARS_SYSDATE_TOKEN 336
#define PARS_PRINTF_TOKEN 337
#define PARS_ASSERT_TOKEN 338
#define PARS_RND_TOKEN 339
#define PARS_RND_STR_TOKEN 340
#define PARS_ROW_PRINTF_TOKEN 341
#define PARS_COMMIT_TOKEN 342
#define PARS_ROLLBACK_TOKEN 343
#define PARS_WORK_TOKEN 344
#define PARS_UNSIGNED_TOKEN 345
#define PARS_EXIT_TOKEN 346
#define PARS_FUNCTION_TOKEN 347
#define NEG 348

View file

@ -29,10 +29,12 @@ que_node_t */
int
yylex(void);
%}
%token PARS_INT_LIT
%token PARS_FLOAT_LIT
%token PARS_STR_LIT
%token PARS_FIXBINARY_LIT
%token PARS_BLOB_LIT
%token PARS_NULL_LIT
%token PARS_ID_TOKEN
%token PARS_AND_TOKEN
@ -115,6 +117,9 @@ yylex(void);
%token PARS_COMMIT_TOKEN
%token PARS_ROLLBACK_TOKEN
%token PARS_WORK_TOKEN
%token PARS_UNSIGNED_TOKEN
%token PARS_EXIT_TOKEN
%token PARS_FUNCTION_TOKEN
%left PARS_AND_TOKEN PARS_OR_TOKEN
%left PARS_NOT_TOKEN
@ -133,6 +138,7 @@ statement:
| predefined_procedure_call ';'
| while_statement ';'
| for_statement ';'
| exit_statement ';'
| if_statement ';'
| return_statement ';'
| assignment_statement ';'
@ -165,6 +171,8 @@ exp:
| PARS_INT_LIT { $$ = $1;}
| PARS_FLOAT_LIT { $$ = $1;}
| PARS_STR_LIT { $$ = $1;}
| PARS_FIXBINARY_LIT { $$ = $1;}
| PARS_BLOB_LIT { $$ = $1;}
| PARS_NULL_LIT { $$ = $1;}
| PARS_SQL_TOKEN { $$ = $1;}
| exp '+' exp { $$ = pars_op('+', $1, $3); }
@ -225,6 +233,10 @@ predefined_procedure_name:
| PARS_ASSERT_TOKEN { $$ = &pars_assert_token; }
;
user_function_call:
PARS_ID_TOKEN '(' ')' { $$ = $1; }
;
table_list:
PARS_ID_TOKEN { $$ = que_node_list_add_last(NULL, $1); }
| table_list ',' PARS_ID_TOKEN
@ -262,14 +274,14 @@ select_item:
que_node_list_add_last(NULL,
$3)); }
;
select_item_list:
/* Nothing */ { $$ = NULL; }
| select_item { $$ = que_node_list_add_last(NULL, $1); }
| select_item_list ',' select_item
{ $$ = que_node_list_add_last($1, $3); }
;
select_list:
'*' { $$ = pars_select_list(&pars_star_denoter,
NULL); }
@ -377,7 +389,7 @@ delete_statement_positioned:
delete_statement_start
cursor_positioned { $$ = pars_update_statement($1, $2, NULL); }
;
row_printf_statement:
PARS_ROW_PRINTF_TOKEN select_statement
{ $$ = pars_row_printf_statement($2); }
@ -428,6 +440,10 @@ for_statement:
{ $$ = pars_for_statement($2, $4, $6, $8); }
;
exit_statement:
PARS_EXIT_TOKEN { $$ = pars_exit_statement(); }
;
return_statement:
PARS_RETURN_TOKEN { $$ = pars_return_statement(); }
;
@ -446,12 +462,14 @@ close_cursor_statement:
fetch_statement:
PARS_FETCH_TOKEN PARS_ID_TOKEN PARS_INTO_TOKEN variable_list
{ $$ = pars_fetch_statement($2, $4); }
{ $$ = pars_fetch_statement($2, $4, NULL); }
| PARS_FETCH_TOKEN PARS_ID_TOKEN PARS_INTO_TOKEN user_function_call
{ $$ = pars_fetch_statement($2, NULL, $4); }
;
column_def:
PARS_ID_TOKEN type_name opt_column_len opt_not_null
{ $$ = pars_column_def($1, $2, $3, $4); }
PARS_ID_TOKEN type_name opt_column_len opt_unsigned opt_not_null
{ $$ = pars_column_def($1, $2, $3, $4, $5); }
;
column_def_list:
@ -466,6 +484,13 @@ opt_column_len:
{ $$ = $2; }
;
opt_unsigned:
/* Nothing */ { $$ = NULL; }
| PARS_UNSIGNED_TOKEN
{ $$ = &pars_int_token;
/* pass any non-NULL pointer */ }
;
opt_not_null:
/* Nothing */ { $$ = NULL; }
| PARS_NOT_TOKEN PARS_NULL_LIT
@ -479,7 +504,7 @@ not_fit_in_memory:
{ $$ = &pars_int_token;
/* pass any non-NULL pointer */ }
;
create_table:
PARS_CREATE_TOKEN PARS_TABLE_TOKEN
PARS_ID_TOKEN '(' column_def_list ')'
@ -550,8 +575,8 @@ variable_declaration:
;
variable_declaration_list:
/* Nothing */
| variable_declaration
/* Nothing */
| variable_declaration
| variable_declaration_list variable_declaration
;
@ -561,10 +586,20 @@ cursor_declaration:
{ $$ = pars_cursor_declaration($3, $5); }
;
function_declaration:
PARS_DECLARE_TOKEN PARS_FUNCTION_TOKEN PARS_ID_TOKEN ';'
{ $$ = pars_function_declaration($3); }
;
declaration:
cursor_declaration
| function_declaration
;
declaration_list:
/* Nothing */
| cursor_declaration
| declaration_list cursor_declaration
| declaration
| declaration_list declaration
;
procedure_definition:
@ -577,5 +612,5 @@ procedure_definition:
PARS_END_TOKEN { $$ = pars_procedure_definition($2, $4,
$10); }
;
%%

View file

@ -12,27 +12,11 @@ not automatically generate them from pars0grm.y and pars0lex.l.
How to make the InnoDB parser and lexer C files:
1. First do
bison -d pars0grm.y
That generates pars0grm.tab.c and pars0grm.tab.h.
1. Run ./make_flex.sh to generate lexer files.
2. Rename pars0grm.tab.c to pars0grm.c and pars0grm.tab.h to pars0grm.h.
2. Run ./make_bison.sh to generate parser files.
3. Copy pars0grm.h also to /innobase/include
4. Do
flex pars0lex.l
That generates lex.yy.c.
5. Rename lex.yy.c to lexyy.c.
6. Add '#include "univ.i"' before #include <stdio.h> in lexyy.c
(Needed for AIX)
7. Add a type cast to int to the assignment below the comment
'need more input.' (Removes a warning on Win64)
These instructions seem to work at least with bison-1.28 and flex-2.5.4 on
These instructions seem to work at least with bison-1.875d and flex-2.5.31 on
Linux.
*******************************************************/
@ -96,11 +80,14 @@ string_append(
}
%}
DIGIT [0-9]
ID [a-z_A-Z][a-z_A-Z0-9]*
BOUND_LIT \:[a-z_A-Z0-9]+
%x comment
%x quoted
%x id
%%
{DIGIT}+ {
@ -115,6 +102,15 @@ ID [a-z_A-Z][a-z_A-Z0-9]*
return(PARS_FLOAT_LIT);
}
{BOUND_LIT} {
ulint type;
yylval = sym_tab_add_bound_lit(pars_sym_tab_global,
yytext + 1, &type);
return(type);
}
"'" {
/* Quoted character string literals are handled in an explicit
start state 'quoted'. This state is entered and the buffer for
@ -153,6 +149,45 @@ In the state 'quoted', only two actions are possible (defined below). */
}
}
\" {
/* Quoted identifiers are handled in an explicit start state 'id'.
This state is entered and the buffer for the scanned string is emptied
upon encountering a starting quote.
In the state 'id', only two actions are possible (defined below). */
BEGIN(id);
stringbuf_len = 0;
}
<id>[^\"]+ {
/* Got a sequence of characters other than '"':
append to string buffer */
string_append(yytext, yyleng);
}
<id>\"+ {
/* Got a sequence of '"' characters:
append half of them to string buffer,
as '""' represents a single '"'.
We apply truncating division,
so that '"""' will result in '"'. */
string_append(yytext, yyleng / 2);
/* If we got an odd number of quotes, then the
last quote we got is the terminating quote.
At the end of the string, we return to the
initial start state and report the scanned
identifier. */
if (yyleng % 2) {
BEGIN(INITIAL);
yylval = sym_tab_add_id(
pars_sym_tab_global,
(byte*) stringbuf, stringbuf_len);
return(PARS_ID_TOKEN);
}
}
"NULL" {
yylval = sym_tab_add_null_lit(pars_sym_tab_global);
@ -462,6 +497,18 @@ In the state 'quoted', only two actions are possible (defined below). */
return(PARS_WORK_TOKEN);
}
"UNSIGNED" {
return(PARS_UNSIGNED_TOKEN);
}
"EXIT" {
return(PARS_EXIT_TOKEN);
}
"FUNCTION" {
return(PARS_FUNCTION_TOKEN);
}
{ID} {
yylval = sym_tab_add_id(pars_sym_tab_global,
(byte*)yytext,

View file

@ -313,7 +313,6 @@ opt_calc_index_goodness(
ulint goodness;
ulint n_fields;
ulint col_no;
ulint mix_id_col_no;
ulint op;
ulint j;
@ -326,8 +325,6 @@ opt_calc_index_goodness(
n_fields = dict_index_get_n_unique_in_tree(index);
mix_id_col_no = dict_table_get_sys_col_no(index->table, DATA_MIX_ID);
for (j = 0; j < n_fields; j++) {
col_no = dict_index_get_nth_col_no(index, j);
@ -335,13 +332,7 @@ opt_calc_index_goodness(
exp = opt_look_for_col_in_cond_before(OPT_EQUAL, col_no,
sel_node->search_cond,
sel_node, nth_table, &op);
if (col_no == mix_id_col_no) {
ut_ad(exp == NULL);
index_plan[j] = NULL;
*last_op = '=';
goodness += 4;
} else if (exp) {
if (exp) {
/* The value for this column is exactly known already
at this stage of the join */
@ -531,7 +522,6 @@ opt_search_plan_for_table(
warning */
ulint best_goodness;
ulint best_last_op = 0; /* remove warning */
ulint mix_id_pos;
que_node_t* index_plan[256];
que_node_t* best_index_plan[256];
@ -601,26 +591,6 @@ opt_search_plan_for_table(
plan->unique_search = FALSE;
}
if ((table->type != DICT_TABLE_ORDINARY)
&& dict_index_is_clust(best_index)) {
plan->mixed_index = TRUE;
mix_id_pos = table->mix_len;
if (mix_id_pos < n_fields) {
/* We have to add the mix id as a (string) literal
expression to the tuple_exps */
plan->tuple_exps[mix_id_pos] =
sym_tab_add_str_lit(pars_sym_tab_global,
table->mix_id_buf,
table->mix_id_len);
}
} else {
plan->mixed_index = FALSE;
}
plan->old_vers_heap = NULL;
btr_pcur_init(&(plan->pcur));
@ -1055,7 +1025,6 @@ opt_clust_access(
dict_table_t* table;
dict_index_t* clust_index;
dict_index_t* index;
dfield_t* dfield;
mem_heap_t* heap;
ulint n_fields;
ulint pos;
@ -1109,22 +1078,7 @@ opt_clust_access(
*(plan->clust_map + i) = pos;
ut_ad((pos != ULINT_UNDEFINED)
|| ((table->type == DICT_TABLE_CLUSTER_MEMBER)
&& (i == table->mix_len)));
}
if (table->type == DICT_TABLE_CLUSTER_MEMBER) {
/* Preset the mix id field to the mix id constant */
dfield = dtuple_get_nth_field(plan->clust_ref, table->mix_len);
dfield_set_data(dfield, mem_heap_alloc(heap,
table->mix_id_len),
table->mix_id_len);
ut_memcpy(dfield_get_data(dfield), table->mix_id_buf,
table->mix_id_len);
ut_ad(pos != ULINT_UNDEFINED);
}
}

View file

@ -373,14 +373,15 @@ pars_resolve_exp_variables_and_types(
}
/* Not resolved yet: look in the symbol table for a variable
or a cursor with the same name */
or a cursor or a function with the same name */
node = UT_LIST_GET_FIRST(pars_sym_tab_global->sym_list);
while (node) {
if (node->resolved
&& ((node->token_type == SYM_VAR)
|| (node->token_type == SYM_CURSOR))
|| (node->token_type == SYM_CURSOR)
|| (node->token_type == SYM_FUNCTION))
&& node->name
&& (sym_node->name_len == node->name_len)
&& (ut_memcmp(sym_node->name, node->name,
@ -486,7 +487,7 @@ pars_resolve_exp_columns(
while (t_node) {
table = t_node->table;
n_cols = dict_table_get_n_user_cols(table);
n_cols = dict_table_get_n_cols(table);
for (i = 0; i < n_cols; i++) {
col = dict_table_get_nth_col(table, i);
@ -786,6 +787,26 @@ pars_cursor_declaration(
return(sym_node);
}
/*************************************************************************
Parses a function declaration. */
que_node_t*
pars_function_declaration(
/*======================*/
/* out: sym_node */
sym_node_t* sym_node) /* in: function id node in the symbol
table */
{
sym_node->resolved = TRUE;
sym_node->token_type = SYM_FUNCTION;
/* Check that the function exists. */
ut_a(pars_info_get_user_func(pars_sym_tab_global->info,
sym_node->name));
return(sym_node);
}
/*************************************************************************
Parses a delete or update statement start. */
@ -1085,6 +1106,8 @@ pars_set_dfield_type(
pars_res_word_t* type, /* in: pointer to a type
token */
ulint len, /* in: length, or 0 */
ibool is_unsigned, /* in: if TRUE, column is
UNSIGNED. */
ibool is_not_null) /* in: if TRUE, column is
NOT NULL. */
{
@ -1094,48 +1117,30 @@ pars_set_dfield_type(
flags |= DATA_NOT_NULL;
}
if (is_unsigned) {
flags |= DATA_UNSIGNED;
}
if (type == &pars_int_token) {
if (len != 0) {
ut_error;
}
ut_a(len == 0);
dtype_set(dfield_get_type(dfield), DATA_INT, flags, 4, 0);
} else if (type == &pars_char_token) {
if (len != 0) {
ut_error;
}
ut_a(len == 0);
dtype_set(dfield_get_type(dfield), DATA_VARCHAR,
DATA_ENGLISH | flags, 0, 0);
} else if (type == &pars_binary_token) {
if (len == 0) {
ut_error;
}
ut_a(len != 0);
dtype_set(dfield_get_type(dfield), DATA_FIXBINARY,
DATA_BINARY_TYPE | flags, len, 0);
} else if (type == &pars_blob_token) {
if (len != 0) {
ut_error;
}
ut_a(len == 0);
dtype_set(dfield_get_type(dfield), DATA_BLOB,
DATA_BINARY_TYPE | flags, 0, 0);
} else if (type == &pars_binary_token) {
if (len == 0) {
ut_error;
}
dtype_set(dfield_get_type(dfield), DATA_FIXBINARY,
DATA_BINARY_TYPE, len, 0);
} else if (type == &pars_blob_token) {
if (len != 0) {
ut_error;
}
dtype_set(dfield_get_type(dfield), DATA_BLOB,
DATA_BINARY_TYPE, 0, 0);
} else {
ut_error;
}
@ -1158,7 +1163,7 @@ pars_variable_declaration(
node->param_type = PARS_NOT_PARAM;
pars_set_dfield_type(que_node_get_val(node), type, 0, FALSE);
pars_set_dfield_type(que_node_get_val(node), type, 0, FALSE, FALSE);
return(node);
}
@ -1346,6 +1351,22 @@ pars_for_statement(
return(node);
}
/*************************************************************************
Parses an exit statement. */
exit_node_t*
pars_exit_statement(void)
/*=====================*/
/* out: exit statement node */
{
exit_node_t* node;
node = mem_heap_alloc(pars_sym_tab_global->heap, sizeof(exit_node_t));
node->common.type = QUE_NODE_EXIT;
return(node);
}
/*************************************************************************
Parses a return-statement. */
@ -1411,26 +1432,42 @@ pars_procedure_call(
}
/*************************************************************************
Parses a fetch statement. */
Parses a fetch statement. into_list or user_func (but not both) must be
non-NULL. */
fetch_node_t*
pars_fetch_statement(
/*=================*/
/* out: fetch statement node */
sym_node_t* cursor, /* in: cursor node */
sym_node_t* into_list) /* in: variables to set */
sym_node_t* into_list, /* in: variables to set, or NULL */
sym_node_t* user_func) /* in: user function name, or NULL */
{
sym_node_t* cursor_decl;
fetch_node_t* node;
/* Logical XOR. */
ut_a(!into_list != !user_func);
node = mem_heap_alloc(pars_sym_tab_global->heap, sizeof(fetch_node_t));
node->common.type = QUE_NODE_FETCH;
pars_resolve_exp_variables_and_types(NULL, cursor);
pars_resolve_exp_list_variables_and_types(NULL, into_list);
node->into_list = into_list;
if (into_list) {
pars_resolve_exp_list_variables_and_types(NULL, into_list);
node->into_list = into_list;
node->func = NULL;
} else {
pars_resolve_exp_variables_and_types(NULL, user_func);
node->func = pars_info_get_user_func(pars_sym_tab_global->info,
user_func->name);
ut_a(node->func);
node->into_list = NULL;
}
cursor_decl = cursor->alias;
@ -1438,8 +1475,11 @@ pars_fetch_statement(
node->cursor_def = cursor_decl->cursor_def;
ut_a(que_node_list_get_len(into_list)
== que_node_list_get_len(node->cursor_def->select_list));
if (into_list) {
ut_a(que_node_list_get_len(into_list)
== que_node_list_get_len(
node->cursor_def->select_list));
}
return(node);
}
@ -1529,6 +1569,8 @@ pars_column_def(
pars_res_word_t* type, /* in: data type */
sym_node_t* len, /* in: length of column, or
NULL */
void* is_unsigned, /* in: if not NULL, column
is of type UNSIGNED. */
void* is_not_null) /* in: if not NULL, column
is of type NOT NULL. */
{
@ -1541,7 +1583,7 @@ pars_column_def(
}
pars_set_dfield_type(que_node_get_val(sym_node), type, len2,
is_not_null != NULL);
is_unsigned != NULL, is_not_null != NULL);
return(sym_node);
}
@ -1798,6 +1840,7 @@ que_t*
pars_sql(
/*=====*/
/* out, own: the query graph */
pars_info_t* info, /* in: extra information, or NULL */
const char* str) /* in: SQL string */
{
sym_node_t* sym_node;
@ -1817,6 +1860,7 @@ pars_sql(
pars_sym_tab_global->sql_string = mem_heap_strdup(heap, str);
pars_sym_tab_global->string_len = strlen(str);
pars_sym_tab_global->next_char_pos = 0;
pars_sym_tab_global->info = info;
yyparse();
@ -1831,6 +1875,7 @@ pars_sql(
graph = pars_sym_tab_global->query_graph;
graph->sym_tab = pars_sym_tab_global;
graph->info = info;
/* fprintf(stderr, "SQL graph size %lu\n", mem_heap_get_size(heap)); */
@ -1867,3 +1912,194 @@ pars_complete_graph_for_exec(
return(thr);
}
/********************************************************************
Create parser info struct.*/
pars_info_t*
pars_info_create(void)
/*==================*/
/* out, own: info struct */
{
pars_info_t* info;
mem_heap_t* heap;
heap = mem_heap_create(512);
info = mem_heap_alloc(heap, sizeof(*info));
info->heap = heap;
info->funcs = NULL;
info->bound_lits = NULL;
info->graph_owns_us = TRUE;
return(info);
}
/********************************************************************
Free info struct and everything it contains.*/
void
pars_info_free(
/*===========*/
pars_info_t* info) /* in: info struct */
{
mem_heap_free(info->heap);
}
/********************************************************************
Add bound literal. */
void
pars_info_add_literal(
/*==================*/
pars_info_t* info, /* in: info struct */
const char* name, /* in: name */
const void* address, /* in: address */
ulint length, /* in: length of data */
ulint type, /* in: type, e.g. DATA_FIXBINARY */
ulint prtype) /* in: precise type, e.g.
DATA_UNSIGNED */
{
pars_bound_lit_t* pbl;
pbl = mem_heap_alloc(info->heap, sizeof(*pbl));
pbl->name = name;
pbl->address = address;
pbl->length = length;
pbl->type = type;
pbl->prtype = prtype;
if (!info->bound_lits) {
info->bound_lits = ib_vector_create(info->heap, 8);
}
ib_vector_push(info->bound_lits, pbl);
}
/********************************************************************
Equivalent to pars_info_add_literal(info, name, str, strlen(str),
DATA_VARCHAR, DATA_ENGLISH). */
void
pars_info_add_str_literal(
/*======================*/
pars_info_t* info, /* in: info struct */
const char* name, /* in: name */
const char* str) /* in: string */
{
pars_info_add_literal(info, name, str, strlen(str),
DATA_VARCHAR, DATA_ENGLISH);
}
/********************************************************************
Equivalent to:
char buf[4];
mach_write_to_4(buf, val);
pars_info_add_literal(info, name, buf, 4, DATA_INT, 0);
except that the buffer is dynamically allocated from the info struct's
heap. */
void
pars_info_add_int4_literal(
/*=======================*/
pars_info_t* info, /* in: info struct */
const char* name, /* in: name */
lint val) /* in: value */
{
byte* buf = mem_heap_alloc(info->heap, 4);
mach_write_to_4(buf, val);
pars_info_add_literal(info, name, buf, 4, DATA_INT, 0);
}
/********************************************************************
Add user function. */
void
pars_info_add_function(
/*===================*/
pars_info_t* info, /* in: info struct */
const char* name, /* in: function name */
pars_user_func_cb_t func, /* in: function address */
void* arg) /* in: user-supplied argument */
{
pars_user_func_t* puf;
puf = mem_heap_alloc(info->heap, sizeof(*puf));
puf->name = name;
puf->func = func;
puf->arg = arg;
if (!info->funcs) {
info->funcs = ib_vector_create(info->heap, 8);
}
ib_vector_push(info->funcs, puf);
}
/********************************************************************
Get user function with the given name.*/
pars_user_func_t*
pars_info_get_user_func(
/*====================*/
/* out: user func, or NULL if not
found */
pars_info_t* info, /* in: info struct */
const char* name) /* in: function name to find*/
{
ulint i;
ib_vector_t* vec;
if (!info || !info->funcs) {
return(NULL);
}
vec = info->funcs;
for (i = 0; i < ib_vector_size(vec); i++) {
pars_user_func_t* puf = ib_vector_get(vec, i);
if (strcmp(puf->name, name) == 0) {
return(puf);
}
}
return(NULL);
}
/********************************************************************
Get bound literal with the given name.*/
pars_bound_lit_t*
pars_info_get_bound_lit(
/*====================*/
/* out: bound literal, or NULL if
not found */
pars_info_t* info, /* in: info struct */
const char* name) /* in: bound literal name to find */
{
ulint i;
ib_vector_t* vec;
if (!info || !info->bound_lits) {
return(NULL);
}
vec = info->bound_lits;
for (i = 0; i < ib_vector_size(vec); i++) {
pars_bound_lit_t* pbl = ib_vector_get(vec, i);
if (strcmp(pbl->name, name) == 0) {
return(pbl);
}
}
return(NULL);
}

View file

@ -15,6 +15,7 @@ Created 12/15/1997 Heikki Tuuri
#include "mem0mem.h"
#include "data0type.h"
#include "data0data.h"
#include "pars0grm.h"
#include "pars0pars.h"
#include "que0que.h"
#include "eval0eval.h"
@ -165,6 +166,74 @@ sym_tab_add_str_lit(
return(node);
}
/**********************************************************************
Add a bound literal to a symbol table. */
sym_node_t*
sym_tab_add_bound_lit(
/*==================*/
/* out: symbol table node */
sym_tab_t* sym_tab, /* in: symbol table */
const char* name, /* in: name of bound literal */
ulint* lit_type) /* out: type of literal (PARS_*_LIT) */
{
sym_node_t* node;
pars_bound_lit_t* blit;
ulint len = 0;
blit = pars_info_get_bound_lit(sym_tab->info, name);
ut_a(blit);
node = mem_heap_alloc(sym_tab->heap, sizeof(sym_node_t));
node->common.type = QUE_NODE_SYMBOL;
node->resolved = TRUE;
node->token_type = SYM_LIT;
node->indirection = NULL;
switch (blit->type) {
case DATA_FIXBINARY:
len = blit->length;
*lit_type = PARS_FIXBINARY_LIT;
break;
case DATA_BLOB:
*lit_type = PARS_BLOB_LIT;
break;
case DATA_VARCHAR:
*lit_type = PARS_STR_LIT;
break;
case DATA_INT:
ut_a(blit->length > 0);
ut_a(blit->length <= 8);
len = blit->length;
*lit_type = PARS_INT_LIT;
break;
default:
ut_error;
}
dtype_set(&(node->common.val.type), blit->type, blit->prtype, len, 0);
dfield_set_data(&(node->common.val), blit->address, blit->length);
node->common.val_buf_size = 0;
node->prefetch_buf = NULL;
node->cursor_def = NULL;
UT_LIST_ADD_LAST(sym_list, sym_tab->sym_list, node);
node->sym_table = sym_tab;
return(node);
}
/**********************************************************************
Adds an SQL null literal to a symbol table. */
@ -220,7 +289,7 @@ sym_tab_add_id(
node->resolved = FALSE;
node->indirection = NULL;
node->name = mem_heap_strdupl(sym_tab->heap, (char*) name, len + 1);
node->name = mem_heap_strdupl(sym_tab->heap, (char*) name, len);
node->name_len = len;
UT_LIST_ADD_LAST(sym_list, sym_tab->sym_list, node);

View file

@ -36,6 +36,50 @@ ibool que_trace_on = FALSE;
ibool que_always_false = FALSE;
/* Short introduction to query graphs
==================================
A query graph consists of nodes linked to each other in various ways. The
execution starts at que_run_threads() which takes a que_thr_t parameter.
que_thr_t contains two fields that control query graph execution: run_node
and prev_node. run_node is the next node to execute and prev_node is the
last node executed.
Each node has a pointer to a 'next' statement, i.e., its brother, and a
pointer to its parent node. The next pointer is NULL in the last statement
of a block.
Loop nodes contain a link to the first statement of the enclosed statement
list. While the loop runs, que_thr_step() checks if execution to the loop
node came from its parent or from one of the statement nodes in the loop. If
it came from the parent of the loop node it starts executing the first
statement node in the loop. If it came from one of the statement nodes in
the loop, then it checks if the statement node has another statement node
following it, and runs it if so.
To signify loop ending, the loop statements (see e.g. while_step()) set
que_thr_t->run_node to the loop node's parent node. This is noticed on the
next call of que_thr_step() and execution proceeds to the node pointed to by
the loop node's 'next' pointer.
For example, the code:
X := 1;
WHILE X < 5 LOOP
X := X + 1;
X := X + 1;
X := 5
will result in the following node hierarchy, with the X-axis indicating
'next' links and the Y-axis indicating parent/child links:
A - W - A
|
|
A - A
A = assign_node_t, W = while_node_t. */
/* How a stored procedure containing COMMIT or ROLLBACK commands
is executed?
@ -128,6 +172,7 @@ que_fork_create(
UT_LIST_INIT(fork->thrs);
fork->sym_tab = NULL;
fork->info = NULL;
fork->heap = heap;
@ -487,7 +532,7 @@ que_graph_free_recursive(
fprintf(stderr,
"que_thr struct appears corrupt; magic n %lu\n",
(unsigned long) thr->magic_n);
mem_analyze_corruption((byte*)thr);
mem_analyze_corruption(thr);
ut_error;
}
@ -583,6 +628,7 @@ que_graph_free_recursive(
break;
case QUE_NODE_ASSIGNMENT:
case QUE_NODE_EXIT:
case QUE_NODE_RETURN:
case QUE_NODE_COMMIT:
case QUE_NODE_ROLLBACK:
@ -599,7 +645,7 @@ que_graph_free_recursive(
fprintf(stderr,
"que_node struct appears corrupt; type %lu\n",
(unsigned long) que_node_get_type(node));
mem_analyze_corruption((byte*)node);
mem_analyze_corruption(node);
ut_error;
}
}
@ -626,6 +672,10 @@ que_graph_free(
sym_tab_free_private(graph->sym_tab);
}
if (graph->info && graph->info->graph_owns_us) {
pars_info_free(graph->info);
}
que_graph_free_recursive(graph);
mem_heap_free(graph->heap);
@ -990,7 +1040,7 @@ que_thr_move_to_run_state_for_mysql(
"que_thr struct appears corrupt; magic n %lu\n",
(unsigned long) thr->magic_n);
mem_analyze_corruption((byte*)thr);
mem_analyze_corruption(thr);
ut_error;
}
@ -1027,7 +1077,7 @@ que_thr_stop_for_mysql_no_error(
"que_thr struct appears corrupt; magic n %lu\n",
(unsigned long) thr->magic_n);
mem_analyze_corruption((byte*)thr);
mem_analyze_corruption(thr);
ut_error;
}
@ -1040,6 +1090,37 @@ que_thr_stop_for_mysql_no_error(
trx->n_active_thrs--;
}
/********************************************************************
Get the first containing loop node (e.g. while_node_t or for_node_t) for the
given node, or NULL if the node is not within a loop. */
que_node_t*
que_node_get_containing_loop_node(
/*==============================*/
/* out: containing loop node, or NULL. */
que_node_t* node) /* in: node */
{
ut_ad(node);
for (;;) {
ulint type;
node = que_node_get_parent(node);
if (!node) {
break;
}
type = que_node_get_type(node);
if ((type == QUE_NODE_FOR) || (type == QUE_NODE_WHILE)) {
break;
}
}
return(node);
}
/**************************************************************************
Prints info of an SQL query graph node. */
@ -1093,6 +1174,8 @@ que_node_print_info(
str = "FOR LOOP";
} else if (type == QUE_NODE_RETURN) {
str = "RETURN";
} else if (type == QUE_NODE_EXIT) {
str = "EXIT";
} else {
str = "UNKNOWN NODE TYPE";
}
@ -1120,8 +1203,8 @@ que_thr_step(
thr->resource++;
type = que_node_get_type(thr->run_node);
node = thr->run_node;
type = que_node_get_type(node);
old_thr = thr;
@ -1160,6 +1243,8 @@ que_thr_step(
proc_step(thr);
} else if (type == QUE_NODE_WHILE) {
while_step(thr);
} else {
ut_error;
}
} else if (type == QUE_NODE_ASSIGNMENT) {
assign_step(thr);
@ -1192,6 +1277,8 @@ que_thr_step(
thr = row_purge_step(thr);
} else if (type == QUE_NODE_RETURN) {
thr = return_step(thr);
} else if (type == QUE_NODE_EXIT) {
thr = exit_step(thr);
} else if (type == QUE_NODE_ROLLBACK) {
thr = trx_rollback_step(thr);
} else if (type == QUE_NODE_CREATE_TABLE) {
@ -1204,7 +1291,11 @@ que_thr_step(
ut_error;
}
old_thr->prev_node = node;
if (type == QUE_NODE_EXIT) {
old_thr->prev_node = que_node_get_containing_loop_node(node);
} else {
old_thr->prev_node = node;
}
return(thr);
}

8
revert_gen.sh Executable file
View file

@ -0,0 +1,8 @@
#!/bin/bash
#
# revert changes to all generated files. this is useful in some situations
# when merging changes between branches.
set -eu
svn revert include/pars0grm.h pars/pars0grm.h pars/lexyy.c pars/pars0grm.c

View file

@ -28,6 +28,7 @@ Created 4/20/1996 Heikki Tuuri
#include "eval0eval.h"
#include "data0data.h"
#include "usr0sess.h"
#include "buf0lru.h"
#define ROW_INS_PREV 1
#define ROW_INS_NEXT 2
@ -139,7 +140,6 @@ row_ins_alloc_sys_fields(
mem_heap_t* heap;
dict_col_t* col;
dfield_t* dfield;
ulint len;
byte* ptr;
row = node->row;
@ -161,21 +161,6 @@ row_ins_alloc_sys_fields(
node->row_id_buf = ptr;
if (table->type == DICT_TABLE_CLUSTER_MEMBER) {
/* 2. Fill in the dfield for mix id */
col = dict_table_get_sys_col(table, DATA_MIX_ID);
dfield = dtuple_get_nth_field(row, dict_col_get_no(col));
len = mach_dulint_get_compressed_size(table->mix_id);
ptr = mem_heap_alloc(heap, DATA_MIX_ID_LEN);
mach_dulint_write_compressed(ptr, table->mix_id);
dfield_set_data(dfield, ptr, len);
}
/* 3. Allocate buffer for trx id */
col = dict_table_get_sys_col(table, DATA_TRX_ID);
@ -282,10 +267,17 @@ row_ins_sec_index_entry_by_modify(
}
} else {
ut_a(mode == BTR_MODIFY_TREE);
if (buf_LRU_buf_pool_running_out()) {
err = DB_LOCK_TABLE_FULL;
goto func_exit;
}
err = btr_cur_pessimistic_update(BTR_KEEP_SYS_FLAG, cursor,
&dummy_big_rec, update, 0, thr, mtr);
}
func_exit:
mem_heap_free(heap);
return(err);
@ -350,10 +342,16 @@ row_ins_clust_index_entry_by_modify(
}
} else {
ut_a(mode == BTR_MODIFY_TREE);
if (buf_LRU_buf_pool_running_out()) {
err = DB_LOCK_TABLE_FULL;
goto func_exit;
}
err = btr_cur_pessimistic_update(0, cursor, big_rec, update,
0, thr, mtr);
}
func_exit:
mem_heap_free(heap);
return(err);
@ -1888,7 +1886,6 @@ row_ins_duplicate_error_in_clust(
err = DB_DUPLICATE_KEY;
goto func_exit;
}
mem_heap_free(heap);
}
ut_a(!dict_index_is_clust(cursor->index));
@ -1897,6 +1894,9 @@ row_ins_duplicate_error_in_clust(
err = DB_SUCCESS;
func_exit:
if (UNIV_LIKELY_NULL(heap)) {
mem_heap_free(heap);
}
return(err);
#else /* UNIV_HOTBACKUP */
/* This function depends on MySQL code that is not included in
@ -2097,6 +2097,12 @@ row_ins_index_entry_low(
ext_vec, n_ext_vec, thr, &mtr);
} else {
ut_a(mode == BTR_MODIFY_TREE);
if (buf_LRU_buf_pool_running_out()) {
err = DB_LOCK_TABLE_FULL;
goto function_exit;
}
err = btr_cur_pessimistic_insert(0, &cursor, entry,
&insert_rec, &big_rec,
ext_vec, n_ext_vec, thr, &mtr);
@ -2429,7 +2435,15 @@ row_ins_step(
/* If this is the first time this node is executed (or when
execution resumes after wait for the table IX lock), set an
IX lock on the table and reset the possible select node. */
IX lock on the table and reset the possible select node. MySQL's
partitioned table code may also call an insert within the same
SQL statement AFTER it has used this table handle to do a search.
This happens, for example, when a row update moves it to another
partition. In that case, we have already set the IX lock on the
table during the search operation, and there is no need to set
it again here. But we must write trx->id to node->trx_id_buf. */
trx_write_trx_id(node->trx_id_buf, trx->id);
if (node->state == INS_NODE_SET_IX_LOCK) {
@ -2437,13 +2451,11 @@ row_ins_step(
its transaction, or it has been committed: */
if (UT_DULINT_EQ(trx->id, node->trx_id)) {
/* No need to do IX-locking or write trx id to buf */
/* No need to do IX-locking */
goto same_trx;
}
trx_write_trx_id(node->trx_id_buf, trx->id);
err = lock_table(0, node->table, LOCK_IX, thr);
if (err != DB_SUCCESS) {

View file

@ -85,9 +85,11 @@ row_mysql_is_system_table(
system table name */
const char* name)
{
if (memcmp(name, "mysql/", 6)) {
if (strncmp(name, "mysql/", 6) != 0) {
return(FALSE);
}
return(0 == strcmp(name + 6, "host")
|| 0 == strcmp(name + 6, "user")
|| 0 == strcmp(name + 6, "db"));
@ -207,7 +209,7 @@ row_mysql_store_blob_ref(
mach_write_to_n_little_endian(dest, col_len - 8, len);
ut_memcpy(dest + col_len - 8, (byte*)&data, sizeof(byte*));
ut_memcpy(dest + col_len - 8, &data, sizeof(byte*));
}
/***********************************************************************
@ -226,7 +228,7 @@ row_mysql_read_blob_ref(
*len = mach_read_from_n_little_endian(ref, col_len - 8);
ut_memcpy((byte*)&data, ref + col_len - 8, sizeof(byte*));
ut_memcpy(&data, ref + col_len - 8, sizeof(byte*));
return(data);
}
@ -681,7 +683,7 @@ row_prebuilt_free(
ut_print_name(stderr, NULL, prebuilt->table->name);
putc('\n', stderr);
mem_analyze_corruption((byte*)prebuilt);
mem_analyze_corruption(prebuilt);
ut_error;
}
@ -761,7 +763,7 @@ row_update_prebuilt_trx(
"InnoDB: trx handle. Magic n %lu\n",
(ulong) trx->magic_n);
mem_analyze_corruption((byte*)trx);
mem_analyze_corruption(trx);
ut_error;
}
@ -774,7 +776,7 @@ row_update_prebuilt_trx(
ut_print_name(stderr, NULL, prebuilt->table->name);
putc('\n', stderr);
mem_analyze_corruption((byte*)prebuilt);
mem_analyze_corruption(prebuilt);
ut_error;
}
@ -1095,7 +1097,7 @@ row_insert_for_mysql(
ut_print_name(stderr, prebuilt->trx, prebuilt->table->name);
putc('\n', stderr);
mem_analyze_corruption((byte*)prebuilt);
mem_analyze_corruption(prebuilt);
ut_error;
}
@ -1330,7 +1332,7 @@ row_update_for_mysql(
ut_print_name(stderr, prebuilt->trx, prebuilt->table->name);
putc('\n', stderr);
mem_analyze_corruption((byte*)prebuilt);
mem_analyze_corruption(prebuilt);
ut_error;
}
@ -1435,7 +1437,8 @@ run_again:
}
/*************************************************************************
This can only be used when srv_locks_unsafe_for_binlog is TRUE. Before
This can only be used when srv_locks_unsafe_for_binlog is TRUE or
this session is using a READ COMMITTED isolation level. Before
calling this function we must use trx_reset_new_rec_lock_info() and
trx_register_new_rec_lock() to store the information which new record locks
really were set. This function removes a newly set lock under prebuilt->pcur,
@ -1466,11 +1469,13 @@ row_unlock_for_mysql(
ut_ad(prebuilt && trx);
ut_ad(trx->mysql_thread_id == os_thread_get_curr_id());
if (!srv_locks_unsafe_for_binlog) {
if (!(srv_locks_unsafe_for_binlog
|| trx->isolation_level == TRX_ISO_READ_COMMITTED)) {
fprintf(stderr,
"InnoDB: Error: calling row_unlock_for_mysql though\n"
"InnoDB: srv_locks_unsafe_for_binlog is FALSE.\n");
"InnoDB: srv_locks_unsafe_for_binlog is FALSE and\n"
"InnoDB: this session is not using READ COMMITTED isolation level.\n");
return(DB_SUCCESS);
}
@ -1670,7 +1675,9 @@ row_mysql_recover_tmp_table(
if (!ptr) {
/* table name does not begin with "/rsql" */
dict_mem_table_free(table);
trx_commit_for_mysql(trx);
return(DB_ERROR);
}
else {
@ -1782,6 +1789,7 @@ row_create_table_for_mysql(
const char* table_name;
ulint table_name_len;
ulint err;
ulint i;
ut_ad(trx->mysql_thread_id == os_thread_get_curr_id());
#ifdef UNIV_SYNC_DEBUG
@ -1799,6 +1807,7 @@ row_create_table_for_mysql(
"InnoDB: with raw, and innodb_force_... is removed.\n",
stderr);
dict_mem_table_free(table);
trx_commit_for_mysql(trx);
return(DB_ERROR);
@ -1813,11 +1822,25 @@ row_create_table_for_mysql(
"InnoDB: MySQL system tables must be of the MyISAM type!\n",
table->name);
dict_mem_table_free(table);
trx_commit_for_mysql(trx);
return(DB_ERROR);
}
/* Check that no reserved column names are used. */
for (i = 0; i < dict_table_get_n_user_cols(table); i++) {
dict_col_t* col = dict_table_get_nth_col(table, i);
if (dict_col_name_is_reserved(col->name)) {
dict_mem_table_free(table);
trx_commit_for_mysql(trx);
return(DB_ERROR);
}
}
trx_start_if_not_started(trx);
if (row_mysql_is_recovered_tmp_table(table->name)) {
@ -2507,7 +2530,7 @@ do not allow the discard. We also reserve the data dictionary latch. */
(ulong) ut_dulint_get_high(new_id),
(ulong) ut_dulint_get_low(new_id));
graph = pars_sql(buf);
graph = pars_sql(NULL, buf);
ut_a(graph);
@ -2939,7 +2962,7 @@ do not allow the TRUNCATE. We also reserve the data dictionary latch. */
(ulong) ut_dulint_get_high(new_id),
(ulong) ut_dulint_get_low(new_id));
graph = pars_sql(sql);
graph = pars_sql(NULL, sql);
ut_a(graph);
@ -3163,7 +3186,7 @@ row_drop_table_for_mysql(
ut_ad(rw_lock_own(&dict_operation_lock, RW_LOCK_EX));
#endif /* UNIV_SYNC_DEBUG */
graph = pars_sql(sql);
graph = pars_sql(NULL, sql);
ut_a(graph);
mem_free(sql);
@ -3778,7 +3801,7 @@ row_rename_table_for_mysql(
ut_a(sqlend == sql + len + 1);
graph = pars_sql(sql);
graph = pars_sql(NULL, sql);
ut_a(graph);
mem_free(sql);

View file

@ -710,12 +710,17 @@ row_sel_get_clust_rec(
if (!node->read_view) {
/* Try to place a lock on the index record */
/* If innodb_locks_unsafe_for_binlog option is used,
/* If innodb_locks_unsafe_for_binlog option is used
or this session is using READ COMMITTED isolation level
we lock only the record, i.e., next-key locking is
not used. */
ulint lock_type;
trx_t* trx;
if (srv_locks_unsafe_for_binlog) {
trx = thr_get_trx(thr);
if (srv_locks_unsafe_for_binlog
|| trx->isolation_level == TRX_ISO_READ_COMMITTED) {
lock_type = LOCK_REC_NOT_GAP;
} else {
lock_type = LOCK_ORDINARY;
@ -1307,16 +1312,22 @@ rec_loop:
if (!consistent_read) {
/* If innodb_locks_unsafe_for_binlog option is used,
we lock only the record, i.e., next-key locking is
not used. */
/* If innodb_locks_unsafe_for_binlog option is used
or this session is using READ COMMITTED isolation
level, we lock only the record, i.e., next-key
locking is not used. */
rec_t* next_rec = page_rec_get_next(rec);
ulint lock_type;
trx_t* trx;
trx = thr_get_trx(thr);
offsets = rec_get_offsets(next_rec, index, offsets,
ULINT_UNDEFINED, &heap);
if (srv_locks_unsafe_for_binlog) {
if (srv_locks_unsafe_for_binlog
|| trx->isolation_level == TRX_ISO_READ_COMMITTED) {
lock_type = LOCK_REC_NOT_GAP;
} else {
lock_type = LOCK_ORDINARY;
@ -1350,15 +1361,21 @@ rec_loop:
if (!consistent_read) {
/* Try to place a lock on the index record */
/* If innodb_locks_unsafe_for_binlog option is used,
/* If innodb_locks_unsafe_for_binlog option is used
or this session is using READ COMMITTED isolation level,
we lock only the record, i.e., next-key locking is
not used. */
ulint lock_type;
trx_t* trx;
offsets = rec_get_offsets(rec, index, offsets,
ULINT_UNDEFINED, &heap);
if (srv_locks_unsafe_for_binlog) {
trx = thr_get_trx(thr);
if (srv_locks_unsafe_for_binlog
|| trx->isolation_level == TRX_ISO_READ_COMMITTED) {
lock_type = LOCK_REC_NOT_GAP;
} else {
lock_type = LOCK_ORDINARY;
@ -1413,14 +1430,6 @@ rec_loop:
/* Ok, no need to test end_conds or mix id */
} else if (plan->mixed_index) {
/* We have to check if the record in a mixed cluster belongs
to this table */
if (!dict_is_mixed_table_rec(plan->table, rec)) {
goto next_rec;
}
}
/* We are ready to look at a possible new index entry in the result
@ -1958,7 +1967,18 @@ fetch_step(
if (sel_node->state != SEL_NODE_NO_MORE_ROWS) {
sel_assign_into_var_values(node->into_list, sel_node);
if (node->into_list) {
sel_assign_into_var_values(node->into_list,
sel_node);
} else {
void* ret = (*node->func->func)(sel_node,
node->func->arg);
if (!ret) {
sel_node->state =
SEL_NODE_NO_MORE_ROWS;
}
}
}
thr->run_node = que_node_get_parent(node);
@ -1974,8 +1994,8 @@ fetch_step(
sel_node->common.parent = node;
if (sel_node->state == SEL_NODE_CLOSED) {
/* SQL error detected */
fprintf(stderr, "SQL error %lu\n", (ulong)DB_ERROR);
fprintf(stderr,
"InnoDB: Error: fetch called on a closed cursor\n");
que_thr_handle_error(thr, DB_ERROR, NULL, 0);
@ -1987,6 +2007,76 @@ fetch_step(
return(thr);
}
/********************************************************************
Sample callback function for fetch that prints each row.*/
void*
row_fetch_print(
/*============*/
/* out: always returns non-NULL */
void* row, /* in: sel_node_t* */
void* user_arg) /* in: not used */
{
sel_node_t* node = row;
que_node_t* exp;
ulint i = 0;
UT_NOT_USED(user_arg);
fprintf(stderr, "row_fetch_print: row %p\n", row);
exp = node->select_list;
while (exp) {
dfield_t* dfield = que_node_get_val(exp);
dtype_t* type = dfield_get_type(dfield);
fprintf(stderr, " column %lu:\n", (ulong)i);
dtype_print(type);
fprintf(stderr, "\n");
ut_print_buf(stderr, dfield_get_data(dfield),
dfield_get_len(dfield));
fprintf(stderr, "\n");
exp = que_node_get_next(exp);
i++;
}
return((void*)42);
}
/********************************************************************
Callback function for fetch that stores an unsigned 4 byte integer to the
location pointed. The column's type must be DATA_INT, DATA_UNSIGNED, length
= 4. */
void*
row_fetch_store_uint4(
/*==================*/
/* out: always returns NULL */
void* row, /* in: sel_node_t* */
void* user_arg) /* in: data pointer */
{
sel_node_t* node = row;
ib_uint32_t* val = user_arg;
ulint tmp;
dfield_t* dfield = que_node_get_val(node->select_list);
dtype_t* type = dfield_get_type(dfield);
ulint len = dfield_get_len(dfield);
ut_a(dtype_get_mtype(type) == DATA_INT);
ut_a(dtype_get_prtype(type) & DATA_UNSIGNED);
ut_a(len == 4);
tmp = mach_read_from_4(dfield_get_data(dfield));
*val = tmp;
return(NULL);
}
/***************************************************************
Prints a row in a select result. */
@ -2396,18 +2486,16 @@ row_sel_field_store_in_mysql_format(
} else if (templ->type == DATA_MYSQL) {
memcpy(dest, data, len);
#if defined(UNIV_RELEASE_NOT_YET_STABLE) || defined(UNIV_DEBUG)
ut_a(templ->mysql_col_len >= len);
ut_a(templ->mbmaxlen >= templ->mbminlen);
ut_ad(templ->mysql_col_len >= len);
ut_ad(templ->mbmaxlen >= templ->mbminlen);
ut_a(templ->mbmaxlen > templ->mbminlen
ut_ad(templ->mbmaxlen > templ->mbminlen
|| templ->mysql_col_len == len);
ut_a(len * templ->mbmaxlen >= templ->mysql_col_len);
#endif /* UNIV_RELEASE_NOT_YET_STABLE || UNIV_DEBUG */
/* The following assertion would fail for old tables
containing UTF-8 ENUM columns due to Bug #9526. */
ut_ad(!templ->mbmaxlen
|| !(templ->mysql_col_len % templ->mbmaxlen));
ut_ad(len * templ->mbmaxlen >= templ->mysql_col_len);
if (templ->mbminlen != templ->mbmaxlen) {
/* Pad with spaces. This undoes the stripping
@ -2417,15 +2505,13 @@ row_sel_field_store_in_mysql_format(
memset(dest + len, 0x20, templ->mysql_col_len - len);
}
} else {
#if defined(UNIV_RELEASE_NOT_YET_STABLE) || defined(UNIV_DEBUG)
ut_a(templ->type == DATA_CHAR
ut_ad(templ->type == DATA_CHAR
|| templ->type == DATA_FIXBINARY
/*|| templ->type == DATA_SYS_CHILD
|| templ->type == DATA_SYS*/
|| templ->type == DATA_FLOAT
|| templ->type == DATA_DOUBLE
|| templ->type == DATA_DECIMAL);
#endif /* UNIV_RELEASE_NOT_YET_STABLE || UNIV_DEBUG */
ut_ad(templ->mysql_col_len == len);
memcpy(dest, data, len);
@ -3160,7 +3246,7 @@ row_search_for_mysql(
ut_print_name(stderr, trx, prebuilt->table->name);
putc('\n', stderr);
mem_analyze_corruption((byte*)prebuilt);
mem_analyze_corruption(prebuilt);
ut_error;
}
@ -3209,11 +3295,13 @@ stderr);
}
/* Reset the new record lock info if srv_locks_unsafe_for_binlog
is set. Then we are able to remove the record locks set here on an
individual row. */
is set or session is using a READ COMMITED isolation level. Then
we are able to remove the record locks set here on an individual
row. */
if (srv_locks_unsafe_for_binlog
&& prebuilt->select_lock_type != LOCK_NONE) {
if ((srv_locks_unsafe_for_binlog
|| trx->isolation_level == TRX_ISO_READ_COMMITTED)
&& prebuilt->select_lock_type != LOCK_NONE) {
trx_reset_new_rec_lock_info(trx);
}
@ -3581,13 +3669,15 @@ rec_loop:
if (page_rec_is_supremum(rec)) {
if (set_also_gap_locks
&& !srv_locks_unsafe_for_binlog
&& prebuilt->select_lock_type != LOCK_NONE) {
&& !(srv_locks_unsafe_for_binlog
|| trx->isolation_level == TRX_ISO_READ_COMMITTED)
&& prebuilt->select_lock_type != LOCK_NONE) {
/* Try to place a lock on the index record */
/* If innodb_locks_unsafe_for_binlog option is used,
we do not lock gaps. Supremum record is really
/* If innodb_locks_unsafe_for_binlog option is used
or this session is using a READ COMMITTED isolation
level we do not lock gaps. Supremum record is really
a gap and therefore we do not set locks there. */
offsets = rec_get_offsets(rec, index, offsets,
@ -3707,12 +3797,14 @@ wrong_offs:
if (0 != cmp_dtuple_rec(search_tuple, rec, offsets)) {
if (set_also_gap_locks
&& !srv_locks_unsafe_for_binlog
&& prebuilt->select_lock_type != LOCK_NONE) {
&& !(srv_locks_unsafe_for_binlog
|| trx->isolation_level == TRX_ISO_READ_COMMITTED)
&& prebuilt->select_lock_type != LOCK_NONE) {
/* Try to place a gap lock on the index
record only if innodb_locks_unsafe_for_binlog
option is not set */
option is not set or this session is not
using a READ COMMITTED isolation level. */
err = sel_set_rec_lock(rec, index, offsets,
prebuilt->select_lock_type,
@ -3738,12 +3830,14 @@ wrong_offs:
if (!cmp_dtuple_is_prefix_of_rec(search_tuple, rec, offsets)) {
if (set_also_gap_locks
&& !srv_locks_unsafe_for_binlog
&& prebuilt->select_lock_type != LOCK_NONE) {
&& !(srv_locks_unsafe_for_binlog
|| trx->isolation_level == TRX_ISO_READ_COMMITTED)
&& prebuilt->select_lock_type != LOCK_NONE) {
/* Try to place a gap lock on the index
record only if innodb_locks_unsafe_for_binlog
option is not set */
option is not set or this session is not
using a READ COMMITTED isolation level. */
err = sel_set_rec_lock(rec, index, offsets,
prebuilt->select_lock_type,
@ -3774,16 +3868,18 @@ wrong_offs:
is a non-delete marked record, then it is enough to lock its
existence with LOCK_REC_NOT_GAP. */
/* If innodb_locks_unsafe_for_binlog option is used,
we lock only the record, i.e., next-key locking is
/* If innodb_locks_unsafe_for_binlog option is used
or this session is using a READ COMMITED isolation
level we lock only the record, i.e., next-key locking is
not used. */
ulint lock_type;
if (!set_also_gap_locks
|| srv_locks_unsafe_for_binlog
|| (unique_search && !UNIV_UNLIKELY(
rec_get_deleted_flag(rec, comp)))) {
|| srv_locks_unsafe_for_binlog
|| trx->isolation_level == TRX_ISO_READ_COMMITTED
|| (unique_search
&& !UNIV_UNLIKELY(rec_get_deleted_flag(rec, comp)))) {
goto no_gap_lock;
} else {
@ -3942,9 +4038,10 @@ no_gap_lock:
/* The record is delete-marked: we can skip it */
if (srv_locks_unsafe_for_binlog
&& prebuilt->select_lock_type != LOCK_NONE
&& !did_semi_consistent_read) {
if ((srv_locks_unsafe_for_binlog
|| trx->isolation_level == TRX_ISO_READ_COMMITTED)
&& prebuilt->select_lock_type != LOCK_NONE
&& !did_semi_consistent_read) {
/* No need to keep a lock on a delete-marked record
if we do not want to use next-key locking. */
@ -3995,8 +4092,9 @@ requires_clust_rec:
/* The record is delete marked: we can skip it */
if (srv_locks_unsafe_for_binlog
&& prebuilt->select_lock_type != LOCK_NONE) {
if ((srv_locks_unsafe_for_binlog
|| trx->isolation_level == TRX_ISO_READ_COMMITTED)
&& prebuilt->select_lock_type != LOCK_NONE) {
/* No need to keep a lock on a delete-marked
record if we do not want to use next-key
@ -4116,8 +4214,9 @@ next_rec:
}
did_semi_consistent_read = FALSE;
if (UNIV_UNLIKELY(srv_locks_unsafe_for_binlog)
&& prebuilt->select_lock_type != LOCK_NONE) {
if (UNIV_UNLIKELY(srv_locks_unsafe_for_binlog
|| trx->isolation_level == TRX_ISO_READ_COMMITTED)
&& prebuilt->select_lock_type != LOCK_NONE) {
trx_reset_new_rec_lock_info(trx);
}
@ -4205,7 +4304,11 @@ lock_wait_or_error:
sel_restore_position_for_mysql(&same_user_rec,
BTR_SEARCH_LEAF, pcur,
moves_up, &mtr);
if (srv_locks_unsafe_for_binlog && !same_user_rec) {
if ((srv_locks_unsafe_for_binlog
|| trx->isolation_level == TRX_ISO_READ_COMMITTED)
&& !same_user_rec) {
/* Since we were not able to restore the cursor
on the same user record, we cannot use
row_unlock_for_mysql() to unlock any records, and

View file

@ -28,6 +28,7 @@ Created 12/27/1996 Heikki Tuuri
#include "log0log.h"
#include "pars0sym.h"
#include "eval0eval.h"
#include "buf0lru.h"
/* What kind of latch and lock can we assume when the control comes to
@ -887,6 +888,10 @@ row_upd_index_replace_new_col_vals_index_pos(
upd_t* update, /* in: an update vector built for the index so
that the field number in an upd_field is the
index position */
ibool order_only,
/* in: if TRUE, limit the replacement to
ordering fields of index; note that this
does not work for non-clustered indexes. */
mem_heap_t* heap) /* in: memory heap to which we allocate and
copy the new values, set this as NULL if you
do not want allocation */
@ -897,13 +902,20 @@ row_upd_index_replace_new_col_vals_index_pos(
dfield_t* new_val;
ulint j;
ulint i;
ulint n_fields;
dtype_t* cur_type;
ut_ad(index);
dtuple_set_info_bits(entry, update->info_bits);
for (j = 0; j < dict_index_get_n_fields(index); j++) {
if (order_only) {
n_fields = dict_index_get_n_unique(index);
} else {
n_fields = dict_index_get_n_fields(index);
}
for (j = 0; j < n_fields; j++) {
field = dict_index_get_nth_field(index, j);
@ -1554,6 +1566,10 @@ row_upd_clust_rec(
return(DB_SUCCESS);
}
if (buf_LRU_buf_pool_running_out()) {
return(DB_LOCK_TABLE_FULL);
}
/* We may have to modify the tree structure: do a pessimistic descent
down the index tree */

View file

@ -1713,6 +1713,8 @@ srv_printf_innodb_monitor(
"; in additional pool allocated " ULINTPF "\n",
ut_total_allocated_memory,
mem_pool_get_reserved(mem_comm_pool));
fprintf(file, "Dictionary memory allocated " ULINTPF "\n",
dict_sys->size);
if (srv_use_awe) {
fprintf(file,

View file

@ -524,7 +524,7 @@ sync_array_cell_print(
"Last time reserved in file %s line %lu, "
#endif /* UNIV_SYNC_DEBUG */
"waiters flag %lu\n",
mutex, mutex->cfile_name, (ulong) mutex->cline,
(void*) mutex, mutex->cfile_name, (ulong) mutex->cline,
(ulong) mutex->lock_word,
#ifdef UNIV_SYNC_DEBUG
mutex->file_name, (ulong) mutex->line,
@ -539,7 +539,7 @@ sync_array_cell_print(
fprintf(file,
" RW-latch at %p created in file %s line %lu\n",
rwlock, rwlock->cfile_name,
(void*) rwlock, rwlock->cfile_name,
(ulong) rwlock->cline);
if (rwlock->writer != RW_LOCK_NOT_LOCKED) {
fprintf(file,
@ -670,7 +670,6 @@ sync_array_detect_deadlock(
rw_lock_debug_t*debug;
ut_a(arr && start && cell);
ut_ad(cell->state == SC_RESERVED);
ut_ad(cell->wait_object);
ut_ad(os_thread_get_curr_id() == start->thread);
ut_ad(depth < 100);
@ -703,7 +702,7 @@ sync_array_detect_deadlock(
if (ret) {
fprintf(stderr,
"Mutex %p owned by thread %lu file %s line %lu\n",
mutex,
(void*) mutex,
(ulong) os_thread_pf(mutex->thread_id),
mutex->file_name, (ulong) mutex->line);
sync_array_cell_print(stderr, cell);
@ -740,7 +739,8 @@ sync_array_detect_deadlock(
thread, debug->pass, depth);
if (ret) {
print:
fprintf(stderr, "rw-lock %p ", lock);
fprintf(stderr, "rw-lock %p ",
(void*) lock);
sync_array_cell_print(stderr, cell);
rw_lock_debug_print(debug);
return(TRUE);
@ -896,11 +896,12 @@ sync_array_signal_object(
if (cell_count == cell_max_count) {
sync_cell_t** old_cell_ptr = cell_ptr;
size_t old_size = cell_max_count *
size_t old_size, new_size;
old_size = cell_max_count *
sizeof(sync_cell_t*);
cell_max_count *= 2;
size_t new_size = cell_max_count *
new_size = cell_max_count *
sizeof(sync_cell_t*);
cell_ptr = malloc(new_size);

View file

@ -246,7 +246,7 @@ lock_loop:
if (srv_print_latch_waits) {
fprintf(stderr,
"Thread %lu spin wait rw-s-lock at %p cfile %s cline %lu rnds %lu\n",
(ulong) os_thread_pf(os_thread_get_curr_id()), lock,
(ulong) os_thread_pf(os_thread_get_curr_id()), (void*) lock,
lock->cfile_name, (ulong) lock->cline, (ulong) i);
}
@ -277,7 +277,8 @@ lock_loop:
fprintf(stderr,
"Thread %lu OS wait rw-s-lock at %p cfile %s cline %lu\n",
os_thread_pf(os_thread_get_curr_id()),
lock, lock->cfile_name, (ulong) lock->cline);
(void*) lock, lock->cfile_name,
(ulong) lock->cline);
}
rw_s_system_call_count++;
@ -495,8 +496,8 @@ lock_loop:
if (srv_print_latch_waits) {
fprintf(stderr,
"Thread %lu spin wait rw-x-lock at %p cfile %s cline %lu rnds %lu\n",
os_thread_pf(os_thread_get_curr_id()), lock,
lock->cfile_name, (ulong) lock->cline, (ulong) i);
os_thread_pf(os_thread_get_curr_id()), (void*) lock,
lock->cfile_name, (ulong) lock->cline, (ulong) i);
}
rw_x_spin_wait_count++;
@ -528,8 +529,8 @@ lock_loop:
if (srv_print_latch_waits) {
fprintf(stderr,
"Thread %lu OS wait for rw-x-lock at %p cfile %s cline %lu\n",
os_thread_pf(os_thread_get_curr_id()), lock,
lock->cfile_name, (ulong) lock->cline);
os_thread_pf(os_thread_get_curr_id()), (void*) lock,
lock->cfile_name, (ulong) lock->cline);
}
rw_x_system_call_count++;
@ -787,7 +788,7 @@ rw_lock_list_print_info(void)
|| (rw_lock_get_reader_count(lock) != 0)
|| (rw_lock_get_waiters(lock) != 0)) {
fprintf(stderr, "RW-LOCK: %p ", lock);
fprintf(stderr, "RW-LOCK: %p ", (void*) lock);
if (rw_lock_get_waiters(lock)) {
fputs(" Waiters for the lock exist\n", stderr);
@ -823,7 +824,7 @@ rw_lock_print(
fprintf(stderr,
"-------------\n"
"RW-LATCH INFO\n"
"RW-LATCH: %p ", lock);
"RW-LATCH: %p ", (void*) lock);
if ((rw_lock_get_writer(lock) != RW_LOCK_NOT_LOCKED)
|| (rw_lock_get_reader_count(lock) != 0)

View file

@ -423,7 +423,7 @@ spin_loop:
#ifdef UNIV_SRV_PRINT_LATCH_WAITS
fprintf(stderr,
"Thread %lu spin wait mutex at %p cfile %s cline %lu rnds %lu\n",
(ulong) os_thread_pf(os_thread_get_curr_id()), mutex,
(ulong) os_thread_pf(os_thread_get_curr_id()), (void*) mutex,
mutex->cfile_name, (ulong) mutex->cline, (ulong) i);
#endif
@ -485,7 +485,7 @@ spin_loop:
fprintf(stderr, "Thread %lu spin wait succeeds at 2:"
" mutex at %p\n",
(ulong) os_thread_pf(os_thread_get_curr_id()),
mutex);
(void*) mutex);
#endif
goto finish_timing;
@ -503,7 +503,7 @@ spin_loop:
#ifdef UNIV_SRV_PRINT_LATCH_WAITS
fprintf(stderr,
"Thread %lu OS wait mutex at %p cfile %s cline %lu rnds %lu\n",
(ulong) os_thread_pf(os_thread_get_curr_id()), mutex,
(ulong) os_thread_pf(os_thread_get_curr_id()), (void*) mutex,
mutex->cfile_name, (ulong) mutex->cline, (ulong) i);
#endif
@ -666,7 +666,7 @@ mutex_list_print_info(void)
&thread_id);
fprintf(stderr,
"Locked mutex: addr %p thread %ld file %s line %ld\n",
mutex, os_thread_pf(thread_id),
(void*) mutex, os_thread_pf(thread_id),
file_name, line);
}
@ -852,10 +852,10 @@ sync_thread_levels_g(
fprintf(stderr,
"InnoDB: Locked mutex: addr %p thread %ld file %s line %ld\n",
mutex, os_thread_pf(thread_id), file_name, (ulong) line);
(void*) mutex, os_thread_pf(thread_id), file_name, (ulong) line);
#else /* UNIV_SYNC_DEBUG */
fprintf(stderr,
"InnoDB: Locked mutex: addr %p\n", mutex);
"InnoDB: Locked mutex: addr %p\n", (void*) mutex);
#endif /* UNIV_SYNC_DEBUG */
} else {
fputs("Not locked\n", stderr);

View file

@ -307,7 +307,7 @@ trx_free(
trx_print(stderr, trx, 600);
ut_print_buf(stderr, (byte*)trx, sizeof(trx_t));
ut_print_buf(stderr, trx, sizeof(trx_t));
}
ut_a(trx->magic_n == TRX_MAGIC_N);
@ -366,8 +366,6 @@ trx_free_for_mysql(
/*===============*/
trx_t* trx) /* in, own: trx object */
{
thr_local_free(trx->mysql_thread_id);
mutex_enter(&kernel_mutex);
UT_LIST_REMOVE(mysql_trx_list, trx_sys->mysql_trx_list, trx);
@ -1770,6 +1768,9 @@ trx_print(
fprintf(f, "%lu lock struct(s), heap size %lu",
(ulong) UT_LIST_GET_LEN(trx->trx_locks),
(ulong) mem_heap_get_size(trx->lock_heap));
fprintf(f, "%lu row lock(s)",
(ulong) lock_number_of_rows_locked(trx));
}
if (trx->has_search_latch) {

View file

@ -1443,7 +1443,7 @@ trx_undo_mem_init_for_reuse(
fprintf(stderr, "InnoDB: Error: undo->id is %lu\n",
(ulong) undo->id);
mem_analyze_corruption((byte*)undo);
mem_analyze_corruption(undo);
ut_error;
}
@ -1589,7 +1589,7 @@ trx_undo_reuse_cached(
if (undo->id >= TRX_RSEG_N_SLOTS) {
fprintf(stderr, "InnoDB: Error: undo->id is %lu\n",
(ulong) undo->id);
mem_analyze_corruption((byte*)undo);
mem_analyze_corruption(undo);
ut_error;
}
@ -1737,7 +1737,7 @@ trx_undo_set_state_at_finish(
if (undo->id >= TRX_RSEG_N_SLOTS) {
fprintf(stderr, "InnoDB: Error: undo->id is %lu\n",
(ulong) undo->id);
mem_analyze_corruption((byte*)undo);
mem_analyze_corruption(undo);
ut_error;
}
@ -1787,7 +1787,7 @@ trx_undo_set_state_at_prepare(
if (undo->id >= TRX_RSEG_N_SLOTS) {
fprintf(stderr, "InnoDB: Error: undo->id is %lu\n",
(ulong) undo->id);
mem_analyze_corruption((byte*)undo);
mem_analyze_corruption(undo);
ut_error;
}

View file

@ -19,6 +19,6 @@ include ../include/Makefile.i
noinst_LIBRARIES = libut.a
libut_a_SOURCES = ut0byte.c ut0dbg.c ut0mem.c ut0rnd.c ut0ut.c
libut_a_SOURCES = ut0byte.c ut0dbg.c ut0mem.c ut0rnd.c ut0ut.c ut0vec.c
EXTRA_PROGRAMS =

View file

@ -437,3 +437,96 @@ ut_memcpyq(
return(dest);
}
/**************************************************************************
Return the number of times s2 occurs in s1. Overlapping instances of s2
are only counted once. */
ulint
ut_strcount(
/*========*/
/* out: the number of times s2 occurs in s1 */
const char* s1, /* in: string to search in */
const char* s2) /* in: string to search for */
{
ulint count = 0;
ulint len = strlen(s2);
if (len == 0) {
return(0);
}
for (;;) {
s1 = strstr(s1, s2);
if (!s1) {
break;
}
count++;
s1 += len;
}
return(count);
}
/**************************************************************************
Replace every occurrence of s1 in str with s2. Overlapping instances of s1
are only replaced once. */
char *
ut_strreplace(
/*==========*/
/* out, own: modified string, must be
freed with mem_free() */
const char* str, /* in: string to operate on */
const char* s1, /* in: string to replace */
const char* s2) /* in: string to replace s1 with */
{
char* new_str;
char* ptr;
const char* str_end;
ulint str_len = strlen(str);
ulint s1_len = strlen(s1);
ulint s2_len = strlen(s2);
ulint count = 0;
int len_delta = (int)s2_len - (int)s1_len;
str_end = str + str_len;
if (len_delta <= 0) {
len_delta = 0;
} else {
count = ut_strcount(str, s1);
}
new_str = mem_alloc(str_len + count * len_delta + 1);
ptr = new_str;
while (str) {
const char* next = strstr(str, s1);
if (!next) {
next = str_end;
}
memcpy(ptr, str, next - str);
ptr += next - str;
if (next == str_end) {
break;
}
memcpy(ptr, s2, s2_len);
ptr += s2_len;
str = next + s1_len;
}
*ptr = '\0';
return(new_str);
}

View file

@ -307,7 +307,7 @@ void
ut_print_buf(
/*=========*/
FILE* file, /* in: file where to print */
const byte* buf, /* in: memory buffer */
const void* buf, /* in: memory buffer */
ulint len) /* in: length of the buffer */
{
const byte* data;
@ -315,13 +315,13 @@ ut_print_buf(
fprintf(file, " len %lu; hex ", len);
for (data = buf, i = 0; i < len; i++) {
for (data = (const byte*)buf, i = 0; i < len; i++) {
fprintf(file, "%02lx", (ulong)*data++);
}
fputs("; asc ", file);
data = buf;
data = (const byte*)buf;
for (i = 0; i < len; i++) {
int c = (int) *data++;

54
ut/ut0vec.c Normal file
View file

@ -0,0 +1,54 @@
#include "ut0vec.h"
#ifdef UNIV_NONINL
#include "ut0vec.ic"
#endif
#include <string.h>
/********************************************************************
Create a new vector with the given initial size. */
ib_vector_t*
ib_vector_create(
/*=============*/
/* out: vector */
mem_heap_t* heap, /* in: heap */
ulint size) /* in: initial size */
{
ib_vector_t* vec;
ut_a(size > 0);
vec = mem_heap_alloc(heap, sizeof(*vec));
vec->heap = heap;
vec->data = mem_heap_alloc(heap, sizeof(void*) * size);
vec->used = 0;
vec->total = size;
return(vec);
}
/********************************************************************
Push a new element to the vector, increasing its size if necessary. */
void
ib_vector_push(
/*===========*/
ib_vector_t* vec, /* in: vector */
void* elem) /* in: data element */
{
if (vec->used >= vec->total) {
void** new_data;
ulint new_total = vec->total * 2;
new_data = mem_heap_alloc(vec->heap,
sizeof(void*) * new_total);
memcpy(new_data, vec->data, sizeof(void*) * vec->total);
vec->data = new_data;
vec->total = new_total;
}
vec->data[vec->used] = elem;
vec->used++;
}