summaryrefslogtreecommitdiff
path: root/mysys
diff options
context:
space:
mode:
authorSergei Golubchik <sergii@pisem.net>2011-10-19 21:45:18 +0200
committerSergei Golubchik <sergii@pisem.net>2011-10-19 21:45:18 +0200
commit76f0b94bb0b2994d639353530c5b251d0f1a204b (patch)
tree9ed50628aac34f89a37637bab2fc4915b86b5eb4 /mysys
parent4e46d8e5bff140f2549841167dc4b65a3c0a645d (diff)
parent5dc1a2231f55bacc9aaf0e24816f3d9c2ee1f21d (diff)
downloadmariadb-git-76f0b94bb0b2994d639353530c5b251d0f1a204b.tar.gz
merge with 5.3
sql/sql_insert.cc: CREATE ... IF NOT EXISTS may do nothing, but it is still not a failure. don't forget to my_ok it. ****** CREATE ... IF NOT EXISTS may do nothing, but it is still not a failure. don't forget to my_ok it. sql/sql_table.cc: small cleanup ****** small cleanup
Diffstat (limited to 'mysys')
-rw-r--r--mysys/CMakeLists.txt2
-rw-r--r--mysys/charset.c5
-rw-r--r--mysys/hash.c22
-rw-r--r--mysys/ma_dyncol.c2111
-rw-r--r--mysys/mf_getdate.c2
-rw-r--r--mysys/mf_iocache.c3
-rw-r--r--mysys/my_bitmap.c385
-rw-r--r--mysys/my_compare.c3
-rw-r--r--mysys/my_fopen.c3
-rw-r--r--mysys/my_getncpus.c2
-rw-r--r--mysys/my_getsystime.c228
-rw-r--r--mysys/my_handler_errors.h8
-rw-r--r--mysys/my_init.c33
-rw-r--r--mysys/my_open.c11
-rw-r--r--mysys/my_port.c40
-rw-r--r--mysys/my_pread.c69
-rw-r--r--mysys/my_redel.c33
-rw-r--r--mysys/my_seek.c2
-rw-r--r--mysys/my_static.c5
-rw-r--r--mysys/my_static.h2
-rw-r--r--mysys/my_symlink.c6
-rw-r--r--mysys/my_sync.c37
-rw-r--r--mysys/my_thr_init.c8
-rw-r--r--mysys/my_uuid.c14
-rw-r--r--mysys/my_wincond.c46
-rw-r--r--mysys/my_write.c5
-rw-r--r--mysys/string.c12
-rw-r--r--mysys/thr_alarm.c26
-rw-r--r--mysys/thr_lock.c129
-rw-r--r--mysys/thr_mutex.c26
-rw-r--r--mysys/thr_rwlock.c2
-rw-r--r--mysys/tree.c9
-rw-r--r--mysys/waiting_threads.c34
33 files changed, 2491 insertions, 832 deletions
diff --git a/mysys/CMakeLists.txt b/mysys/CMakeLists.txt
index 662a4c79757..ca338369dad 100644
--- a/mysys/CMakeLists.txt
+++ b/mysys/CMakeLists.txt
@@ -34,7 +34,7 @@ SET(MYSYS_SOURCES array.c charset-def.c charset.c checksum.c default.c
thr_rwlock.c tree.c typelib.c base64.c my_memmem.c my_getpagesize.c
lf_alloc-pin.c lf_dynarray.c lf_hash.c
my_atomic.c my_getncpus.c my_safehash.c my_chmod.c my_rnd.c
- my_uuid.c wqueue.c waiting_threads.c
+ my_uuid.c wqueue.c waiting_threads.c ma_dyncol.c
my_rdtsc.c)
IF (WIN32)
diff --git a/mysys/charset.c b/mysys/charset.c
index f859ceae394..98b87ba9feb 100644
--- a/mysys/charset.c
+++ b/mysys/charset.c
@@ -97,6 +97,9 @@ static my_bool init_state_maps(struct charset_info_st *cs)
state_map[(uchar)'@']= (uchar) MY_LEX_USER_END;
state_map[(uchar) '`']= (uchar) MY_LEX_USER_VARIABLE_DELIMITER;
state_map[(uchar)'"']= (uchar) MY_LEX_STRING_OR_DELIMITER;
+ state_map[(uchar)'-']= (uchar) MY_LEX_MINUS_OR_COMMENT;
+ state_map[(uchar)',']= (uchar) MY_LEX_COMMA;
+ state_map[(uchar)'?']= (uchar) MY_LEX_PLACEHOLDER;
/*
Create a second map to make it faster to find identifiers
@@ -199,6 +202,7 @@ static my_bool simple_cs_is_full(CHARSET_INFO *cs)
}
+#if defined(HAVE_UCA_COLLATIONS) && (defined(HAVE_CHARSET_ucs2) || defined(HAVE_CHARSET_utf8))
static void
copy_uca_collation(struct charset_info_st *to, CHARSET_INFO *from)
{
@@ -212,6 +216,7 @@ copy_uca_collation(struct charset_info_st *to, CHARSET_INFO *from)
to->state|= MY_CS_AVAILABLE | MY_CS_LOADED |
MY_CS_STRNXFRM | MY_CS_UNICODE;
}
+#endif
static int add_collation(struct charset_info_st *cs)
diff --git a/mysys/hash.c b/mysys/hash.c
index 55b96afe615..38914d5f350 100644
--- a/mysys/hash.c
+++ b/mysys/hash.c
@@ -132,7 +132,8 @@ static inline void my_hash_free_elements(HASH *hash)
void my_hash_free(HASH *hash)
{
DBUG_ENTER("my_hash_free");
- DBUG_PRINT("enter",("hash: 0x%lx", (long) hash));
+ DBUG_PRINT("enter",("hash: 0x%lx elements: %ld",
+ (long) hash, hash->records));
my_hash_free_elements(hash);
hash->free= 0;
@@ -184,8 +185,9 @@ my_hash_key(const HASH *hash, const uchar *record, size_t *length,
static uint my_hash_mask(my_hash_value_type hashnr, size_t buffmax,
size_t maxlength)
{
- if ((hashnr & (buffmax-1)) < maxlength) return (hashnr & (buffmax-1));
- return (hashnr & ((buffmax >> 1) -1));
+ if ((hashnr & (buffmax-1)) < maxlength)
+ return (uint) (hashnr & (buffmax-1));
+ return (uint) (hashnr & ((buffmax >> 1) -1));
}
static uint my_hash_rec_mask(const HASH *hash, HASH_LINK *pos,
@@ -521,8 +523,9 @@ my_bool my_hash_insert(HASH *info, const uchar *record)
my_bool my_hash_delete(HASH *hash, uchar *record)
{
- uint blength,pos2,idx,empty_index;
+ uint pos2,idx,empty_index;
my_hash_value_type pos_hashnr, lastpos_hashnr;
+ size_t blength;
HASH_LINK *data,*lastpos,*gpos,*pos,*pos3,*empty;
DBUG_ENTER("my_hash_delete");
if (!hash->records)
@@ -611,8 +614,8 @@ exit:
my_bool my_hash_update(HASH *hash, uchar *record, uchar *old_key,
size_t old_key_length)
{
- uint new_index,new_pos_index,blength,records;
- size_t idx,empty;
+ uint new_index,new_pos_index,records;
+ size_t idx, empty, blength;
HASH_LINK org_link,*data,*previous,*pos;
DBUG_ENTER("my_hash_update");
@@ -694,7 +697,7 @@ my_bool my_hash_update(HASH *hash, uchar *record, uchar *old_key,
if (new_index != new_pos_index)
{ /* Other record in wrong position */
data[empty] = *pos;
- movelink(data,new_index,new_pos_index,empty);
+ movelink(data,new_index,new_pos_index, (uint) empty);
org_link.next=NO_RECORD;
data[new_index]= org_link;
}
@@ -702,7 +705,7 @@ my_bool my_hash_update(HASH *hash, uchar *record, uchar *old_key,
{ /* Link in chain at right position */
org_link.next=data[new_index].next;
data[empty]=org_link;
- data[new_index].next=empty;
+ data[new_index].next= (uint) empty;
}
DBUG_RETURN(0);
}
@@ -766,7 +769,8 @@ my_bool my_hash_check(HASH *hash)
{
int error;
uint i,rec_link,found,max_links,seek,links,idx;
- uint records,blength;
+ uint records;
+ size_t blength;
HASH_LINK *data,*hash_info;
records=hash->records; blength=hash->blength;
diff --git a/mysys/ma_dyncol.c b/mysys/ma_dyncol.c
new file mode 100644
index 00000000000..0116cdd2c20
--- /dev/null
+++ b/mysys/ma_dyncol.c
@@ -0,0 +1,2111 @@
+/* Copyright (c) 2011, Monty Program Ab
+ Copyright (c) 2011, Oleksandr Byelkin
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are
+ met:
+
+ 1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+ 2. Redistributions in binary form must the following disclaimer in
+ the documentation and/or other materials provided with the
+ distribution.
+
+ THIS SOFTWARE IS PROVIDED BY <COPYRIGHT HOLDER> ``AS IS'' AND ANY
+ EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> OR
+ CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ SUCH DAMAGE.
+*/
+
+#include "mysys_priv.h"
+#include <m_string.h>
+#include <ma_dyncol.h>
+
+/*
+ Flag byte bits
+
+ 2 bits which determinate size of offset in the header -1
+*/
+/* mask to get above bits */
+#define DYNCOL_FLG_OFFSET 3
+/* All known flags mask */
+#define DYNCOL_FLG_KNOWN 3
+
+/* dynamic column size reserve */
+#define DYNCOL_SYZERESERVE 80
+
+/* length of fixed string header 1 byte - flags, 2 bytes - columns counter */
+#define FIXED_HEADER_SIZE 3
+
+#define COLUMN_NUMBER_SIZE 2
+
+#define MAX_OFFSET_LENGTH 5
+
+static enum enum_dyncol_func_result
+dynamic_column_time_store(DYNAMIC_COLUMN *str,
+ MYSQL_TIME *value);
+static enum enum_dyncol_func_result
+dynamic_column_date_store(DYNAMIC_COLUMN *str,
+ MYSQL_TIME *value);
+static enum enum_dyncol_func_result
+dynamic_column_time_read_internal(DYNAMIC_COLUMN_VALUE *store_it_here,
+ uchar *data, size_t length);
+static enum enum_dyncol_func_result
+dynamic_column_date_read_internal(DYNAMIC_COLUMN_VALUE *store_it_here,
+ uchar *data, size_t length);
+
+/**
+ Initialize dynamic column string with (make it empty but correct format)
+
+ @param str The string to initialize
+ @param size Amount of preallocated memory for the string.
+
+ @retval FALSE OK
+ @retval TRUE error
+*/
+
+static my_bool dynamic_column_init_str(DYNAMIC_COLUMN *str, size_t size)
+{
+ DBUG_ASSERT(size != 0);
+
+ /*
+ Make string with no fields (empty header)
+ - First \0 is flags
+ - other 2 \0 is number of fields
+ */
+ if (init_dynamic_string(str, NULL,
+ size + FIXED_HEADER_SIZE, DYNCOL_SYZERESERVE))
+ return TRUE;
+ bzero(str->str, FIXED_HEADER_SIZE);
+ str->length= FIXED_HEADER_SIZE;
+ return FALSE;
+}
+
+
+/**
+ Calculate how many bytes needed to store val as variable length integer
+ where first bit indicate continuation of the sequence.
+
+ @param val The value for which we are calculating length
+
+ @return number of bytes
+*/
+
+static size_t dynamic_column_var_uint_bytes(ulonglong val)
+{
+ size_t len= 0;
+ do
+ {
+ len++;
+ val>>= 7;
+ } while (val);
+ return len;
+}
+
+
+/**
+ Stores variable length unsigned integer value to a string
+
+ @param str The string where to append the value
+ @param val The value to put in the string
+
+ @return ER_DYNCOL_* return code
+
+ @notes
+ This is used to store a number together with other data in the same
+ object. (Like decimals, length of string etc)
+ (As we don't know the length of this object, we can't store 0 in 0 bytes)
+*/
+
+static enum enum_dyncol_func_result
+dynamic_column_var_uint_store(DYNAMIC_COLUMN *str, ulonglong val)
+{
+ if (dynstr_realloc(str, 10)) /* max what we can use */
+ return ER_DYNCOL_RESOURCE;
+
+ do
+ {
+ ulonglong rest= val >> 7;
+ str->str[str->length++]= ((val & 0x7f) | (rest ? 0x80 : 0x00));
+ val= rest;
+ } while (val);
+ return ER_DYNCOL_OK;
+}
+
+
+/**
+ Reads variable length unsigned integer value from a string
+
+ @param data The string from which the int should be read
+ @param data_length Max length of data
+ @param len Where to put length of the string read in bytes
+
+ @return value of the unsigned integer read from the string
+
+ In case of error, *len is set to 0
+*/
+
+static ulonglong
+dynamic_column_var_uint_get(uchar *data, size_t data_length,
+ size_t *len)
+{
+ ulonglong val= 0;
+ uint length;
+ uchar *end= data + data_length;
+
+ for (length=0; data < end ; data++)
+ {
+ val+= (((ulonglong)((*data) & 0x7f)) << (length * 7));
+ length++;
+ if (!((*data) & 0x80))
+ {
+ /* End of data */
+ *len= length;
+ return val;
+ }
+ }
+ /* Something was wrong with data */
+ *len= 0; /* Mark error */
+ return 0;
+}
+
+
+/**
+ Calculate how many bytes needed to store val as unsigned.
+
+ @param val The value for which we are calculating length
+
+ @return number of bytes (0-8)
+*/
+
+static size_t dynamic_column_uint_bytes(ulonglong val)
+{
+ size_t len;
+
+ for (len= 0; val ; val>>= 8, len++)
+ ;
+ return len;
+}
+
+
+/**
+ Append the string with given unsigned int value.
+
+ @param str The string where to put the value
+ @param val The value to put in the string
+
+ @return ER_DYNCOL_* return code
+*/
+
+static enum enum_dyncol_func_result
+dynamic_column_uint_store(DYNAMIC_COLUMN *str, ulonglong val)
+{
+ if (dynstr_realloc(str, 8)) /* max what we can use */
+ return ER_DYNCOL_RESOURCE;
+
+ for (; val; val>>= 8)
+ str->str[str->length++]= (char) (val & 0xff);
+ return ER_DYNCOL_OK;
+}
+
+
+/**
+ Read unsigned int value of given length from the string
+
+ @param store_it_here The structure to store the value
+ @param data The string which should be read
+ @param length The length (in bytes) of the value in nthe string
+
+ @return ER_DYNCOL_* return code
+*/
+
+static enum enum_dyncol_func_result
+dynamic_column_uint_read(DYNAMIC_COLUMN_VALUE *store_it_here,
+ uchar *data, size_t length)
+{
+ ulonglong value= 0;
+ size_t i;
+
+ for (i= 0; i < length; i++)
+ value+= ((ulonglong)data[i]) << (i*8);
+
+ store_it_here->ulong_value= value;
+ return ER_DYNCOL_OK;
+}
+
+/**
+ Calculate how many bytes needed to store val as signed in following encoding:
+ 0 -> 0
+ -1 -> 1
+ 1 -> 2
+ -2 -> 3
+ 2 -> 4
+ ...
+
+ @param val The value for which we are calculating length
+
+ @return number of bytes
+*/
+
+static size_t dynamic_column_sint_bytes(longlong val)
+{
+ return dynamic_column_uint_bytes((val << 1) ^
+ (val < 0 ? ULL(0xffffffffffffffff) : 0));
+}
+
+
+/**
+ Append the string with given signed int value.
+
+ @param str the string where to put the value
+ @param val the value to put in the string
+
+ @return ER_DYNCOL_* return code
+*/
+
+static enum enum_dyncol_func_result
+dynamic_column_sint_store(DYNAMIC_COLUMN *str, longlong val)
+{
+ return dynamic_column_uint_store(str,
+ (val << 1) ^
+ (val < 0 ? ULL(0xffffffffffffffff) : 0));
+}
+
+
+/**
+ Read signed int value of given length from the string
+
+ @param store_it_here The structure to store the value
+ @param data The string which should be read
+ @param length The length (in bytes) of the value in the string
+
+ @return ER_DYNCOL_* return code
+*/
+
+static enum enum_dyncol_func_result
+dynamic_column_sint_read(DYNAMIC_COLUMN_VALUE *store_it_here,
+ uchar *data, size_t length)
+{
+ ulonglong val;
+ dynamic_column_uint_read(store_it_here, data, length);
+ val= store_it_here->ulong_value;
+ if (val & 1)
+ val= (val >> 1) ^ ULL(0xffffffffffffffff);
+ else
+ val>>= 1;
+ store_it_here->long_value= (longlong) val;
+ return ER_DYNCOL_OK;
+}
+
+
+/**
+ Calculate how many bytes needed to store the value.
+
+ @param value The value for which we are calculating length
+
+ @return
+ Error: (size_t) ~0
+ ok number of bytes
+*/
+
+static size_t
+dynamic_column_value_len(DYNAMIC_COLUMN_VALUE *value)
+{
+ switch (value->type) {
+ case DYN_COL_NULL:
+ return 0;
+ case DYN_COL_INT:
+ return dynamic_column_sint_bytes(value->long_value);
+ case DYN_COL_UINT:
+ return dynamic_column_uint_bytes(value->ulong_value);
+ case DYN_COL_DOUBLE:
+ return 8;
+ case DYN_COL_STRING:
+ return (dynamic_column_var_uint_bytes(value->charset->number) +
+ value->string_value.length);
+ case DYN_COL_DECIMAL:
+ {
+ int precision= value->decimal_value.intg + value->decimal_value.frac;
+ int scale= value->decimal_value.frac;
+
+ if (precision == 0 || decimal_is_zero(&value->decimal_value))
+ {
+ /* This is here to simplify dynamic_column_decimal_store() */
+ value->decimal_value.intg= value->decimal_value.frac= 0;
+ return 0;
+ }
+ /*
+ Check if legal decimal; This is needed to not get an assert in
+ decimal_bin_size(). However this should be impossible as all
+ decimals entered here should be valid and we have the special check
+ above to handle the unlikely but possible case that decimal_value.intg
+ and decimal.frac is 0.
+ */
+ if (scale < 0 || precision <= 0)
+ {
+ DBUG_ASSERT(0); /* Impossible */
+ return (size_t) ~0;
+ }
+ return (dynamic_column_var_uint_bytes(value->decimal_value.intg) +
+ dynamic_column_var_uint_bytes(value->decimal_value.frac) +
+ decimal_bin_size(precision, scale));
+ }
+ case DYN_COL_DATETIME:
+ /* date+time in bits: 14 + 4 + 5 + 10 + 6 + 6 + 20 + 1 66bits ~= 9 bytes */
+ return 9;
+ case DYN_COL_DATE:
+ /* date in dits: 14 + 4 + 5 = 23bits ~= 3bytes*/
+ return 3;
+ case DYN_COL_TIME:
+ /* time in bits: 10 + 6 + 6 + 20 + 1 = 43bits ~= 6bytes*/
+ return 6;
+ }
+ DBUG_ASSERT(0);
+ return 0;
+}
+
+
+/**
+ Append double value to a string
+
+ @param str the string where to put the value
+ @param val the value to put in the string
+
+ @return ER_DYNCOL_* return code
+*/
+
+static enum enum_dyncol_func_result
+dynamic_column_double_store(DYNAMIC_COLUMN *str, double val)
+{
+ if (dynstr_realloc(str, 8))
+ return ER_DYNCOL_RESOURCE;
+ float8store(str->str + str->length, val);
+ str->length+= 8;
+ return ER_DYNCOL_OK;
+}
+
+
+/**
+ Read double value of given length from the string
+
+ @param store_it_here The structure to store the value
+ @param data The string which should be read
+ @param length The length (in bytes) of the value in nthe string
+
+ @return ER_DYNCOL_* return code
+*/
+
+static enum enum_dyncol_func_result
+dynamic_column_double_read(DYNAMIC_COLUMN_VALUE *store_it_here,
+ uchar *data, size_t length)
+{
+ if (length != 8)
+ return ER_DYNCOL_FORMAT;
+ float8get(store_it_here->double_value, data);
+ return ER_DYNCOL_OK;
+}
+
+
+/**
+ Append the string with given string value.
+
+ @param str the string where to put the value
+ @param val the value to put in the string
+
+ @return ER_DYNCOL_* return code
+*/
+
+static enum enum_dyncol_func_result
+dynamic_column_string_store(DYNAMIC_COLUMN *str, LEX_STRING *string,
+ CHARSET_INFO *charset)
+{
+ enum enum_dyncol_func_result rc;
+ if ((rc= dynamic_column_var_uint_store(str, charset->number)))
+ return rc;
+ if (dynstr_append_mem(str, string->str, string->length))
+ return ER_DYNCOL_RESOURCE;
+ return ER_DYNCOL_OK;
+}
+
+
+/**
+ Read string value of given length from the packed string
+
+ @param store_it_here The structure to store the value
+ @param data The packed string which should be read
+ @param length The length (in bytes) of the value in nthe string
+
+ @return ER_DYNCOL_* return code
+*/
+
+static enum enum_dyncol_func_result
+dynamic_column_string_read(DYNAMIC_COLUMN_VALUE *store_it_here,
+ uchar *data, size_t length)
+{
+ size_t len;
+ uint charset_nr= (uint)dynamic_column_var_uint_get(data, length, &len);
+ if (len == 0) /* Wrong packed number */
+ return ER_DYNCOL_FORMAT;
+ store_it_here->charset= get_charset(charset_nr, MYF(MY_WME));
+ if (store_it_here->charset == NULL)
+ return ER_DYNCOL_UNKNOWN_CHARSET;
+ data+= len;
+ store_it_here->string_value.length= (length-= len);
+ store_it_here->string_value.str= (char*) data;
+ return ER_DYNCOL_OK;
+}
+
+
+/**
+ Append the string with given decimal value.
+
+ @param str the string where to put the value
+ @param val the value to put in the string
+
+ @return ER_DYNCOL_* return code
+*/
+
+static enum enum_dyncol_func_result
+dynamic_column_decimal_store(DYNAMIC_COLUMN *str,
+ decimal_t *value)
+{
+ uint bin_size;
+ int precision= value->intg + value->frac;
+
+ /* Store decimal zero as empty string */
+ if (precision == 0)
+ return ER_DYNCOL_OK;
+
+ bin_size= decimal_bin_size(precision, value->frac);
+ if (dynstr_realloc(str, bin_size + 20))
+ return ER_DYNCOL_RESOURCE;
+
+ /* The following can't fail as memory is already allocated */
+ (void) dynamic_column_var_uint_store(str, value->intg);
+ (void) dynamic_column_var_uint_store(str, value->frac);
+
+ decimal2bin(value, (uchar *) str->str + str->length,
+ precision, value->frac);
+ str->length+= bin_size;
+ return ER_DYNCOL_OK;
+}
+
+
+/**
+ Prepare the value to be used as decimal.
+
+ @param value The value structure which sould be setup.
+*/
+
+void dynamic_column_prepare_decimal(DYNAMIC_COLUMN_VALUE *value)
+{
+ value->decimal_value.buf= value->decimal_buffer;
+ value->decimal_value.len= DECIMAL_BUFF_LENGTH;
+ /* just to be safe */
+ value->type= DYN_COL_DECIMAL;
+ decimal_make_zero(&value->decimal_value);
+}
+
+
+/**
+ Read decimal value of given length from the string
+
+ @param store_it_here The structure to store the value
+ @param data The string which should be read
+ @param length The length (in bytes) of the value in nthe string
+
+ @return ER_DYNCOL_* return code
+*/
+
+static enum enum_dyncol_func_result
+dynamic_column_decimal_read(DYNAMIC_COLUMN_VALUE *store_it_here,
+ uchar *data, size_t length)
+{
+ size_t intg_len, frac_len;
+ int intg, frac, precision, scale;
+
+ dynamic_column_prepare_decimal(store_it_here);
+ /* Decimals 0.0 is stored as a zero length string */
+ if (length == 0)
+ return ER_DYNCOL_OK; /* value contains zero */
+
+ intg= (int)dynamic_column_var_uint_get(data, length, &intg_len);
+ data+= intg_len;
+ frac= (int)dynamic_column_var_uint_get(data, length - intg_len, &frac_len);
+ data+= frac_len;
+
+ /* Check the size of data is correct */
+ precision= intg + frac;
+ scale= frac;
+ if (scale < 0 || precision <= 0 || scale > precision ||
+ (length - intg_len - frac_len) >
+ (size_t) (DECIMAL_BUFF_LENGTH*sizeof(decimal_digit_t)) ||
+ decimal_bin_size(intg + frac, frac) !=
+ (int) (length - intg_len - frac_len))
+ return ER_DYNCOL_FORMAT;
+
+ if (bin2decimal(data, &store_it_here->decimal_value, precision, scale) !=
+ E_DEC_OK)
+ return ER_DYNCOL_FORMAT;
+ return ER_DYNCOL_OK;
+}
+
+
+/**
+ Append the string with given datetime value.
+
+ @param str the string where to put the value
+ @param value the value to put in the string
+
+ @return ER_DYNCOL_* return code
+*/
+
+static enum enum_dyncol_func_result
+dynamic_column_date_time_store(DYNAMIC_COLUMN *str, MYSQL_TIME *value)
+{
+ enum enum_dyncol_func_result rc;
+ /*
+ 0<----year----><mn><day>00000!<-hours--><min-><sec-><---microseconds--->
+ 12345678901234123412345 1123456789012345612345612345678901234567890
+ <123456><123456><123456><123456><123456><123456><123456><123456><123456>
+ */
+ if ((rc= dynamic_column_date_store(str, value)) ||
+ (rc= dynamic_column_time_store(str, value)))
+ return rc;
+ return ER_DYNCOL_OK;
+}
+
+
+/**
+ Read datetime value of given length from the packed string
+
+ @param store_it_here The structure to store the value
+ @param data The packed string which should be read
+ @param length The length (in bytes) of the value in nthe string
+
+ @return ER_DYNCOL_* return code
+*/
+
+static enum enum_dyncol_func_result
+dynamic_column_date_time_read(DYNAMIC_COLUMN_VALUE *store_it_here,
+ uchar *data, size_t length)
+{
+ enum enum_dyncol_func_result rc= ER_DYNCOL_FORMAT;
+ /*
+ 0<----year----><mn><day>00000!<-hours--><min-><sec-><---microseconds--->
+ 12345678901234123412345 1123456789012345612345612345678901234567890
+ <123456><123456><123456><123456><123456><123456><123456><123456><123456>
+ */
+ if (length != 9)
+ goto err;
+ store_it_here->time_value.time_type= MYSQL_TIMESTAMP_DATETIME;
+ if ((rc= dynamic_column_date_read_internal(store_it_here, data, 3)) ||
+ (rc= dynamic_column_time_read_internal(store_it_here, data + 3, 6)))
+ goto err;
+ return ER_DYNCOL_OK;
+
+err:
+ store_it_here->time_value.time_type= MYSQL_TIMESTAMP_ERROR;
+ return rc;
+}
+
+
+/**
+ Append the string with given time value.
+
+ @param str the string where to put the value
+ @param value the value to put in the string
+
+ @return ER_DYNCOL_* return code
+*/
+
+static enum enum_dyncol_func_result
+dynamic_column_time_store(DYNAMIC_COLUMN *str, MYSQL_TIME *value)
+{
+ uchar *buf;
+ if (dynstr_realloc(str, 6))
+ return ER_DYNCOL_RESOURCE;
+
+ buf= ((uchar *)str->str) + str->length;
+
+ if (value->time_type == MYSQL_TIMESTAMP_NONE ||
+ value->time_type == MYSQL_TIMESTAMP_ERROR ||
+ value->time_type == MYSQL_TIMESTAMP_DATE)
+ {
+ value->neg= 0;
+ value->second_part= 0;
+ value->hour= 0;
+ value->minute= 0;
+ value->second= 0;
+ }
+ DBUG_ASSERT(value->hour <= 838);
+ DBUG_ASSERT(value->minute <= 59);
+ DBUG_ASSERT(value->second <= 59);
+ DBUG_ASSERT(value->second_part <= 999999);
+ /*
+ 00000!<-hours--><min-><sec-><---microseconds--->
+ 1123456789012345612345612345678901234567890
+ <123456><123456><123456><123456><123456><123456>
+ */
+ buf[0]= (value->second_part & 0xff);
+ buf[1]= ((value->second_part & 0xff00) >> 8);
+ buf[2]= (uchar)(((value->second & 0xf) << 4) |
+ ((value->second_part & 0xf0000) >> 16));
+ buf[3]= ((value->minute << 2) | ((value->second & 0x30) >> 4));
+ buf[4]= (value->hour & 0xff);
+ buf[5]= ((value->neg ? 0x4 : 0) | (value->hour >> 8));
+ str->length+= 6;
+ return ER_DYNCOL_OK;
+}
+
+
+/**
+ Read time value of given length from the packed string
+
+ @param store_it_here The structure to store the value
+ @param data The packed string which should be read
+ @param length The length (in bytes) of the value in nthe string
+
+ @return ER_DYNCOL_* return code
+*/
+
+static enum enum_dyncol_func_result
+dynamic_column_time_read(DYNAMIC_COLUMN_VALUE *store_it_here,
+ uchar *data, size_t length)
+{
+ store_it_here->time_value.year= store_it_here->time_value.month=
+ store_it_here->time_value.day= 0;
+ store_it_here->time_value.time_type= MYSQL_TIMESTAMP_TIME;
+ return dynamic_column_time_read_internal(store_it_here, data, length);
+}
+
+/**
+ Internal function for reading time part from the string.
+
+ @param store_it_here The structure to store the value
+ @param data The packed string which should be read
+ @param length The length (in bytes) of the value in nthe string
+
+ @return ER_DYNCOL_* return code
+*/
+
+static enum enum_dyncol_func_result
+dynamic_column_time_read_internal(DYNAMIC_COLUMN_VALUE *store_it_here,
+ uchar *data, size_t length)
+{
+ if (length != 6)
+ goto err;
+ /*
+ 00000!<-hours--><min-><sec-><---microseconds--->
+ 1123456789012345612345612345678901234567890
+ <123456><123456><123456><123456><123456><123456>
+ */
+ store_it_here->time_value.second_part= (data[0] |
+ (data[1] << 8) |
+ ((data[2] & 0xf) << 16));
+ store_it_here->time_value.second= ((data[2] >> 4) |
+ ((data[3] & 0x3) << 4));
+ store_it_here->time_value.minute= (data[3] >> 2);
+ store_it_here->time_value.hour= (((((uint)data[5]) & 0x3 ) << 8) | data[4]);
+ store_it_here->time_value.neg= ((data[5] & 0x4) ? 1 : 0);
+ if (store_it_here->time_value.second > 59 ||
+ store_it_here->time_value.minute > 59 ||
+ store_it_here->time_value.hour > 838 ||
+ store_it_here->time_value.second_part > 999999)
+ goto err;
+ return ER_DYNCOL_OK;
+
+err:
+ store_it_here->time_value.time_type= MYSQL_TIMESTAMP_ERROR;
+ return ER_DYNCOL_FORMAT;
+}
+
+
+/**
+ Append the string with given date value.
+
+ @param str the string where to put the value
+ @param value the value to put in the string
+
+ @return ER_DYNCOL_* return code
+*/
+
+static enum enum_dyncol_func_result
+dynamic_column_date_store(DYNAMIC_COLUMN *str, MYSQL_TIME *value)
+{
+ uchar *buf;
+ if (dynstr_realloc(str, 3))
+ return ER_DYNCOL_RESOURCE;
+
+ buf= ((uchar *)str->str) + str->length;
+ if (value->time_type == MYSQL_TIMESTAMP_NONE ||
+ value->time_type == MYSQL_TIMESTAMP_ERROR ||
+ value->time_type == MYSQL_TIMESTAMP_TIME)
+ value->year= value->month= value->day = 0;
+ DBUG_ASSERT(value->year <= 9999);
+ DBUG_ASSERT(value->month <= 12);
+ DBUG_ASSERT(value->day <= 31);
+ /*
+ 0<----year----><mn><day>
+ 012345678901234123412345
+ <123456><123456><123456>
+ */
+ buf[0]= (value->day |
+ ((value->month & 0x7) << 5));
+ buf[1]= ((value->month >> 3) | ((value->year & 0x7F) << 1));
+ buf[2]= (value->year >> 7);
+ str->length+= 3;
+ return ER_DYNCOL_OK;
+}
+
+
+
+/**
+ Read date value of given length from the packed string
+
+ @param store_it_here The structure to store the value
+ @param data The packed string which should be read
+ @param length The length (in bytes) of the value in nthe string
+
+ @return ER_DYNCOL_* return code
+*/
+
+static enum enum_dyncol_func_result
+dynamic_column_date_read(DYNAMIC_COLUMN_VALUE *store_it_here,
+ uchar *data, size_t length)
+{
+ store_it_here->time_value.neg= 0;
+ store_it_here->time_value.second_part= 0;
+ store_it_here->time_value.hour= 0;
+ store_it_here->time_value.minute= 0;
+ store_it_here->time_value.second= 0;
+ store_it_here->time_value.time_type= MYSQL_TIMESTAMP_DATE;
+ return dynamic_column_date_read_internal(store_it_here, data, length);
+}
+
+/**
+ Internal function for reading date part from the string.
+
+ @param store_it_here The structure to store the value
+ @param data The packed string which should be read
+ @param length The length (in bytes) of the value in nthe string
+
+ @return ER_DYNCOL_* return code
+*/
+
+static enum enum_dyncol_func_result
+dynamic_column_date_read_internal(DYNAMIC_COLUMN_VALUE *store_it_here,
+ uchar *data,
+ size_t length)
+{
+ if (length != 3)
+ goto err;
+ /*
+ 0<----year----><mn><day>
+ 12345678901234123412345
+ <123456><123456><123456>
+ */
+ store_it_here->time_value.day= (data[0] & 0x1f);
+ store_it_here->time_value.month= (((data[1] & 0x1) << 3) |
+ (data[0] >> 5));
+ store_it_here->time_value.year= ((((uint)data[2]) << 7) |
+ (data[1] >> 1));
+ if (store_it_here->time_value.day > 31 ||
+ store_it_here->time_value.month > 12 ||
+ store_it_here->time_value.year > 9999)
+ goto err;
+ return ER_DYNCOL_OK;
+
+err:
+ store_it_here->time_value.time_type= MYSQL_TIMESTAMP_ERROR;
+ return ER_DYNCOL_FORMAT;
+}
+
+
+/**
+ Append the string with given value.
+
+ @param str the string where to put the value
+ @param value the value to put in the string
+
+ @return ER_DYNCOL_* return code
+*/
+
+static enum enum_dyncol_func_result
+data_store(DYNAMIC_COLUMN *str, DYNAMIC_COLUMN_VALUE *value)
+{
+ switch (value->type) {
+ case DYN_COL_INT:
+ return dynamic_column_sint_store(str, value->long_value);
+ case DYN_COL_UINT:
+ return dynamic_column_uint_store(str, value->ulong_value);
+ case DYN_COL_DOUBLE:
+ return dynamic_column_double_store(str, value->double_value);
+ case DYN_COL_STRING:
+ return dynamic_column_string_store(str, &value->string_value,
+ value->charset);
+ case DYN_COL_DECIMAL:
+ return dynamic_column_decimal_store(str, &value->decimal_value);
+ case DYN_COL_DATETIME:
+ /* date+time in bits: 14 + 4 + 5 + 5 + 6 + 6 40bits = 5 bytes */
+ return dynamic_column_date_time_store(str, &value->time_value);
+ case DYN_COL_DATE:
+ /* date in dits: 14 + 4 + 5 = 23bits ~= 3bytes*/
+ return dynamic_column_date_store(str, &value->time_value);
+ case DYN_COL_TIME:
+ /* time in bits: 5 + 6 + 6 = 17bits ~= 3bytes*/
+ return dynamic_column_time_store(str, &value->time_value);
+ case DYN_COL_NULL:
+ break; /* Impossible */
+ }
+ DBUG_ASSERT(0);
+ return ER_DYNCOL_OK; /* Impossible */
+}
+
+
+/**
+ Calculate length of offset field for given data length
+
+ @param data_length Length of the data segment
+
+ @return number of bytes
+*/
+
+static size_t dynamic_column_offset_bytes(size_t data_length)
+{
+ if (data_length < 0x1f) /* all 1 value is reserved */
+ return 1;
+ if (data_length < 0x1fff) /* all 1 value is reserved */
+ return 2;
+ if (data_length < 0x1fffff) /* all 1 value is reserved */
+ return 3;
+ if (data_length < 0x1fffffff) /* all 1 value is reserved */
+ return 4;
+ return MAX_OFFSET_LENGTH; /* For future */
+}
+
+/**
+ Store offset and type information in the given place
+
+ @param place Beginning of the index entry
+ @param offset_size Size of offset field in bytes
+ @param type Type to be written
+ @param offset Offset to be written
+*/
+
+static void type_and_offset_store(uchar *place, size_t offset_size,
+ DYNAMIC_COLUMN_TYPE type,
+ size_t offset)
+{
+ ulong val = (((ulong) offset) << 3) | (type - 1);
+ DBUG_ASSERT(type != DYN_COL_NULL);
+ DBUG_ASSERT(((type - 1) & (~7)) == 0); /* fit in 3 bits */
+
+ /* Index entry starts with column number; Jump over it */
+ place+= COLUMN_NUMBER_SIZE;
+
+ switch (offset_size) {
+ case 1:
+ DBUG_ASSERT(offset < 0x1f); /* all 1 value is reserved */
+ place[0]= (uchar)val;
+ break;
+ case 2:
+ DBUG_ASSERT(offset < 0x1fff); /* all 1 value is reserved */
+ int2store(place, val);
+ break;
+ case 3:
+ DBUG_ASSERT(offset < 0x1fffff); /* all 1 value is reserved */
+ int3store(place, val);
+ break;
+ case 4:
+ DBUG_ASSERT(offset < 0x1fffffff); /* all 1 value is reserved */
+ int4store(place, val);
+ break;
+ default:
+ DBUG_ASSERT(0); /* impossible */
+ }
+}
+
+
+/**
+ Read offset and type information from index entry
+
+ @param type Where to put type info
+ @param offset Where to put offset info
+ @param place Beginning of the index entry
+ @param offset_size Size of offset field in bytes
+*/
+
+static void type_and_offset_read(DYNAMIC_COLUMN_TYPE *type,
+ size_t *offset,
+ uchar *place, size_t offset_size)
+{
+ ulong val;
+ LINT_INIT(val);
+
+ place+= COLUMN_NUMBER_SIZE; /* skip column number */
+ switch (offset_size) {
+ case 1:
+ val= (ulong)place[0];
+ break;
+ case 2:
+ val= uint2korr(place);
+ break;
+ case 3:
+ val= uint3korr(place);
+ break;
+ case 4:
+ val= uint4korr(place);
+ break;
+ default:
+ DBUG_ASSERT(0); /* impossible */
+ }
+ *type= (val & 0x7) + 1;
+ *offset= val >> 3;
+}
+
+
+/**
+ Comparator function for references on column numbers for qsort
+*/
+
+static int column_sort(const void *a, const void *b)
+{
+ return **((uint **)a) - **((uint **)b);
+}
+
+
+/**
+ Write information to the fixed header
+
+ @param str String where to write the header
+ @param offset_size Size of offset field in bytes
+ @param column_count Number of columns
+*/
+
+static void set_fixed_header(DYNAMIC_COLUMN *str,
+ uint offset_size,
+ uint column_count)
+{
+ DBUG_ASSERT(column_count <= 0xffff);
+ DBUG_ASSERT(offset_size <= 4);
+ str->str[0]= ((str->str[0] & ~DYNCOL_FLG_OFFSET) |
+ (offset_size - 1)); /* size of offset */
+ int2store(str->str + 1, column_count); /* columns number */
+ DBUG_ASSERT((str->str[0] & (~DYNCOL_FLG_KNOWN)) == 0);
+}
+
+/*
+ Calculate entry size (E) and header size (H) by offset size (O) and column
+ count (C).
+*/
+
+#define calc_param(E,H,O,C) do { \
+ (*(E))= (O) + COLUMN_NUMBER_SIZE; \
+ (*(H))= (*(E)) * (C); \
+}while(0);
+
+
+/**
+ Adds columns into the empty string
+
+ @param str String where to write the data
+ @param header_size Size of the header without fixed part
+ @param offset_size Size of offset field in bytes
+ @param column_count Number of columns in the arrays
+ @parem not_null_count Number of non-null columns in the arrays
+ @param data_size Size of the data segment
+ @param column_numbers Array of columns numbers
+ @param values Array of columns values
+ @param new_str True if we need to allocate new string
+
+ @return ER_DYNCOL_* return code
+*/
+
+static enum enum_dyncol_func_result
+dynamic_new_column_store(DYNAMIC_COLUMN *str,
+ size_t header_size,
+ size_t offset_size,
+ uint column_count,
+ uint not_null_count,
+ size_t data_size,
+ uint *column_numbers,
+ DYNAMIC_COLUMN_VALUE *values,
+ my_bool new_str)
+{
+ uchar *header_end;
+ uint **columns_order;
+ uint i;
+ uint entry_size= COLUMN_NUMBER_SIZE + offset_size;
+ enum enum_dyncol_func_result rc= ER_DYNCOL_RESOURCE;
+
+ if (!(columns_order= malloc(sizeof(uint*)*column_count)))
+ return ER_DYNCOL_RESOURCE;
+ if (new_str)
+ {
+ if (dynamic_column_init_str(str,
+ data_size + header_size + DYNCOL_SYZERESERVE))
+ goto err;
+ }
+ else
+ {
+ str->length= 0;
+ if (dynstr_realloc(str, data_size + header_size + DYNCOL_SYZERESERVE))
+ goto err;
+ bzero(str->str, FIXED_HEADER_SIZE);
+ str->length= FIXED_HEADER_SIZE;
+ }
+
+ /* sort columns for the header */
+ for (i= 0; i < column_count; i++)
+ columns_order[i]= column_numbers + i;
+ qsort(columns_order, (size_t)column_count, sizeof(uint*), &column_sort);
+
+ /*
+ For now we don't allow creating two columns with the same number
+ at the time of create. This can be fixed later to just use the later
+ by comparing the pointers.
+ */
+ for (i= 0; i < column_count - 1; i++)
+ {
+ if (columns_order[i][0] > UINT_MAX16 ||
+ columns_order[i][0] == columns_order[i + 1][0])
+ {
+ rc= ER_DYNCOL_DATA;
+ goto err;
+ }
+ }
+ if (columns_order[i][0] > UINT_MAX16)
+ {
+ rc= ER_DYNCOL_DATA;
+ goto err;
+ }
+
+ DBUG_ASSERT(str->max_length >= str->length + header_size);
+ set_fixed_header(str, offset_size, not_null_count);
+ str->length+= header_size; /* reserve place for header */
+ header_end= (uchar *)str->str + FIXED_HEADER_SIZE;
+ for (i= 0; i < column_count; i++)
+ {
+ uint ord= columns_order[i] - column_numbers;
+ if (values[ord].type != DYN_COL_NULL)
+ {
+ /* Store header first in the str */
+ int2store(header_end, column_numbers[ord]);
+ type_and_offset_store(header_end, offset_size,
+ values[ord].type,
+ str->length - header_size - FIXED_HEADER_SIZE);
+
+ /* Store value in 'str + str->length' and increase str->length */
+ if ((rc= data_store(str, values + ord)))
+ goto err;
+ header_end+= entry_size;
+ }
+ }
+ rc= ER_DYNCOL_OK;
+err:
+ free(columns_order);
+ return rc;
+}
+
+/**
+ Create packed string which contains given columns (internal)
+
+ @param str String where to write the data
+ @param column_count Number of columns in the arrays
+ @param column_numbers Array of columns numbers
+ @param values Array of columns values
+ @param new_str True if we need allocate new string
+
+ @return ER_DYNCOL_* return code
+*/
+
+static enum enum_dyncol_func_result
+dynamic_column_create_many_internal(DYNAMIC_COLUMN *str,
+ uint column_count,
+ uint *column_numbers,
+ DYNAMIC_COLUMN_VALUE *values,
+ my_bool new_str)
+{
+ size_t data_size= 0;
+ size_t header_size, offset_size;
+ uint i;
+ int not_null_column_count= 0;
+
+ if (new_str)
+ {
+ /* to make dynstr_free() working in case of errors */
+ bzero(str, sizeof(DYNAMIC_COLUMN));
+ }
+
+ for (i= 0; i < column_count; i++)
+ {
+ if (values[i].type != DYN_COL_NULL)
+ {
+ size_t tmp;
+ not_null_column_count++;
+ data_size+= (tmp=dynamic_column_value_len(values + i));
+ if (tmp == (size_t) ~0)
+ return ER_DYNCOL_DATA;
+ }
+ }
+
+ /* We can handle data up to 1fffffff = 536870911 bytes now */
+ if ((offset_size= dynamic_column_offset_bytes(data_size)) >=
+ MAX_OFFSET_LENGTH)
+ return ER_DYNCOL_LIMIT;
+
+ /* header entry is column number + offset & type */
+ header_size= not_null_column_count * (offset_size + 2);
+
+ return dynamic_new_column_store(str,
+ header_size, offset_size,
+ column_count,
+ not_null_column_count,
+ data_size,
+ column_numbers, values,
+ new_str);
+}
+
+
+/**
+ Create packed string which contains given columns
+
+ @param str String where to write the data
+ @param column_count Number of columns in the arrays
+ @param column_numbers Array of columns numbers
+ @param values Array of columns values
+
+ @return ER_DYNCOL_* return code
+*/
+
+enum enum_dyncol_func_result
+dynamic_column_create_many(DYNAMIC_COLUMN *str,
+ uint column_count,
+ uint *column_numbers,
+ DYNAMIC_COLUMN_VALUE *values)
+{
+ DBUG_ENTER("dynamic_column_create_many");
+ DBUG_RETURN(dynamic_column_create_many_internal(str, column_count,
+ column_numbers, values,
+ TRUE));
+}
+
+
+/**
+ Create packed string which contains given column
+
+ @param str String where to write the data
+ @param column_number Column number
+ @param value The columns value
+
+ @return ER_DYNCOL_* return code
+*/
+
+enum enum_dyncol_func_result
+dynamic_column_create(DYNAMIC_COLUMN *str, uint column_nr,
+ DYNAMIC_COLUMN_VALUE *value)
+{
+ DBUG_ENTER("dynamic_column_create");
+ DBUG_RETURN(dynamic_column_create_many(str, 1, &column_nr, value));
+}
+
+
+/**
+ Calculate length of data between given two header entries
+
+ @param entry Pointer to the first entry
+ @param entry_next Pointer to the last entry
+ @param header_end Pointer to the header end
+ @param offset_size Size of offset field in bytes
+ @param last_offset Size of the data segment
+
+ @return number of bytes
+*/
+
+static size_t get_length_interval(uchar *entry, uchar *entry_next,
+ uchar *header_end, size_t offset_size,
+ size_t last_offset)
+{
+ size_t offset, offset_next;
+ DYNAMIC_COLUMN_TYPE type, type_next;
+ DBUG_ASSERT(entry < entry_next);
+
+ type_and_offset_read(&type, &offset, entry, offset_size);
+ if (entry_next >= header_end)
+ return (last_offset - offset);
+ type_and_offset_read(&type_next, &offset_next, entry_next, offset_size);
+ return (offset_next - offset);
+}
+
+/*
+ Calculate length of data of one column
+
+
+ @param entry Pointer to the first entry
+ @param header_end Pointer to the header end
+ @param offset_size Size of offset field in bytes
+ @param last_offset Size of the data segment
+
+ @return number of bytes
+*/
+
+static size_t get_length(uchar *entry, uchar *header_end,
+ size_t offset_size,
+ size_t last_offset)
+{
+ return get_length_interval(entry,
+ entry + offset_size + COLUMN_NUMBER_SIZE,
+ header_end, offset_size, last_offset);
+}
+
+
+/**
+ Comparator function for references to header entries for qsort
+*/
+
+static int header_compar(const void *a, const void *b)
+{
+ uint va= uint2korr((uchar*)a), vb= uint2korr((uchar*)b);
+ return (va > vb ? 1 : (va < vb ? -1 : 0));
+}
+
+
+/**
+ Find column and fill information about it
+
+ @param type Returns type of the column
+ @param data Returns a pointer to the data
+ @param length Returns length of the data
+ @param offset_size Size of offset field in bytes
+ @param column_count Number of column in the packed string
+ @param data_end Pointer to the data end
+ @param num Number of the column we want to fetch
+ @param entry_pos NULL or place where to put reference to the entry
+
+ @return 0 ok
+ @return 1 error in data
+*/
+
+static my_bool
+find_column(DYNAMIC_COLUMN_TYPE *type, uchar **data, size_t *length,
+ uchar *header, size_t offset_size, uint column_count,
+ uchar *data_end, uint num, uchar **entry_pos)
+{
+ uchar *entry;
+ size_t offset, total_data, header_size, entry_size;
+ uchar key[2+4];
+
+ if (!entry_pos)
+ entry_pos= &entry;
+
+ calc_param(&entry_size, &header_size, offset_size, column_count);
+
+ if (header + header_size > data_end)
+ return 1;
+
+ int2store(key, num);
+ entry= bsearch(key, header, (size_t)column_count, entry_size,
+ &header_compar);
+ if (!entry)
+ {
+ /* Column not found */
+ *type= DYN_COL_NULL;
+ *entry_pos= NULL;
+ return 0;
+ }
+ type_and_offset_read(type, &offset, entry, offset_size);
+ total_data= data_end - (header + header_size);
+ if (offset > total_data)
+ return 1;
+ *data= header + header_size + offset;
+ *length= get_length(entry, header + header_size, offset_size,
+ total_data);
+ /*
+ Check that the found data is withing the ranges. This can happen if
+ we get data with wrong offsets.
+ */
+ if ((long) *length < 0 || offset + *length > total_data)
+ return 1;
+
+ *entry_pos= entry;
+ return 0;
+}
+
+
+/**
+ Read and check the header of the dynamic string
+
+ @param str Dynamic string
+
+ @retval FALSE OK
+ @retval TRUE error
+
+ Note
+ We don't check for str->length == 0 as all code that calls this
+ already have handled this case.
+*/
+
+static inline my_bool read_fixed_header(DYNAMIC_COLUMN *str,
+ size_t *offset_size,
+ uint *column_count)
+{
+ DBUG_ASSERT(str != NULL && str->length != 0);
+ if ((str->length < FIXED_HEADER_SIZE) ||
+ (str->str[0] & (~DYNCOL_FLG_KNOWN)))
+ return 1; /* Wrong header */
+ *offset_size= (str->str[0] & DYNCOL_FLG_OFFSET) + 1;
+ *column_count= uint2korr(str->str + 1);
+ return 0;
+}
+
+
+/**
+ Get dynamic column value
+
+ @param str The packed string to extract the column
+ @param column_nr Number of column to fetch
+ @param store_it_here Where to store the extracted value
+
+ @return ER_DYNCOL_* return code
+*/
+
+int dynamic_column_get(DYNAMIC_COLUMN *str, uint column_nr,
+ DYNAMIC_COLUMN_VALUE *store_it_here)
+{
+ uchar *data;
+ size_t offset_size, length;
+ uint column_count;
+ enum enum_dyncol_func_result rc= ER_DYNCOL_FORMAT;
+
+ if (str->length == 0)
+ goto null;
+
+ if (read_fixed_header(str, &offset_size, &column_count))
+ goto err;
+
+ if (column_count == 0)
+ goto null;
+
+ if (find_column(&store_it_here->type, &data, &length,
+ (uchar*)str->str + FIXED_HEADER_SIZE,
+ offset_size, column_count, (uchar*)str->str + str->length,
+ column_nr, NULL))
+ goto err;
+
+ switch (store_it_here->type) {
+ case DYN_COL_INT:
+ rc= dynamic_column_sint_read(store_it_here, data, length);
+ break;
+ case DYN_COL_UINT:
+ rc= dynamic_column_uint_read(store_it_here, data, length);
+ break;
+ case DYN_COL_DOUBLE:
+ rc= dynamic_column_double_read(store_it_here, data, length);
+ break;
+ case DYN_COL_STRING:
+ rc= dynamic_column_string_read(store_it_here, data, length);
+ break;
+ case DYN_COL_DECIMAL:
+ rc= dynamic_column_decimal_read(store_it_here, data, length);
+ break;
+ case DYN_COL_DATETIME:
+ rc= dynamic_column_date_time_read(store_it_here, data, length);
+ break;
+ case DYN_COL_DATE:
+ rc= dynamic_column_date_read(store_it_here, data, length);
+ break;
+ case DYN_COL_TIME:
+ rc= dynamic_column_time_read(store_it_here, data, length);
+ break;
+ case DYN_COL_NULL:
+ rc= ER_DYNCOL_OK;
+ break;
+ default:
+ goto err;
+ }
+ return rc;
+
+null:
+ rc= ER_DYNCOL_OK;
+err:
+ store_it_here->type= DYN_COL_NULL;
+ return rc;
+}
+
+/**
+ Delete column with given number from the packed string
+
+ @param str The packed string to delete the column
+ @param column_nr Number of column to delete
+
+ @return ER_DYNCOL_* return code
+*/
+
+int dynamic_column_delete(DYNAMIC_COLUMN *str, uint column_nr)
+{
+ uchar *data, *header_entry, *read, *write;
+ size_t offset_size, new_offset_size, length, entry_size, new_entry_size,
+ header_size, new_header_size, data_size, new_data_size,
+ deleted_entry_offset;
+ uint column_count, i;
+ DYNAMIC_COLUMN_TYPE type;
+
+ if (str->length == 0)
+ return ER_DYNCOL_OK; /* no columns */
+
+ if (read_fixed_header(str, &offset_size, &column_count))
+ return ER_DYNCOL_FORMAT;
+
+ if (column_count == 0)
+ {
+ str->length= 0;
+ return ER_DYNCOL_OK; /* no columns */
+ }
+
+ if (find_column(&type, &data, &length, (uchar*)str->str + FIXED_HEADER_SIZE,
+ offset_size, column_count, (uchar*)str->str + str->length,
+ column_nr, &header_entry))
+ return ER_DYNCOL_FORMAT;
+
+ if (type == DYN_COL_NULL)
+ return ER_DYNCOL_OK; /* no such column */
+
+ if (column_count == 1)
+ {
+ /* delete the only column; Return empty string */
+ str->length= 0;
+ return ER_DYNCOL_OK;
+ }
+
+ /* Calculate entry_size and header_size */
+ calc_param(&entry_size, &header_size, offset_size, column_count);
+ data_size= str->length - FIXED_HEADER_SIZE - header_size;
+
+ new_data_size= data_size - length;
+ if ((new_offset_size= dynamic_column_offset_bytes(new_data_size)) >=
+ MAX_OFFSET_LENGTH)
+ return ER_DYNCOL_LIMIT;
+ DBUG_ASSERT(new_offset_size <= offset_size);
+
+ calc_param(&new_entry_size, &new_header_size,
+ new_offset_size, column_count - 1);
+
+ deleted_entry_offset= ((data - (uchar*) str->str) -
+ header_size - FIXED_HEADER_SIZE);
+
+ /* rewrite header*/
+ set_fixed_header(str, new_offset_size, column_count - 1);
+ for (i= 0, write= read= (uchar *)str->str + FIXED_HEADER_SIZE;
+ i < column_count;
+ i++, read+= entry_size, write+= new_entry_size)
+ {
+ size_t offs;
+ uint nm;
+ DYNAMIC_COLUMN_TYPE tp;
+ if (read == header_entry)
+ {
+#ifndef DBUG_OFF
+ nm= uint2korr(read);
+ type_and_offset_read(&tp, &offs, read,
+ offset_size);
+ DBUG_ASSERT(nm == column_nr);
+ DBUG_ASSERT(offs == deleted_entry_offset);
+#endif
+ write-= new_entry_size; /* do not move writer */
+ continue; /* skip removed field */
+ }
+
+ nm= uint2korr(read),
+ type_and_offset_read(&tp, &offs, read,
+ offset_size);
+
+ if (offs > deleted_entry_offset)
+ offs-= length; /* data stored after removed data */
+
+ int2store(write, nm);
+ type_and_offset_store(write, new_offset_size, tp, offs);
+ }
+
+ /* move data */
+ {
+ size_t first_chunk_len= ((data - (uchar *)str->str) -
+ FIXED_HEADER_SIZE - header_size);
+ size_t second_chunk_len= new_data_size - first_chunk_len;
+ if (first_chunk_len)
+ memmove(str->str + FIXED_HEADER_SIZE + new_header_size,
+ str->str + FIXED_HEADER_SIZE + header_size,
+ first_chunk_len);
+ if (second_chunk_len)
+ memmove(str->str +
+ FIXED_HEADER_SIZE + new_header_size + first_chunk_len,
+ str->str +
+ FIXED_HEADER_SIZE + header_size + first_chunk_len + length,
+ second_chunk_len);
+ }
+
+ /* fix str length */
+ DBUG_ASSERT(str->length >=
+ FIXED_HEADER_SIZE + new_header_size + new_data_size);
+ str->length= FIXED_HEADER_SIZE + new_header_size + new_data_size;
+
+ return ER_DYNCOL_OK;
+}
+
+
+/**
+ Check existence of the column in the packed string
+
+ @param str The packed string to check the column
+ @param column_nr Number of column to check
+
+ @return ER_DYNCOL_* return code
+*/
+
+enum enum_dyncol_func_result
+dynamic_column_exists(DYNAMIC_COLUMN *str, uint column_nr)
+{
+ uchar *data;
+ size_t offset_size, length;
+ uint column_count;
+ DYNAMIC_COLUMN_TYPE type;
+
+ if (str->length == 0)
+ return ER_DYNCOL_NO; /* no columns */
+
+ if (read_fixed_header(str, &offset_size, &column_count))
+ return ER_DYNCOL_FORMAT;
+
+ if (column_count == 0)
+ return ER_DYNCOL_NO; /* no columns */
+
+ if (find_column(&type, &data, &length, (uchar*)str->str + FIXED_HEADER_SIZE,
+ offset_size, column_count, (uchar*)str->str + str->length,
+ column_nr, NULL))
+ return ER_DYNCOL_FORMAT;
+
+ return (type != DYN_COL_NULL ? ER_DYNCOL_YES : ER_DYNCOL_NO);
+}
+
+
+/**
+ List not-null columns in the packed string
+
+ @param str The packed string
+ @param array_of_uint Where to put reference on created array
+
+ @return ER_DYNCOL_* return code
+*/
+
+enum enum_dyncol_func_result
+dynamic_column_list(DYNAMIC_COLUMN *str, DYNAMIC_ARRAY *array_of_uint)
+{
+ uchar *read;
+ size_t offset_size, entry_size;
+ uint column_count, i;
+
+ bzero(array_of_uint, sizeof(*array_of_uint)); /* In case of errors */
+ if (str->length == 0)
+ return ER_DYNCOL_OK; /* no columns */
+
+ if (read_fixed_header(str, &offset_size, &column_count))
+ return ER_DYNCOL_FORMAT;
+
+ entry_size= COLUMN_NUMBER_SIZE + offset_size;
+
+ if (entry_size * column_count + FIXED_HEADER_SIZE > str->length)
+ return ER_DYNCOL_FORMAT;
+
+ if (init_dynamic_array(array_of_uint, sizeof(uint), column_count, 0))
+ return ER_DYNCOL_RESOURCE;
+
+ for (i= 0, read= (uchar *)str->str + FIXED_HEADER_SIZE;
+ i < column_count;
+ i++, read+= entry_size)
+ {
+ uint nm= uint2korr(read);
+ /* Insert can't never fail as it's pre-allocated above */
+ (void) insert_dynamic(array_of_uint, (uchar *)&nm);
+ }
+ return ER_DYNCOL_OK;
+}
+
+
+/**
+ Find the place of the column in the header or place where it should be put
+
+ @param num Number of the column
+ @param header Pointer to the header
+ @param entry_size Size of a header entry
+ @param column_count Number of columns in the packed string
+ @param entry Return pointer to the entry or next entry
+
+ @retval TRUE found
+ @retval FALSE pointer set to the next row
+*/
+
+static my_bool
+find_place(uint num, uchar *header, size_t entry_size,
+ uint column_count, uchar **entry)
+{
+ uint mid, start, end, val;
+ int flag;
+ LINT_INIT(flag); /* 100 % safe */
+
+ start= 0;
+ end= column_count -1;
+ mid= 1;
+ while (start != end)
+ {
+ uint val;
+ mid= (start + end) / 2;
+ val= uint2korr(header + mid * entry_size);
+ if ((flag= CMP_NUM(num, val)) <= 0)
+ end= mid;
+ else
+ start= mid + 1;
+ }
+ if (start != mid)
+ {
+ val= uint2korr(header + start * entry_size);
+ flag= CMP_NUM(num, val);
+ }
+ *entry= header + start * entry_size;
+ if (flag > 0)
+ *entry+= entry_size; /* Point at next bigger key */
+ return flag == 0;
+}
+
+
+/*
+ Description of plan of adding/removing/updating a packed string
+*/
+
+typedef enum {PLAN_REPLACE, PLAN_ADD, PLAN_DELETE, PLAN_NOP} PLAN_ACT;
+
+struct st_plan {
+ DYNAMIC_COLUMN_VALUE *val;
+ uint *num;
+ uchar *place;
+ size_t length;
+ int hdelta, ddelta;
+ PLAN_ACT act;
+};
+typedef struct st_plan PLAN;
+
+
+static int plan_sort(const void *a, const void *b)
+{
+ return ((PLAN *)a)->num[0] - ((PLAN *)b)->num[0];
+}
+
+#define DELTA_CHECK(S, D, C) \
+ if ((S) == 0) \
+ (S)= (D); \
+ else if (((S) > 0 && (D) < 0) || \
+ ((S) < 0 && (D) > 0)) \
+ { \
+ (C)= TRUE; \
+ break; \
+ } \
+
+
+/**
+ Update the packed string with the given columns
+
+ @param str String where to write the data
+ @param add_column_count Number of columns in the arrays
+ @param column_numbers Array of columns numbers
+ @param values Array of columns values
+
+ @return ER_DYNCOL_* return code
+*/
+
+enum enum_dyncol_func_result
+dynamic_column_update_many(DYNAMIC_COLUMN *str,
+ uint add_column_count,
+ uint *column_numbers,
+ DYNAMIC_COLUMN_VALUE *values)
+{
+ PLAN *plan;
+ uchar *header_end;
+ long data_delta= 0;
+ uint i, j, k;
+ uint new_column_count, column_count, not_null;
+ enum enum_dyncol_func_result rc;
+ int header_delta, header_delta_sign, data_delta_sign;
+ size_t offset_size, entry_size, header_size, data_size;
+ size_t new_offset_size, new_entry_size, new_header_size, new_data_size;
+ size_t max_offset;
+ my_bool copy;
+
+ if (add_column_count == 0)
+ return ER_DYNCOL_OK;
+
+ /*
+ Get columns in column order. As the data in 'str' is already
+ in column order this allows to replace all columns in one loop.
+ */
+
+ if (!(plan= my_malloc(sizeof(PLAN) * (add_column_count + 1), MYF(0))))
+ return ER_DYNCOL_RESOURCE;
+
+ not_null= add_column_count;
+ for (i= 0; i < add_column_count; i++)
+ {
+ if (column_numbers[i] > UINT_MAX16)
+ {
+ rc= ER_DYNCOL_DATA;
+ goto end;
+ }
+
+ plan[i].val= values + i;
+ plan[i].num= column_numbers + i;
+ if (values[i].type == DYN_COL_NULL)
+ not_null--;
+
+ }
+
+ if (str->length == 0)
+ {
+ /*
+ Just add new columns. If there was no columns to add we return
+ an empty string.
+ */
+ goto create_new_string;
+ }
+
+ /* Check that header is ok */
+ if (read_fixed_header(str, &offset_size, &column_count))
+ {
+ rc= ER_DYNCOL_FORMAT;
+ goto end;
+ }
+ if (column_count == 0)
+ goto create_new_string;
+
+ qsort(plan, (size_t)add_column_count, sizeof(PLAN), &plan_sort);
+
+ new_column_count= column_count;
+ calc_param(&entry_size, &header_size, offset_size, column_count);
+ max_offset= str->length - (FIXED_HEADER_SIZE + header_size);
+ header_end= (uchar*) str->str + FIXED_HEADER_SIZE + header_size;
+
+ if (header_size + FIXED_HEADER_SIZE > str->length)
+ {
+ rc= ER_DYNCOL_FORMAT;
+ goto end;
+ }
+
+ /*
+ Calculate how many columns and data is added/deleted and make a 'plan'
+ for each of them.
+ */
+ header_delta= 0;
+ for (i= 0; i < add_column_count; i++)
+ {
+ uchar *entry;
+
+ /*
+ For now we don't allow creating two columns with the same number
+ at the time of create. This can be fixed later to just use the later
+ by comparing the pointers.
+ */
+ if (i < add_column_count - 1 && plan[i].num[0] == plan[i + 1].num[0])
+ {
+ rc= ER_DYNCOL_DATA;
+ goto end;
+ }
+
+ /* Set common variables for all plans */
+ plan[i].ddelta= data_delta;
+ /* get header delta in entries */
+ plan[i].hdelta= header_delta;
+ plan[i].length= 0; /* Length if NULL */
+
+ if (find_place(plan[i].num[0],
+ (uchar *)str->str + FIXED_HEADER_SIZE,
+ entry_size, column_count, &entry))
+ {
+ size_t entry_data_size;
+
+ /* Data existed; We have to replace or delete it */
+
+ entry_data_size= get_length(entry, header_end,
+ offset_size, max_offset);
+ if ((long) entry_data_size < 0)
+ {
+ rc= ER_DYNCOL_FORMAT;
+ goto end;
+ }
+
+ if (plan[i].val->type == DYN_COL_NULL)
+ {
+ /* Inserting a NULL means delete the old data */
+
+ plan[i].act= PLAN_DELETE; /* Remove old value */
+ header_delta--; /* One row less in header */
+ data_delta-= entry_data_size; /* Less data to store */
+ }
+ else
+ {
+ /* Replace the value */
+
+ plan[i].act= PLAN_REPLACE;
+ /* get data delta in bytes */
+ if ((plan[i].length= dynamic_column_value_len(plan[i].val)) ==
+ (size_t) ~0)
+ {
+ rc= ER_DYNCOL_DATA;
+ goto end;
+ }
+ data_delta+= plan[i].length - entry_data_size;
+ }
+ }
+ else
+ {
+ /* Data did not exists. Add if it it's not NULL */
+
+ if (plan[i].val->type == DYN_COL_NULL)
+ {
+ plan[i].act= PLAN_NOP; /* Mark entry to be skiped */
+ }
+ else
+ {
+ /* Add new value */
+
+ plan[i].act= PLAN_ADD;
+ header_delta++; /* One more row in header */
+ /* get data delta in bytes */
+ if ((plan[i].length= dynamic_column_value_len(plan[i].val)) ==
+ (size_t) ~0)
+ {
+ rc= ER_DYNCOL_DATA;
+ goto end;
+ }
+ data_delta+= plan[i].length;
+ }
+ }
+ plan[i].place= entry;
+ }
+ plan[add_column_count].hdelta= header_delta;
+ plan[add_column_count].ddelta= data_delta;
+ new_column_count= column_count + header_delta;
+
+ /*
+ Check if it is only "increasing" or only "decreasing" plan for (header
+ and data separately).
+ */
+ data_size= str->length - header_size - FIXED_HEADER_SIZE;
+ new_data_size= data_size + data_delta;
+ if ((new_offset_size= dynamic_column_offset_bytes(new_data_size)) >=
+ MAX_OFFSET_LENGTH)
+ {
+ rc= ER_DYNCOL_LIMIT;
+ goto end;
+ }
+
+ /* if (new_offset_size != offset_size) then we have to rewrite header */
+ header_delta_sign= new_offset_size - offset_size;
+ data_delta_sign= 0;
+ copy= FALSE;
+ for (i= 0; i < add_column_count; i++)
+ {
+ /* This is the check for increasing/decreasing */
+ DELTA_CHECK(header_delta_sign, plan[i].hdelta, copy);
+ DELTA_CHECK(data_delta_sign, plan[i].ddelta, copy);
+ }
+
+ calc_param(&new_entry_size, &new_header_size,
+ new_offset_size, new_column_count);
+
+ /*
+ The following code always make a copy. In future we can do a more
+ optimized version when data is only increasing / decreasing.
+ */
+
+ /*if (copy) */
+ {
+ DYNAMIC_COLUMN tmp;
+ uchar *header_base= (uchar *)str->str + FIXED_HEADER_SIZE,
+ *write;
+ if (dynamic_column_init_str(&tmp,
+ (FIXED_HEADER_SIZE + new_header_size +
+ new_data_size + DYNCOL_SYZERESERVE)))
+ {
+ rc= ER_DYNCOL_RESOURCE;
+ goto end;
+ }
+ write= (uchar *)tmp.str + FIXED_HEADER_SIZE;
+ /* Adjust tmp to contain whole the future header */
+ tmp.length= FIXED_HEADER_SIZE + new_header_size;
+ set_fixed_header(&tmp, new_offset_size, new_column_count);
+ data_delta= 0;
+
+ /*
+ Copy data to the new string
+ i= index in array of changes
+ j= index in packed string header index
+ */
+
+ for (i= 0, j= 0; i < add_column_count || j < column_count; i++)
+ {
+ size_t first_offset;
+ uint start= j, end;
+ LINT_INIT(first_offset);
+
+ /*
+ Search in i and j for the next column to add from i and where to
+ add.
+ */
+
+ while (i < add_column_count && plan[i].act == PLAN_NOP)
+ i++; /* skip NOP */
+ if (i == add_column_count)
+ j= end= column_count;
+ else
+ {
+ /*
+ old data portion. We don't need to check that j < column_count
+ as plan[i].place is guaranteed to have a pointer inside the
+ data.
+ */
+ while (header_base + j * entry_size < plan[i].place)
+ j++;
+ end= j;
+ if ((plan[i].act == PLAN_REPLACE || plan[i].act == PLAN_DELETE))
+ j++; /* data at 'j' will be removed */
+ }
+
+ if (plan[i].ddelta == 0 && offset_size == new_offset_size)
+ {
+ uchar *read= header_base + start * entry_size;
+ DYNAMIC_COLUMN_TYPE tp;
+ /*
+ It's safe to copy the header unchanged. This is usually the
+ case for the first header block before any changed data.
+ */
+ if (start < end) /* Avoid memcpy with 0 */
+ {
+ size_t length= entry_size * (end - start);
+ memcpy(write, read, length);
+ write+= length;
+ }
+ /* Read first_offset */
+ type_and_offset_read(&tp, &first_offset, read, offset_size);
+ }
+ else
+ {
+ /*
+ Adjust all headers since last loop.
+ We have to do this as the offset for data has moved
+ */
+ for (k= start; k < end; k++)
+ {
+ uchar *read= header_base + k * entry_size;
+ size_t offs;
+ uint nm;
+ DYNAMIC_COLUMN_TYPE tp;
+
+ nm= uint2korr(read); /* Column nummber */
+ type_and_offset_read(&tp, &offs, read, offset_size);
+ if (k == start)
+ first_offset= offs;
+ else if (offs < first_offset)
+ {
+ dynamic_column_column_free(&tmp);
+ rc= ER_DYNCOL_FORMAT;
+ goto end;
+ }
+
+ offs+= plan[i].ddelta;
+ int2store(write, nm);
+ /* write rest of data at write + COLUMN_NUMBER_SIZE */
+ type_and_offset_store(write, new_offset_size, tp, offs);
+ write+= new_entry_size;
+ }
+ }
+
+ /* copy first the data that was not replaced in original packed data */
+ if (start < end)
+ {
+ /* Add old data last in 'tmp' */
+ size_t data_size=
+ get_length_interval(header_base + start * entry_size,
+ header_base + end * entry_size,
+ header_end, offset_size, max_offset);
+ if ((long) data_size < 0 ||
+ data_size > max_offset - first_offset)
+ {
+ dynamic_column_column_free(&tmp);
+ rc= ER_DYNCOL_FORMAT;
+ goto end;
+ }
+
+ memcpy(tmp.str + tmp.length, (char *)header_end + first_offset,
+ data_size);
+ tmp.length+= data_size;
+ }
+
+ /* new data adding */
+ if (i < add_column_count)
+ {
+ if( plan[i].act == PLAN_ADD || plan[i].act == PLAN_REPLACE)
+ {
+ int2store(write, plan[i].num[0]);
+ type_and_offset_store(write, new_offset_size,
+ plan[i].val[0].type,
+ tmp.length -
+ (FIXED_HEADER_SIZE + new_header_size));
+ write+= new_entry_size;
+ data_store(&tmp, plan[i].val); /* Append new data */
+ }
+ data_delta= plan[i].ddelta;
+ }
+ }
+ dynamic_column_column_free(str);
+ *str= tmp;
+ }
+
+ rc= ER_DYNCOL_OK;
+
+end:
+ my_free(plan);
+ return rc;
+
+create_new_string:
+ /* There is no columns from before, so let's just add the new ones */
+ rc= ER_DYNCOL_OK;
+ if (not_null != 0)
+ rc= dynamic_column_create_many_internal(str, add_column_count,
+ column_numbers, values,
+ str->str == NULL);
+ goto end;
+}
+
+
+/**
+ Update the packed string with the given column
+
+ @param str String where to write the data
+ @param column_number Array of columns number
+ @param values Array of columns values
+
+ @return ER_DYNCOL_* return code
+*/
+
+
+int dynamic_column_update(DYNAMIC_COLUMN *str, uint column_nr,
+ DYNAMIC_COLUMN_VALUE *value)
+{
+ return dynamic_column_update_many(str, 1, &column_nr, value);
+}
diff --git a/mysys/mf_getdate.c b/mysys/mf_getdate.c
index 9475bebd107..70278e64003 100644
--- a/mysys/mf_getdate.c
+++ b/mysys/mf_getdate.c
@@ -42,7 +42,7 @@ void get_date(register char * to, int flag, time_t date)
struct tm tm_tmp;
#endif
- skr=date ? (time_t) date : my_time(0);
+ skr=date ? date : (time_t) my_time(0);
#if defined(HAVE_LOCALTIME_R) && defined(_REENTRANT)
if (flag & GETDATE_GMT)
gmtime_r(&skr,&tm_tmp);
diff --git a/mysys/mf_iocache.c b/mysys/mf_iocache.c
index 82098a7c9cc..cde11f3cae5 100644
--- a/mysys/mf_iocache.c
+++ b/mysys/mf_iocache.c
@@ -1683,9 +1683,6 @@ int my_block_write(register IO_CACHE *info, const uchar *Buffer, size_t Count,
Buffer+=length;
pos+= length;
Count-= length;
-#ifndef HAVE_PREAD
- info->seek_not_done=1;
-#endif
}
/* Check if we want to write inside the used part of the buffer.*/
diff --git a/mysys/my_bitmap.c b/mysys/my_bitmap.c
index 762a89cd921..8f86e5832f6 100644
--- a/mysys/my_bitmap.c
+++ b/mysys/my_bitmap.c
@@ -1,4 +1,6 @@
-/* Copyright (C) 2000 MySQL AB, 2008-2009 Sun Microsystems, Inc
+/* Copyright (C) 2000 MySQL AB
+ Copyright (c) 2000, 2011, Oracle and/or its affiliates.
+ Copyright (C) 2009- 2011 Monty Program Ab
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -258,7 +260,10 @@ void bitmap_set_prefix(MY_BITMAP *map, uint prefix_size)
memset(m, 0xff, prefix_bytes);
m+= prefix_bytes;
if ((prefix_bits= prefix_size & 7))
+ {
*m++= (1 << prefix_bits)-1;
+ prefix_bytes++;
+ }
if ((d= no_bytes_in_map(map)-prefix_bytes))
bzero(m, d);
}
@@ -293,6 +298,7 @@ my_bool bitmap_is_prefix(const MY_BITMAP *map, uint prefix_size)
return ((*m & last_byte_mask(map->n_bits)) == 0);
}
+
my_bool bitmap_is_set_all(const MY_BITMAP *map)
{
my_bitmap_map *data_ptr= map->bitmap;
@@ -307,8 +313,8 @@ my_bool bitmap_is_set_all(const MY_BITMAP *map)
my_bool bitmap_is_clear_all(const MY_BITMAP *map)
{
my_bitmap_map *data_ptr= map->bitmap;
- my_bitmap_map *end;
- end= map->last_word_ptr;
+ my_bitmap_map *end= map->last_word_ptr;
+
for (; data_ptr < end; data_ptr++)
if (*data_ptr)
return FALSE;
@@ -493,6 +499,7 @@ void bitmap_copy(MY_BITMAP *map, const MY_BITMAP *map2)
DBUG_ASSERT(map->bitmap && map2->bitmap &&
map->n_bits==map2->n_bits);
end= map->last_word_ptr;
+
while (to <= end)
*to++ = *from++;
}
@@ -587,375 +594,3 @@ void bitmap_lock_clear_bit(MY_BITMAP *map, uint bitmap_bit)
bitmap_unlock(map);
}
-#ifdef MAIN
-
-uint get_rand_bit(uint bitsize)
-{
- return (rand() % bitsize);
-}
-
-my_bool test_set_get_clear_bit(MY_BITMAP *map, uint bitsize)
-{
- uint i, test_bit;
- uint no_loops= bitsize > 128 ? 128 : bitsize;
- for (i=0; i < no_loops; i++)
- {
- test_bit= get_rand_bit(bitsize);
- bitmap_set_bit(map, test_bit);
- if (!bitmap_is_set(map, test_bit))
- goto error1;
- bitmap_clear_bit(map, test_bit);
- if (bitmap_is_set(map, test_bit))
- goto error2;
- }
- return FALSE;
-error1:
- printf("Error in set bit, bit %u, bitsize = %u", test_bit, bitsize);
- return TRUE;
-error2:
- printf("Error in clear bit, bit %u, bitsize = %u", test_bit, bitsize);
- return TRUE;
-}
-
-my_bool test_flip_bit(MY_BITMAP *map, uint bitsize)
-{
- uint i, test_bit;
- uint no_loops= bitsize > 128 ? 128 : bitsize;
- for (i=0; i < no_loops; i++)
- {
- test_bit= get_rand_bit(bitsize);
- bitmap_flip_bit(map, test_bit);
- if (!bitmap_is_set(map, test_bit))
- goto error1;
- bitmap_flip_bit(map, test_bit);
- if (bitmap_is_set(map, test_bit))
- goto error2;
- }
- return FALSE;
-error1:
- printf("Error in flip bit 1, bit %u, bitsize = %u", test_bit, bitsize);
- return TRUE;
-error2:
- printf("Error in flip bit 2, bit %u, bitsize = %u", test_bit, bitsize);
- return TRUE;
-}
-
-my_bool test_operators(MY_BITMAP *map __attribute__((unused)),
- uint bitsize __attribute__((unused)))
-{
- return FALSE;
-}
-
-my_bool test_get_all_bits(MY_BITMAP *map, uint bitsize)
-{
- uint i;
- bitmap_set_all(map);
- if (!bitmap_is_set_all(map))
- goto error1;
- if (!bitmap_is_prefix(map, bitsize))
- goto error5;
- bitmap_clear_all(map);
- if (!bitmap_is_clear_all(map))
- goto error2;
- if (!bitmap_is_prefix(map, 0))
- goto error6;
- for (i=0; i<bitsize;i++)
- bitmap_set_bit(map, i);
- if (!bitmap_is_set_all(map))
- goto error3;
- for (i=0; i<bitsize;i++)
- bitmap_clear_bit(map, i);
- if (!bitmap_is_clear_all(map))
- goto error4;
- return FALSE;
-error1:
- printf("Error in set_all, bitsize = %u", bitsize);
- return TRUE;
-error2:
- printf("Error in clear_all, bitsize = %u", bitsize);
- return TRUE;
-error3:
- printf("Error in bitmap_is_set_all, bitsize = %u", bitsize);
- return TRUE;
-error4:
- printf("Error in bitmap_is_clear_all, bitsize = %u", bitsize);
- return TRUE;
-error5:
- printf("Error in set_all through set_prefix, bitsize = %u", bitsize);
- return TRUE;
-error6:
- printf("Error in clear_all through set_prefix, bitsize = %u", bitsize);
- return TRUE;
-}
-
-my_bool test_compare_operators(MY_BITMAP *map, uint bitsize)
-{
- uint i, j, test_bit1, test_bit2, test_bit3,test_bit4;
- uint no_loops= bitsize > 128 ? 128 : bitsize;
- MY_BITMAP map2_obj, map3_obj;
- MY_BITMAP *map2= &map2_obj, *map3= &map3_obj;
- my_bitmap_map map2buf[1024];
- my_bitmap_map map3buf[1024];
- bitmap_init(&map2_obj, map2buf, bitsize, FALSE);
- bitmap_init(&map3_obj, map3buf, bitsize, FALSE);
- bitmap_clear_all(map2);
- bitmap_clear_all(map3);
- for (i=0; i < no_loops; i++)
- {
- test_bit1=get_rand_bit(bitsize);
- bitmap_set_prefix(map, test_bit1);
- test_bit2=get_rand_bit(bitsize);
- bitmap_set_prefix(map2, test_bit2);
- bitmap_intersect(map, map2);
- test_bit3= test_bit2 < test_bit1 ? test_bit2 : test_bit1;
- bitmap_set_prefix(map3, test_bit3);
- if (!bitmap_cmp(map, map3))
- goto error1;
- bitmap_clear_all(map);
- bitmap_clear_all(map2);
- bitmap_clear_all(map3);
- test_bit1=get_rand_bit(bitsize);
- test_bit2=get_rand_bit(bitsize);
- test_bit3=get_rand_bit(bitsize);
- bitmap_set_prefix(map, test_bit1);
- bitmap_set_prefix(map2, test_bit2);
- test_bit3= test_bit2 > test_bit1 ? test_bit2 : test_bit1;
- bitmap_set_prefix(map3, test_bit3);
- bitmap_union(map, map2);
- if (!bitmap_cmp(map, map3))
- goto error2;
- bitmap_clear_all(map);
- bitmap_clear_all(map2);
- bitmap_clear_all(map3);
- test_bit1=get_rand_bit(bitsize);
- test_bit2=get_rand_bit(bitsize);
- test_bit3=get_rand_bit(bitsize);
- bitmap_set_prefix(map, test_bit1);
- bitmap_set_prefix(map2, test_bit2);
- bitmap_xor(map, map2);
- test_bit3= test_bit2 > test_bit1 ? test_bit2 : test_bit1;
- test_bit4= test_bit2 < test_bit1 ? test_bit2 : test_bit1;
- bitmap_set_prefix(map3, test_bit3);
- for (j=0; j < test_bit4; j++)
- bitmap_clear_bit(map3, j);
- if (!bitmap_cmp(map, map3))
- goto error3;
- bitmap_clear_all(map);
- bitmap_clear_all(map2);
- bitmap_clear_all(map3);
- test_bit1=get_rand_bit(bitsize);
- test_bit2=get_rand_bit(bitsize);
- test_bit3=get_rand_bit(bitsize);
- bitmap_set_prefix(map, test_bit1);
- bitmap_set_prefix(map2, test_bit2);
- bitmap_subtract(map, map2);
- if (test_bit2 < test_bit1)
- {
- bitmap_set_prefix(map3, test_bit1);
- for (j=0; j < test_bit2; j++)
- bitmap_clear_bit(map3, j);
- }
- if (!bitmap_cmp(map, map3))
- goto error4;
- bitmap_clear_all(map);
- bitmap_clear_all(map2);
- bitmap_clear_all(map3);
- test_bit1=get_rand_bit(bitsize);
- bitmap_set_prefix(map, test_bit1);
- bitmap_invert(map);
- bitmap_set_all(map3);
- for (j=0; j < test_bit1; j++)
- bitmap_clear_bit(map3, j);
- if (!bitmap_cmp(map, map3))
- goto error5;
- bitmap_clear_all(map);
- bitmap_clear_all(map3);
- }
- return FALSE;
-error1:
- printf("intersect error bitsize=%u,size1=%u,size2=%u", bitsize,
- test_bit1,test_bit2);
- return TRUE;
-error2:
- printf("union error bitsize=%u,size1=%u,size2=%u", bitsize,
- test_bit1,test_bit2);
- return TRUE;
-error3:
- printf("xor error bitsize=%u,size1=%u,size2=%u", bitsize,
- test_bit1,test_bit2);
- return TRUE;
-error4:
- printf("subtract error bitsize=%u,size1=%u,size2=%u", bitsize,
- test_bit1,test_bit2);
- return TRUE;
-error5:
- printf("invert error bitsize=%u,size=%u", bitsize,
- test_bit1);
- return TRUE;
-}
-
-my_bool test_count_bits_set(MY_BITMAP *map, uint bitsize)
-{
- uint i, bit_count=0, test_bit;
- uint no_loops= bitsize > 128 ? 128 : bitsize;
- for (i=0; i < no_loops; i++)
- {
- test_bit=get_rand_bit(bitsize);
- if (!bitmap_is_set(map, test_bit))
- {
- bitmap_set_bit(map, test_bit);
- bit_count++;
- }
- }
- if (bit_count==0 && bitsize > 0)
- goto error1;
- if (bitmap_bits_set(map) != bit_count)
- goto error2;
- return FALSE;
-error1:
- printf("No bits set bitsize = %u", bitsize);
- return TRUE;
-error2:
- printf("Wrong count of bits set, bitsize = %u", bitsize);
- return TRUE;
-}
-
-my_bool test_get_first_bit(MY_BITMAP *map, uint bitsize)
-{
- uint i, test_bit;
- uint no_loops= bitsize > 128 ? 128 : bitsize;
- for (i=0; i < no_loops; i++)
- {
- test_bit=get_rand_bit(bitsize);
- bitmap_set_bit(map, test_bit);
- if (bitmap_get_first_set(map) != test_bit)
- goto error1;
- bitmap_set_all(map);
- bitmap_clear_bit(map, test_bit);
- if (bitmap_get_first(map) != test_bit)
- goto error2;
- bitmap_clear_all(map);
- }
- return FALSE;
-error1:
- printf("get_first_set error bitsize=%u,prefix_size=%u",bitsize,test_bit);
- return TRUE;
-error2:
- printf("get_first error bitsize= %u, prefix_size= %u",bitsize,test_bit);
- return TRUE;
-}
-
-my_bool test_get_next_bit(MY_BITMAP *map, uint bitsize)
-{
- uint i, j, test_bit;
- uint no_loops= bitsize > 128 ? 128 : bitsize;
- for (i=0; i < no_loops; i++)
- {
- test_bit=get_rand_bit(bitsize);
- for (j=0; j < test_bit; j++)
- bitmap_set_next(map);
- if (!bitmap_is_prefix(map, test_bit))
- goto error1;
- bitmap_clear_all(map);
- }
- return FALSE;
-error1:
- printf("get_next error bitsize= %u, prefix_size= %u", bitsize,test_bit);
- return TRUE;
-}
-
-my_bool test_prefix(MY_BITMAP *map, uint bitsize)
-{
- uint i, j, test_bit;
- uint no_loops= bitsize > 128 ? 128 : bitsize;
- for (i=0; i < no_loops; i++)
- {
- test_bit=get_rand_bit(bitsize);
- bitmap_set_prefix(map, test_bit);
- if (!bitmap_is_prefix(map, test_bit))
- goto error1;
- bitmap_clear_all(map);
- for (j=0; j < test_bit; j++)
- bitmap_set_bit(map, j);
- if (!bitmap_is_prefix(map, test_bit))
- goto error2;
- bitmap_set_all(map);
- for (j=bitsize - 1; ~(j-test_bit); j--)
- bitmap_clear_bit(map, j);
- if (!bitmap_is_prefix(map, test_bit))
- goto error3;
- bitmap_clear_all(map);
- }
- return FALSE;
-error1:
- printf("prefix1 error bitsize = %u, prefix_size = %u", bitsize,test_bit);
- return TRUE;
-error2:
- printf("prefix2 error bitsize = %u, prefix_size = %u", bitsize,test_bit);
- return TRUE;
-error3:
- printf("prefix3 error bitsize = %u, prefix_size = %u", bitsize,test_bit);
- return TRUE;
-}
-
-
-my_bool do_test(uint bitsize)
-{
- MY_BITMAP map;
- my_bitmap_map buf[1024];
- if (bitmap_init(&map, buf, bitsize, FALSE))
- {
- printf("init error for bitsize %d", bitsize);
- goto error;
- }
- if (test_set_get_clear_bit(&map,bitsize))
- goto error;
- bitmap_clear_all(&map);
- if (test_flip_bit(&map,bitsize))
- goto error;
- bitmap_clear_all(&map);
- if (test_operators(&map,bitsize))
- goto error;
- bitmap_clear_all(&map);
- if (test_get_all_bits(&map, bitsize))
- goto error;
- bitmap_clear_all(&map);
- if (test_compare_operators(&map,bitsize))
- goto error;
- bitmap_clear_all(&map);
- if (test_count_bits_set(&map,bitsize))
- goto error;
- bitmap_clear_all(&map);
- if (test_get_first_bit(&map,bitsize))
- goto error;
- bitmap_clear_all(&map);
- if (test_get_next_bit(&map,bitsize))
- goto error;
- if (test_prefix(&map,bitsize))
- goto error;
- return FALSE;
-error:
- printf("\n");
- return TRUE;
-}
-
-int main()
-{
- int i;
- for (i= 1; i < 4096; i++)
- {
- printf("Start test for bitsize=%u\n",i);
- if (do_test(i))
- return -1;
- }
- printf("OK\n");
- return 0;
-}
-
-/*
- In directory mysys:
- make test_bitmap
- will build the bitmap tests and ./test_bitmap will execute it
-*/
-
-#endif
diff --git a/mysys/my_compare.c b/mysys/my_compare.c
index 4629a3bae18..9e192e52fb7 100644
--- a/mysys/my_compare.c
+++ b/mysys/my_compare.c
@@ -1,4 +1,5 @@
-/* Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
+/* Copyright (c) 2011, Oracle and/or its affiliates.
+ Copyright (C) 2009-2011 Monty Program Ab
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
diff --git a/mysys/my_fopen.c b/mysys/my_fopen.c
index 9bc740c80fd..54469d2c05a 100644
--- a/mysys/my_fopen.c
+++ b/mysys/my_fopen.c
@@ -1,4 +1,5 @@
-/* Copyright (c) 2000, 2011, Oracle and/or its affiliates. All rights reserved.
+/* Copyright (c) 2000, 2011, Oracle and/or its affiliates.
+ Copyright (c) 1985-2011 Monty Program Ab
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
diff --git a/mysys/my_getncpus.c b/mysys/my_getncpus.c
index 5be961e3bc9..a7631e15966 100644
--- a/mysys/my_getncpus.c
+++ b/mysys/my_getncpus.c
@@ -41,7 +41,7 @@ int my_getncpus()
ncpus= sysinfo.dwNumberOfProcessors;
#else
-/* unknown so play safe: assume SMP and forbid uniprocessor build */
+ /* unknown so play safe: assume SMP and forbid uniprocessor build */
ncpus= 2;
#endif
}
diff --git a/mysys/my_getsystime.c b/mysys/my_getsystime.c
index 60cd06b3968..bc21b07e24d 100644
--- a/mysys/my_getsystime.c
+++ b/mysys/my_getsystime.c
@@ -1,4 +1,5 @@
-/* Copyright (C) 2004 MySQL AB, 2008-2009 Sun Microsystems, Inc
+/* Copyright (c) 2004, 2011, Oracle and/or its affiliates.
+ Copyright (c) 2009-2011 Monty Program Ab
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -13,213 +14,96 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
-/* get time since epoc in 100 nanosec units */
-/* thus to get the current time we should use the system function
- with the highest possible resolution */
-
-/*
- TODO: in functions my_micro_time() and my_micro_time_and_time() there
- exists some common code that should be merged into a function.
-*/
#include "mysys_priv.h"
#include "my_static.h"
+#ifdef __WIN__
+#define OFFSET_TO_EPOC 116444736000000000LL
+static ulonglong query_performance_frequency;
+#endif
#ifdef HAVE_LINUX_UNISTD_H
#include <linux/unistd.h>
#endif
-ulonglong my_getsystime()
+/*
+ return number of nanoseconds since unspecified (but always the same)
+ point in the past
+
+ NOTE:
+ Thus to get the current time we should use the system function
+ with the highest possible resolution
+
+ The value is not anchored to any specific point in time (e.g. epoch) nor
+ is it subject to resetting or drifting by way of adjtime() or settimeofday(),
+ and thus it is *NOT* appropriate for getting the current timestamp. It can be
+ used for calculating time intervals, though.
+*/
+
+ulonglong my_interval_timer()
{
#ifdef HAVE_CLOCK_GETTIME
struct timespec tp;
- clock_gettime(CLOCK_REALTIME, &tp);
- return (ulonglong)tp.tv_sec*10000000+(ulonglong)tp.tv_nsec/100;
+ clock_gettime(CLOCK_MONOTONIC, &tp);
+ return tp.tv_sec*1000000000ULL+tp.tv_nsec;
+#elif defined(HAVE_GETHRTIME)
+ return gethrtime();
#elif defined(__WIN__)
LARGE_INTEGER t_cnt;
if (query_performance_frequency)
{
QueryPerformanceCounter(&t_cnt);
- return ((t_cnt.QuadPart / query_performance_frequency * 10000000) +
- ((t_cnt.QuadPart % query_performance_frequency) * 10000000 /
- query_performance_frequency) + query_performance_offset);
+ return (t_cnt.QuadPart / query_performance_frequency * 1000000000ULL) +
+ ((t_cnt.QuadPart % query_performance_frequency) * 1000000000ULL /
+ query_performance_frequency);
+ }
+ else
+ {
+ ulonglong newtime;
+ GetSystemTimeAsFileTime((FILETIME*)&newtime);
+ return newtime*100ULL;
}
- return 0;
#else
/* TODO: check for other possibilities for hi-res timestamping */
struct timeval tv;
gettimeofday(&tv,NULL);
- return (ulonglong)tv.tv_sec*10000000+(ulonglong)tv.tv_usec*10;
-#endif
-}
-
-
-/*
- Return current time
-
- SYNOPSIS
- my_time()
- flags If MY_WME is set, write error if time call fails
-
-*/
-
-time_t my_time(myf flags __attribute__((unused)))
-{
- time_t t;
-#ifdef HAVE_GETHRTIME
- (void) my_micro_time_and_time(&t);
- return t;
-#else
- /* The following loop is here beacuse time() may fail on some systems */
- while ((t= time(0)) == (time_t) -1)
- {
- if (flags & MY_WME)
- fprintf(stderr, "%s: Warning: time() call failed\n", my_progname);
- }
- return t;
+ return tv.tv_sec*1000000000ULL+tv.tv_usec*1000ULL;
#endif
}
-/*
- Return time in micro seconds
-
- SYNOPSIS
- my_micro_time()
-
- NOTES
- This function is to be used to measure performance in micro seconds.
- As it's not defined whats the start time for the clock, this function
- us only useful to measure time between two moments.
-
- For windows platforms we need the frequency value of the CUP. This is
- initalized in my_init.c through QueryPerformanceFrequency().
-
- If Windows platform doesn't support QueryPerformanceFrequency() we will
- obtain the time via GetClockCount, which only supports milliseconds.
+/* Return current time in HRTIME_RESOLUTION (microseconds) since epoch */
- RETURN
- Value in microseconds from some undefined point in time
-*/
-
-ulonglong my_micro_time()
+my_hrtime_t my_hrtime()
{
+ my_hrtime_t hrtime;
#if defined(__WIN__)
ulonglong newtime;
GetSystemTimeAsFileTime((FILETIME*)&newtime);
- return (newtime/10);
-#elif defined(HAVE_GETHRTIME)
- return gethrtime()/1000;
-#else
- ulonglong newtime;
- struct timeval t;
- /*
- The following loop is here because gettimeofday may fail on some systems
- */
- while (gettimeofday(&t, NULL) != 0)
- {}
- newtime= (ulonglong)t.tv_sec * 1000000 + t.tv_usec;
- return newtime;
-#endif /* defined(__WIN__) */
-}
-
-
-/*
- Return time in seconds and timer in microseconds (not different start!)
-
- SYNOPSIS
- my_micro_time_and_time()
- time_arg Will be set to seconds since epoch (00:00:00 UTC,
- January 1, 1970)
-
- NOTES
- This function is to be useful when we need both the time and microtime.
- For example in MySQL this is used to get the query time start of a query
- and to measure the time of a query (for the slow query log)
-
- IMPLEMENTATION
- Value of time is as in time() call.
- Value of microtime is same as my_micro_time(), which may be totally
- unrealated to time()
-
- RETURN
- Value in microseconds from some undefined point in time
-*/
-
-#define DELTA_FOR_SECONDS 500000000LL /* Half a second */
-
-/* Difference between GetSystemTimeAsFileTime() and now() */
-#define OFFSET_TO_EPOCH 116444736000000000ULL
-
-ulonglong my_micro_time_and_time(time_t *time_arg)
-{
-#if defined(__WIN__)
- ulonglong newtime;
- GetSystemTimeAsFileTime((FILETIME*)&newtime);
- *time_arg= (time_t) ((newtime - OFFSET_TO_EPOCH) / 10000000);
- return (newtime/10);
-#elif defined(HAVE_GETHRTIME)
- /*
- Solaris has a very slow time() call. We optimize this by using the very
- fast gethrtime() call and only calling time() every 1/2 second
- */
- static hrtime_t prev_gethrtime= 0;
- static time_t cur_time= 0;
- hrtime_t cur_gethrtime;
-
- mysql_mutex_lock(&THR_LOCK_time);
- cur_gethrtime= gethrtime();
- if ((cur_gethrtime - prev_gethrtime) > DELTA_FOR_SECONDS)
- {
- cur_time= time(0);
- prev_gethrtime= cur_gethrtime;
- }
- *time_arg= cur_time;
- mysql_mutex_unlock(&THR_LOCK_time);
- return cur_gethrtime/1000;
+ newtime -= OFFSET_TO_EPOC;
+ hrtime.val= newtime/10;
+#elif defined(HAVE_CLOCK_GETTIME)
+ struct timespec tp;
+ clock_gettime(CLOCK_REALTIME, &tp);
+ hrtime.val= tp.tv_sec*1000000ULL+tp.tv_nsec/1000ULL;
#else
- ulonglong newtime;
struct timeval t;
- /*
- The following loop is here because gettimeofday may fail on some systems
- */
- while (gettimeofday(&t, NULL) != 0)
- {}
- *time_arg= t.tv_sec;
- newtime= (ulonglong)t.tv_sec * 1000000 + t.tv_usec;
- return newtime;
-#endif /* defined(__WIN__) */
+ /* The following loop is here because gettimeofday may fail */
+ while (gettimeofday(&t, NULL) != 0) {}
+ hrtime.val= t.tv_sec*1000000ULL + t.tv_usec;
+#endif
+ return hrtime;
}
-/*
- Returns current time
-
- SYNOPSIS
- my_time_possible_from_micro()
- microtime Value from very recent my_micro_time()
-
- NOTES
- This function returns the current time. The microtime argument is only used
- if my_micro_time() uses a function that can safely be converted to the
- current time.
-
- RETURN
- current time
-*/
-
-time_t my_time_possible_from_micro(ulonglong microtime __attribute__((unused)))
+void my_time_init()
{
-#if defined(__WIN__)
- time_t t;
- while ((t= time(0)) == (time_t) -1)
- {}
- return t;
-#elif defined(HAVE_GETHRTIME)
- return my_time(0); /* Cached time */
-#else
- return (time_t) (microtime / 1000000);
-#endif /* defined(__WIN__) */
+#ifdef __WIN__
+ compile_time_assert(sizeof(LARGE_INTEGER) ==
+ sizeof(query_performance_frequency));
+ if (QueryPerformanceFrequency((LARGE_INTEGER *)&query_performance_frequency) == 0)
+ query_performance_frequency= 0;
+#endif
}
diff --git a/mysys/my_handler_errors.h b/mysys/my_handler_errors.h
index aed08b0151c..8f2a8b750bd 100644
--- a/mysys/my_handler_errors.h
+++ b/mysys/my_handler_errors.h
@@ -50,8 +50,7 @@ static const char *handler_error_messages[]=
"There's no partition in table for the given value",
"Row-based binary logging of row failed",
"Index needed in foreign key constraint",
- "Upholding foreign key constraints would lead to a duplicate key error in "
- "some other table",
+ "Upholding foreign key constraints would lead to a duplicate key error in some other table",
"Table needs to be upgraded before it can be used",
"Table is read only",
"Failed to get next auto increment value",
@@ -67,11 +66,12 @@ static const char *handler_error_messages[]=
"Read page with wrong checksum",
"Too many active concurrent transactions",
"Index column length exceeds limit",
- "Row is not visible by the current transaction"
+ "Row is not visible by the current transaction",
+ "Operation was interrupted by end user (probably kill command?)",
+ "Disk full"
};
extern void my_handler_error_register(void);
extern void my_handler_error_unregister(void);
-
#endif /* MYSYS_MY_HANDLER_ERRORS_INCLUDED */
diff --git a/mysys/my_init.c b/mysys/my_init.c
index 92da047a3fb..580e29c381a 100644
--- a/mysys/my_init.c
+++ b/mysys/my_init.c
@@ -110,6 +110,7 @@ my_bool my_init(void)
{
DBUG_ENTER("my_init");
DBUG_PROCESS((char*) (my_progname ? my_progname : "unknown"));
+ my_time_init();
my_win_init();
DBUG_PRINT("exit", ("home: '%s'", home_dir));
#ifdef __WIN__
@@ -250,6 +251,7 @@ void my_parameter_handler(const wchar_t * expression, const wchar_t * function,
{
DBUG_PRINT("my",("Expression: %s function: %s file: %s, line: %d",
expression, function, file, line));
+ __debugbreak();
}
@@ -274,41 +276,13 @@ int handle_rtc_failure(int err_type, const char *file, int line,
fprintf(stderr, " At %s:%d\n", file, line);
va_end(args);
(void) fflush(stderr);
+ __debugbreak();
return 0; /* Error is handled */
}
#pragma runtime_checks("", restore)
#endif
-#define OFFSET_TO_EPOC ((__int64) 134774 * 24 * 60 * 60 * 1000 * 1000 * 10)
-#define MS 10000000
-
-static void win_init_time(void)
-{
- /* The following is used by time functions */
- FILETIME ft;
- LARGE_INTEGER li, t_cnt;
-
- DBUG_ASSERT(sizeof(LARGE_INTEGER) == sizeof(query_performance_frequency));
-
- if (QueryPerformanceFrequency((LARGE_INTEGER *)&query_performance_frequency) == 0)
- query_performance_frequency= 0;
- else
- {
- GetSystemTimeAsFileTime(&ft);
- li.LowPart= ft.dwLowDateTime;
- li.HighPart= ft.dwHighDateTime;
- query_performance_offset= li.QuadPart-OFFSET_TO_EPOC;
- QueryPerformanceCounter(&t_cnt);
- query_performance_offset-= (t_cnt.QuadPart /
- query_performance_frequency * MS +
- t_cnt.QuadPart %
- query_performance_frequency * MS /
- query_performance_frequency);
- }
-}
-
-
/*
Open HKEY_LOCAL_MACHINE\SOFTWARE\MySQL and set any strings found
there as environment variables
@@ -392,7 +366,6 @@ static void my_win_init(void)
_tzset();
- win_init_time();
win_init_registry();
DBUG_VOID_RETURN;
diff --git a/mysys/my_open.c b/mysys/my_open.c
index db627c72f91..bac0be46766 100644
--- a/mysys/my_open.c
+++ b/mysys/my_open.c
@@ -90,9 +90,6 @@ int my_close(File fd, myf MyFlags)
if ((uint) fd < my_file_limit && my_file_info[fd].type != UNOPEN)
{
my_free(my_file_info[fd].name);
-#if !defined(HAVE_PREAD) && !defined(_WIN32)
- mysql_mutex_destroy(&my_file_info[fd].mutex);
-#endif
my_file_info[fd].type = UNOPEN;
}
my_file_opened--;
@@ -126,12 +123,8 @@ File my_register_filename(File fd, const char *FileName, enum file_type
{
if ((uint) fd >= my_file_limit)
{
-#if !defined(HAVE_PREAD)
- my_errno= EMFILE;
-#else
thread_safe_increment(my_file_opened,&THR_LOCK_open);
DBUG_RETURN(fd); /* safeguard */
-#endif
}
else
{
@@ -141,10 +134,6 @@ File my_register_filename(File fd, const char *FileName, enum file_type
my_file_opened++;
my_file_total_opened++;
my_file_info[fd].type = type_of_file;
-#if !defined(HAVE_PREAD) && !defined(_WIN32)
- mysql_mutex_init(key_my_file_info_mutex, &my_file_info[fd].mutex,
- MY_MUTEX_INIT_FAST);
-#endif
mysql_mutex_unlock(&THR_LOCK_open);
DBUG_PRINT("exit",("fd: %d",fd));
DBUG_RETURN(fd);
diff --git a/mysys/my_port.c b/mysys/my_port.c
new file mode 100644
index 00000000000..96dbe10b1bd
--- /dev/null
+++ b/mysys/my_port.c
@@ -0,0 +1,40 @@
+/* Copyright (C) 2002 MySQL AB
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; version 2
+ of the License.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+ MA 02111-1307, USA */
+
+/*
+ Small functions to make code portable
+*/
+
+#include "mysys_priv.h"
+
+#ifdef _AIX
+
+/*
+ On AIX, at least with gcc 3.1, the expression
+ '(double) (ulonglong) var' doesn't always work for big unsigned
+ integers like '18446744073709551615'. The end result is that the
+ high bit is simply dropped. (probably bug in gcc optimizations)
+ Handling the conversion in a sub function seems to work.
+
+ It doesn't work to make this function inline.
+*/
+
+double my_ulonglong2double(unsigned long long nr)
+{
+ return (double) nr;
+}
+#endif /* _AIX */
diff --git a/mysys/my_pread.c b/mysys/my_pread.c
index e006360c11b..9d513a08418 100644
--- a/mysys/my_pread.c
+++ b/mysys/my_pread.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 2000 MySQL AB, 2008-2009 Sun Microsystems, Inc
+/* Copyright (C) 2000 MySQL AB
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -18,12 +18,10 @@
#include "my_base.h"
#include <m_string.h>
#include <errno.h>
-#if defined (HAVE_PREAD) && !defined(_WIN32)
+#ifndef _WIN32
#include <unistd.h>
#endif
-
-
/*
Read a chunk of bytes from a file from a given position
@@ -50,49 +48,34 @@ size_t my_pread(File Filedes, uchar *Buffer, size_t Count, my_off_t offset,
{
size_t readbytes;
int error= 0;
-#if !defined (HAVE_PREAD) && !defined (_WIN32)
- int save_errno;
-#endif
+
DBUG_ENTER("my_pread");
DBUG_PRINT("my",("fd: %d Seek: %llu Buffer: %p Count: %lu MyFlags: %d",
Filedes, (ulonglong)offset, Buffer, (ulong)Count, MyFlags));
for (;;)
{
errno= 0; /* Linux, Windows don't reset this on EOF/success */
-#if !defined (HAVE_PREAD) && !defined (_WIN32)
- mysql_mutex_lock(&my_file_info[Filedes].mutex);
- readbytes= (uint) -1;
- error= (lseek(Filedes, offset, MY_SEEK_SET) == (my_off_t) -1 ||
- (readbytes= read(Filedes, Buffer, Count)) != Count);
- save_errno= errno;
- mysql_mutex_unlock(&my_file_info[Filedes].mutex);
- if (error)
- errno= save_errno;
-#else
-#if defined(_WIN32)
+#ifdef _WIN32
readbytes= my_win_pread(Filedes, Buffer, Count, offset);
-#else
+#else
readbytes= pread(Filedes, Buffer, Count, offset);
#endif
- error= (readbytes != Count);
-#endif
- if(error)
+ error = (readbytes != Count);
+
+ if (error)
{
my_errno= errno ? errno : -1;
if (errno == 0 || (readbytes != (size_t) -1 &&
- (MyFlags & (MY_NABP | MY_FNABP))))
- my_errno= HA_ERR_FILE_TOO_SHORT;
-
+ (MyFlags & (MY_NABP | MY_FNABP))))
+ my_errno= HA_ERR_FILE_TOO_SHORT;
DBUG_PRINT("warning",("Read only %d bytes off %u from %d, errno: %d",
(int) readbytes, (uint) Count,Filedes,my_errno));
-
if ((readbytes == 0 || readbytes == (size_t) -1) && errno == EINTR)
{
DBUG_PRINT("debug", ("my_pread() was interrupted and returned %d",
(int) readbytes));
continue; /* Interrupted */
}
-
if (MyFlags & (MY_WME | MY_FAE | MY_FNABP))
{
if (readbytes == (size_t) -1)
@@ -133,50 +116,38 @@ size_t my_pread(File Filedes, uchar *Buffer, size_t Count, my_off_t offset,
# Number of bytes read
*/
-size_t my_pwrite(File Filedes, const uchar *Buffer, size_t Count,
+size_t my_pwrite(int Filedes, const uchar *Buffer, size_t Count,
my_off_t offset, myf MyFlags)
{
size_t writtenbytes, written;
uint errors;
-
DBUG_ENTER("my_pwrite");
DBUG_PRINT("my",("fd: %d Seek: %llu Buffer: %p Count: %lu MyFlags: %d",
- Filedes, offset, Buffer, (ulong)Count, MyFlags));
+ Filedes, (ulonglong)offset, Buffer, (ulong)Count, MyFlags));
errors= 0;
written= 0;
for (;;)
{
-#if !defined (HAVE_PREAD) && !defined (_WIN32)
- int error;
- writtenbytes= (size_t) -1;
- mysql_mutex_lock(&my_file_info[Filedes].mutex);
- error= (lseek(Filedes, offset, MY_SEEK_SET) != (my_off_t) -1 &&
- (writtenbytes= write(Filedes, Buffer, Count)) == Count);
- mysql_mutex_unlock(&my_file_info[Filedes].mutex);
- if (error)
- break;
-#elif defined (_WIN32)
- writtenbytes= my_win_pwrite(Filedes, Buffer, Count, offset);
+#ifdef _WIN32
+ writtenbytes= my_win_pwrite(Filedes, Buffer, Count,offset);
#else
writtenbytes= pwrite(Filedes, Buffer, Count, offset);
#endif
- if(writtenbytes == Count)
+ if (writtenbytes == Count)
break;
my_errno= errno;
if (writtenbytes != (size_t) -1)
- {
- written+= writtenbytes;
- Buffer+= writtenbytes;
- Count-= writtenbytes;
- offset+= writtenbytes;
+ { /* Safegueard */
+ written+=writtenbytes;
+ Buffer+=writtenbytes;
+ Count-=writtenbytes;
+ offset+=writtenbytes;
}
DBUG_PRINT("error",("Write only %u bytes", (uint) writtenbytes));
#ifndef NO_BACKGROUND
-
if (my_thread_var->abort)
MyFlags&= ~ MY_WAIT_IF_FULL; /* End if aborted by user */
-
if ((my_errno == ENOSPC || my_errno == EDQUOT) &&
(MyFlags & MY_WAIT_IF_FULL))
{
diff --git a/mysys/my_redel.c b/mysys/my_redel.c
index 2fa5832bf0d..1b200568a47 100644
--- a/mysys/my_redel.c
+++ b/mysys/my_redel.c
@@ -40,7 +40,8 @@ struct utimbuf {
#define REDEL_EXT ".BAK"
-int my_redel(const char *org_name, const char *tmp_name, myf MyFlags)
+int my_redel(const char *org_name, const char *tmp_name,
+ time_t backup_time_stamp, myf MyFlags)
{
int error=1;
DBUG_ENTER("my_redel");
@@ -51,13 +52,9 @@ int my_redel(const char *org_name, const char *tmp_name, myf MyFlags)
goto end;
if (MyFlags & MY_REDEL_MAKE_BACKUP)
{
- char name_buff[FN_REFLEN+20];
- char ext[20];
- ext[0]='-';
- get_date(ext+1,2+4,(time_t) 0);
- strmov(strend(ext),REDEL_EXT);
- if (my_rename(org_name, fn_format(name_buff, org_name, "", ext, 2),
- MyFlags))
+ char name_buff[FN_REFLEN + MY_BACKUP_NAME_EXTRA_LENGTH];
+ my_create_backup_name(name_buff, org_name, backup_time_stamp);
+ if (my_rename(org_name, name_buff, MyFlags))
goto end;
}
else if (my_delete_allow_opened(org_name, MyFlags))
@@ -138,3 +135,23 @@ int my_copystat(const char *from, const char *to, int MyFlags)
return 0;
} /* my_copystat */
+
+
+/**
+ Create a backup file name.
+ @fn my_create_backup_name()
+ @param to Store new file name here
+ @param from Original name
+
+ @info
+ The backup name is made by adding -YYMMDDHHMMSS.BAK to the file name
+*/
+
+void my_create_backup_name(char *to, const char *from, time_t backup_start)
+{
+ char ext[MY_BACKUP_NAME_EXTRA_LENGTH+1];
+ ext[0]='-';
+ get_date(ext+1, GETDATE_SHORT_DATE | GETDATE_HHMMSSTIME, backup_start);
+ strmov(strend(ext),REDEL_EXT);
+ strmov(strmov(to, from), ext);
+}
diff --git a/mysys/my_seek.c b/mysys/my_seek.c
index ca12a2e95d1..efe0416c49a 100644
--- a/mysys/my_seek.c
+++ b/mysys/my_seek.c
@@ -55,7 +55,7 @@ my_off_t my_seek(File fd, my_off_t pos, int whence, myf MyFlags)
Make sure we are using a valid file descriptor!
*/
DBUG_ASSERT(fd != -1);
-#if defined (_WIN32)
+#ifdef _WIN32
newpos= my_win_lseek(fd, pos, whence);
#else
newpos= lseek(fd, pos, whence);
diff --git a/mysys/my_static.c b/mysys/my_static.c
index ac0ad2467f7..60e23e8dfa9 100644
--- a/mysys/my_static.c
+++ b/mysys/my_static.c
@@ -94,11 +94,6 @@ const char *(*proc_info_hook)(void *, const char *, const char *, const char *,
void (*debug_sync_C_callback_ptr)(const char *, size_t);
#endif /* defined(ENABLED_DEBUG_SYNC) */
-#ifdef __WIN__
-/* from my_getsystime.c */
-ulonglong query_performance_frequency, query_performance_offset;
-#endif
-
/* How to disable options */
my_bool my_disable_locking=0;
my_bool my_disable_sync=0;
diff --git a/mysys/my_static.h b/mysys/my_static.h
index 7fde15ff133..0f1cd34a04e 100644
--- a/mysys/my_static.h
+++ b/mysys/my_static.h
@@ -43,8 +43,6 @@ extern uint my_once_extra;
extern struct st_my_file_info my_file_info_default[MY_NFILE];
-extern ulonglong query_performance_frequency, query_performance_offset;
-
C_MODE_END
#endif /* MYSYS_MY_STATIC_INCLUDED */
diff --git a/mysys/my_symlink.c b/mysys/my_symlink.c
index 9657ea6bf58..b001354275d 100644
--- a/mysys/my_symlink.c
+++ b/mysys/my_symlink.c
@@ -149,9 +149,7 @@ int my_realpath(char *to, const char *filename, myf MyFlags)
DBUG_RETURN(result);
#else
#ifdef _WIN32
- int ret= GetFullPathName(filename,FN_REFLEN,
- to,
- NULL);
+ int ret= GetFullPathName(filename,FN_REFLEN, to, NULL);
if (ret == 0 || ret > FN_REFLEN)
{
if (ret > FN_REFLEN)
@@ -160,7 +158,7 @@ int my_realpath(char *to, const char *filename, myf MyFlags)
my_errno= EACCES;
if (MyFlags & MY_WME)
my_error(EE_REALPATH, MYF(0), filename, my_errno);
- return -1;
+ return -1;
}
#else
my_load_path(to, filename, NullS);
diff --git a/mysys/my_sync.c b/mysys/my_sync.c
index f39b10253dd..4d187631786 100644
--- a/mysys/my_sync.c
+++ b/mysys/my_sync.c
@@ -123,7 +123,6 @@ int my_sync(File fd, myf my_flags)
static const char cur_dir_name[]= {FN_CURLIB, 0};
-
/*
Force directory information to disk.
@@ -136,10 +135,10 @@ static const char cur_dir_name[]= {FN_CURLIB, 0};
0 if ok, !=0 if error
*/
-#ifdef NEED_EXPLICIT_SYNC_DIR
-
-int my_sync_dir(const char *dir_name, myf my_flags)
+int my_sync_dir(const char *dir_name __attribute__((unused)),
+ myf my_flags __attribute__((unused)))
{
+#ifdef NEED_EXPLICIT_SYNC_DIR
File dir_fd;
int res= 0;
const char *correct_dir_name;
@@ -161,19 +160,11 @@ int my_sync_dir(const char *dir_name, myf my_flags)
else
res= 1;
DBUG_RETURN(res);
-}
-
-#else /* NEED_EXPLICIT_SYNC_DIR */
-
-int my_sync_dir(const char *dir_name __attribute__((unused)),
- myf my_flags __attribute__((unused)))
-{
+#else
return 0;
+#endif
}
-#endif /* NEED_EXPLICIT_SYNC_DIR */
-
-
/*
Force directory information to disk.
@@ -186,23 +177,15 @@ int my_sync_dir(const char *dir_name __attribute__((unused)),
0 if ok, !=0 if error
*/
-#ifdef NEED_EXPLICIT_SYNC_DIR
-
-int my_sync_dir_by_file(const char *file_name, myf my_flags)
+int my_sync_dir_by_file(const char *file_name __attribute__((unused)),
+ myf my_flags __attribute__((unused)))
{
+#ifdef NEED_EXPLICIT_SYNC_DIR
char dir_name[FN_REFLEN];
size_t dir_name_length;
dirname_part(dir_name, file_name, &dir_name_length);
return my_sync_dir(dir_name, my_flags);
-}
-
-#else /* NEED_EXPLICIT_SYNC_DIR */
-
-int my_sync_dir_by_file(const char *file_name __attribute__((unused)),
- myf my_flags __attribute__((unused)))
-{
+#else
return 0;
+#endif
}
-
-#endif /* NEED_EXPLICIT_SYNC_DIR */
-
diff --git a/mysys/my_thr_init.c b/mysys/my_thr_init.c
index 41f9cdf99ed..121392be8c3 100644
--- a/mysys/my_thr_init.c
+++ b/mysys/my_thr_init.c
@@ -433,6 +433,14 @@ extern void **my_thread_var_dbug()
}
#endif /* DBUG_OFF */
+/* Return pointer to mutex_in_use */
+
+safe_mutex_t **my_thread_var_mutex_in_use()
+{
+ struct st_my_thread_var *tmp=
+ my_pthread_getspecific(struct st_my_thread_var*,THR_KEY_mysys);
+ return tmp ? &tmp->mutex_in_use : 0;
+}
static uint get_thread_lib(void)
{
diff --git a/mysys/my_uuid.c b/mysys/my_uuid.c
index 0c4d34ace8b..ab1b259ae0f 100644
--- a/mysys/my_uuid.c
+++ b/mysys/my_uuid.c
@@ -47,9 +47,10 @@ static my_bool my_uuid_inited= 0;
static struct my_rnd_struct uuid_rand;
static uint nanoseq;
static ulonglong uuid_time= 0;
+static longlong interval_timer_offset;
static uchar uuid_suffix[2+6]; /* clock_seq and node */
-mysql_mutex_t LOCK_uuid_generator;
+static mysql_mutex_t LOCK_uuid_generator;
/*
Number of 100-nanosecond intervals between
@@ -68,6 +69,8 @@ static void set_clock_seq()
{
uint16 clock_seq= ((uint)(my_rnd(&uuid_rand)*16383)) | UUID_VARIANT;
mi_int2store(uuid_suffix, clock_seq);
+ interval_timer_offset= (my_hrtime().val * 10 - my_interval_timer()/100 +
+ UUID_TIME_OFFSET);
}
@@ -91,7 +94,7 @@ void my_uuid_init(ulong seed1, ulong seed2)
if (my_uuid_inited)
return;
my_uuid_inited= 1;
- now= my_getsystime();
+ now= my_interval_timer()/100 + interval_timer_offset;
nanoseq= 0;
if (my_gethwaddr(mac))
@@ -132,7 +135,7 @@ void my_uuid(uchar *to)
DBUG_ASSERT(my_uuid_inited);
mysql_mutex_lock(&LOCK_uuid_generator);
- tv= my_getsystime() + UUID_TIME_OFFSET + nanoseq;
+ tv= my_interval_timer()/100 + interval_timer_offset + nanoseq;
if (likely(tv > uuid_time))
{
@@ -185,7 +188,7 @@ void my_uuid(uchar *to)
irrelevant in the new numberspace.
*/
set_clock_seq();
- tv= my_getsystime() + UUID_TIME_OFFSET;
+ tv= my_interval_timer()/100 + interval_timer_offset;
nanoseq= 0;
DBUG_PRINT("uuid",("making new numberspace"));
}
@@ -226,7 +229,8 @@ void my_uuid2str(const uchar *guid, char *s)
{
*s++= _dig_vec_lower[guid[i] >>4];
*s++= _dig_vec_lower[guid[i] & 15];
- if(i == 3 || i == 5 || i == 7 || i == 9)
+ /* Set '-' at intervals 3, 5, 7 and 9 */
+ if ((1 << i) & ((1 << 3) | (1 << 5) | (1 << 7) | (1 << 9)))
*s++= '-';
}
}
diff --git a/mysys/my_wincond.c b/mysys/my_wincond.c
index 58c09e332d6..bed64230aea 100644
--- a/mysys/my_wincond.c
+++ b/mysys/my_wincond.c
@@ -31,7 +31,7 @@
*/
/* Prototypes and function pointers for condition variable functions */
-typedef VOID (WINAPI * InitializeConditionVariableProc)
+typedef void (WINAPI * InitializeConditionVariableProc)
(PCONDITION_VARIABLE ConditionVariable);
typedef BOOL (WINAPI * SleepConditionVariableCSProc)
@@ -39,10 +39,10 @@ typedef BOOL (WINAPI * SleepConditionVariableCSProc)
PCRITICAL_SECTION CriticalSection,
DWORD dwMilliseconds);
-typedef VOID (WINAPI * WakeAllConditionVariableProc)
+typedef void (WINAPI * WakeAllConditionVariableProc)
(PCONDITION_VARIABLE ConditionVariable);
-typedef VOID (WINAPI * WakeConditionVariableProc)
+typedef void (WINAPI * WakeConditionVariableProc)
(PCONDITION_VARIABLE ConditionVariable);
static InitializeConditionVariableProc my_InitializeConditionVariable;
@@ -88,36 +88,20 @@ static void check_native_cond_availability(void)
static DWORD get_milliseconds(const struct timespec *abstime)
{
- long long millis;
- union ft64 now;
+ struct timespec current_time;
+ long long ms;
if (abstime == NULL)
- return INFINITE;
-
- GetSystemTimeAsFileTime(&now.ft);
-
- /*
- Calculate time left to abstime
- - subtract start time from current time(values are in 100ns units)
- - convert to millisec by dividing with 10000
- */
- millis= (abstime->tv.i64 - now.i64) / 10000;
-
- /* Don't allow the timeout to be negative */
- if (millis < 0)
- return 0;
-
- /*
- Make sure the calculated timeout does not exceed original timeout
- value which could cause "wait for ever" if system time changes
- */
- if (millis > abstime->max_timeout_msec)
- millis= abstime->max_timeout_msec;
-
- if (millis > UINT_MAX)
- millis= UINT_MAX;
-
- return (DWORD)millis;
+ return INFINITE;
+
+ set_timespec_nsec(current_time, 0);
+ ms= (abstime->tv_sec - current_time.tv_sec)*1000LL +
+ (abstime->tv_nsec - current_time.tv_nsec)/1000000LL;
+ if(ms < 0 )
+ ms= 0;
+ if(ms > UINT_MAX)
+ ms= INFINITE;
+ return (DWORD)ms;
}
diff --git a/mysys/my_write.c b/mysys/my_write.c
index 64f7546620f..46b0d749944 100644
--- a/mysys/my_write.c
+++ b/mysys/my_write.c
@@ -36,6 +36,11 @@ size_t my_write(File Filedes, const uchar *Buffer, size_t Count, myf MyFlags)
for (;;)
{
#ifdef _WIN32
+ if(Filedes < 0)
+ {
+ my_errno= errno= EBADF;
+ DBUG_RETURN((size_t)-1);
+ }
writtenbytes= my_win_write(Filedes, Buffer, Count);
#else
writtenbytes= write(Filedes, Buffer, Count);
diff --git a/mysys/string.c b/mysys/string.c
index 0aa175e8991..fa669ceda3a 100644
--- a/mysys/string.c
+++ b/mysys/string.c
@@ -181,3 +181,15 @@ void dynstr_free(DYNAMIC_STRING *str)
my_free(str->str);
str->str= NULL;
}
+
+
+/* Give over the control of the dynamic string to caller */
+
+void dynstr_reassociate(DYNAMIC_STRING *str, char **ptr, size_t *length,
+ size_t *alloc_length)
+{
+ *ptr= str->str;
+ *length= str->length;
+ *alloc_length= str->max_length;
+ str->str=0;
+}
diff --git a/mysys/thr_alarm.c b/mysys/thr_alarm.c
index 725b32fa4a6..f902057a71b 100644
--- a/mysys/thr_alarm.c
+++ b/mysys/thr_alarm.c
@@ -37,7 +37,7 @@
uint thr_client_alarm;
static int alarm_aborted=1; /* No alarm thread */
-my_bool thr_alarm_inited= 0;
+my_bool thr_alarm_inited= 0, my_disable_thr_alarm= 0;
volatile my_bool alarm_thread_running= 0;
time_t next_alarm_expire_time= ~ (time_t) 0;
static sig_handler process_alarm_part2(int sig);
@@ -173,6 +173,21 @@ my_bool thr_alarm(thr_alarm_t *alrm, uint sec, ALARM *alarm_data)
DBUG_ENTER("thr_alarm");
DBUG_PRINT("enter",("thread: %s sec: %d",my_thread_name(),sec));
+ if (my_disable_thr_alarm)
+ {
+ (*alrm)= &alarm_data->alarmed;
+ alarm_data->alarmed= 1; /* Abort if interrupted */
+ DBUG_RETURN(0);
+ }
+
+ if (unlikely(alarm_aborted))
+ { /* No signal thread */
+ DBUG_PRINT("info", ("alarm aborted"));
+ if (alarm_aborted > 0)
+ goto abort_no_unlock;
+ sec= 1; /* Abort mode */
+ }
+
now= my_time(0);
if (!alarm_data)
{
@@ -190,13 +205,6 @@ my_bool thr_alarm(thr_alarm_t *alrm, uint sec, ALARM *alarm_data)
one_signal_hand_sigmask(SIG_BLOCK,&full_signal_set,&old_mask);
mysql_mutex_lock(&LOCK_alarm); /* Lock from threads & alarms */
- if (unlikely(alarm_aborted))
- { /* No signal thread */
- DBUG_PRINT("info", ("alarm aborted"));
- if (alarm_aborted > 0)
- goto abort;
- sec= 1; /* Abort mode */
- }
if (alarm_queue.elements >= max_used_alarms)
{
if (alarm_queue.elements == alarm_queue.max_elements)
@@ -251,6 +259,8 @@ void thr_end_alarm(thr_alarm_t *alarmed)
#endif
DBUG_ENTER("thr_end_alarm");
+ if (my_disable_thr_alarm)
+ DBUG_VOID_RETURN;
one_signal_hand_sigmask(SIG_BLOCK,&full_signal_set,&old_mask);
alarm_data= (ALARM*) ((uchar*) *alarmed - offsetof(ALARM,alarmed));
mysql_mutex_lock(&LOCK_alarm);
diff --git a/mysys/thr_lock.c b/mysys/thr_lock.c
index bc992a3e35b..b2e51cde260 100644
--- a/mysys/thr_lock.c
+++ b/mysys/thr_lock.c
@@ -116,6 +116,31 @@ static inline mysql_cond_t *get_cond(void)
return &my_thread_var->suspend;
}
+
+/*
+ Sort locks in priority order
+
+ LOCK_CMP()
+ A First lock
+ B Second lock
+
+ Return:
+ 0 if A >= B
+ 1 if A < B
+
+ Priority for locks (decides in which order locks are locked)
+ We want all write locks to be first, followed by read locks.
+ Locks from MERGE tables has a little lower priority than other
+ locks, to allow one to release merge tables without having
+ to unlock and re-lock other locks.
+ The lower the number, the higher the priority for the lock.
+ For MERGE tables we add 2 (THR_LOCK_MERGE_PRIV) to the lock priority.
+ THR_LOCK_LATE_PRIV (1) is used when one locks other tables to be merged
+ with existing locks. This way we prioritize the original locks over the
+ new locks.
+*/
+
+
static inline int LOCK_CMP(THR_LOCK_DATA *a, THR_LOCK_DATA *b)
{
if (a->lock != b->lock)
@@ -154,15 +179,13 @@ static int check_lock(struct st_lock_list *list, const char* lock_type,
{
THR_LOCK_DATA *data,**prev;
uint count=0;
- THR_LOCK_INFO *UNINIT_VAR(first_owner);
prev= &list->data;
if (list->data)
{
- enum thr_lock_type last_lock_type=list->data->type;
+ enum thr_lock_type last_lock_type= list->data->type;
+ THR_LOCK_INFO *first_owner= list->data->owner;
- if (same_owner && list->data)
- first_owner= list->data->owner;
for (data=list->data; data && count++ < MAX_LOCKS ; data=data->next)
{
if (data->type != last_lock_type)
@@ -180,8 +203,10 @@ static int check_lock(struct st_lock_list *list, const char* lock_type,
last_lock_type != TL_WRITE_CONCURRENT_INSERT)
{
fprintf(stderr,
- "Warning: Found locks from different threads in %s: %s\n",
- lock_type,where);
+ "Warning: Found locks from different threads for lock '%s' in '%s' at '%s'. org_lock_type: %d last_lock_type: %d new_lock_type: %d\n",
+ data->lock->name ? data->lock->name : "",
+ lock_type, where, list->data->type, last_lock_type,
+ data->type);
return 1;
}
if (no_cond && data->cond)
@@ -211,6 +236,7 @@ static int check_lock(struct st_lock_list *list, const char* lock_type,
static void check_locks(THR_LOCK *lock, const char *where,
+ enum thr_lock_type type,
my_bool allow_no_locks)
{
uint old_found_errors=found_errors;
@@ -226,14 +252,16 @@ static void check_locks(THR_LOCK *lock, const char *where,
if (found_errors < MAX_FOUND_ERRORS)
{
- uint count=0;
+ uint count=0, count2= 0;
THR_LOCK_DATA *data;
for (data=lock->read.data ; data ; data=data->next)
{
+ count2++;
if (data->type == TL_READ_NO_INSERT)
count++;
/* Protect against infinite loop. */
- DBUG_ASSERT(count <= lock->read_no_write_count);
+ DBUG_ASSERT(count <= lock->read_no_write_count &&
+ count2 <= MAX_LOCKS);
}
if (count != lock->read_no_write_count)
{
@@ -274,6 +302,7 @@ static void check_locks(THR_LOCK *lock, const char *where,
found_errors++;
fprintf(stderr,
"Warning at '%s': Write lock %d waiting while no exclusive read locks\n",where,(int) lock->write_wait.data->type);
+ DBUG_PRINT("warning", ("Warning at '%s': Write lock %d waiting while no exclusive read locks\n",where,(int) lock->write_wait.data->type));
}
}
}
@@ -283,13 +312,18 @@ static void check_locks(THR_LOCK *lock, const char *where,
if (lock->write.data->type == TL_WRITE_CONCURRENT_INSERT)
{
THR_LOCK_DATA *data;
- for (data=lock->write.data->next ; data ; data=data->next)
+ uint count= 0;
+ for (data=lock->write.data->next;
+ data && count < MAX_LOCKS;
+ data=data->next)
{
if (data->type != TL_WRITE_CONCURRENT_INSERT)
{
fprintf(stderr,
- "Warning at '%s': Found TL_WRITE_CONCURRENT_INSERT lock mixed with other write locks\n",
- where);
+ "Warning at '%s': Found TL_WRITE_CONCURRENT_INSERT lock mixed with other write lock: %d\n",
+ where, data->type);
+ DBUG_PRINT("warning", ("Warning at '%s': Found TL_WRITE_CONCURRENT_INSERT lock mixed with other write lock: %d\n",
+ where, data->type));
break;
}
}
@@ -304,26 +338,34 @@ static void check_locks(THR_LOCK *lock, const char *where,
fprintf(stderr,
"Warning at '%s': Found WRITE_ALLOW_WRITE lock waiting for WRITE_ALLOW_WRITE lock\n",
where);
+ DBUG_PRINT("warning", ("Warning at '%s': Found WRITE_ALLOW_WRITE lock waiting for WRITE_ALLOW_WRITE lock\n",
+ where));
+
}
}
if (lock->read.data)
{
- if (!thr_lock_owner_equal(lock->write.data->owner,
- lock->read.data->owner) &&
+ THR_LOCK_DATA *data;
+ for (data=lock->read.data ; data ; data=data->next)
+ {
+ if (!thr_lock_owner_equal(lock->write.data->owner,
+ data->owner) &&
((lock->write.data->type > TL_WRITE_DELAYED &&
lock->write.data->type != TL_WRITE_ONLY) ||
((lock->write.data->type == TL_WRITE_CONCURRENT_INSERT ||
lock->write.data->type == TL_WRITE_ALLOW_WRITE) &&
- lock->read_no_write_count)))
- {
- found_errors++;
- fprintf(stderr,
- "Warning at '%s': Found lock of type %d that is write and read locked\n",
- where, lock->write.data->type);
- DBUG_PRINT("warning",("At '%s': Found lock of type %d that is write and read locked\n",
- where, lock->write.data->type));
-
- }
+ data->type == TL_READ_NO_INSERT)))
+ {
+ found_errors++;
+ fprintf(stderr,
+ "Warning at '%s' for lock: %d: Found lock of type %d that is write and read locked. Read_no_write_count: %d\n",
+ where, (int) type, lock->write.data->type,
+ lock->read_no_write_count);
+ DBUG_PRINT("warning",("At '%s' for lock %d: Found lock of type %d that is write and read locked\n",
+ where, (int) type,
+ lock->write.data->type));
+ }
+ }
}
if (lock->read_wait.data)
{
@@ -349,7 +391,7 @@ static void check_locks(THR_LOCK *lock, const char *where,
}
#else /* EXTRA_DEBUG */
-#define check_locks(A,B,C)
+#define check_locks(A,B,C,D)
#endif
@@ -401,6 +443,7 @@ void thr_lock_data_init(THR_LOCK *lock,THR_LOCK_DATA *data, void *param)
data->status_param=param;
data->cond=0;
data->priority= 0;
+ data->debug_print_param= 0;
}
@@ -478,7 +521,7 @@ wait_for_lock(struct st_lock_list *wait, THR_LOCK_DATA *data,
data->cond= cond;
old_proc_info= proc_info_hook(NULL, "Waiting for table level lock",
- __func__, __FILE__, __LINE__);
+ __func__, __FILE__, __LINE__);
/*
Since before_lock_wait potentially can create more threads to
@@ -544,13 +587,14 @@ wait_for_lock(struct st_lock_list *wait, THR_LOCK_DATA *data,
else
wait->last=data->prev;
data->type= TL_UNLOCK; /* No lock */
- check_locks(data->lock, "killed or timed out wait_for_lock", 1);
+ check_locks(data->lock, "killed or timed out wait_for_lock", data->type,
+ 1);
wake_up_waiters(data->lock);
}
else
{
DBUG_PRINT("thr_lock", ("lock aborted"));
- check_locks(data->lock, "aborted wait_for_lock", 0);
+ check_locks(data->lock, "aborted wait_for_lock", data->type, 0);
}
}
else
@@ -559,7 +603,7 @@ wait_for_lock(struct st_lock_list *wait, THR_LOCK_DATA *data,
if (data->lock->get_status)
(*data->lock->get_status)(data->status_param,
data->type == TL_WRITE_CONCURRENT_INSERT);
- check_locks(data->lock,"got wait_for_lock",0);
+ check_locks(data->lock,"got wait_for_lock", data->type, 0);
}
mysql_mutex_unlock(&data->lock->mutex);
@@ -594,7 +638,7 @@ thr_lock(THR_LOCK_DATA *data, THR_LOCK_INFO *owner,
(long) data, data->owner->thread_id,
(long) lock, (int) lock_type));
check_locks(lock,(uint) lock_type <= (uint) TL_READ_NO_INSERT ?
- "enter read_lock" : "enter write_lock",0);
+ "enter read_lock" : "enter write_lock", lock_type, 0);
if ((int) lock_type <= (int) TL_READ_NO_INSERT)
{
/* Request for READ lock */
@@ -639,7 +683,7 @@ thr_lock(THR_LOCK_DATA *data, THR_LOCK_INFO *owner,
lock->read.last= &data->next;
if (lock_type == TL_READ_NO_INSERT)
lock->read_no_write_count++;
- check_locks(lock,"read lock with old write lock",0);
+ check_locks(lock,"read lock with old write lock", lock_type, 0);
if (lock->get_status)
(*lock->get_status)(data->status_param, 0);
statistic_increment(locks_immediate,&THR_LOCK_lock);
@@ -663,7 +707,7 @@ thr_lock(THR_LOCK_DATA *data, THR_LOCK_INFO *owner,
lock->read.last= &data->next;
if (lock_type == TL_READ_NO_INSERT)
lock->read_no_write_count++;
- check_locks(lock,"read lock with no write locks",0);
+ check_locks(lock,"read lock with no write locks", lock_type, 0);
if (lock->get_status)
(*lock->get_status)(data->status_param, 0);
statistic_increment(locks_immediate,&THR_LOCK_lock);
@@ -769,7 +813,7 @@ thr_lock(THR_LOCK_DATA *data, THR_LOCK_INFO *owner,
(*lock->write.last)=data; /* Add to running fifo */
data->prev=lock->write.last;
lock->write.last= &data->next;
- check_locks(lock,"second write lock",0);
+ check_locks(lock,"second write lock", lock_type, 0);
if (lock->get_status)
(*lock->get_status)(data->status_param,
lock_type == TL_WRITE_CONCURRENT_INSERT);
@@ -807,7 +851,7 @@ thr_lock(THR_LOCK_DATA *data, THR_LOCK_INFO *owner,
lock->write.last= &data->next;
if (lock->get_status)
(*lock->get_status)(data->status_param, concurrent_insert);
- check_locks(lock,"only write lock",0);
+ check_locks(lock,"only write lock", lock_type, 0);
statistic_increment(locks_immediate,&THR_LOCK_lock);
goto end;
}
@@ -830,7 +874,7 @@ static inline void free_all_read_locks(THR_LOCK *lock,
{
THR_LOCK_DATA *data=lock->read_wait.data;
- check_locks(lock,"before freeing read locks",1);
+ check_locks(lock,"before freeing read locks", TL_UNLOCK, 1);
/* move all locks from read_wait list to read list */
(*lock->read.last)=data;
@@ -872,7 +916,7 @@ static inline void free_all_read_locks(THR_LOCK *lock,
*lock->read_wait.last=0;
if (!lock->read_wait.data)
lock->write_lock_count=0;
- check_locks(lock,"after giving read locks",0);
+ check_locks(lock,"after giving read locks", TL_UNLOCK, 0);
}
/* Unlock lock and free next thread on same lock */
@@ -885,7 +929,7 @@ void thr_unlock(THR_LOCK_DATA *data, uint unlock_flags)
DBUG_PRINT("lock",("data: 0x%lx thread: 0x%lx lock: 0x%lx",
(long) data, data->owner->thread_id, (long) lock));
mysql_mutex_lock(&lock->mutex);
- check_locks(lock,"start of release lock",0);
+ check_locks(lock,"start of release lock", lock_type, 0);
if (((*data->prev)=data->next)) /* remove from lock-list */
data->next->prev= data->prev;
@@ -919,8 +963,9 @@ void thr_unlock(THR_LOCK_DATA *data, uint unlock_flags)
if (lock_type == TL_READ_NO_INSERT)
lock->read_no_write_count--;
data->type=TL_UNLOCK; /* Mark unlocked */
- check_locks(lock,"after releasing lock",1);
+ check_locks(lock,"after releasing lock", lock_type, 1);
wake_up_waiters(lock);
+ check_locks(lock,"end of thr_unlock", lock_type, 1);
mysql_mutex_unlock(&lock->mutex);
DBUG_VOID_RETURN;
}
@@ -1045,7 +1090,7 @@ static void wake_up_waiters(THR_LOCK *lock)
free_all_read_locks(lock,0);
}
end:
- check_locks(lock, "after waking up waiters", 0);
+ check_locks(lock, "after waking up waiters", TL_UNLOCK, 0);
DBUG_VOID_RETURN;
}
@@ -1350,7 +1395,7 @@ void thr_downgrade_write_lock(THR_LOCK_DATA *in_data,
DBUG_ASSERT(old_lock_type == TL_WRITE_ONLY);
DBUG_ASSERT(old_lock_type > new_lock_type);
in_data->type= new_lock_type;
- check_locks(lock,"after downgrading lock",0);
+ check_locks(lock,"after downgrading lock", old_lock_type, 0);
mysql_mutex_unlock(&lock->mutex);
DBUG_VOID_RETURN;
@@ -1372,7 +1417,7 @@ my_bool thr_upgrade_write_delay_lock(THR_LOCK_DATA *data,
mysql_mutex_unlock(&lock->mutex);
DBUG_RETURN(data->type == TL_UNLOCK); /* Test if Aborted */
}
- check_locks(lock,"before upgrading lock",0);
+ check_locks(lock,"before upgrading lock", data->type, 0);
/* TODO: Upgrade to TL_WRITE_CONCURRENT_INSERT in some cases */
data->type= new_lock_type; /* Upgrade lock */
@@ -1400,11 +1445,11 @@ my_bool thr_upgrade_write_delay_lock(THR_LOCK_DATA *data,
lock->write_wait.last= &data->next;
data->prev= &lock->write_wait.data;
lock->write_wait.data=data;
- check_locks(lock,"upgrading lock",0);
+ check_locks(lock,"upgrading lock", new_lock_type, 0);
}
else
{
- check_locks(lock,"waiting for lock",0);
+ check_locks(lock,"waiting for lock", new_lock_type, 0);
}
res= wait_for_lock(&lock->write_wait, data, 1, lock_wait_timeout);
if (res == THR_LOCK_SUCCESS && lock->start_trans)
diff --git a/mysys/thr_mutex.c b/mysys/thr_mutex.c
index fdc25b67049..86a7ce9684b 100644
--- a/mysys/thr_mutex.c
+++ b/mysys/thr_mutex.c
@@ -171,16 +171,16 @@ static int safe_mutex_lazy_init_deadlock_detection(safe_mutex_t *mp)
pthread_mutex_lock(&THR_LOCK_mutex);
mp->id= ++safe_mutex_id;
pthread_mutex_unlock(&THR_LOCK_mutex);
- my_hash_init(mp->locked_mutex, &my_charset_bin,
- 1000,
- offsetof(safe_mutex_deadlock_t, id),
- sizeof(mp->id),
- 0, 0, HASH_UNIQUE);
- my_hash_init(mp->used_mutex, &my_charset_bin,
- 1000,
- offsetof(safe_mutex_t, id),
- sizeof(mp->id),
- 0, 0, HASH_UNIQUE);
+ my_hash_init2(mp->locked_mutex, 64, &my_charset_bin,
+ 128,
+ offsetof(safe_mutex_deadlock_t, id),
+ sizeof(mp->id),
+ 0, 0, HASH_UNIQUE);
+ my_hash_init2(mp->used_mutex, 64, &my_charset_bin,
+ 128,
+ offsetof(safe_mutex_t, id),
+ sizeof(mp->id),
+ 0, 0, HASH_UNIQUE);
return 0;
}
@@ -711,12 +711,6 @@ void safe_mutex_end(FILE *file __attribute__((unused)))
#endif /* SAFE_MUTEX_DETECT_DESTROY */
}
-safe_mutex_t **my_thread_var_mutex_in_use()
-{
- struct st_my_thread_var *tmp= my_thread_var;
- return tmp ? &tmp->mutex_in_use : 0;
-}
-
static my_bool add_used_to_locked_mutex(safe_mutex_t *used_mutex,
safe_mutex_deadlock_t *locked_mutex)
{
diff --git a/mysys/thr_rwlock.c b/mysys/thr_rwlock.c
index bad80b43eef..a6eb16a4b1b 100644
--- a/mysys/thr_rwlock.c
+++ b/mysys/thr_rwlock.c
@@ -142,7 +142,7 @@ static int srw_unlock(my_rw_lock_t *rwp)
* Multithreaded Demo Source
*
* Copyright (C) 1995 by Sun Microsystems, Inc.
-* All rights reserved.
+*
*
* This file is a product of SunSoft, Inc. and is provided for
* unrestricted use provided that this legend is included on all
diff --git a/mysys/tree.c b/mysys/tree.c
index c922c8f505a..03c4ac5b36b 100644
--- a/mysys/tree.c
+++ b/mysys/tree.c
@@ -221,7 +221,10 @@ TREE_ELEMENT *tree_insert(TREE *tree, void *key, uint key_size,
}
if (element == &tree->null_element)
{
- uint alloc_size=sizeof(TREE_ELEMENT)+key_size+tree->size_of_element;
+ uint alloc_size;
+ if (tree->flag & TREE_ONLY_DUPS)
+ return((TREE_ELEMENT *) 1);
+ alloc_size=sizeof(TREE_ELEMENT)+key_size+tree->size_of_element;
tree->allocated+=alloc_size;
if (tree->memory_limit && tree->elements_in_tree
@@ -375,6 +378,7 @@ void *tree_search_key(TREE *tree, const void *key,
case HA_READ_KEY_EXACT:
case HA_READ_KEY_OR_NEXT:
case HA_READ_BEFORE_KEY:
+ case HA_READ_KEY_OR_PREV:
last_equal_element= parents;
cmp= 1;
break;
@@ -418,6 +422,9 @@ void *tree_search_key(TREE *tree, const void *key,
case HA_READ_BEFORE_KEY:
*last_pos= last_right_step_parent;
break;
+ case HA_READ_KEY_OR_PREV:
+ *last_pos= last_equal_element ? last_equal_element : last_right_step_parent;
+ break;
default:
return NULL;
}
diff --git a/mysys/waiting_threads.c b/mysys/waiting_threads.c
index f8980185ae0..ddc06a3ae5e 100644
--- a/mysys/waiting_threads.c
+++ b/mysys/waiting_threads.c
@@ -481,9 +481,9 @@ void wt_end()
(or even most) of them will never be used for deadlock detection.
@param ds a pointer to deadlock search depth short value
- @param ts a pointer to deadlock timeout short value
+ @param ts a pointer to deadlock timeout short value (microseconds)
@param dl a pointer to deadlock search depth long value
- @param tl a pointer to deadlock timeout long value
+ @param tl a pointer to deadlock timeout long value (microseconds)
@note these are pointers to values, and WT_THD stores them as pointers.
It allows one later to change search depths and timeouts for existing
@@ -1039,8 +1039,9 @@ int wt_thd_cond_timedwait(WT_THD *thd, mysql_mutex_t *mutex)
{
int ret= WT_TIMEOUT;
struct timespec timeout;
- ulonglong before, after, starttime;
+ my_hrtime_t before, after, starttime;
WT_RESOURCE *rc= thd->waiting_for;
+ ulonglong end_wait_time;
DBUG_ENTER("wt_thd_cond_timedwait");
DBUG_PRINT("wt", ("enter: thd=%s, rc=%p", thd->name, rc));
@@ -1052,29 +1053,15 @@ int wt_thd_cond_timedwait(WT_THD *thd, mysql_mutex_t *mutex)
mysql_mutex_assert_owner(mutex);
#endif
- before= starttime= my_getsystime();
-
-#ifdef __WIN__
- /*
- only for the sake of Windows we distinguish between
- 'before' and 'starttime':
-
- my_getsystime() returns high-resolution value, that cannot be used for
- waiting (it doesn't follow system clock changes), but is good for time
- intervals.
-
- GetSystemTimeAsFileTime() follows system clock, but is low-resolution
- and will result in lousy intervals.
- */
- GetSystemTimeAsFileTime((PFILETIME)&starttime);
-#endif
+ before= starttime= my_hrtime();
rc_wrlock(rc);
if (rc->owners.elements == 0)
ret= WT_OK;
rc_unlock(rc);
- set_timespec_time_nsec(timeout, starttime, (*thd->timeout_short)*ULL(1000));
+ end_wait_time= starttime.val *1000 + (*thd->timeout_short)*ULL(1000000);
+ set_timespec_time_nsec(timeout, end_wait_time);
if (ret == WT_TIMEOUT && !thd->killed)
ret= mysql_cond_timedwait(&rc->cond, mutex, &timeout);
if (ret == WT_TIMEOUT && !thd->killed)
@@ -1086,15 +1073,16 @@ int wt_thd_cond_timedwait(WT_THD *thd, mysql_mutex_t *mutex)
ret= WT_DEADLOCK;
else if (*thd->timeout_long > *thd->timeout_short)
{
- set_timespec_time_nsec(timeout, starttime, (*thd->timeout_long)*ULL(1000));
+ end_wait_time= starttime.val *1000 + (*thd->timeout_long)*ULL(1000000);
+ set_timespec_time_nsec(timeout, end_wait_time);
if (!thd->killed)
ret= mysql_cond_timedwait(&rc->cond, mutex, &timeout);
}
}
- after= my_getsystime();
+ after= my_hrtime();
if (stop_waiting(thd) == WT_DEADLOCK) /* if we're killed */
ret= WT_DEADLOCK;
- increment_wait_stats(after-before, ret);
+ increment_wait_stats(after.val-before.val, ret);
if (ret == WT_OK)
increment_success_stats();
DBUG_RETURN(ret);