summaryrefslogtreecommitdiff
path: root/mysys
diff options
context:
space:
mode:
Diffstat (limited to 'mysys')
-rw-r--r--mysys/CMakeLists.txt4
-rw-r--r--mysys/Makefile.am4
-rw-r--r--mysys/charset.c3
-rw-r--r--mysys/default_modify.c8
-rw-r--r--mysys/hash.c19
-rw-r--r--mysys/ma_dyncol.c2112
-rw-r--r--mysys/mf_getdate.c2
-rw-r--r--mysys/mf_iocache.c3
-rw-r--r--mysys/my_chsize.c19
-rw-r--r--mysys/my_compare.c2
-rw-r--r--mysys/my_create.c15
-rw-r--r--mysys/my_dup.c6
-rw-r--r--mysys/my_file.c1
-rw-r--r--mysys/my_fopen.c48
-rw-r--r--mysys/my_fstream.c17
-rw-r--r--mysys/my_getsystime.c228
-rw-r--r--mysys/my_handler_errors.h4
-rw-r--r--mysys/my_init.c53
-rw-r--r--mysys/my_lib.c26
-rw-r--r--mysys/my_lock.c137
-rw-r--r--mysys/my_mmap.c6
-rw-r--r--mysys/my_open.c228
-rw-r--r--mysys/my_pread.c65
-rw-r--r--mysys/my_quick.c22
-rw-r--r--mysys/my_read.c7
-rw-r--r--mysys/my_seek.c17
-rw-r--r--mysys/my_static.c7
-rw-r--r--mysys/my_static.h2
-rw-r--r--mysys/my_sync.c2
-rw-r--r--mysys/my_uuid.c12
-rw-r--r--mysys/my_wincond.c220
-rw-r--r--mysys/my_winerr.c123
-rw-r--r--mysys/my_winfile.c681
-rw-r--r--mysys/my_winthread.c15
-rw-r--r--mysys/my_write.c36
-rw-r--r--mysys/mysys_priv.h24
-rw-r--r--mysys/queues.c635
-rw-r--r--mysys/string.c12
-rw-r--r--mysys/thr_alarm.c203
-rw-r--r--mysys/thr_lock.c11
-rw-r--r--mysys/thr_rwlock.c160
-rw-r--r--mysys/tree.c5
-rw-r--r--mysys/waiting_threads.c34
43 files changed, 3959 insertions, 1279 deletions
diff --git a/mysys/CMakeLists.txt b/mysys/CMakeLists.txt
index 9ab19222caf..87f40af2fe8 100644
--- a/mysys/CMakeLists.txt
+++ b/mysys/CMakeLists.txt
@@ -38,9 +38,9 @@ SET(MYSYS_SOURCES array.c charset-def.c charset.c checksum.c default.c default_
my_mkdir.c my_mmap.c my_net.c my_once.c my_open.c my_pread.c my_pthread.c
my_quick.c my_read.c my_realloc.c my_redel.c my_rename.c my_seek.c my_sleep.c
my_static.c my_symlink.c my_symlink2.c my_sync.c my_thr_init.c my_wincond.c
- my_windac.c my_winthread.c my_write.c ptr_cmp.c queues.c stacktrace.c
+ my_winerr.c my_winfile.c my_windac.c my_winthread.c my_write.c ptr_cmp.c queues.c stacktrace.c
rijndael.c safemalloc.c sha1.c string.c thr_alarm.c thr_lock.c thr_mutex.c
- thr_rwlock.c tree.c typelib.c my_vle.c base64.c my_memmem.c my_getpagesize.c
+ thr_rwlock.c tree.c typelib.c my_vle.c base64.c my_memmem.c my_getpagesize.c ma_dyncol.c
lf_alloc-pin.c lf_dynarray.c lf_hash.c
my_atomic.c my_getncpus.c my_rnd.c
my_uuid.c wqueue.c waiting_threads.c
diff --git a/mysys/Makefile.am b/mysys/Makefile.am
index 1dd4cc0f780..e479134df8e 100644
--- a/mysys/Makefile.am
+++ b/mysys/Makefile.am
@@ -27,7 +27,7 @@ libmysys_la_SOURCES = my_init.c my_getwd.c mf_getdate.c my_mmap.c \
mf_path.c mf_loadpath.c my_file.c \
my_open.c my_create.c my_dup.c my_seek.c my_read.c \
my_pread.c my_write.c my_getpagesize.c \
- my_crc32.c \
+ my_crc32.c ma_dyncol.c \
mf_iocache.c mf_iocache2.c mf_cache.c mf_tempfile.c \
mf_tempdir.c my_lock.c mf_brkhant.c my_alarm.c \
my_malloc.c my_realloc.c my_once.c mulalloc.c \
@@ -74,7 +74,7 @@ endif
EXTRA_DIST = thr_alarm.c thr_lock.c my_pthread.c my_thr_init.c \
thr_mutex.c thr_rwlock.c waiting_threads.c \
CMakeLists.txt mf_soundex.c \
- my_conio.c my_wincond.c my_winthread.c
+ my_conio.c my_wincond.c my_winthread.c my_winfile.c my_winerr.c
# test_dir_DEPENDENCIES= $(LIBRARIES)
# testhash_DEPENDENCIES= $(LIBRARIES)
# test_charset_DEPENDENCIES= $(LIBRARIES)
diff --git a/mysys/charset.c b/mysys/charset.c
index 7b72f1f5ae3..c7756583b19 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
diff --git a/mysys/default_modify.c b/mysys/default_modify.c
index 88df0122da2..ccbf47176a6 100644
--- a/mysys/default_modify.c
+++ b/mysys/default_modify.c
@@ -21,7 +21,7 @@
#define BUFF_SIZE 1024
#define RESERVE 1024 /* Extend buffer with this extent */
-#ifdef __WIN__
+#ifdef _WIN32
#define NEWLINE "\r\n"
#define NEWLINE_LEN 2
#else
@@ -78,7 +78,7 @@ int modify_defaults_file(const char *file_location, const char *option,
DBUG_RETURN(2);
/* my_fstat doesn't use the flag parameter */
- if (my_fstat(fileno(cnf_file), &file_stat, MYF(0)))
+ if (my_fstat(my_fileno(cnf_file), &file_stat, MYF(0)))
goto malloc_err;
if (option && option_value)
@@ -96,7 +96,7 @@ int modify_defaults_file(const char *file_location, const char *option,
NEWLINE_LEN + /* Space for newline */
RESERVE); /* Some additional space */
- buffer_size= (file_stat.st_size +
+ buffer_size= (uint)(file_stat.st_size +
1); /* The ending zero */
/*
@@ -213,7 +213,7 @@ int modify_defaults_file(const char *file_location, const char *option,
if (opt_applied)
{
/* Don't write the file if there are no changes to be made */
- if (my_chsize(fileno(cnf_file), (my_off_t) (dst_ptr - file_buffer), 0,
+ if (my_chsize(my_fileno(cnf_file), (my_off_t) (dst_ptr - file_buffer), 0,
MYF(MY_WME)) ||
my_fseek(cnf_file, 0, MY_SEEK_SET, MYF(0)) ||
my_fwrite(cnf_file, (uchar*) file_buffer, (size_t) (dst_ptr - file_buffer),
diff --git a/mysys/hash.c b/mysys/hash.c
index 924f0ef418d..5ff3c2e99ce 100644
--- a/mysys/hash.c
+++ b/mysys/hash.c
@@ -182,8 +182,9 @@ my_hash_key(const HASH *hash, const uchar *record, size_t *length,
static uint my_hash_mask(size_t 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,
@@ -484,7 +485,8 @@ my_bool my_hash_insert(HASH *info, const uchar *record)
my_bool my_hash_delete(HASH *hash, uchar *record)
{
- uint blength,pos2,pos_hashnr,lastpos_hashnr,idx,empty_index;
+ uint pos2,pos_hashnr,lastpos_hashnr,idx,empty_index;
+ size_t blength;
HASH_LINK *data,*lastpos,*gpos,*pos,*pos3,*empty;
DBUG_ENTER("my_hash_delete");
if (!hash->records)
@@ -573,8 +575,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");
@@ -656,7 +658,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;
}
@@ -664,7 +666,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);
}
@@ -728,7 +730,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..dcb03d7f073
--- /dev/null
+++ b/mysys/ma_dyncol.c
@@ -0,0 +1,2112 @@
+/* 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 CALLER_INFO))
+ 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, MYF(0));
+ 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 876ee941f27..ef5d53710d2 100644
--- a/mysys/mf_iocache.c
+++ b/mysys/mf_iocache.c
@@ -1657,9 +1657,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_chsize.c b/mysys/my_chsize.c
index b1dbb22c687..b9013811b34 100644
--- a/mysys/my_chsize.c
+++ b/mysys/my_chsize.c
@@ -52,20 +52,13 @@ int my_chsize(File fd, my_off_t newlength, int filler, myf MyFlags)
if (oldsize > newlength)
{
-#if defined(HAVE_SETFILEPOINTER)
- /* This is for the moment only true on windows */
- long is_success;
- HANDLE win_file= (HANDLE) _get_osfhandle(fd);
- long length_low, length_high;
- length_low= (long) (ulong) newlength;
- length_high= (long) ((ulonglong) newlength >> 32);
- is_success= SetFilePointer(win_file, length_low, &length_high, FILE_BEGIN);
- if (is_success == -1 && (my_errno= GetLastError()) != NO_ERROR)
+#ifdef _WIN32
+ if (my_win_chsize(fd, newlength))
+ {
+ my_errno= errno;
goto err;
- if (SetEndOfFile(win_file))
- DBUG_RETURN(0);
- my_errno= GetLastError();
- goto err;
+ }
+ DBUG_RETURN(0);
#elif defined(HAVE_FTRUNCATE)
if (ftruncate(fd, (off_t) newlength))
{
diff --git a/mysys/my_compare.c b/mysys/my_compare.c
index f9f18ae0867..19a76593f42 100644
--- a/mysys/my_compare.c
+++ b/mysys/my_compare.c
@@ -658,7 +658,7 @@ void my_handler_error_register(void)
/*
If you got compilation error here about compile_time_assert array, check
that every HA_ERR_xxx constant has a corresponding error message in
- handler_error_messages[] list (check mysys/ma_handler_errors.h and
+ handler_error_messages[] list (check mysys/my_handler_errors.h and
include/my_base.h).
*/
compile_time_assert(HA_ERR_FIRST + array_elements(handler_error_messages) ==
diff --git a/mysys/my_create.c b/mysys/my_create.c
index 5c9a1e027d2..d0436276d03 100644
--- a/mysys/my_create.c
+++ b/mysys/my_create.c
@@ -18,7 +18,7 @@
#include "mysys_err.h"
#include <errno.h>
#include <my_sys.h>
-#if defined(__WIN__)
+#if defined(_WIN32)
#include <share.h>
#endif
@@ -41,16 +41,12 @@ File my_create(const char *FileName, int CreateFlags, int access_flags,
FileName, CreateFlags, access_flags, MyFlags));
#if !defined(NO_OPEN_3)
- fd = open((char *) FileName, access_flags | O_CREAT,
+ fd= open((char *) FileName, access_flags | O_CREAT,
CreateFlags ? CreateFlags : my_umask);
-#elif defined(VMS)
- fd = open((char *) FileName, access_flags | O_CREAT, 0,
- "ctx=stm","ctx=bin");
-#elif defined(__WIN__)
- fd= my_sopen((char *) FileName, access_flags | O_CREAT | O_BINARY,
- SH_DENYNO, MY_S_IREAD | MY_S_IWRITE);
+#elif defined(_WIN32)
+ fd= my_win_open(FileName, access_flags | O_CREAT);
#else
- fd = open(FileName, access_flags);
+ fd= open(FileName, access_flags);
#endif
if ((MyFlags & MY_SYNC_DIR) && (fd >=0) &&
@@ -71,6 +67,7 @@ File my_create(const char *FileName, int CreateFlags, int access_flags,
if (unlikely(fd >= 0 && rc < 0))
{
int tmp= my_errno;
+ my_close(fd, MyFlags);
my_delete(FileName, MyFlags);
my_errno= tmp;
}
diff --git a/mysys/my_dup.c b/mysys/my_dup.c
index 55f5e0c0099..5fdd6e9f364 100644
--- a/mysys/my_dup.c
+++ b/mysys/my_dup.c
@@ -29,7 +29,11 @@ File my_dup(File file, myf MyFlags)
const char *filename;
DBUG_ENTER("my_dup");
DBUG_PRINT("my",("file: %d MyFlags: %d", file, MyFlags));
- fd = dup(file);
+#ifdef _WIN32
+ fd= my_win_dup(file);
+#else
+ fd= dup(file);
+#endif
filename= (((uint) file < my_file_limit) ?
my_file_info[(int) file].name : "Unknown");
DBUG_RETURN(my_register_filename(fd, filename, FILE_BY_DUP,
diff --git a/mysys/my_file.c b/mysys/my_file.c
index 594f361437f..d8d51b91ab2 100644
--- a/mysys/my_file.c
+++ b/mysys/my_file.c
@@ -97,6 +97,7 @@ uint my_set_max_open_files(uint files)
DBUG_ENTER("my_set_max_open_files");
DBUG_PRINT("enter",("files: %u my_file_limit: %u", files, my_file_limit));
+ files+= MY_FILE_MIN;
files= set_max_open_files(min(files, OS_FILE_LIMIT));
if (files <= MY_NFILE)
DBUG_RETURN(files);
diff --git a/mysys/my_fopen.c b/mysys/my_fopen.c
index a4b0c9f895d..ae631a59353 100644
--- a/mysys/my_fopen.c
+++ b/mysys/my_fopen.c
@@ -46,24 +46,14 @@ FILE *my_fopen(const char *filename, int flags, myf MyFlags)
DBUG_ENTER("my_fopen");
DBUG_PRINT("my",("Name: '%s' flags: %d MyFlags: %d",
filename, flags, MyFlags));
- /*
- if we are not creating, then we need to use my_access to make sure
- the file exists since Windows doesn't handle files like "com1.sym"
- very well
- */
-#ifdef __WIN__
- if (check_if_legal_filename(filename))
- {
- errno= EACCES;
- fd= 0;
- }
- else
+
+ make_ftype(type,flags);
+
+#ifdef _WIN32
+ fd= my_win_fopen(filename, type);
+#else
+ fd= fopen(filename, type);
#endif
- {
- make_ftype(type,flags);
- fd = fopen(filename, type);
- }
-
if (fd != 0)
{
/*
@@ -71,18 +61,20 @@ FILE *my_fopen(const char *filename, int flags, myf MyFlags)
on some OS (SUNOS). Actually the filename save isn't that important
so we can ignore if this doesn't work.
*/
- if ((uint) fileno(fd) >= my_file_limit)
+
+ int filedesc= my_fileno(fd);
+ if ((uint)filedesc >= my_file_limit)
{
thread_safe_increment(my_stream_opened,&THR_LOCK_open);
DBUG_RETURN(fd); /* safeguard */
}
pthread_mutex_lock(&THR_LOCK_open);
- if ((my_file_info[fileno(fd)].name = (char*)
+ if ((my_file_info[filedesc].name= (char*)
my_strdup(filename,MyFlags)))
{
my_stream_opened++;
my_file_total_opened++;
- my_file_info[fileno(fd)].type = STREAM_BY_FOPEN;
+ my_file_info[filedesc].type= STREAM_BY_FOPEN;
pthread_mutex_unlock(&THR_LOCK_open);
DBUG_PRINT("exit",("stream: 0x%lx", (long) fd));
DBUG_RETURN(fd);
@@ -240,8 +232,13 @@ int my_fclose(FILE *fd, myf MyFlags)
DBUG_PRINT("my",("stream: 0x%lx MyFlags: %d", (long) fd, MyFlags));
pthread_mutex_lock(&THR_LOCK_open);
- file=fileno(fd);
- if ((err = fclose(fd)) < 0)
+ file= my_fileno(fd);
+#ifndef _WIN32
+ err= fclose(fd);
+#else
+ err= my_win_fclose(fd);
+#endif
+ if(err < 0)
{
my_errno=errno;
if (MyFlags & (MY_FAE | MY_WME))
@@ -272,7 +269,12 @@ FILE *my_fdopen(File Filedes, const char *name, int Flags, myf MyFlags)
Filedes, Flags, MyFlags));
make_ftype(type,Flags);
- if ((fd = fdopen(Filedes, type)) == 0)
+#ifdef _WIN32
+ fd= my_win_fdopen(Filedes, type);
+#else
+ fd= fdopen(Filedes, type);
+#endif
+ if (!fd)
{
my_errno=errno;
if (MyFlags & (MY_FAE | MY_WME))
diff --git a/mysys/my_fstream.c b/mysys/my_fstream.c
index f3b5418b906..2059e1a9f18 100644
--- a/mysys/my_fstream.c
+++ b/mysys/my_fstream.c
@@ -56,11 +56,11 @@ size_t my_fread(FILE *stream, uchar *Buffer, size_t Count, myf MyFlags)
{
if (ferror(stream))
my_error(EE_READ, MYF(ME_BELL+ME_WAITTANG),
- my_filename(fileno(stream)),errno);
+ my_filename(my_fileno(stream)),errno);
else
if (MyFlags & (MY_NABP | MY_FNABP))
my_error(EE_EOFERR, MYF(ME_BELL+ME_WAITTANG),
- my_filename(fileno(stream)),errno);
+ my_filename(my_fileno(stream)),errno);
}
my_errno=errno ? errno : -1;
if (ferror(stream) || MyFlags & (MY_NABP | MY_FNABP))
@@ -142,7 +142,7 @@ size_t my_fwrite(FILE *stream, const uchar *Buffer, size_t Count, myf MyFlags)
if (MyFlags & (MY_WME | MY_FAE | MY_FNABP))
{
my_error(EE_WRITE, MYF(ME_BELL+ME_WAITTANG),
- my_filename(fileno(stream)),errno);
+ my_filename(my_fileno(stream)),errno);
}
writtenbytes= (size_t) -1; /* Return that we got error */
break;
@@ -182,3 +182,14 @@ my_off_t my_ftell(FILE *stream, myf MyFlags __attribute__((unused)))
DBUG_PRINT("exit",("ftell: %lu",(ulong) pos));
DBUG_RETURN((my_off_t) pos);
} /* my_ftell */
+
+
+/* Get a File corresponding to the stream*/
+int my_fileno(FILE *f)
+{
+#ifdef _WIN32
+ return my_win_fileno(f);
+#else
+ return fileno(f);
+#endif
+}
diff --git a/mysys/my_getsystime.c b/mysys/my_getsystime.c
index 6bffcd65d30..cb063e27c1f 100644
--- a/mysys/my_getsystime.c
+++ b/mysys/my_getsystime.c
@@ -14,224 +14,102 @@
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 __NETWARE__
#include <nks/time.h>
+#elif defined(__WIN__)
+#define OFFSET_TO_EPOC 116444736000000000LL
+static ulonglong query_performance_frequency;
#endif
#ifdef HAVE_LINUX_UNISTD_H
#include <linux/unistd.h>
#endif
+/*
+ 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
-ulonglong my_getsystime()
+ 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;
#elif defined(__NETWARE__)
NXTime_t tm;
NXGetTime(NX_SINCE_1970, NX_NSECONDS, &tm);
- return (ulonglong)tm/100;
+ return (ulonglong)tm;
#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;
+ return tv.tv_sec*1000000000ULL+tv.tv_usec*1000ULL;
#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;
-#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
- Value in microseconds from some undefined point in time
-*/
-
-ulonglong my_micro_time()
-{
-#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 current time in HRTIME_RESOLUTION (microseconds) since epoch */
- RETURN
- Value in microseconds from some undefined point in time
-*/
-
-#define DELTA_FOR_SECONDS LL(500000000) /* Half a second */
-
-ulonglong my_micro_time_and_time(time_t *time_arg)
+my_hrtime_t my_hrtime()
{
+ my_hrtime_t hrtime;
#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;
-
- pthread_mutex_lock(&THR_LOCK_time);
- cur_gethrtime= gethrtime();
- /*
- Due to bugs in the Solaris (x86) implementation of gethrtime(),
- the time returned by it might not be monotonic. Don't use the
- cached time(2) value if this is a case.
- */
- if ((prev_gethrtime > cur_gethrtime) ||
- ((cur_gethrtime - prev_gethrtime) > DELTA_FOR_SECONDS))
- {
- cur_time= time(0);
- prev_gethrtime= cur_gethrtime;
- }
- *time_arg= cur_time;
- pthread_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 071b3d82f6c..6213ab188cc 100644
--- a/mysys/my_handler_errors.h
+++ b/mysys/my_handler_errors.h
@@ -63,5 +63,7 @@ static const char *handler_error_messages[]=
"File too short; Expected more data in file",
"Read page with wrong checksum",
"Too many active concurrent transactions",
- "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"
};
diff --git a/mysys/my_init.c b/mysys/my_init.c
index 0b0d7d85f15..bb9900b425c 100644
--- a/mysys/my_init.c
+++ b/mysys/my_init.c
@@ -104,6 +104,7 @@ my_bool my_init(void)
DBUG_PROCESS((char*) (my_progname ? my_progname : "unknown"));
if (!home_dir)
{ /* Don't initialize twice */
+ my_time_init();
my_win_init();
if ((home_dir=getenv("HOME")) != 0)
home_dir=intern_filename(home_dir_buff,home_dir);
@@ -260,7 +261,6 @@ void my_debug_put_break_here(void)
#ifdef __WIN__
-
/*
my_parameter_handler
@@ -276,6 +276,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();
}
@@ -300,7 +301,7 @@ 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)
@@ -334,54 +335,6 @@ static void my_win_init(void)
_tzset();
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- /* The following is used by time functions */
-#define OFFSET_TO_EPOC ((__int64) 134774 * 24 * 60 * 60 * 1000 * 1000 * 10)
-#define MS 10000000
- {
- 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
diff --git a/mysys/my_lib.c b/mysys/my_lib.c
index c18d14fb549..033f8789b49 100644
--- a/mysys/my_lib.c
+++ b/mysys/my_lib.c
@@ -35,8 +35,7 @@
# if defined(HAVE_NDIR_H)
# include <ndir.h>
# endif
-# if defined(__WIN__)
-# include <dos.h>
+# if defined(_WIN32)
# ifdef __BORLANDC__
# include <dir.h>
# endif
@@ -92,7 +91,7 @@ static int comp_names(struct fileinfo *a, struct fileinfo *b)
} /* comp_names */
-#if !defined(__WIN__)
+#if !defined(_WIN32)
MY_DIR *my_dir(const char *path, myf MyFlags)
{
@@ -507,19 +506,24 @@ error:
DBUG_RETURN((MY_DIR *) NULL);
} /* my_dir */
-#endif /* __WIN__ */
+#endif /* _WIN32 */
/****************************************************************************
** File status
** Note that MY_STAT is assumed to be same as struct stat
****************************************************************************/
-int my_fstat(int Filedes, MY_STAT *stat_area,
+
+int my_fstat(File Filedes, MY_STAT *stat_area,
myf MyFlags __attribute__((unused)))
{
DBUG_ENTER("my_fstat");
DBUG_PRINT("my",("fd: %d MyFlags: %d", Filedes, MyFlags));
+#ifdef _WIN32
+ DBUG_RETURN(my_win_fstat(Filedes, stat_area));
+#else
DBUG_RETURN(fstat(Filedes, (struct stat *) stat_area));
+#endif
}
@@ -531,11 +535,15 @@ MY_STAT *my_stat(const char *path, MY_STAT *stat_area, myf my_flags)
(long) stat_area, my_flags));
if ((m_used= (stat_area == NULL)))
- if (!(stat_area = (MY_STAT *) my_malloc(sizeof(MY_STAT), my_flags)))
+ if (!(stat_area= (MY_STAT *) my_malloc(sizeof(MY_STAT), my_flags)))
goto error;
- if (! stat((char *) path, (struct stat *) stat_area) )
- DBUG_RETURN(stat_area);
-
+#ifndef _WIN32
+ if (! stat((char *) path, (struct stat *) stat_area) )
+ DBUG_RETURN(stat_area);
+#else
+ if (! my_win_stat(path, stat_area) )
+ DBUG_RETURN(stat_area);
+#endif
DBUG_PRINT("error",("Got errno: %d from stat", errno));
my_errno= errno;
if (m_used) /* Free if new area */
diff --git a/mysys/my_lock.c b/mysys/my_lock.c
index 8450fcfc30a..6bbb177e4b6 100644
--- a/mysys/my_lock.c
+++ b/mysys/my_lock.c
@@ -22,13 +22,113 @@
#undef NO_ALARM_LOOP
#endif
#include <my_alarm.h>
-#ifdef __WIN__
-#include <sys/locking.h>
-#endif
#ifdef __NETWARE__
#include <nks/fsio.h>
#endif
+#ifdef _WIN32
+#define WIN_LOCK_INFINITE -1
+#define WIN_LOCK_SLEEP_MILLIS 100
+
+static int win_lock(File fd, int locktype, my_off_t start, my_off_t length,
+ int timeout_sec)
+{
+ LARGE_INTEGER liOffset,liLength;
+ DWORD dwFlags;
+ OVERLAPPED ov= {0};
+ HANDLE hFile= (HANDLE)my_get_osfhandle(fd);
+ DWORD lastError= 0;
+ int i;
+ int timeout_millis= timeout_sec * 1000;
+
+ DBUG_ENTER("win_lock");
+
+ liOffset.QuadPart= start;
+ liLength.QuadPart= length;
+
+ ov.Offset= liOffset.LowPart;
+ ov.OffsetHigh= liOffset.HighPart;
+
+ if (locktype == F_UNLCK)
+ {
+ if (UnlockFileEx(hFile, 0, liLength.LowPart, liLength.HighPart, &ov))
+ DBUG_RETURN(0);
+ /*
+ For compatibility with fcntl implementation, ignore error,
+ if region was not locked
+ */
+ if (GetLastError() == ERROR_NOT_LOCKED)
+ {
+ SetLastError(0);
+ DBUG_RETURN(0);
+ }
+ goto error;
+ }
+ else if (locktype == F_RDLCK)
+ /* read lock is mapped to a shared lock. */
+ dwFlags= 0;
+ else
+ /* write lock is mapped to an exclusive lock. */
+ dwFlags= LOCKFILE_EXCLUSIVE_LOCK;
+
+ /*
+ Drop old lock first to avoid double locking.
+ During analyze of Bug#38133 (Myisamlog test fails on Windows)
+ I met the situation that the program myisamlog locked the file
+ exclusively, then additionally shared, then did one unlock, and
+ then blocked on an attempt to lock it exclusively again.
+ Unlocking before every lock fixed the problem.
+ Note that this introduces a race condition. When the application
+ wants to convert an exclusive lock into a shared one, it will now
+ first unlock the file and then lock it shared. A waiting exclusive
+ lock could step in here. For reasons described in Bug#38133 and
+ Bug#41124 (Server hangs on Windows with --external-locking after
+ INSERT...SELECT) and in the review thread at
+ http://lists.mysql.com/commits/60721 it seems to be the better
+ option than not to unlock here.
+ If one day someone notices a way how to do file lock type changes
+ on Windows without unlocking before taking the new lock, please
+ change this code accordingly to fix the race condition.
+ */
+ if (!UnlockFileEx(hFile, 0, liLength.LowPart, liLength.HighPart, &ov) &&
+ (GetLastError() != ERROR_NOT_LOCKED))
+ goto error;
+
+ if (timeout_sec == WIN_LOCK_INFINITE)
+ {
+ if (LockFileEx(hFile, dwFlags, 0, liLength.LowPart, liLength.HighPart, &ov))
+ DBUG_RETURN(0);
+ goto error;
+ }
+
+ dwFlags|= LOCKFILE_FAIL_IMMEDIATELY;
+ timeout_millis= timeout_sec * 1000;
+ /* Try lock in a loop, until the lock is acquired or timeout happens */
+ for(i= 0; ;i+= WIN_LOCK_SLEEP_MILLIS)
+ {
+ if (LockFileEx(hFile, dwFlags, 0, liLength.LowPart, liLength.HighPart, &ov))
+ DBUG_RETURN(0);
+
+ if (GetLastError() != ERROR_LOCK_VIOLATION)
+ goto error;
+
+ if (i >= timeout_millis)
+ break;
+ Sleep(WIN_LOCK_SLEEP_MILLIS);
+ }
+
+ /* timeout */
+ errno= EAGAIN;
+ DBUG_RETURN(-1);
+
+error:
+ my_osmaperr(GetLastError());
+ DBUG_RETURN(-1);
+}
+#endif
+
+
+
/*
Lock a part of a file
@@ -97,29 +197,16 @@ int my_lock(File fd, int locktype, my_off_t start, my_off_t length,
DBUG_RETURN(0);
}
}
-#elif defined(HAVE_LOCKING)
- /* Windows */
+#elif defined(_WIN32)
{
- my_bool error= FALSE;
- pthread_mutex_lock(&my_file_info[fd].mutex);
- if (MyFlags & MY_SEEK_NOT_DONE)
- {
- if( my_seek(fd,start,MY_SEEK_SET,MYF(MyFlags & ~MY_SEEK_NOT_DONE))
- == MY_FILEPOS_ERROR )
- {
- /*
- If my_seek fails my_errno will already contain an error code;
- just unlock and return error code.
- */
- DBUG_PRINT("error",("my_errno: %d (%d)",my_errno,errno));
- pthread_mutex_unlock(&my_file_info[fd].mutex);
- DBUG_RETURN(-1);
- }
- }
- error= locking(fd,locktype,(ulong) length) && errno != EINVAL;
- pthread_mutex_unlock(&my_file_info[fd].mutex);
- if (!error)
- DBUG_RETURN(0);
+ int timeout_sec;
+ if (MyFlags & MY_NO_WAIT)
+ timeout_sec= 0;
+ else
+ timeout_sec= WIN_LOCK_INFINITE;
+
+ if(win_lock(fd, locktype, start, length, timeout_sec) == 0)
+ DBUG_RETURN(0);
}
#else
#if defined(HAVE_FCNTL)
diff --git a/mysys/my_mmap.c b/mysys/my_mmap.c
index 023a06fd896..303d8efaf30 100644
--- a/mysys/my_mmap.c
+++ b/mysys/my_mmap.c
@@ -27,17 +27,17 @@ int my_msync(int fd, void *addr, size_t len, int flags)
return my_sync(fd, MYF(0));
}
-#elif defined(__WIN__)
+#elif defined(_WIN32)
static SECURITY_ATTRIBUTES mmap_security_attributes=
{sizeof(SECURITY_ATTRIBUTES), 0, TRUE};
void *my_mmap(void *addr, size_t len, int prot,
- int flags, int fd, my_off_t offset)
+ int flags, File fd, my_off_t offset)
{
HANDLE hFileMap;
LPVOID ptr;
- HANDLE hFile= (HANDLE)_get_osfhandle(fd);
+ HANDLE hFile= (HANDLE)my_get_osfhandle(fd);
if (hFile == INVALID_HANDLE_VALUE)
return MAP_FAILED;
diff --git a/mysys/my_open.c b/mysys/my_open.c
index 3980e3a9a77..dc2fcaf04c6 100644
--- a/mysys/my_open.c
+++ b/mysys/my_open.c
@@ -17,9 +17,7 @@
#include "mysys_err.h"
#include <my_dir.h>
#include <errno.h>
-#if defined(__WIN__)
-#include <share.h>
-#endif
+
/*
Open a file
@@ -45,30 +43,8 @@ File my_open(const char *FileName, int Flags, myf MyFlags)
FileName, Flags, MyFlags));
if (!(MyFlags & (MY_WME | MY_FAE | MY_FFNF)))
MyFlags|= my_global_flags;
-
-#if defined(__WIN__)
- /*
- Check that we don't try to open or create a file name that may
- cause problems for us in the future (like PRN)
- */
- if (check_if_legal_filename(FileName))
- {
- errno= EACCES;
- DBUG_RETURN(my_register_filename(-1, FileName, FILE_BY_OPEN,
- EE_FILENOTFOUND, MyFlags));
- }
-#ifndef __WIN__
- if (Flags & O_SHARE)
- fd = sopen((char *) FileName, (Flags & ~O_SHARE) | O_BINARY, SH_DENYNO,
- MY_S_IREAD | MY_S_IWRITE);
- else
- fd = open((char *) FileName, Flags | O_BINARY,
- MY_S_IREAD | MY_S_IWRITE);
-#else
- fd= my_sopen((char *) FileName, (Flags & ~O_SHARE) | O_BINARY, SH_DENYNO,
- MY_S_IREAD | MY_S_IWRITE);
-#endif
-
+#if defined(_WIN32)
+ fd= my_win_open(FileName, Flags);
#elif !defined(NO_OPEN_3)
fd = open(FileName, Flags, my_umask); /* Normal unix */
#else
@@ -99,11 +75,14 @@ int my_close(File fd, myf MyFlags)
MyFlags|= my_global_flags;
pthread_mutex_lock(&THR_LOCK_open);
+#ifndef _WIN32
do
{
err= close(fd);
} while (err == -1 && errno == EINTR);
-
+#else
+ err= my_win_close(fd);
+#endif
if (err)
{
DBUG_PRINT("error",("Got error %d on close",err));
@@ -115,9 +94,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, MYF(0));
-#if defined(THREAD) && !defined(HAVE_PREAD)
- pthread_mutex_destroy(&my_file_info[fd].mutex);
-#endif
my_file_info[fd].type = UNOPEN;
}
my_file_opened--;
@@ -147,16 +123,12 @@ File my_register_filename(File fd, const char *FileName, enum file_type
type_of_file, uint error_message_number, myf MyFlags)
{
DBUG_ENTER("my_register_filename");
- if ((int) fd >= 0)
+ if ((int) fd >= MY_FILE_MIN)
{
if ((uint) fd >= my_file_limit)
{
-#if defined(THREAD) && !defined(HAVE_PREAD)
- my_errno= EMFILE;
-#else
thread_safe_increment(my_file_opened,&THR_LOCK_open);
DBUG_RETURN(fd); /* safeguard */
-#endif
}
else
{
@@ -166,9 +138,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(THREAD) && !defined(HAVE_PREAD)
- pthread_mutex_init(&my_file_info[fd].mutex,MY_MUTEX_INIT_FAST);
-#endif
pthread_mutex_unlock(&THR_LOCK_open);
DBUG_PRINT("exit",("fd: %d",fd));
DBUG_RETURN(fd);
@@ -193,188 +162,7 @@ File my_register_filename(File fd, const char *FileName, enum file_type
DBUG_RETURN(-1);
}
-#ifdef __WIN__
-
-extern void __cdecl _dosmaperr(unsigned long);
-
-/*
- Open a file with sharing. Similar to _sopen() from libc, but allows managing
- share delete on win32
-
- SYNOPSIS
- my_sopen()
- path fully qualified file name
- oflag operation flags
- shflag share flag
- pmode permission flags
-
- RETURN VALUE
- File descriptor of opened file if success
- -1 and sets errno if fails.
-*/
-
-File my_sopen(const char *path, int oflag, int shflag, int pmode)
-{
- int fh; /* handle of opened file */
- int mask;
- HANDLE osfh; /* OS handle of opened file */
- DWORD fileaccess; /* OS file access (requested) */
- DWORD fileshare; /* OS file sharing mode */
- DWORD filecreate; /* OS method of opening/creating */
- DWORD fileattrib; /* OS file attribute flags */
- SECURITY_ATTRIBUTES SecurityAttributes;
-
- SecurityAttributes.nLength= sizeof(SecurityAttributes);
- SecurityAttributes.lpSecurityDescriptor= NULL;
- SecurityAttributes.bInheritHandle= !(oflag & _O_NOINHERIT);
- /*
- * decode the access flags
- */
- switch (oflag & (_O_RDONLY | _O_WRONLY | _O_RDWR)) {
- case _O_RDONLY: /* read access */
- fileaccess= GENERIC_READ;
- break;
- case _O_WRONLY: /* write access */
- fileaccess= GENERIC_WRITE;
- break;
- case _O_RDWR: /* read and write access */
- fileaccess= GENERIC_READ | GENERIC_WRITE;
- break;
- default: /* error, bad oflag */
- errno= EINVAL;
- _doserrno= 0L; /* not an OS error */
- return -1;
- }
-
- /*
- * decode sharing flags
- */
- switch (shflag) {
- case _SH_DENYRW: /* exclusive access except delete */
- fileshare= FILE_SHARE_DELETE;
- break;
- case _SH_DENYWR: /* share read and delete access */
- fileshare= FILE_SHARE_READ | FILE_SHARE_DELETE;
- break;
- case _SH_DENYRD: /* share write and delete access */
- fileshare= FILE_SHARE_WRITE | FILE_SHARE_DELETE;
- break;
- case _SH_DENYNO: /* share read, write and delete access */
- fileshare= FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE;
- break;
- case _SH_DENYRWD: /* exclusive access */
- fileshare= 0L;
- break;
- case _SH_DENYWRD: /* share read access */
- fileshare= FILE_SHARE_READ;
- break;
- case _SH_DENYRDD: /* share write access */
- fileshare= FILE_SHARE_WRITE;
- break;
- case _SH_DENYDEL: /* share read and write access */
- fileshare= FILE_SHARE_READ | FILE_SHARE_WRITE;
- break;
- default: /* error, bad shflag */
- errno= EINVAL;
- _doserrno= 0L; /* not an OS error */
- return -1;
- }
-
- /*
- * decode open/create method flags
- */
- switch (oflag & (_O_CREAT | _O_EXCL | _O_TRUNC)) {
- case 0:
- case _O_EXCL: /* ignore EXCL w/o CREAT */
- filecreate= OPEN_EXISTING;
- break;
-
- case _O_CREAT:
- filecreate= OPEN_ALWAYS;
- break;
-
- case _O_CREAT | _O_EXCL:
- case _O_CREAT | _O_TRUNC | _O_EXCL:
- filecreate= CREATE_NEW;
- break;
-
- case _O_TRUNC:
- case _O_TRUNC | _O_EXCL: /* ignore EXCL w/o CREAT */
- filecreate= TRUNCATE_EXISTING;
- break;
-
- case _O_CREAT | _O_TRUNC:
- filecreate= CREATE_ALWAYS;
- break;
-
- default:
- /* this can't happen ... all cases are covered */
- errno= EINVAL;
- _doserrno= 0L;
- return -1;
- }
-
- /*
- * decode file attribute flags if _O_CREAT was specified
- */
- fileattrib= FILE_ATTRIBUTE_NORMAL; /* default */
- if (oflag & _O_CREAT)
- {
- _umask((mask= _umask(0)));
-
- if (!((pmode & ~mask) & _S_IWRITE))
- fileattrib= FILE_ATTRIBUTE_READONLY;
- }
-
- /*
- * Set temporary file (delete-on-close) attribute if requested.
- */
- if (oflag & _O_TEMPORARY)
- {
- fileattrib|= FILE_FLAG_DELETE_ON_CLOSE;
- fileaccess|= DELETE;
- }
-
- /*
- * Set temporary file (delay-flush-to-disk) attribute if requested.
- */
- if (oflag & _O_SHORT_LIVED)
- fileattrib|= FILE_ATTRIBUTE_TEMPORARY;
-
- /*
- * Set sequential or random access attribute if requested.
- */
- if (oflag & _O_SEQUENTIAL)
- fileattrib|= FILE_FLAG_SEQUENTIAL_SCAN;
- else if (oflag & _O_RANDOM)
- fileattrib|= FILE_FLAG_RANDOM_ACCESS;
-
- /*
- * try to open/create the file
- */
- if ((osfh= CreateFile(path, fileaccess, fileshare, &SecurityAttributes,
- filecreate, fileattrib, NULL)) == INVALID_HANDLE_VALUE)
- {
- /*
- * OS call to open/create file failed! map the error, release
- * the lock, and return -1. note that it's not necessary to
- * call _free_osfhnd (it hasn't been used yet).
- */
- _dosmaperr(GetLastError()); /* map error */
- return -1; /* return error to caller */
- }
-
- if ((fh= _open_osfhandle((intptr_t)osfh,
- oflag & (_O_APPEND | _O_RDONLY | _O_TEXT))) == -1)
- {
- _dosmaperr(GetLastError()); /* map error */
- CloseHandle(osfh);
- }
-
- return fh; /* return handle */
-}
-#endif /* __WIN__ */
#ifdef EXTRA_DEBUG
diff --git a/mysys/my_pread.c b/mysys/my_pread.c
index 5d991f849c9..f8799561c09 100644
--- a/mysys/my_pread.c
+++ b/mysys/my_pread.c
@@ -18,7 +18,7 @@
#include "my_base.h"
#include <m_string.h>
#include <errno.h>
-#ifdef HAVE_PREAD
+#ifndef _WIN32
#include <unistd.h>
#endif
@@ -48,9 +48,7 @@ size_t my_pread(File Filedes, uchar *Buffer, size_t Count, my_off_t offset,
{
size_t readbytes;
int error= 0;
-#ifndef HAVE_PREAD
- int save_errno;
-#endif
+
#ifndef DBUG_OFF
char llbuf[22];
DBUG_ENTER("my_pread");
@@ -64,20 +62,15 @@ size_t my_pread(File Filedes, uchar *Buffer, size_t Count, my_off_t offset,
for (;;)
{
errno= 0; /* Linux, Windows don't reset this on EOF/success */
-#ifndef HAVE_PREAD
- pthread_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, (uint) Count)) != Count);
- save_errno= errno;
- pthread_mutex_unlock(&my_file_info[Filedes].mutex);
- if (error)
- {
- errno= save_errno;
+#ifdef _WIN32
+ readbytes= my_win_pread(Filedes, Buffer, Count, offset);
#else
- if ((error= ((readbytes= pread(Filedes, Buffer, Count, offset)) != Count)))
- {
+ readbytes= pread(Filedes, Buffer, Count, offset);
#endif
+ error = (readbytes != Count);
+
+ if (error)
+ {
my_errno= errno ? errno : -1;
if (errno == 0 || (readbytes != (size_t) -1 &&
(MyFlags & (MY_NABP | MY_FNABP))))
@@ -104,11 +97,11 @@ size_t my_pread(File Filedes, uchar *Buffer, size_t Count, my_off_t offset,
my_filename(Filedes),my_errno);
}
if (readbytes == (size_t) -1 || (MyFlags & (MY_FNABP | MY_NABP)))
- DBUG_RETURN(MY_FILE_ERROR); /* Return with error */
+ DBUG_RETURN(MY_FILE_ERROR); /* Return with error */
}
if (MyFlags & (MY_NABP | MY_FNABP))
- DBUG_RETURN(0); /* Read went ok; Return 0 */
- DBUG_RETURN(readbytes); /* purecov: inspected */
+ DBUG_RETURN(0); /* Read went ok; Return 0 */
+ DBUG_RETURN(readbytes); /* purecov: inspected */
}
} /* my_pread */
@@ -137,7 +130,7 @@ size_t my_pread(File Filedes, uchar *Buffer, size_t Count, my_off_t offset,
size_t my_pwrite(int Filedes, const uchar *Buffer, size_t Count,
my_off_t offset, myf MyFlags)
{
- size_t writenbytes, written;
+ size_t writtenbytes, written;
uint errors;
#ifndef DBUG_OFF
char llbuf[22];
@@ -153,28 +146,22 @@ size_t my_pwrite(int Filedes, const uchar *Buffer, size_t Count,
for (;;)
{
-#ifndef HAVE_PREAD
- int error;
- writenbytes= (size_t) -1;
- pthread_mutex_lock(&my_file_info[Filedes].mutex);
- error= (lseek(Filedes, offset, MY_SEEK_SET) != (my_off_t) -1 &&
- (writenbytes = write(Filedes, Buffer, (uint) Count)) == Count);
- pthread_mutex_unlock(&my_file_info[Filedes].mutex);
- if (error)
- break;
+#ifdef _WIN32
+ writtenbytes= my_win_pwrite(Filedes, Buffer, Count,offset);
#else
- if ((writenbytes= pwrite(Filedes, Buffer, Count,offset)) == Count)
+ writtenbytes= pwrite(Filedes, Buffer, Count, offset);
+#endif
+ if (writtenbytes == Count)
break;
my_errno= errno;
-#endif
- if (writenbytes != (size_t) -1)
+ if (writtenbytes != (size_t) -1)
{ /* Safegueard */
- written+=writenbytes;
- Buffer+=writenbytes;
- Count-=writenbytes;
- offset+=writenbytes;
+ written+=writtenbytes;
+ Buffer+=writtenbytes;
+ Count-=writtenbytes;
+ offset+=writtenbytes;
}
- DBUG_PRINT("error",("Write only %u bytes", (uint) writenbytes));
+ DBUG_PRINT("error",("Write only %u bytes", (uint) writtenbytes));
#ifndef NO_BACKGROUND
#ifdef THREAD
if (my_thread_var->abort)
@@ -187,7 +174,7 @@ size_t my_pwrite(int Filedes, const uchar *Buffer, size_t Count,
errors++;
continue;
}
- if ((writenbytes && writenbytes != (size_t) -1) || my_errno == EINTR)
+ if ((writtenbytes && writtenbytes != (size_t) -1) || my_errno == EINTR)
continue; /* Retry */
#endif
@@ -204,5 +191,5 @@ size_t my_pwrite(int Filedes, const uchar *Buffer, size_t Count,
DBUG_EXECUTE_IF("check", my_seek(Filedes, -1, SEEK_SET, MYF(0)););
if (MyFlags & (MY_NABP | MY_FNABP))
DBUG_RETURN(0); /* Want only errors */
- DBUG_RETURN(writenbytes+written); /* purecov: inspected */
+ DBUG_RETURN(writtenbytes+written); /* purecov: inspected */
} /* my_pwrite */
diff --git a/mysys/my_quick.c b/mysys/my_quick.c
index 0ba20a5bdee..b93e7e17224 100644
--- a/mysys/my_quick.c
+++ b/mysys/my_quick.c
@@ -19,11 +19,19 @@
#include "my_nosys.h"
+#ifdef _WIN32
+extern size_t my_win_read(File Filedes,uchar *Buffer,size_t Count);
+#endif
+
size_t my_quick_read(File Filedes,uchar *Buffer,size_t Count,myf MyFlags)
{
size_t readbytes;
-
- if ((readbytes = read(Filedes, Buffer, (uint) Count)) != Count)
+#ifdef _WIN32
+ readbytes= my_win_read(Filedes, Buffer, Count);
+#else
+ readbytes= read(Filedes, Buffer, Count);
+#endif
+ if(readbytes != Count)
{
#ifndef DBUG_OFF
if ((readbytes == 0 || readbytes == (size_t) -1) && errno == EINTR)
@@ -40,8 +48,13 @@ size_t my_quick_read(File Filedes,uchar *Buffer,size_t Count,myf MyFlags)
}
-size_t my_quick_write(File Filedes,const uchar *Buffer,size_t Count)
+
+size_t my_quick_write(File Filedes, const uchar *Buffer, size_t Count)
{
+#ifdef _WIN32
+ return my_win_write(Filedes, Buffer, Count);
+#else
+
#ifndef DBUG_OFF
size_t writtenbytes;
#endif
@@ -50,7 +63,7 @@ size_t my_quick_write(File Filedes,const uchar *Buffer,size_t Count)
#ifndef DBUG_OFF
writtenbytes =
#endif
- (size_t) write(Filedes,Buffer, (uint) Count)) != Count)
+ (size_t) write(Filedes,Buffer,Count)) != Count)
{
#ifndef DBUG_OFF
if ((writtenbytes == 0 || writtenbytes == (size_t) -1) && errno == EINTR)
@@ -64,4 +77,5 @@ size_t my_quick_write(File Filedes,const uchar *Buffer,size_t Count)
return (size_t) -1;
}
return 0;
+#endif
}
diff --git a/mysys/my_read.c b/mysys/my_read.c
index e2023b14337..8ababb31324 100644
--- a/mysys/my_read.c
+++ b/mysys/my_read.c
@@ -46,7 +46,12 @@ size_t my_read(File Filedes, uchar *Buffer, size_t Count, myf MyFlags)
for (;;)
{
errno= 0; /* Linux, Windows don't reset this on EOF/success */
- if ((readbytes= read(Filedes, Buffer, (uint) Count)) != Count)
+#ifdef _WIN32
+ readbytes= my_win_read(Filedes, Buffer, Count);
+#else
+ readbytes= read(Filedes, Buffer, Count);
+#endif
+ if (readbytes != Count)
{
my_errno= errno;
if (errno == 0 || (readbytes != (size_t) -1 &&
diff --git a/mysys/my_seek.c b/mysys/my_seek.c
index d186d56869a..24941517487 100644
--- a/mysys/my_seek.c
+++ b/mysys/my_seek.c
@@ -56,16 +56,11 @@ 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(THREAD) && !defined(HAVE_PREAD)
- if (MyFlags & MY_THREADSAFE)
- {
- pthread_mutex_lock(&my_file_info[fd].mutex);
- newpos= lseek(fd, pos, whence);
- pthread_mutex_unlock(&my_file_info[fd].mutex);
- }
- else
+#ifdef _WIN32
+ newpos= my_win_lseek(fd, pos, whence);
+#else
+ newpos= lseek(fd, pos, whence);
#endif
- newpos= lseek(fd, pos, whence);
if (newpos == (os_off_t) -1)
{
my_errno= errno;
@@ -91,7 +86,9 @@ my_off_t my_tell(File fd, myf MyFlags)
DBUG_ENTER("my_tell");
DBUG_PRINT("my",("fd: %d MyFlags: %d",fd, MyFlags));
DBUG_ASSERT(fd >= 0);
-#ifdef HAVE_TELL
+#ifdef _WIN32
+ pos= my_seek(fd, 0, MY_SEEK_CUR,0);
+#elif defined(HAVE_TELL)
pos=tell(fd);
#else
pos=lseek(fd, 0L, MY_SEEK_CUR);
diff --git a/mysys/my_static.c b/mysys/my_static.c
index c519542c6f6..a117bed1496 100644
--- a/mysys/my_static.c
+++ b/mysys/my_static.c
@@ -37,7 +37,7 @@ my_bool my_assert_on_error= 0;
#ifndef THREAD
int NEAR my_errno=0;
#endif
-struct st_my_file_info my_file_info_default[MY_NFILE]= {{0,UNOPEN}};
+struct st_my_file_info my_file_info_default[MY_NFILE];
uint my_file_limit= MY_NFILE;
struct st_my_file_info *my_file_info= my_file_info_default;
@@ -114,11 +114,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 NEAR my_disable_locking=0;
my_bool NEAR my_disable_sync=0;
diff --git a/mysys/my_static.h b/mysys/my_static.h
index 90168b099a8..5e853c2a559 100644
--- a/mysys/my_static.h
+++ b/mysys/my_static.h
@@ -66,8 +66,6 @@ extern struct st_irem *sf_malloc_root;
extern struct st_my_file_info my_file_info_default[MY_NFILE];
-extern ulonglong query_performance_frequency, query_performance_offset;
-
#if defined(THREAD) && !defined(__WIN__)
extern sigset_t my_signals; /* signals blocked by mf_brkhant */
#endif
diff --git a/mysys/my_sync.c b/mysys/my_sync.c
index dae20b0163e..9c5fbce7ab7 100644
--- a/mysys/my_sync.c
+++ b/mysys/my_sync.c
@@ -71,7 +71,7 @@ int my_sync(File fd, myf my_flags)
if (res == -1 && errno == ENOLCK)
res= 0; /* Result Bug in Old FreeBSD */
#elif defined(__WIN__)
- res= _commit(fd);
+ res= my_win_fsync(fd);
#else
#error Cannot find a way to sync a file, durability in danger
res= 0; /* No sync (strange OS) */
diff --git a/mysys/my_uuid.c b/mysys/my_uuid.c
index e2372391b06..3df2dda2af5 100644
--- a/mysys/my_uuid.c
+++ b/mysys/my_uuid.c
@@ -47,6 +47,7 @@ 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 */
#ifdef THREAD
@@ -70,6 +71,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);
}
@@ -93,7 +96,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))
@@ -134,7 +137,7 @@ void my_uuid(uchar *to)
DBUG_ASSERT(my_uuid_inited);
pthread_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))
{
@@ -187,7 +190,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"));
}
@@ -228,7 +231,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 b869b22bdea..a6483ae61a3 100644
--- a/mysys/my_wincond.c
+++ b/mysys/my_wincond.c
@@ -26,7 +26,92 @@
#include <process.h>
#include <sys/timeb.h>
-int pthread_cond_init(pthread_cond_t *cond, const pthread_condattr_t *attr)
+
+/*
+ Windows native condition variables. We use runtime loading / function
+ pointers, because they are not available on XP
+*/
+
+/* Prototypes and function pointers for condition variable functions */
+typedef void (WINAPI * InitializeConditionVariableProc)
+ (PCONDITION_VARIABLE ConditionVariable);
+
+typedef BOOL (WINAPI * SleepConditionVariableCSProc)
+ (PCONDITION_VARIABLE ConditionVariable,
+ PCRITICAL_SECTION CriticalSection,
+ DWORD dwMilliseconds);
+
+typedef void (WINAPI * WakeAllConditionVariableProc)
+ (PCONDITION_VARIABLE ConditionVariable);
+
+typedef void (WINAPI * WakeConditionVariableProc)
+ (PCONDITION_VARIABLE ConditionVariable);
+
+static InitializeConditionVariableProc my_InitializeConditionVariable;
+static SleepConditionVariableCSProc my_SleepConditionVariableCS;
+static WakeAllConditionVariableProc my_WakeAllConditionVariable;
+static WakeConditionVariableProc my_WakeConditionVariable;
+
+
+/**
+ Indicates if we have native condition variables,
+ initialized first time pthread_cond_init is called.
+*/
+
+static BOOL have_native_conditions= FALSE;
+
+
+/**
+ Check if native conditions can be used, load function pointers
+*/
+
+static void check_native_cond_availability(void)
+{
+ HMODULE module= GetModuleHandle("kernel32");
+
+ my_InitializeConditionVariable= (InitializeConditionVariableProc)
+ GetProcAddress(module, "InitializeConditionVariable");
+ my_SleepConditionVariableCS= (SleepConditionVariableCSProc)
+ GetProcAddress(module, "SleepConditionVariableCS");
+ my_WakeAllConditionVariable= (WakeAllConditionVariableProc)
+ GetProcAddress(module, "WakeAllConditionVariable");
+ my_WakeConditionVariable= (WakeConditionVariableProc)
+ GetProcAddress(module, "WakeConditionVariable");
+
+ if (my_InitializeConditionVariable)
+ have_native_conditions= TRUE;
+}
+
+
+
+/**
+ Convert abstime to milliseconds
+*/
+
+static DWORD get_milliseconds(const struct timespec *abstime)
+{
+ struct timespec current_time;
+ long long ms;
+
+ if (abstime == NULL)
+ 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;
+}
+
+
+/*
+ Old (pre-vista) implementation using events
+*/
+
+static int legacy_cond_init(pthread_cond_t *cond, const pthread_condattr_t *attr)
{
cond->waiting= 0;
InitializeCriticalSection(&cond->lock_waiting);
@@ -55,7 +140,8 @@ int pthread_cond_init(pthread_cond_t *cond, const pthread_condattr_t *attr)
return 0;
}
-int pthread_cond_destroy(pthread_cond_t *cond)
+
+static int legacy_cond_destroy(pthread_cond_t *cond)
{
DeleteCriticalSection(&cond->lock_waiting);
@@ -67,41 +153,26 @@ int pthread_cond_destroy(pthread_cond_t *cond)
}
-int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex)
-{
- return pthread_cond_timedwait(cond,mutex,NULL);
-}
-
-
-int pthread_cond_timedwait(pthread_cond_t *cond, pthread_mutex_t *mutex,
+static int legacy_cond_timedwait(pthread_cond_t *cond, pthread_mutex_t *mutex,
struct timespec *abstime)
{
int result;
- long timeout;
- union ft64 now;
-
+ DWORD timeout;
+ long long timeout_us;
+ my_hrtime_t now;
+ my_hrtime_t then;
if( abstime != NULL )
{
- 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
- */
- timeout= (long)((abstime->tv.i64 - now.i64) / 10000);
-
- /* Don't allow the timeout to be negative */
- if (timeout < 0)
- timeout= 0L;
-
- /*
- Make sure the calucated timeout does not exceed original timeout
- value which could cause "wait for ever" if system time changes
- */
- if (timeout > abstime->max_timeout_msec)
- timeout= abstime->max_timeout_msec;
-
+ now= my_hrtime();
+ then.val= 1000000ULL*abstime->tv_sec + abstime->tv_nsec/1000;
+ timeout_us= then.val - now.val;
+
+ if (timeout_us < 0)
+ timeout= 0;
+ else if (timeout_us > 1000ULL*INFINITE)
+ timeout= INFINITE;
+ else
+ timeout= (DWORD)(timeout_us/1000);
}
else
{
@@ -144,7 +215,7 @@ int pthread_cond_timedwait(pthread_cond_t *cond, pthread_mutex_t *mutex,
return result == WAIT_TIMEOUT ? ETIMEDOUT : 0;
}
-int pthread_cond_signal(pthread_cond_t *cond)
+static int legacy_cond_signal(pthread_cond_t *cond)
{
EnterCriticalSection(&cond->lock_waiting);
@@ -157,7 +228,7 @@ int pthread_cond_signal(pthread_cond_t *cond)
}
-int pthread_cond_broadcast(pthread_cond_t *cond)
+static int legacy_cond_broadcast(pthread_cond_t *cond)
{
EnterCriticalSection(&cond->lock_waiting);
/*
@@ -179,6 +250,87 @@ int pthread_cond_broadcast(pthread_cond_t *cond)
}
+/*
+ Posix API functions. Just choose between native and legacy implementation.
+*/
+
+int pthread_cond_init(pthread_cond_t *cond, const pthread_condattr_t *attr)
+{
+ /*
+ Once initialization is used here rather than in my_init(), to
+ 1) avoid my_init() pitfalls- undefined order in which initialization should
+ run
+ 2) be potentially useful C++ (in static constructors that run before main())
+ 3) just to simplify the API.
+ Also, the overhead of my_pthread_once is very small.
+ */
+ static my_pthread_once_t once_control= MY_PTHREAD_ONCE_INIT;
+ my_pthread_once(&once_control, check_native_cond_availability);
+
+ if (have_native_conditions)
+ {
+ my_InitializeConditionVariable(&cond->native_cond);
+ return 0;
+ }
+ else
+ return legacy_cond_init(cond, attr);
+}
+
+
+int pthread_cond_destroy(pthread_cond_t *cond)
+{
+ if (have_native_conditions)
+ return 0; /* no destroy function */
+ else
+ return legacy_cond_destroy(cond);
+}
+
+
+int pthread_cond_broadcast(pthread_cond_t *cond)
+{
+ if (have_native_conditions)
+ {
+ my_WakeAllConditionVariable(&cond->native_cond);
+ return 0;
+ }
+ else
+ return legacy_cond_broadcast(cond);
+}
+
+
+int pthread_cond_signal(pthread_cond_t *cond)
+{
+ if (have_native_conditions)
+ {
+ my_WakeConditionVariable(&cond->native_cond);
+ return 0;
+ }
+ else
+ return legacy_cond_signal(cond);
+}
+
+
+int pthread_cond_timedwait(pthread_cond_t *cond, pthread_mutex_t *mutex,
+ struct timespec *abstime)
+{
+ if (have_native_conditions)
+ {
+ DWORD timeout= get_milliseconds(abstime);
+ if (!my_SleepConditionVariableCS(&cond->native_cond, mutex, timeout))
+ return ETIMEDOUT;
+ return 0;
+ }
+ else
+ return legacy_cond_timedwait(cond, mutex, abstime);
+}
+
+
+int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex)
+{
+ return pthread_cond_timedwait(cond, mutex, NULL);
+}
+
+
int pthread_attr_init(pthread_attr_t *connect_att)
{
connect_att->dwStackSize = 0;
diff --git a/mysys/my_winerr.c b/mysys/my_winerr.c
new file mode 100644
index 00000000000..534078b6737
--- /dev/null
+++ b/mysys/my_winerr.c
@@ -0,0 +1,123 @@
+/* Copyright (C) 2008 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
+the Free Software Foundation; version 2 of the License.
+
+This program 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 General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+/*
+ Convert Windows API error (GetLastError() to Posix equivalent (errno)
+ The exported function my_osmaperr() is modelled after and borrows
+ heavily from undocumented _dosmaperr()(found of the static Microsoft C runtime).
+*/
+
+#include <my_global.h>
+#include <my_sys.h>
+
+
+struct errentry
+{
+ unsigned long oscode; /* OS return value */
+ int sysv_errno; /* System V error code */
+};
+
+static struct errentry errtable[]= {
+ { ERROR_INVALID_FUNCTION, EINVAL }, /* 1 */
+ { ERROR_FILE_NOT_FOUND, ENOENT }, /* 2 */
+ { ERROR_PATH_NOT_FOUND, ENOENT }, /* 3 */
+ { ERROR_TOO_MANY_OPEN_FILES, EMFILE }, /* 4 */
+ { ERROR_ACCESS_DENIED, EACCES }, /* 5 */
+ { ERROR_INVALID_HANDLE, EBADF }, /* 6 */
+ { ERROR_ARENA_TRASHED, ENOMEM }, /* 7 */
+ { ERROR_NOT_ENOUGH_MEMORY, ENOMEM }, /* 8 */
+ { ERROR_INVALID_BLOCK, ENOMEM }, /* 9 */
+ { ERROR_BAD_ENVIRONMENT, E2BIG }, /* 10 */
+ { ERROR_BAD_FORMAT, ENOEXEC }, /* 11 */
+ { ERROR_INVALID_ACCESS, EINVAL }, /* 12 */
+ { ERROR_INVALID_DATA, EINVAL }, /* 13 */
+ { ERROR_INVALID_DRIVE, ENOENT }, /* 15 */
+ { ERROR_CURRENT_DIRECTORY, EACCES }, /* 16 */
+ { ERROR_NOT_SAME_DEVICE, EXDEV }, /* 17 */
+ { ERROR_NO_MORE_FILES, ENOENT }, /* 18 */
+ { ERROR_LOCK_VIOLATION, EACCES }, /* 33 */
+ { ERROR_BAD_NETPATH, ENOENT }, /* 53 */
+ { ERROR_NETWORK_ACCESS_DENIED, EACCES }, /* 65 */
+ { ERROR_BAD_NET_NAME, ENOENT }, /* 67 */
+ { ERROR_FILE_EXISTS, EEXIST }, /* 80 */
+ { ERROR_CANNOT_MAKE, EACCES }, /* 82 */
+ { ERROR_FAIL_I24, EACCES }, /* 83 */
+ { ERROR_INVALID_PARAMETER, EINVAL }, /* 87 */
+ { ERROR_NO_PROC_SLOTS, EAGAIN }, /* 89 */
+ { ERROR_DRIVE_LOCKED, EACCES }, /* 108 */
+ { ERROR_BROKEN_PIPE, EPIPE }, /* 109 */
+ { ERROR_DISK_FULL, ENOSPC }, /* 112 */
+ { ERROR_INVALID_TARGET_HANDLE, EBADF }, /* 114 */
+ { ERROR_INVALID_HANDLE, EINVAL }, /* 124 */
+ { ERROR_WAIT_NO_CHILDREN, ECHILD }, /* 128 */
+ { ERROR_CHILD_NOT_COMPLETE, ECHILD }, /* 129 */
+ { ERROR_DIRECT_ACCESS_HANDLE, EBADF }, /* 130 */
+ { ERROR_NEGATIVE_SEEK, EINVAL }, /* 131 */
+ { ERROR_SEEK_ON_DEVICE, EACCES }, /* 132 */
+ { ERROR_DIR_NOT_EMPTY, ENOTEMPTY }, /* 145 */
+ { ERROR_NOT_LOCKED, EACCES }, /* 158 */
+ { ERROR_BAD_PATHNAME, ENOENT }, /* 161 */
+ { ERROR_MAX_THRDS_REACHED, EAGAIN }, /* 164 */
+ { ERROR_LOCK_FAILED, EACCES }, /* 167 */
+ { ERROR_ALREADY_EXISTS, EEXIST }, /* 183 */
+ { ERROR_FILENAME_EXCED_RANGE, ENOENT }, /* 206 */
+ { ERROR_NESTING_NOT_ALLOWED, EAGAIN }, /* 215 */
+ { ERROR_NOT_ENOUGH_QUOTA, ENOMEM } /* 1816 */
+};
+
+/* size of the table */
+#define ERRTABLESIZE (sizeof(errtable)/sizeof(errtable[0]))
+
+/* The following two constants must be the minimum and maximum
+values in the (contiguous) range of Exec Failure errors. */
+#define MIN_EXEC_ERROR ERROR_INVALID_STARTING_CODESEG
+#define MAX_EXEC_ERROR ERROR_INFLOOP_IN_RELOC_CHAIN
+
+/* These are the low and high value in the range of errors that are
+access violations */
+#define MIN_EACCES_RANGE ERROR_WRITE_PROTECT
+#define MAX_EACCES_RANGE ERROR_SHARING_BUFFER_EXCEEDED
+
+
+static int get_errno_from_oserr(unsigned long oserrno)
+{
+ int i;
+
+ /* check the table for the OS error code */
+ for (i= 0; i < ERRTABLESIZE; ++i)
+ {
+ if (oserrno == errtable[i].oscode)
+ {
+ return errtable[i].sysv_errno;
+ }
+ }
+
+ /* The error code wasn't in the table. We check for a range of */
+ /* EACCES errors or exec failure errors (ENOEXEC). Otherwise */
+ /* EINVAL is returned. */
+
+ if (oserrno >= MIN_EACCES_RANGE && oserrno <= MAX_EACCES_RANGE)
+ return EACCES;
+ else if (oserrno >= MIN_EXEC_ERROR && oserrno <= MAX_EXEC_ERROR)
+ return ENOEXEC;
+ else
+ return EINVAL;
+}
+
+/* Set errno corresponsing to GetLastError() value */
+void my_osmaperr ( unsigned long oserrno)
+{
+ errno= get_errno_from_oserr(oserrno);
+}
diff --git a/mysys/my_winfile.c b/mysys/my_winfile.c
new file mode 100644
index 00000000000..f63c35ba47b
--- /dev/null
+++ b/mysys/my_winfile.c
@@ -0,0 +1,681 @@
+/* Copyright (C) 2008 MySQL AB, 2008-2009 Sun Microsystems, Inc
+
+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
+the Free Software Foundation; version 2 of the License.
+
+This program 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 General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+/*
+ The purpose of this file is to provide implementation of file IO routines on
+ Windows that can be thought as drop-in replacement for corresponding C runtime
+ functionality.
+
+ Compared to Windows CRT, this one
+ - does not have the same file descriptor
+ limitation (default is 16384 and can be increased further, whereas CRT poses
+ a hard limit of 2048 file descriptors)
+ - the file operations are not serialized
+ - positional IO pread/pwrite is ported here.
+ - no text mode for files, all IO is "binary"
+
+ Naming convention:
+ All routines are prefixed with my_win_, e.g Posix open() is implemented with
+ my_win_open()
+
+ Implemented are
+ - POSIX routines(e.g open, read, lseek ...)
+ - Some ANSI C stream routines (fopen, fdopen, fileno, fclose)
+ - Windows CRT equvalients (my_get_osfhandle, open_osfhandle)
+
+ Worth to note:
+ - File descriptors used here are located in a range that is not compatible
+ with CRT on purpose. Attempt to use a file descriptor from Windows CRT library
+ range in my_win_* function will be punished with DBUG_ASSERT()
+
+ - File streams (FILE *) are actually from the C runtime. The routines provided
+ here are useful only in scernarios that use low-level IO with my_win_fileno()
+*/
+
+#ifdef _WIN32
+
+#include "mysys_priv.h"
+#include <share.h>
+#include <sys/stat.h>
+
+/* Associates a file descriptor with an existing operating-system file handle.*/
+File my_open_osfhandle(HANDLE handle, int oflag)
+{
+ int offset= -1;
+ uint i;
+ DBUG_ENTER("my_open_osfhandle");
+
+ pthread_mutex_lock(&THR_LOCK_open);
+ for(i= MY_FILE_MIN; i < my_file_limit;i++)
+ {
+ if(my_file_info[i].fhandle == 0)
+ {
+ struct st_my_file_info *finfo= &(my_file_info[i]);
+ finfo->type= FILE_BY_OPEN;
+ finfo->fhandle= handle;
+ finfo->oflag= oflag;
+ offset= i;
+ break;
+ }
+ }
+ pthread_mutex_unlock(&THR_LOCK_open);
+ if(offset == -1)
+ errno= EMFILE; /* to many file handles open */
+ DBUG_RETURN(offset);
+}
+
+
+static void invalidate_fd(File fd)
+{
+ DBUG_ENTER("invalidate_fd");
+ DBUG_ASSERT(fd >= MY_FILE_MIN && fd < (int)my_file_limit);
+ my_file_info[fd].fhandle= 0;
+ DBUG_VOID_RETURN;
+}
+
+
+/* Get Windows handle for a file descriptor */
+HANDLE my_get_osfhandle(File fd)
+{
+ DBUG_ENTER("my_get_osfhandle");
+ DBUG_ASSERT(fd >= MY_FILE_MIN && fd < (int)my_file_limit);
+ DBUG_RETURN(my_file_info[fd].fhandle);
+}
+
+
+static int my_get_open_flags(File fd)
+{
+ DBUG_ENTER("my_get_open_flags");
+ DBUG_ASSERT(fd >= MY_FILE_MIN && fd < (int)my_file_limit);
+ DBUG_RETURN(my_file_info[fd].oflag);
+}
+
+
+/*
+ Open a file with sharing. Similar to _sopen() from libc, but allows managing
+ share delete on win32
+
+ SYNOPSIS
+ my_win_sopen()
+ path file name
+ oflag operation flags
+ shflag share flag
+ pmode permission flags
+
+ RETURN VALUE
+ File descriptor of opened file if success
+ -1 and sets errno if fails.
+*/
+
+File my_win_sopen(const char *path, int oflag, int shflag, int pmode)
+{
+ int fh; /* handle of opened file */
+ int mask;
+ HANDLE osfh; /* OS handle of opened file */
+ DWORD fileaccess; /* OS file access (requested) */
+ DWORD fileshare; /* OS file sharing mode */
+ DWORD filecreate; /* OS method of opening/creating */
+ DWORD fileattrib; /* OS file attribute flags */
+ SECURITY_ATTRIBUTES SecurityAttributes;
+
+ DBUG_ENTER("my_win_sopen");
+
+ if (check_if_legal_filename(path))
+ {
+ errno= EACCES;
+ DBUG_RETURN(-1);
+ }
+ SecurityAttributes.nLength= sizeof(SecurityAttributes);
+ SecurityAttributes.lpSecurityDescriptor= NULL;
+ SecurityAttributes.bInheritHandle= !(oflag & _O_NOINHERIT);
+
+ /* decode the access flags */
+ switch (oflag & (_O_RDONLY | _O_WRONLY | _O_RDWR)) {
+ case _O_RDONLY: /* read access */
+ fileaccess= GENERIC_READ;
+ break;
+ case _O_WRONLY: /* write access */
+ fileaccess= GENERIC_WRITE;
+ break;
+ case _O_RDWR: /* read and write access */
+ fileaccess= GENERIC_READ | GENERIC_WRITE;
+ break;
+ default: /* error, bad oflag */
+ errno= EINVAL;
+ DBUG_RETURN(-1);
+ }
+
+ /* decode sharing flags */
+ switch (shflag) {
+ case _SH_DENYRW: /* exclusive access except delete */
+ fileshare= FILE_SHARE_DELETE;
+ break;
+ case _SH_DENYWR: /* share read and delete access */
+ fileshare= FILE_SHARE_READ | FILE_SHARE_DELETE;
+ break;
+ case _SH_DENYRD: /* share write and delete access */
+ fileshare= FILE_SHARE_WRITE | FILE_SHARE_DELETE;
+ break;
+ case _SH_DENYNO: /* share read, write and delete access */
+ fileshare= FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE;
+ break;
+ case _SH_DENYRWD: /* exclusive access */
+ fileshare= 0L;
+ break;
+ case _SH_DENYWRD: /* share read access */
+ fileshare= FILE_SHARE_READ;
+ break;
+ case _SH_DENYRDD: /* share write access */
+ fileshare= FILE_SHARE_WRITE;
+ break;
+ case _SH_DENYDEL: /* share read and write access */
+ fileshare= FILE_SHARE_READ | FILE_SHARE_WRITE;
+ break;
+ default: /* error, bad shflag */
+ errno= EINVAL;
+ DBUG_RETURN(-1);
+ }
+
+ /* decode open/create method flags */
+ switch (oflag & (_O_CREAT | _O_EXCL | _O_TRUNC)) {
+ case 0:
+ case _O_EXCL: /* ignore EXCL w/o CREAT */
+ filecreate= OPEN_EXISTING;
+ break;
+
+ case _O_CREAT:
+ filecreate= OPEN_ALWAYS;
+ break;
+
+ case _O_CREAT | _O_EXCL:
+ case _O_CREAT | _O_TRUNC | _O_EXCL:
+ filecreate= CREATE_NEW;
+ break;
+
+ case _O_TRUNC:
+ case _O_TRUNC | _O_EXCL: /* ignore EXCL w/o CREAT */
+ filecreate= TRUNCATE_EXISTING;
+ break;
+
+ case _O_CREAT | _O_TRUNC:
+ filecreate= CREATE_ALWAYS;
+ break;
+
+ default:
+ /* this can't happen ... all cases are covered */
+ errno= EINVAL;
+ DBUG_RETURN(-1);
+ }
+
+ /* decode file attribute flags if _O_CREAT was specified */
+ fileattrib= FILE_ATTRIBUTE_NORMAL; /* default */
+ if (oflag & _O_CREAT)
+ {
+ _umask((mask= _umask(0)));
+
+ if (!((pmode & ~mask) & _S_IWRITE))
+ fileattrib= FILE_ATTRIBUTE_READONLY;
+ }
+
+ /* Set temporary file (delete-on-close) attribute if requested. */
+ if (oflag & _O_TEMPORARY)
+ {
+ fileattrib|= FILE_FLAG_DELETE_ON_CLOSE;
+ fileaccess|= DELETE;
+ }
+
+ /* Set temporary file (delay-flush-to-disk) attribute if requested.*/
+ if (oflag & _O_SHORT_LIVED)
+ fileattrib|= FILE_ATTRIBUTE_TEMPORARY;
+
+ /* Set sequential or random access attribute if requested. */
+ if (oflag & _O_SEQUENTIAL)
+ fileattrib|= FILE_FLAG_SEQUENTIAL_SCAN;
+ else if (oflag & _O_RANDOM)
+ fileattrib|= FILE_FLAG_RANDOM_ACCESS;
+
+ /* try to open/create the file */
+ if ((osfh= CreateFile(path, fileaccess, fileshare, &SecurityAttributes,
+ filecreate, fileattrib, NULL)) == INVALID_HANDLE_VALUE)
+ {
+ /*
+ OS call to open/create file failed! map the error, release
+ the lock, and return -1. note that it's not necessary to
+ call _free_osfhnd (it hasn't been used yet).
+ */
+ my_osmaperr(GetLastError()); /* map error */
+ DBUG_RETURN(-1); /* return error to caller */
+ }
+
+ if ((fh= my_open_osfhandle(osfh,
+ oflag & (_O_APPEND | _O_RDONLY | _O_TEXT))) == -1)
+ {
+ CloseHandle(osfh);
+ }
+
+ DBUG_RETURN(fh); /* return handle */
+}
+
+
+File my_win_open(const char *path, int flags)
+{
+ DBUG_ENTER("my_win_open");
+ DBUG_RETURN(my_win_sopen((char *) path, flags | _O_BINARY, _SH_DENYNO,
+ _S_IREAD | S_IWRITE));
+}
+
+
+int my_win_close(File fd)
+{
+ DBUG_ENTER("my_win_close");
+ if(CloseHandle(my_get_osfhandle(fd)))
+ {
+ invalidate_fd(fd);
+ DBUG_RETURN(0);
+ }
+ my_osmaperr(GetLastError());
+ DBUG_RETURN(-1);
+}
+
+
+size_t my_win_pread(File Filedes, uchar *Buffer, size_t Count, my_off_t offset)
+{
+ DWORD nBytesRead;
+ HANDLE hFile;
+ OVERLAPPED ov= {0};
+ LARGE_INTEGER li;
+
+ DBUG_ENTER("my_win_pread");
+
+ if(!Count)
+ DBUG_RETURN(0);
+#ifdef _WIN64
+ if(Count > UINT_MAX)
+ Count= UINT_MAX;
+#endif
+
+ hFile= (HANDLE)my_get_osfhandle(Filedes);
+ li.QuadPart= offset;
+ ov.Offset= li.LowPart;
+ ov.OffsetHigh= li.HighPart;
+
+ if(!ReadFile(hFile, Buffer, (DWORD)Count, &nBytesRead, &ov))
+ {
+ DWORD lastError= GetLastError();
+ /*
+ ERROR_BROKEN_PIPE is returned when no more data coming
+ through e.g. a command pipe in windows : see MSDN on ReadFile.
+ */
+ if(lastError == ERROR_HANDLE_EOF || lastError == ERROR_BROKEN_PIPE)
+ DBUG_RETURN(0); /*return 0 at EOF*/
+ my_osmaperr(lastError);
+ DBUG_RETURN((size_t)-1);
+ }
+ DBUG_RETURN(nBytesRead);
+}
+
+
+size_t my_win_read(File Filedes, uchar *Buffer, size_t Count)
+{
+ DWORD nBytesRead;
+ HANDLE hFile;
+
+ DBUG_ENTER("my_win_read");
+ if(!Count)
+ DBUG_RETURN(0);
+#ifdef _WIN64
+ if(Count > UINT_MAX)
+ Count= UINT_MAX;
+#endif
+
+ hFile= (HANDLE)my_get_osfhandle(Filedes);
+
+ if(!ReadFile(hFile, Buffer, (DWORD)Count, &nBytesRead, NULL))
+ {
+ DWORD lastError= GetLastError();
+ /*
+ ERROR_BROKEN_PIPE is returned when no more data coming
+ through e.g. a command pipe in windows : see MSDN on ReadFile.
+ */
+ if(lastError == ERROR_HANDLE_EOF || lastError == ERROR_BROKEN_PIPE)
+ DBUG_RETURN(0); /*return 0 at EOF*/
+ my_osmaperr(lastError);
+ DBUG_RETURN((size_t)-1);
+ }
+ DBUG_RETURN(nBytesRead);
+}
+
+
+size_t my_win_pwrite(File Filedes, const uchar *Buffer, size_t Count,
+ my_off_t offset)
+{
+ DWORD nBytesWritten;
+ HANDLE hFile;
+ OVERLAPPED ov= {0};
+ LARGE_INTEGER li;
+
+ DBUG_ENTER("my_win_pwrite");
+ DBUG_PRINT("my",("Filedes: %d, Buffer: %p, Count: %llu, offset: %llu",
+ Filedes, Buffer, (ulonglong)Count, (ulonglong)offset));
+
+ if(!Count)
+ DBUG_RETURN(0);
+
+#ifdef _WIN64
+ if(Count > UINT_MAX)
+ Count= UINT_MAX;
+#endif
+
+ hFile= (HANDLE)my_get_osfhandle(Filedes);
+ li.QuadPart= offset;
+ ov.Offset= li.LowPart;
+ ov.OffsetHigh= li.HighPart;
+
+ if(!WriteFile(hFile, Buffer, (DWORD)Count, &nBytesWritten, &ov))
+ {
+ my_osmaperr(GetLastError());
+ DBUG_RETURN((size_t)-1);
+ }
+ else
+ DBUG_RETURN(nBytesWritten);
+}
+
+
+my_off_t my_win_lseek(File fd, my_off_t pos, int whence)
+{
+ LARGE_INTEGER offset;
+ LARGE_INTEGER newpos;
+
+ DBUG_ENTER("my_win_lseek");
+
+ /* Check compatibility of Windows and Posix seek constants */
+ compile_time_assert(FILE_BEGIN == SEEK_SET && FILE_CURRENT == SEEK_CUR
+ && FILE_END == SEEK_END);
+
+ offset.QuadPart= pos;
+ if(!SetFilePointerEx(my_get_osfhandle(fd), offset, &newpos, whence))
+ {
+ my_osmaperr(GetLastError());
+ newpos.QuadPart= -1;
+ }
+ DBUG_RETURN(newpos.QuadPart);
+}
+
+
+#ifndef FILE_WRITE_TO_END_OF_FILE
+#define FILE_WRITE_TO_END_OF_FILE 0xffffffff
+#endif
+size_t my_win_write(File fd, const uchar *Buffer, size_t Count)
+{
+ DWORD nWritten;
+ OVERLAPPED ov;
+ OVERLAPPED *pov= NULL;
+ HANDLE hFile;
+
+ DBUG_ENTER("my_win_write");
+ DBUG_PRINT("my",("Filedes: %d, Buffer: %p, Count %llu", fd, Buffer,
+ (ulonglong)Count));
+
+ if(!Count)
+ DBUG_RETURN(0);
+
+#ifdef _WIN64
+ if(Count > UINT_MAX)
+ Count= UINT_MAX;
+#endif
+
+ if(my_get_open_flags(fd) & _O_APPEND)
+ {
+ /*
+ Atomic append to the end of file is is done by special initialization of
+ the OVERLAPPED structure. See MSDN WriteFile documentation for more info.
+ */
+ memset(&ov, 0, sizeof(ov));
+ ov.Offset= FILE_WRITE_TO_END_OF_FILE;
+ ov.OffsetHigh= -1;
+ pov= &ov;
+ }
+
+ hFile= my_get_osfhandle(fd);
+ if(!WriteFile(hFile, Buffer, (DWORD)Count, &nWritten, pov))
+ {
+ my_osmaperr(GetLastError());
+ DBUG_RETURN((size_t)-1);
+ }
+ DBUG_RETURN(nWritten);
+}
+
+
+int my_win_chsize(File fd, my_off_t newlength)
+{
+ HANDLE hFile;
+ LARGE_INTEGER length;
+ DBUG_ENTER("my_win_chsize");
+
+ hFile= (HANDLE) my_get_osfhandle(fd);
+ length.QuadPart= newlength;
+ if (!SetFilePointerEx(hFile, length , NULL , FILE_BEGIN))
+ goto err;
+ if (!SetEndOfFile(hFile))
+ goto err;
+ DBUG_RETURN(0);
+err:
+ my_osmaperr(GetLastError());
+ my_errno= errno;
+ DBUG_RETURN(-1);
+}
+
+
+/* Get the file descriptor for stdin,stdout or stderr */
+static File my_get_stdfile_descriptor(FILE *stream)
+{
+ HANDLE hFile;
+ DWORD nStdHandle;
+ DBUG_ENTER("my_get_stdfile_descriptor");
+
+ if(stream == stdin)
+ nStdHandle= STD_INPUT_HANDLE;
+ else if(stream == stdout)
+ nStdHandle= STD_OUTPUT_HANDLE;
+ else if(stream == stderr)
+ nStdHandle= STD_ERROR_HANDLE;
+ else
+ DBUG_RETURN(-1);
+
+ hFile= GetStdHandle(nStdHandle);
+ if(hFile != INVALID_HANDLE_VALUE)
+ DBUG_RETURN(my_open_osfhandle(hFile, 0));
+ DBUG_RETURN(-1);
+}
+
+
+File my_win_fileno(FILE *file)
+{
+ HANDLE hFile= (HANDLE)_get_osfhandle(fileno(file));
+ int retval= -1;
+ uint i;
+
+ DBUG_ENTER("my_win_fileno");
+
+ for(i= MY_FILE_MIN; i < my_file_limit; i++)
+ {
+ if(my_file_info[i].fhandle == hFile)
+ {
+ retval= i;
+ break;
+ }
+ }
+ if(retval == -1)
+ /* try std stream */
+ DBUG_RETURN(my_get_stdfile_descriptor(file));
+ DBUG_RETURN(retval);
+}
+
+
+FILE *my_win_fopen(const char *filename, const char *type)
+{
+ FILE *file;
+ int flags= 0;
+ DBUG_ENTER("my_win_open");
+
+ /*
+ If we are not creating, then we need to use my_access to make sure
+ the file exists since Windows doesn't handle files like "com1.sym"
+ very well
+ */
+ if (check_if_legal_filename(filename))
+ {
+ errno= EACCES;
+ DBUG_RETURN(NULL);
+ }
+
+ file= fopen(filename, type);
+ if(!file)
+ DBUG_RETURN(NULL);
+
+ if(strchr(type,'a') != NULL)
+ flags= O_APPEND;
+
+ /*
+ Register file handle in my_table_info.
+ Necessary for my_fileno()
+ */
+ if(my_open_osfhandle((HANDLE)_get_osfhandle(fileno(file)), flags) < 0)
+ {
+ fclose(file);
+ DBUG_RETURN(NULL);
+ }
+ DBUG_RETURN(file);
+}
+
+
+FILE * my_win_fdopen(File fd, const char *type)
+{
+ FILE *file;
+ int crt_fd;
+ int flags= 0;
+
+ DBUG_ENTER("my_win_fdopen");
+
+ if(strchr(type,'a') != NULL)
+ flags= O_APPEND;
+ /* Convert OS file handle to CRT file descriptor and then call fdopen*/
+ crt_fd= _open_osfhandle((intptr_t)my_get_osfhandle(fd), flags);
+ if(crt_fd < 0)
+ file= NULL;
+ else
+ file= fdopen(crt_fd, type);
+ DBUG_RETURN(file);
+}
+
+
+int my_win_fclose(FILE *file)
+{
+ File fd;
+
+ DBUG_ENTER("my_win_close");
+ fd= my_fileno(file);
+ if(fd < 0)
+ DBUG_RETURN(-1);
+ if(fclose(file) < 0)
+ DBUG_RETURN(-1);
+ invalidate_fd(fd);
+ DBUG_RETURN(0);
+}
+
+
+
+/*
+ Quick and dirty my_fstat() implementation for Windows.
+ Use CRT fstat on temporarily allocated file descriptor.
+ Patch file size, because size that fstat returns is not
+ reliable (may be outdated)
+*/
+int my_win_fstat(File fd, struct _stati64 *buf)
+{
+ int crt_fd;
+ int retval;
+ HANDLE hFile, hDup;
+
+ DBUG_ENTER("my_win_fstat");
+
+ hFile= my_get_osfhandle(fd);
+ if(!DuplicateHandle( GetCurrentProcess(), hFile, GetCurrentProcess(),
+ &hDup ,0,FALSE,DUPLICATE_SAME_ACCESS))
+ {
+ my_osmaperr(GetLastError());
+ DBUG_RETURN(-1);
+ }
+ if ((crt_fd= _open_osfhandle((intptr_t)hDup,0)) < 0)
+ DBUG_RETURN(-1);
+
+ retval= _fstati64(crt_fd, buf);
+ if(retval == 0)
+ {
+ /* File size returned by stat is not accurate (may be outdated), fix it*/
+ GetFileSizeEx(hDup, (PLARGE_INTEGER) (&(buf->st_size)));
+ }
+ _close(crt_fd);
+ DBUG_RETURN(retval);
+}
+
+
+
+int my_win_stat( const char *path, struct _stati64 *buf)
+{
+ DBUG_ENTER("my_win_stat");
+ if(_stati64( path, buf) == 0)
+ {
+ /* File size returned by stat is not accurate (may be outdated), fix it*/
+ WIN32_FILE_ATTRIBUTE_DATA data;
+ if (GetFileAttributesEx(path, GetFileExInfoStandard, &data))
+ {
+ LARGE_INTEGER li;
+ li.LowPart= data.nFileSizeLow;
+ li.HighPart= data.nFileSizeHigh;
+ buf->st_size= li.QuadPart;
+ }
+ DBUG_RETURN(0);
+ }
+ DBUG_RETURN(-1);
+}
+
+
+
+int my_win_fsync(File fd)
+{
+ DBUG_ENTER("my_win_fsync");
+ if(FlushFileBuffers(my_get_osfhandle(fd)))
+ DBUG_RETURN(0);
+ my_osmaperr(GetLastError());
+ DBUG_RETURN(-1);
+}
+
+
+
+int my_win_dup(File fd)
+{
+ HANDLE hDup;
+ DBUG_ENTER("my_win_dup");
+ if (DuplicateHandle(GetCurrentProcess(), my_get_osfhandle(fd),
+ GetCurrentProcess(), &hDup, 0, FALSE, DUPLICATE_SAME_ACCESS))
+ {
+ DBUG_RETURN(my_open_osfhandle(hDup, my_get_open_flags(fd)));
+ }
+ my_osmaperr(GetLastError());
+ DBUG_RETURN(-1);
+}
+
+#endif /*_WIN32*/
diff --git a/mysys/my_winthread.c b/mysys/my_winthread.c
index 6adf24ef543..5fbad39597c 100644
--- a/mysys/my_winthread.c
+++ b/mysys/my_winthread.c
@@ -156,8 +156,19 @@ int win_pthread_setspecific(void *a,void *b,uint length)
int my_pthread_once(my_pthread_once_t *once_control,
void (*init_routine)(void))
{
- LONG state= InterlockedCompareExchange(once_control, MY_PTHREAD_ONCE_INPROGRESS,
- MY_PTHREAD_ONCE_INIT);
+ LONG state;
+
+ /*
+ Do "dirty" read to find out if initialization is already done, to
+ save an interlocked operation in common case. Memory barriers are ensured by
+ Visual C++ volatile implementation.
+ */
+ if (*once_control == MY_PTHREAD_ONCE_DONE)
+ return 0;
+
+ state= InterlockedCompareExchange(once_control, MY_PTHREAD_ONCE_INPROGRESS,
+ MY_PTHREAD_ONCE_INIT);
+
switch(state)
{
case MY_PTHREAD_ONCE_INIT:
diff --git a/mysys/my_write.c b/mysys/my_write.c
index 3ab9f21be16..ae2eb155068 100644
--- a/mysys/my_write.c
+++ b/mysys/my_write.c
@@ -22,7 +22,7 @@
size_t my_write(int Filedes, const uchar *Buffer, size_t Count, myf MyFlags)
{
- size_t writenbytes, written;
+ size_t writtenbytes, written;
uint errors;
DBUG_ENTER("my_write");
DBUG_PRINT("my",("fd: %d Buffer: 0x%lx Count: %lu MyFlags: %d",
@@ -37,17 +37,27 @@ size_t my_write(int Filedes, const uchar *Buffer, size_t Count, myf MyFlags)
for (;;)
{
- if ((writenbytes= write(Filedes, Buffer, Count)) == Count)
+#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);
+#endif
+ if (writtenbytes == Count)
break;
- if (writenbytes != (size_t) -1)
+ if (writtenbytes != (size_t) -1)
{ /* Safeguard */
- written+=writenbytes;
- Buffer+=writenbytes;
- Count-=writenbytes;
+ written+= writtenbytes;
+ Buffer+= writtenbytes;
+ Count-= writtenbytes;
}
- my_errno=errno;
+ my_errno= errno;
DBUG_PRINT("error",("Write only %ld bytes, error: %d",
- (long) writenbytes, my_errno));
+ (long) writtenbytes, my_errno));
#ifndef NO_BACKGROUND
#ifdef THREAD
if (my_thread_var->abort)
@@ -61,19 +71,19 @@ size_t my_write(int Filedes, const uchar *Buffer, size_t Count, myf MyFlags)
continue;
}
- if ((writenbytes == 0 || writenbytes == (size_t) -1))
+ if ((writtenbytes == 0 || writtenbytes == (size_t) -1))
{
if (my_errno == EINTR)
{
DBUG_PRINT("debug", ("my_write() was interrupted and returned %ld",
- (long) writenbytes));
+ (long) writtenbytes));
continue; /* Interrupted */
}
- if (!writenbytes && !errors++) /* Retry once */
+ if (!writtenbytes && !errors++) /* Retry once */
{
/* We may come here if the file quota is exeeded */
- errno=EFBIG; /* Assume this is the error */
+ errno= EFBIG; /* Assume this is the error */
continue;
}
}
@@ -95,5 +105,5 @@ size_t my_write(int Filedes, const uchar *Buffer, size_t Count, myf MyFlags)
}
if (MyFlags & (MY_NABP | MY_FNABP))
DBUG_RETURN(0); /* Want only errors */
- DBUG_RETURN(writenbytes+written);
+ DBUG_RETURN(writtenbytes+written);
} /* my_write */
diff --git a/mysys/mysys_priv.h b/mysys/mysys_priv.h
index 113b64005f2..6d39999aa86 100644
--- a/mysys/mysys_priv.h
+++ b/mysys/mysys_priv.h
@@ -45,3 +45,27 @@ extern pthread_mutex_t THR_LOCK_charset, THR_LOCK_time;
void my_error_unregister_all(void);
void my_thread_destroy_mutex(void);
my_bool my_wait_for_other_threads_to_die(uint number_of_threads);
+
+#ifdef _WIN32
+/* my_winfile.c exports, should not be used outside mysys */
+extern File my_win_open(const char *path, int oflag);
+extern int my_win_close(File fd);
+extern size_t my_win_read(File fd, uchar *buffer, size_t count);
+extern size_t my_win_write(File fd, const uchar *buffer, size_t count);
+extern size_t my_win_pread(File fd, uchar *buffer, size_t count,
+ my_off_t offset);
+extern size_t my_win_pwrite(File fd, const uchar *buffer, size_t count,
+ my_off_t offset);
+extern my_off_t my_win_lseek(File fd, my_off_t pos, int whence);
+extern int my_win_chsize(File fd, my_off_t newlength);
+extern FILE* my_win_fopen(const char *filename, const char *type);
+extern File my_win_fclose(FILE *file);
+extern File my_win_fileno(FILE *file);
+extern FILE* my_win_fdopen(File Filedes, const char *type);
+extern int my_win_stat(const char *path, struct _stat64 *buf);
+extern int my_win_fstat(File fd, struct _stat64 *buf);
+extern int my_win_fsync(File fd);
+extern File my_win_dup(File fd);
+extern File my_win_sopen(const char *path, int oflag, int shflag, int perm);
+extern File my_open_osfhandle(HANDLE handle, int oflag);
+#endif
diff --git a/mysys/queues.c b/mysys/queues.c
index 9c85e493141..d1f2dab18bc 100644
--- a/mysys/queues.c
+++ b/mysys/queues.c
@@ -1,25 +1,42 @@
-/* Copyright (C) 2000, 2005 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
- the Free Software Foundation; version 2 of the License.
-
- This program 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 General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+/* Copyright (C) 2010 Monty Program Ab
+ All Rights reserved
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the following disclaimer
+ in the documentation and/or other materials provided with the
+ distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ "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> 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.
+*/
/*
+ This code originates from the Unireg project.
+
Code for generell handling of priority Queues.
Implemention of queues from "Algoritms in C" by Robert Sedgewick.
- An optimisation of _downheap suggested in Exercise 7.51 in "Data
- Structures & Algorithms in C++" by Mark Allen Weiss, Second Edition
- was implemented by Mikael Ronstrom 2005. Also the O(N) algorithm
- of queue_fix was implemented.
+
+ The queue can optionally store the position in queue in the element
+ that is in the queue. This allows one to remove any element from the queue
+ in O(1) time.
+
+ Optimisation of _downheap() and queue_fix() is inspired by code done
+ by Mikael Ronström, based on an optimisation of _downheap from
+ Exercise 7.51 in "Data Structures & Algorithms in C++" by Mark Allen
+ Weiss, Second Edition.
*/
#include "mysys_priv.h"
@@ -39,6 +56,10 @@
max_at_top Set to 1 if you want biggest element on top.
compare Compare function for elements, takes 3 arguments.
first_cmp_arg First argument to compare function
+ offset_to_queue_pos If <> 0, then offset+1 in element to store position
+ in queue (for fast delete of element in queue)
+ auto_extent When the queue is full and there is insert operation
+ extend the queue.
NOTES
Will allocate max_element pointers for queue array
@@ -50,74 +71,33 @@
int init_queue(QUEUE *queue, uint max_elements, uint offset_to_key,
pbool max_at_top, int (*compare) (void *, uchar *, uchar *),
- void *first_cmp_arg)
+ void *first_cmp_arg, uint offset_to_queue_pos,
+ uint auto_extent)
+
{
DBUG_ENTER("init_queue");
- if ((queue->root= (uchar **) my_malloc((max_elements+1)*sizeof(void*),
+ if ((queue->root= (uchar **) my_malloc((max_elements + 1) * sizeof(void*),
MYF(MY_WME))) == 0)
DBUG_RETURN(1);
- queue->elements=0;
- queue->compare=compare;
- queue->first_cmp_arg=first_cmp_arg;
- queue->max_elements=max_elements;
- queue->offset_to_key=offset_to_key;
+ queue->elements= 0;
+ queue->compare= compare;
+ queue->first_cmp_arg= first_cmp_arg;
+ queue->max_elements= max_elements;
+ queue->offset_to_key= offset_to_key;
+ queue->offset_to_queue_pos= offset_to_queue_pos;
+ queue->auto_extent= auto_extent;
queue_set_max_at_top(queue, max_at_top);
DBUG_RETURN(0);
}
-
-/*
- Init queue, uses init_queue internally for init work but also accepts
- auto_extent as parameter
-
- SYNOPSIS
- init_queue_ex()
- queue Queue to initialise
- max_elements Max elements that will be put in queue
- offset_to_key Offset to key in element stored in queue
- Used when sending pointers to compare function
- max_at_top Set to 1 if you want biggest element on top.
- compare Compare function for elements, takes 3 arguments.
- first_cmp_arg First argument to compare function
- auto_extent When the queue is full and there is insert operation
- extend the queue.
-
- NOTES
- Will allocate max_element pointers for queue array
-
- RETURN
- 0 ok
- 1 Could not allocate memory
-*/
-
-int init_queue_ex(QUEUE *queue, uint max_elements, uint offset_to_key,
- pbool max_at_top, int (*compare) (void *, uchar *, uchar *),
- void *first_cmp_arg, uint auto_extent)
-{
- int ret;
- DBUG_ENTER("init_queue_ex");
-
- if ((ret= init_queue(queue, max_elements, offset_to_key, max_at_top, compare,
- first_cmp_arg)))
- DBUG_RETURN(ret);
-
- queue->auto_extent= auto_extent;
- DBUG_RETURN(0);
-}
-
/*
Reinitialize queue for other usage
SYNOPSIS
reinit_queue()
queue Queue to initialise
- max_elements Max elements that will be put in queue
- offset_to_key Offset to key in element stored in queue
- Used when sending pointers to compare function
- max_at_top Set to 1 if you want biggest element on top.
- compare Compare function for elements, takes 3 arguments.
- first_cmp_arg First argument to compare function
+ For rest of arguments, see init_queue() above
NOTES
This will delete all elements from the queue. If you don't want this,
@@ -125,21 +105,23 @@ int init_queue_ex(QUEUE *queue, uint max_elements, uint offset_to_key,
RETURN
0 ok
- EE_OUTOFMEMORY Wrong max_elements
+ 1 Wrong max_elements; Queue has old size
*/
int reinit_queue(QUEUE *queue, uint max_elements, uint offset_to_key,
pbool max_at_top, int (*compare) (void *, uchar *, uchar *),
- void *first_cmp_arg)
+ void *first_cmp_arg, uint offset_to_queue_pos,
+ uint auto_extent)
{
DBUG_ENTER("reinit_queue");
- queue->elements=0;
- queue->compare=compare;
- queue->first_cmp_arg=first_cmp_arg;
- queue->offset_to_key=offset_to_key;
+ queue->elements= 0;
+ queue->compare= compare;
+ queue->first_cmp_arg= first_cmp_arg;
+ queue->offset_to_key= offset_to_key;
+ queue->offset_to_queue_pos= offset_to_queue_pos;
+ queue->auto_extent= auto_extent;
queue_set_max_at_top(queue, max_at_top);
- resize_queue(queue, max_elements);
- DBUG_RETURN(0);
+ DBUG_RETURN(resize_queue(queue, max_elements));
}
@@ -167,8 +149,8 @@ int resize_queue(QUEUE *queue, uint max_elements)
if (queue->max_elements == max_elements)
DBUG_RETURN(0);
if ((new_root= (uchar **) my_realloc((void *)queue->root,
- (max_elements+1)*sizeof(void*),
- MYF(MY_WME))) == 0)
+ (max_elements + 1)* sizeof(void*),
+ MYF(MY_WME))) == 0)
DBUG_RETURN(1);
set_if_smaller(queue->elements, max_elements);
queue->max_elements= max_elements;
@@ -197,39 +179,58 @@ void delete_queue(QUEUE *queue)
if (queue->root)
{
my_free((uchar*) queue->root,MYF(0));
- queue->root=0;
+ queue->root=0; /* Allow multiple calls */
}
DBUG_VOID_RETURN;
}
- /* Code for insert, search and delete of elements */
+/*
+ Insert element in queue
+
+ SYNOPSIS
+ queue_insert()
+ queue Queue to use
+ element Element to insert
+*/
void queue_insert(register QUEUE *queue, uchar *element)
{
reg2 uint idx, next;
+ uint offset_to_queue_pos= queue->offset_to_queue_pos;
DBUG_ASSERT(queue->elements < queue->max_elements);
- queue->root[0]= element;
+
idx= ++queue->elements;
/* max_at_top swaps the comparison if we want to order by desc */
- while ((queue->compare(queue->first_cmp_arg,
+ while (idx > 1 &&
+ (queue->compare(queue->first_cmp_arg,
element + queue->offset_to_key,
queue->root[(next= idx >> 1)] +
queue->offset_to_key) * queue->max_at_top) < 0)
{
queue->root[idx]= queue->root[next];
+ if (offset_to_queue_pos)
+ (*(uint*) (queue->root[idx] + offset_to_queue_pos-1))= idx;
idx= next;
}
queue->root[idx]= element;
+ if (offset_to_queue_pos)
+ (*(uint*) (element+ offset_to_queue_pos-1))= idx;
}
+
/*
- Does safe insert. If no more space left on the queue resize it.
- Return codes:
- 0 - OK
- 1 - Cannot allocate more memory
- 2 - auto_extend is 0, the operation would
-
+ Like queue_insert, but resize queue if queue is full
+
+ SYNOPSIS
+ queue_insert_safe()
+ queue Queue to use
+ element Element to insert
+
+ RETURN
+ 0 OK
+ 1 Cannot allocate more memory
+ 2 auto_extend is 0; No insertion done
*/
int queue_insert_safe(register QUEUE *queue, uchar *element)
@@ -239,7 +240,7 @@ int queue_insert_safe(register QUEUE *queue, uchar *element)
{
if (!queue->auto_extent)
return 2;
- else if (resize_queue(queue, queue->max_elements + queue->auto_extent))
+ if (resize_queue(queue, queue->max_elements + queue->auto_extent))
return 1;
}
@@ -248,40 +249,51 @@ int queue_insert_safe(register QUEUE *queue, uchar *element)
}
- /* Remove item from queue */
- /* Returns pointer to removed element */
+/*
+ Remove item from queue
+
+ SYNOPSIS
+ queue_remove()
+ queue Queue to use
+ element Index of element to remove.
+ First element in queue is 'queue_first_element(queue)'
+
+ RETURN
+ pointer to removed element
+*/
uchar *queue_remove(register QUEUE *queue, uint idx)
{
uchar *element;
- DBUG_ASSERT(idx < queue->max_elements);
- element= queue->root[++idx]; /* Intern index starts from 1 */
- queue->root[idx]= queue->root[queue->elements--];
- _downheap(queue, idx);
+ DBUG_ASSERT(idx >= 1 && idx <= queue->elements);
+ element= queue->root[idx];
+ _downheap(queue, idx, queue->root[queue->elements--]);
return element;
}
- /* Fix when element on top has been replaced */
-#ifndef queue_replaced
-void queue_replaced(QUEUE *queue)
-{
- _downheap(queue,1);
-}
-#endif
+/*
+ Add element to fixed position and update heap
-#ifndef OLD_VERSION
+ SYNOPSIS
+ _downheap()
+ queue Queue to use
+ idx Index of element to change
+ element Element to store at 'idx'
+
+ NOTE
+ This only works if element is >= all elements <= start_idx
+*/
-void _downheap(register QUEUE *queue, uint idx)
+void _downheap(register QUEUE *queue, uint start_idx, uchar *element)
{
- uchar *element;
- uint elements,half_queue,offset_to_key, next_index;
+ uint elements,half_queue,offset_to_key, next_index, offset_to_queue_pos;
+ register uint idx= start_idx;
my_bool first= TRUE;
- uint start_idx= idx;
offset_to_key=queue->offset_to_key;
- element=queue->root[idx];
- half_queue=(elements=queue->elements) >> 1;
+ offset_to_queue_pos= queue->offset_to_queue_pos;
+ half_queue= (elements= queue->elements) >> 1;
while (idx <= half_queue)
{
@@ -298,393 +310,68 @@ void _downheap(register QUEUE *queue, uint idx)
element+offset_to_key) * queue->max_at_top) >= 0)))
{
queue->root[idx]= element;
+ if (offset_to_queue_pos)
+ (*(uint*) (element + offset_to_queue_pos-1))= idx;
return;
}
- queue->root[idx]=queue->root[next_index];
- idx=next_index;
first= FALSE;
- }
-
- next_index= idx >> 1;
- while (next_index > start_idx)
- {
- if ((queue->compare(queue->first_cmp_arg,
- queue->root[next_index]+offset_to_key,
- element+offset_to_key) *
- queue->max_at_top) < 0)
- break;
- queue->root[idx]=queue->root[next_index];
+ queue->root[idx]= queue->root[next_index];
+ if (offset_to_queue_pos)
+ (*(uint*) (queue->root[idx] + offset_to_queue_pos-1))= idx;
idx=next_index;
- next_index= idx >> 1;
}
- queue->root[idx]=element;
-}
-#else
/*
- The old _downheap version is kept for comparisons with the benchmark
- suit or new benchmarks anyone wants to run for comparisons.
+ Insert the element into the right position. This is the same code
+ as we have in queue_insert()
*/
- /* Fix heap when index have changed */
-void _downheap(register QUEUE *queue, uint idx)
-{
- uchar *element;
- uint elements,half_queue,next_index,offset_to_key;
-
- offset_to_key=queue->offset_to_key;
- element=queue->root[idx];
- half_queue=(elements=queue->elements) >> 1;
-
- while (idx <= half_queue)
+ while ((next_index= (idx >> 1)) > start_idx &&
+ queue->compare(queue->first_cmp_arg,
+ element+offset_to_key,
+ queue->root[next_index]+offset_to_key)*
+ queue->max_at_top < 0)
{
- next_index=idx+idx;
- if (next_index < elements &&
- (queue->compare(queue->first_cmp_arg,
- queue->root[next_index]+offset_to_key,
- queue->root[next_index+1]+offset_to_key) *
- queue->max_at_top) > 0)
- next_index++;
- if ((queue->compare(queue->first_cmp_arg,
- queue->root[next_index]+offset_to_key,
- element+offset_to_key) * queue->max_at_top) >= 0)
- break;
- queue->root[idx]=queue->root[next_index];
- idx=next_index;
+ queue->root[idx]= queue->root[next_index];
+ if (offset_to_queue_pos)
+ (*(uint*) (queue->root[idx] + offset_to_queue_pos-1))= idx;
+ idx= next_index;
}
- queue->root[idx]=element;
+ queue->root[idx]= element;
+ if (offset_to_queue_pos)
+ (*(uint*) (element + offset_to_queue_pos-1))= idx;
}
-#endif
-
/*
Fix heap when every element was changed.
+
+ SYNOPSIS
+ queue_fix()
+ queue Queue to use
*/
void queue_fix(QUEUE *queue)
{
uint i;
for (i= queue->elements >> 1; i > 0; i--)
- _downheap(queue, i);
+ _downheap(queue, i, queue_element(queue, i));
}
-#ifdef MAIN
- /*
- A test program for the priority queue implementation.
- It can also be used to benchmark changes of the implementation
- Build by doing the following in the directory mysys
- make test_priority_queue
- ./test_priority_queue
-
- Written by Mikael Ronström, 2005
- */
-
-static uint num_array[1025];
-static uint tot_no_parts= 0;
-static uint tot_no_loops= 0;
-static uint expected_part= 0;
-static uint expected_num= 0;
-static bool max_ind= 0;
-static bool fix_used= 0;
-static ulonglong start_time= 0;
-
-static bool is_divisible_by(uint num, uint divisor)
-{
- uint quotient= num / divisor;
- if (quotient * divisor == num)
- return TRUE;
- return FALSE;
-}
-
-void calculate_next()
-{
- uint part= expected_part, num= expected_num;
- uint no_parts= tot_no_parts;
- if (max_ind)
- {
- do
- {
- while (++part <= no_parts)
- {
- if (is_divisible_by(num, part) &&
- (num <= ((1 << 21) + part)))
- {
- expected_part= part;
- expected_num= num;
- return;
- }
- }
- part= 0;
- } while (--num);
- }
- else
- {
- do
- {
- while (--part > 0)
- {
- if (is_divisible_by(num, part))
- {
- expected_part= part;
- expected_num= num;
- return;
- }
- }
- part= no_parts + 1;
- } while (++num);
- }
-}
-void calculate_end_next(uint part)
-{
- uint no_parts= tot_no_parts, num;
- num_array[part]= 0;
- if (max_ind)
- {
- expected_num= 0;
- for (part= no_parts; part > 0 ; part--)
- {
- if (num_array[part])
- {
- num= num_array[part] & 0x3FFFFF;
- if (num >= expected_num)
- {
- expected_num= num;
- expected_part= part;
- }
- }
- }
- if (expected_num == 0)
- expected_part= 0;
- }
- else
- {
- expected_num= 0xFFFFFFFF;
- for (part= 1; part <= no_parts; part++)
- {
- if (num_array[part])
- {
- num= num_array[part] & 0x3FFFFF;
- if (num <= expected_num)
- {
- expected_num= num;
- expected_part= part;
- }
- }
- }
- if (expected_num == 0xFFFFFFFF)
- expected_part= 0;
- }
- return;
-}
-static int test_compare(void *null_arg, uchar *a, uchar *b)
-{
- uint a_num= (*(uint*)a) & 0x3FFFFF;
- uint b_num= (*(uint*)b) & 0x3FFFFF;
- uint a_part, b_part;
- if (a_num > b_num)
- return +1;
- if (a_num < b_num)
- return -1;
- a_part= (*(uint*)a) >> 22;
- b_part= (*(uint*)b) >> 22;
- if (a_part < b_part)
- return +1;
- if (a_part > b_part)
- return -1;
- return 0;
-}
-
-bool check_num(uint num_part)
-{
- uint part= num_part >> 22;
- uint num= num_part & 0x3FFFFF;
- if (part == expected_part)
- if (num == expected_num)
- return FALSE;
- printf("Expect part %u Expect num 0x%x got part %u num 0x%x max_ind %u fix_used %u \n",
- expected_part, expected_num, part, num, max_ind, fix_used);
- return TRUE;
-}
-
-
-void perform_insert(QUEUE *queue)
-{
- uint i= 1, no_parts= tot_no_parts;
- uint backward_start= 0;
-
- expected_part= 1;
- expected_num= 1;
-
- if (max_ind)
- backward_start= 1 << 21;
-
- do
- {
- uint num= (i + backward_start);
- if (max_ind)
- {
- while (!is_divisible_by(num, i))
- num--;
- if (max_ind && (num > expected_num ||
- (num == expected_num && i < expected_part)))
- {
- expected_num= num;
- expected_part= i;
- }
- }
- num_array[i]= num + (i << 22);
- if (fix_used)
- queue_element(queue, i-1)= (uchar*)&num_array[i];
- else
- queue_insert(queue, (uchar*)&num_array[i]);
- } while (++i <= no_parts);
- if (fix_used)
- {
- queue->elements= no_parts;
- queue_fix(queue);
- }
-}
-
-bool perform_ins_del(QUEUE *queue, bool max_ind)
-{
- uint i= 0, no_loops= tot_no_loops, j= tot_no_parts;
- do
- {
- uint num_part= *(uint*)queue_top(queue);
- uint part= num_part >> 22;
- if (check_num(num_part))
- return TRUE;
- if (j++ >= no_loops)
- {
- calculate_end_next(part);
- queue_remove(queue, (uint) 0);
- }
- else
- {
- calculate_next();
- if (max_ind)
- num_array[part]-= part;
- else
- num_array[part]+= part;
- queue_top(queue)= (uchar*)&num_array[part];
- queue_replaced(queue);
- }
- } while (++i < no_loops);
- return FALSE;
-}
-
-bool do_test(uint no_parts, uint l_max_ind, bool l_fix_used)
-{
- QUEUE queue;
- bool result;
- max_ind= l_max_ind;
- fix_used= l_fix_used;
- init_queue(&queue, no_parts, 0, max_ind, test_compare, NULL);
- tot_no_parts= no_parts;
- tot_no_loops= 1024;
- perform_insert(&queue);
- if ((result= perform_ins_del(&queue, max_ind)))
- delete_queue(&queue);
- if (result)
- {
- printf("Error\n");
- return TRUE;
- }
- return FALSE;
-}
-
-static void start_measurement()
-{
- start_time= my_getsystime();
-}
-
-static void stop_measurement()
-{
- ulonglong stop_time= my_getsystime();
- uint time_in_micros;
- stop_time-= start_time;
- stop_time/= 10; /* Convert to microseconds */
- time_in_micros= (uint)stop_time;
- printf("Time expired is %u microseconds \n", time_in_micros);
-}
-
-static void benchmark_test()
-{
- QUEUE queue_real;
- QUEUE *queue= &queue_real;
- uint i, add;
- fix_used= TRUE;
- max_ind= FALSE;
- tot_no_parts= 1024;
- init_queue(queue, tot_no_parts, 0, max_ind, test_compare, NULL);
- /*
- First benchmark whether queue_fix is faster than using queue_insert
- for sizes of 16 partitions.
- */
- for (tot_no_parts= 2, add=2; tot_no_parts < 128;
- tot_no_parts+= add, add++)
- {
- printf("Start benchmark queue_fix, tot_no_parts= %u \n", tot_no_parts);
- start_measurement();
- for (i= 0; i < 128; i++)
- {
- perform_insert(queue);
- queue_remove_all(queue);
- }
- stop_measurement();
+/*
+ Change element at fixed position
- fix_used= FALSE;
- printf("Start benchmark queue_insert\n");
- start_measurement();
- for (i= 0; i < 128; i++)
- {
- perform_insert(queue);
- queue_remove_all(queue);
- }
- stop_measurement();
- }
- /*
- Now benchmark insertion and deletion of 16400 elements.
- Used in consecutive runs this shows whether the optimised _downheap
- is faster than the standard implementation.
- */
- printf("Start benchmarking _downheap \n");
- start_measurement();
- perform_insert(queue);
- for (i= 0; i < 65536; i++)
- {
- uint num, part;
- num= *(uint*)queue_top(queue);
- num+= 16;
- part= num >> 22;
- num_array[part]= num;
- queue_top(queue)= (uchar*)&num_array[part];
- queue_replaced(queue);
- }
- for (i= 0; i < 16; i++)
- queue_remove(queue, (uint) 0);
- queue_remove_all(queue);
- stop_measurement();
-}
+ SYNOPSIS
+ queue_replace()
+ queue Queue to use
+ idx Index of element to change
+ element Element to store at 'idx'
+*/
-int main()
+void queue_replace(QUEUE *queue, uint idx)
{
- int i, add= 1;
- for (i= 1; i < 1024; i+=add, add++)
- {
- printf("Start test for priority queue of size %u\n", i);
- if (do_test(i, 0, 1))
- return -1;
- if (do_test(i, 1, 1))
- return -1;
- if (do_test(i, 0, 0))
- return -1;
- if (do_test(i, 1, 0))
- return -1;
- }
- benchmark_test();
- printf("OK\n");
- return 0;
+ uchar *element= queue->root[idx];
+ DBUG_ASSERT(idx >= 1 && idx <= queue->elements);
+ queue_remove(queue, idx);
+ queue_insert(queue, element);
}
-#endif
diff --git a/mysys/string.c b/mysys/string.c
index 10a72b8a295..030178c6667 100644
--- a/mysys/string.c
+++ b/mysys/string.c
@@ -183,3 +183,15 @@ void dynstr_free(DYNAMIC_STRING *str)
str->str=0;
}
}
+
+
+/* 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 386691be4de..98c746af8ca 100644
--- a/mysys/thr_alarm.c
+++ b/mysys/thr_alarm.c
@@ -36,11 +36,24 @@
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);
+#ifdef DBUG_OFF
+#define reset_index_in_queue(alarm_data)
+#else
+#define reset_index_in_queue(alarm_data) alarm_data->index_in_queue= 0;
+#endif /* DBUG_OFF */
+
+#ifndef USE_ONE_SIGNAL_HAND
+#define one_signal_hand_sigmask(A,B,C) pthread_sigmask((A), (B), (C))
+#else
+#define one_signal_hand_sigmask(A,B,C)
+#endif
+
+
#if !defined(__WIN__)
static pthread_mutex_t LOCK_alarm;
@@ -72,8 +85,8 @@ void init_thr_alarm(uint max_alarms)
DBUG_ENTER("init_thr_alarm");
alarm_aborted=0;
next_alarm_expire_time= ~ (time_t) 0;
- init_queue(&alarm_queue,max_alarms+1,offsetof(ALARM,expire_time),0,
- compare_ulong,NullS);
+ init_queue(&alarm_queue, max_alarms+1, offsetof(ALARM,expire_time), 0,
+ compare_ulong, NullS, offsetof(ALARM, index_in_queue)+1, 0);
sigfillset(&full_signal_set); /* Neaded to block signals */
pthread_mutex_init(&LOCK_alarm,MY_MUTEX_INIT_FAST);
pthread_cond_init(&COND_alarm,NULL);
@@ -151,7 +164,7 @@ void resize_thr_alarm(uint max_alarms)
my_bool thr_alarm(thr_alarm_t *alrm, uint sec, ALARM *alarm_data)
{
- time_t now;
+ time_t now, next;
#ifndef USE_ONE_SIGNAL_HAND
sigset_t old_mask;
#endif
@@ -160,80 +173,77 @@ 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));
- now= my_time(0);
-#ifndef USE_ONE_SIGNAL_HAND
- pthread_sigmask(SIG_BLOCK,&full_signal_set,&old_mask);
-#endif
- pthread_mutex_lock(&LOCK_alarm); /* Lock from threads & alarms */
- if (alarm_aborted > 0)
+ 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"));
- *alrm= 0; /* No alarm */
- pthread_mutex_unlock(&LOCK_alarm);
-#ifndef USE_ONE_SIGNAL_HAND
- pthread_sigmask(SIG_SETMASK,&old_mask,NULL);
-#endif
- DBUG_RETURN(1);
- }
- if (alarm_aborted < 0)
+ if (alarm_aborted > 0)
+ goto abort_no_unlock;
sec= 1; /* Abort mode */
+ }
+ now= my_time(0);
+ if (!alarm_data)
+ {
+ if (!(alarm_data=(ALARM*) my_malloc(sizeof(ALARM),MYF(MY_WME))))
+ goto abort_no_unlock;
+ alarm_data->malloced= 1;
+ }
+ else
+ alarm_data->malloced= 0;
+ next= now + sec;
+ alarm_data->expire_time= next;
+ alarm_data->alarmed= 0;
+ alarm_data->thread= current_my_thread_var->pthread_self;
+ alarm_data->thread_id= current_my_thread_var->id;
+
+ one_signal_hand_sigmask(SIG_BLOCK,&full_signal_set,&old_mask);
+ pthread_mutex_lock(&LOCK_alarm); /* Lock from threads & alarms */
if (alarm_queue.elements >= max_used_alarms)
{
if (alarm_queue.elements == alarm_queue.max_elements)
{
DBUG_PRINT("info", ("alarm queue full"));
fprintf(stderr,"Warning: thr_alarm queue is full\n");
- *alrm= 0; /* No alarm */
- pthread_mutex_unlock(&LOCK_alarm);
-#ifndef USE_ONE_SIGNAL_HAND
- pthread_sigmask(SIG_SETMASK,&old_mask,NULL);
-#endif
- DBUG_RETURN(1);
+ goto abort;
}
max_used_alarms=alarm_queue.elements+1;
}
- reschedule= (ulong) next_alarm_expire_time > (ulong) now + sec;
- if (!alarm_data)
- {
- if (!(alarm_data=(ALARM*) my_malloc(sizeof(ALARM),MYF(MY_WME))))
- {
- DBUG_PRINT("info", ("failed my_malloc()"));
- *alrm= 0; /* No alarm */
- pthread_mutex_unlock(&LOCK_alarm);
-#ifndef USE_ONE_SIGNAL_HAND
- pthread_sigmask(SIG_SETMASK,&old_mask,NULL);
-#endif
- DBUG_RETURN(1);
- }
- alarm_data->malloced=1;
- }
- else
- alarm_data->malloced=0;
- alarm_data->expire_time=now+sec;
- alarm_data->alarmed=0;
- alarm_data->thread= current_my_thread_var->pthread_self;
- alarm_data->thread_id= current_my_thread_var->id;
+ reschedule= (ulong) next_alarm_expire_time > (ulong) next;
queue_insert(&alarm_queue,(uchar*) alarm_data);
+ assert(alarm_data->index_in_queue > 0);
/* Reschedule alarm if the current one has more than sec left */
- if (reschedule)
+ if (unlikely(reschedule))
{
DBUG_PRINT("info", ("reschedule"));
if (pthread_equal(pthread_self(),alarm_thread))
{
alarm(sec); /* purecov: inspected */
- next_alarm_expire_time= now + sec;
+ next_alarm_expire_time= next;
}
else
reschedule_alarms(); /* Reschedule alarms */
}
pthread_mutex_unlock(&LOCK_alarm);
-#ifndef USE_ONE_SIGNAL_HAND
- pthread_sigmask(SIG_SETMASK,&old_mask,NULL);
-#endif
+ one_signal_hand_sigmask(SIG_SETMASK,&old_mask,NULL);
(*alrm)= &alarm_data->alarmed;
DBUG_RETURN(0);
+
+abort:
+ if (alarm_data->malloced)
+ my_free(alarm_data, MYF(0));
+ pthread_mutex_unlock(&LOCK_alarm);
+ one_signal_hand_sigmask(SIG_SETMASK,&old_mask,NULL);
+abort_no_unlock:
+ *alrm= 0; /* No alarm */
+ DBUG_RETURN(1);
}
@@ -247,41 +257,20 @@ void thr_end_alarm(thr_alarm_t *alarmed)
#ifndef USE_ONE_SIGNAL_HAND
sigset_t old_mask;
#endif
- uint i, found=0;
DBUG_ENTER("thr_end_alarm");
-#ifndef USE_ONE_SIGNAL_HAND
- pthread_sigmask(SIG_BLOCK,&full_signal_set,&old_mask);
-#endif
- pthread_mutex_lock(&LOCK_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));
- for (i=0 ; i < alarm_queue.elements ; i++)
- {
- if ((ALARM*) queue_element(&alarm_queue,i) == alarm_data)
- {
- queue_remove(&alarm_queue,i),MYF(0);
- if (alarm_data->malloced)
- my_free((uchar*) alarm_data,MYF(0));
- found++;
-#ifdef DBUG_OFF
- break;
-#endif
- }
- }
- DBUG_ASSERT(!*alarmed || found == 1);
- if (!found)
- {
- if (*alarmed)
- fprintf(stderr,"Warning: Didn't find alarm 0x%lx in queue of %d alarms\n",
- (long) *alarmed, alarm_queue.elements);
- DBUG_PRINT("warning",("Didn't find alarm 0x%lx in queue\n",
- (long) *alarmed));
- }
+ pthread_mutex_lock(&LOCK_alarm);
+ DBUG_ASSERT(alarm_data->index_in_queue != 0);
+ DBUG_ASSERT(queue_element(&alarm_queue, alarm_data->index_in_queue) ==
+ alarm_data);
+ queue_remove(&alarm_queue, alarm_data->index_in_queue);
pthread_mutex_unlock(&LOCK_alarm);
-#ifndef USE_ONE_SIGNAL_HAND
- pthread_sigmask(SIG_SETMASK,&old_mask,NULL);
-#endif
+ one_signal_hand_sigmask(SIG_SETMASK,&old_mask,NULL);
+ reset_index_in_queue(alarm_data);
DBUG_VOID_RETURN;
}
@@ -344,12 +333,13 @@ static sig_handler process_alarm_part2(int sig __attribute__((unused)))
#if defined(MAIN) && !defined(__bsdi__)
printf("process_alarm\n"); fflush(stdout);
#endif
- if (alarm_queue.elements)
+ if (likely(alarm_queue.elements))
{
- if (alarm_aborted)
+ if (unlikely(alarm_aborted))
{
uint i;
- for (i=0 ; i < alarm_queue.elements ;)
+ for (i= queue_first_element(&alarm_queue) ;
+ i <= queue_last_element(&alarm_queue) ;)
{
alarm_data=(ALARM*) queue_element(&alarm_queue,i);
alarm_data->alarmed=1; /* Info to thread */
@@ -360,6 +350,7 @@ static sig_handler process_alarm_part2(int sig __attribute__((unused)))
printf("Warning: pthread_kill couldn't find thread!!!\n");
#endif
queue_remove(&alarm_queue,i); /* No thread. Remove alarm */
+ reset_index_in_queue(alarm_data);
}
else
i++; /* Signal next thread */
@@ -371,8 +362,8 @@ static sig_handler process_alarm_part2(int sig __attribute__((unused)))
}
else
{
- ulong now=(ulong) my_time(0);
- ulong next=now+10-(now%10);
+ time_t now= my_time(0);
+ time_t next= now+10-(now%10);
while ((alarm_data=(ALARM*) queue_top(&alarm_queue))->expire_time <= now)
{
alarm_data->alarmed=1; /* Info to thread */
@@ -382,15 +373,16 @@ static sig_handler process_alarm_part2(int sig __attribute__((unused)))
{
#ifdef MAIN
printf("Warning: pthread_kill couldn't find thread!!!\n");
-#endif
- queue_remove(&alarm_queue,0); /* No thread. Remove alarm */
+#endif /* MAIN */
+ queue_remove_top(&alarm_queue); /* No thread. Remove alarm */
+ reset_index_in_queue(alarm_data);
if (!alarm_queue.elements)
break;
}
else
{
alarm_data->expire_time=next;
- queue_replaced(&alarm_queue);
+ queue_replace_top(&alarm_queue);
}
}
#ifndef USE_ALARM_THREAD
@@ -483,21 +475,27 @@ void end_thr_alarm(my_bool free_structures)
void thr_alarm_kill(my_thread_id thread_id)
{
uint i;
+ DBUG_ENTER("thr_alarm_kill");
+
if (alarm_aborted)
return;
pthread_mutex_lock(&LOCK_alarm);
- for (i=0 ; i < alarm_queue.elements ; i++)
+ for (i= queue_first_element(&alarm_queue) ;
+ i <= queue_last_element(&alarm_queue);
+ i++)
{
- if (((ALARM*) queue_element(&alarm_queue,i))->thread_id == thread_id)
+ ALARM *element= (ALARM*) queue_element(&alarm_queue,i);
+ if (element->thread_id == thread_id)
{
- ALARM *tmp=(ALARM*) queue_remove(&alarm_queue,i);
- tmp->expire_time=0;
- queue_insert(&alarm_queue,(uchar*) tmp);
+ DBUG_PRINT("info", ("found thread; Killing it"));
+ element->expire_time= 0;
+ queue_replace(&alarm_queue, i);
reschedule_alarms();
break;
}
}
pthread_mutex_unlock(&LOCK_alarm);
+ DBUG_VOID_RETURN;
}
@@ -508,7 +506,7 @@ void thr_alarm_info(ALARM_INFO *info)
info->max_used_alarms= max_used_alarms;
if ((info->active_alarms= alarm_queue.elements))
{
- ulong now=(ulong) my_time(0);
+ time_t now= my_time(0);
long time_diff;
ALARM *alarm_data= (ALARM*) queue_top(&alarm_queue);
time_diff= (long) (alarm_data->expire_time - now);
@@ -556,7 +554,7 @@ static void *alarm_handler(void *arg __attribute__((unused)))
{
if (alarm_queue.elements)
{
- ulong sleep_time,now= my_time(0);
+ time_t sleep_time,now= my_time(0);
if (alarm_aborted)
sleep_time=now+1;
else
@@ -792,19 +790,6 @@ static void *test_thread(void *arg)
return 0;
}
-#ifdef USE_ONE_SIGNAL_HAND
-static sig_handler print_signal_warning(int sig)
-{
- printf("Warning: Got signal %d from thread %s\n",sig,my_thread_name());
- fflush(stdout);
-#ifdef SIGNAL_HANDLER_RESET_ON_DELIVERY
- my_sigset(sig,print_signal_warning); /* int. thread system calls */
-#endif
- if (sig == SIGALRM)
- alarm(2); /* reschedule alarm */
-}
-#endif /* USE_ONE_SIGNAL_HAND */
-
static void *signal_hand(void *arg __attribute__((unused)))
{
diff --git a/mysys/thr_lock.c b/mysys/thr_lock.c
index 32593ca3f4f..ac70282c050 100644
--- a/mysys/thr_lock.c
+++ b/mysys/thr_lock.c
@@ -243,14 +243,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)
{
@@ -302,7 +304,10 @@ 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)
{
diff --git a/mysys/thr_rwlock.c b/mysys/thr_rwlock.c
index ea98a854a4d..2978d91090d 100644
--- a/mysys/thr_rwlock.c
+++ b/mysys/thr_rwlock.c
@@ -19,6 +19,119 @@
#if defined(THREAD) && !defined(HAVE_PTHREAD_RWLOCK_RDLOCK) && !defined(HAVE_RWLOCK_INIT)
#include <errno.h>
+#ifdef _WIN32
+
+static BOOL have_srwlock= FALSE;
+/* Prototypes and function pointers for windows functions */
+typedef VOID (WINAPI* srw_func) (PSRWLOCK SRWLock);
+typedef BOOL (WINAPI* srw_bool_func) (PSRWLOCK SRWLock);
+
+static srw_func my_InitializeSRWLock;
+static srw_func my_AcquireSRWLockExclusive;
+static srw_func my_ReleaseSRWLockExclusive;
+static srw_func my_AcquireSRWLockShared;
+static srw_func my_ReleaseSRWLockShared;
+
+static srw_bool_func my_TryAcquireSRWLockExclusive;
+static srw_bool_func my_TryAcquireSRWLockShared;
+
+/**
+ Check for presence of Windows slim reader writer lock function.
+ Load function pointers.
+*/
+
+static void check_srwlock_availability(void)
+{
+ HMODULE module= GetModuleHandle("kernel32");
+
+ my_InitializeSRWLock= (srw_func) GetProcAddress(module,
+ "InitializeSRWLock");
+ my_AcquireSRWLockExclusive= (srw_func) GetProcAddress(module,
+ "AcquireSRWLockExclusive");
+ my_AcquireSRWLockShared= (srw_func) GetProcAddress(module,
+ "AcquireSRWLockShared");
+ my_ReleaseSRWLockExclusive= (srw_func) GetProcAddress(module,
+ "ReleaseSRWLockExclusive");
+ my_ReleaseSRWLockShared= (srw_func) GetProcAddress(module,
+ "ReleaseSRWLockShared");
+ my_TryAcquireSRWLockExclusive= (srw_bool_func) GetProcAddress(module,
+ "TryAcquireSRWLockExclusive");
+ my_TryAcquireSRWLockShared= (srw_bool_func) GetProcAddress(module,
+ "TryAcquireSRWLockShared");
+
+ /*
+ We currently require TryAcquireSRWLockExclusive. This API is missing on
+ Vista, this means SRWLock are only used starting with Win7.
+
+ If "trylock" usage for rwlocks is eliminated from server codebase (it is used
+ in a single place currently, in query cache), then SRWLock can be enabled on
+ Vista too. In this case condition below needs to be changed to e.g check
+ for my_InitializeSRWLock.
+ */
+
+ if (my_TryAcquireSRWLockExclusive)
+ have_srwlock= TRUE;
+
+}
+
+
+static int srw_init(my_rw_lock_t *rwp)
+{
+ my_InitializeSRWLock(&rwp->srwlock);
+ rwp->have_exclusive_srwlock = FALSE;
+ return 0;
+}
+
+
+static int srw_rdlock(my_rw_lock_t *rwp)
+{
+ my_AcquireSRWLockShared(&rwp->srwlock);
+ return 0;
+}
+
+
+static int srw_tryrdlock(my_rw_lock_t *rwp)
+{
+
+ if (!my_TryAcquireSRWLockShared(&rwp->srwlock))
+ return EBUSY;
+ return 0;
+}
+
+
+static int srw_wrlock(my_rw_lock_t *rwp)
+{
+ my_AcquireSRWLockExclusive(&rwp->srwlock);
+ rwp->have_exclusive_srwlock= TRUE;
+ return 0;
+}
+
+
+static int srw_trywrlock(my_rw_lock_t *rwp)
+{
+ if (!my_TryAcquireSRWLockExclusive(&rwp->srwlock))
+ return EBUSY;
+ rwp->have_exclusive_srwlock= TRUE;
+ return 0;
+}
+
+
+static int srw_unlock(my_rw_lock_t *rwp)
+{
+ if (rwp->have_exclusive_srwlock)
+ {
+ rwp->have_exclusive_srwlock= FALSE;
+ my_ReleaseSRWLockExclusive(&rwp->srwlock);
+ }
+ else
+ {
+ my_ReleaseSRWLockShared(&rwp->srwlock);
+ }
+ return 0;
+}
+
+#endif /*_WIN32 */
+
/*
Source base from Sun Microsystems SPILT, simplified for MySQL use
-- Joshua Chamas
@@ -62,6 +175,22 @@ int my_rwlock_init(rw_lock_t *rwp, void *arg __attribute__((unused)))
{
pthread_condattr_t cond_attr;
+#ifdef _WIN32
+ /*
+ Once initialization is used here rather than in my_init(), in order to
+ - avoid my_init() pitfalls- (undefined order in which initialization should
+ run)
+ - be potentially useful C++ (static constructors)
+ - just to simplify the API.
+ Also, the overhead is of my_pthread_once is very small.
+ */
+ static my_pthread_once_t once_control= MY_PTHREAD_ONCE_INIT;
+ my_pthread_once(&once_control, check_srwlock_availability);
+
+ if (have_srwlock)
+ return srw_init(rwp);
+#endif
+
pthread_mutex_init( &rwp->lock, MY_MUTEX_INIT_FAST);
pthread_condattr_init( &cond_attr );
pthread_cond_init( &rwp->readers, &cond_attr );
@@ -77,6 +206,10 @@ int my_rwlock_init(rw_lock_t *rwp, void *arg __attribute__((unused)))
int my_rwlock_destroy(rw_lock_t *rwp)
{
+#ifdef _WIN32
+ if (have_srwlock)
+ return 0; /* no destroy function */
+#endif
pthread_mutex_destroy( &rwp->lock );
pthread_cond_destroy( &rwp->readers );
pthread_cond_destroy( &rwp->writers );
@@ -86,6 +219,11 @@ int my_rwlock_destroy(rw_lock_t *rwp)
int my_rw_rdlock(rw_lock_t *rwp)
{
+#ifdef _WIN32
+ if (have_srwlock)
+ return srw_rdlock(rwp);
+#endif
+
pthread_mutex_lock(&rwp->lock);
/* active or queued writers */
@@ -100,6 +238,12 @@ int my_rw_rdlock(rw_lock_t *rwp)
int my_rw_tryrdlock(rw_lock_t *rwp)
{
int res;
+
+#ifdef _WIN32
+ if (have_srwlock)
+ return srw_tryrdlock(rwp);
+#endif
+
pthread_mutex_lock(&rwp->lock);
if ((rwp->state < 0 ) || rwp->waiters)
res= EBUSY; /* Can't get lock */
@@ -115,6 +259,11 @@ int my_rw_tryrdlock(rw_lock_t *rwp)
int my_rw_wrlock(rw_lock_t *rwp)
{
+#ifdef _WIN32
+ if (have_srwlock)
+ return srw_wrlock(rwp);
+#endif
+
pthread_mutex_lock(&rwp->lock);
rwp->waiters++; /* another writer queued */
@@ -130,6 +279,12 @@ int my_rw_wrlock(rw_lock_t *rwp)
int my_rw_trywrlock(rw_lock_t *rwp)
{
int res;
+
+#ifdef _WIN32
+ if (have_srwlock)
+ return srw_trywrlock(rwp);
+#endif
+
pthread_mutex_lock(&rwp->lock);
if (rwp->state)
res= EBUSY; /* Can't get lock */
@@ -145,6 +300,11 @@ int my_rw_trywrlock(rw_lock_t *rwp)
int my_rw_unlock(rw_lock_t *rwp)
{
+#ifdef _WIN32
+ if (have_srwlock)
+ return srw_unlock(rwp);
+#endif
+
DBUG_PRINT("rw_unlock",
("state: %d waiters: %d", rwp->state, rwp->waiters));
pthread_mutex_lock(&rwp->lock);
diff --git a/mysys/tree.c b/mysys/tree.c
index 68eaecbb27b..eba058b22f8 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
diff --git a/mysys/waiting_threads.c b/mysys/waiting_threads.c
index 732929f6d99..6ee79cb8e87 100644
--- a/mysys/waiting_threads.c
+++ b/mysys/waiting_threads.c
@@ -479,9 +479,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
@@ -1037,8 +1037,9 @@ int wt_thd_cond_timedwait(WT_THD *thd, pthread_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));
@@ -1050,29 +1051,15 @@ int wt_thd_cond_timedwait(WT_THD *thd, pthread_mutex_t *mutex)
safe_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= pthread_cond_timedwait(&rc->cond, mutex, &timeout);
if (ret == WT_TIMEOUT && !thd->killed)
@@ -1084,15 +1071,16 @@ int wt_thd_cond_timedwait(WT_THD *thd, pthread_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= pthread_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);