ported double tracking from TC
This commit is contained in:
221
deps/mysqllite/mysys/ChangeLog
vendored
Normal file
221
deps/mysqllite/mysys/ChangeLog
vendored
Normal file
@@ -0,0 +1,221 @@
|
||||
2000-02-16 Michael Widenius <monty@monty.pp.sci.fi>
|
||||
|
||||
* Added an extra argument to the compare routine for queues to allow
|
||||
more advanced key compare functions.
|
||||
|
||||
2000-02-10 Michael Widenius <monty@monty.pp.sci.fi>
|
||||
|
||||
* Added THR_READ_NO_INSERT lock privilege to thr_lock.
|
||||
|
||||
1999-08-21 Michael Widenius <monty@tik.pp.sci.fi>
|
||||
|
||||
* Fix that '-1.49 or -1.49' is true
|
||||
* Allow negative hexadecimal numbers (like -0x0f).
|
||||
* Fixed problem with auto_increment on float and double.
|
||||
|
||||
Wed Dec 17 02:13:58 1997 <monty@monty.pp.sci.fi>
|
||||
|
||||
* Faster flush of keycache.
|
||||
|
||||
Sat Dec 2 21:36:20 1995 Michael Widenius (monty@bitch)
|
||||
|
||||
* array.c push_element & alloc_element.
|
||||
|
||||
Wed Mar 3 00:54:20 1993 Michael Widenius (monty@bitch)
|
||||
|
||||
* Removed automatic O_TRUNC from my_create.
|
||||
|
||||
Wed Oct 28 02:10:56 1992 Michael Widenius (monty@bitch)
|
||||
|
||||
* Enabled ASNYNC_IO on SUN.
|
||||
|
||||
Mon Aug 31 23:51:13 1992 Michael Widenius (monty@bitch)
|
||||
|
||||
* Changed tree_insert to return element if ok.
|
||||
* Added new define tree_set_pointer().
|
||||
* Chagned delete_queue() to not free if allready freed.
|
||||
|
||||
Mon Aug 17 01:46:36 1992 Michael Widenius (monty@bitch)
|
||||
|
||||
* Added ny cashing-rutine mf_iocash for quicker io.
|
||||
|
||||
Wed Aug 12 13:41:18 1992 Michael Widenius (monty@bitch)
|
||||
|
||||
* Added new function get_copy_of_memory for combined malloc/copy.
|
||||
* Splitted my_malloc to three files.
|
||||
|
||||
Thu Jan 23 22:02:37 1992 Michael Widenius (monty at LYNX)
|
||||
|
||||
* Added range-checks and aligned checks on ptrs to
|
||||
safe_malloc:free and safe_malloc:realloc to catch more
|
||||
error nicely without core-dumps.
|
||||
|
||||
Wed Nov 13 01:52:18 1991 Michael Widenius (monty at LYNX)
|
||||
|
||||
* Added use of mysys as a shared library.
|
||||
|
||||
Sat Nov 9 14:38:21 1991 Michael Widenius (monty at LYNX)
|
||||
|
||||
* Added expand of ~username to unpack_dirname.
|
||||
|
||||
Tue Sep 17 21:15:08 1991 Michael Widenius (monty at LYNX)
|
||||
|
||||
* Don't free null-pointers if passed to my_free
|
||||
|
||||
Fri May 17 20:11:27 1991 Michael Widenius (monty at LYNX)
|
||||
|
||||
* Changed all char * to string. (Can't change const char * because
|
||||
of bug in C-definition.
|
||||
|
||||
Tue Apr 30 01:32:56 1991 Michael Widenius (monty at LYNX)
|
||||
|
||||
* my_path now examines environment for posix variable "_" if
|
||||
progname is given and has no path.
|
||||
|
||||
Mon Apr 22 16:12:56 1991 Michael Widenius (monty at LYNX)
|
||||
|
||||
* Added function my_load_path() to fix path to a hard-path.
|
||||
|
||||
Mon Apr 15 22:08:58 1991 Michael Widenius (monty at LYNX)
|
||||
|
||||
* Added more info on DBUG-stream when freeing unallocated data.
|
||||
|
||||
Wed Apr 3 18:41:28 1991 Michael Widenius (monty at LYNX)
|
||||
|
||||
* Added global flag sf_malloc_no_sanity to make it possibly
|
||||
to avoid sanity-checks in right code with uses malloc a lot.
|
||||
|
||||
Tue Mar 26 15:09:45 1991 Mikael WIDENIUS (monty at panther)
|
||||
|
||||
* Made soundex look nicer
|
||||
|
||||
Sat Mar 23 10:49:49 1991 Michael Widenius (monty at LYNX)
|
||||
|
||||
* Added init of alarm variables to skip some warnings from gcc.
|
||||
|
||||
Tue Mar 5 16:50:34 1991 Michael Widenius (monty at LYNX)
|
||||
|
||||
* Our qsort now only test if compare() function returns >= 0
|
||||
and is optimized for compare() returning > 0.
|
||||
|
||||
Fri Nov 23 23:53:46 1990 Michael Widenius (monty at LYNX)
|
||||
|
||||
* Added function my_set_alarm_variable to get a variable set
|
||||
on some time.
|
||||
my_alarm.h added for functions who want to print stat after
|
||||
a given time or after a number of loops.
|
||||
Changed my_lock to use new function and use defines in my_alarm.h
|
||||
|
||||
Mon Oct 1 13:16:15 1990 Michael Widenius (monty at LYNX)
|
||||
|
||||
* Added use of asynchronic io in read_cash_record().
|
||||
* Added write_cash and flush_write_cash to record cashing.
|
||||
|
||||
Sun Sep 16 22:05:25 1990 Michael Widenius (monty at LYNX)
|
||||
|
||||
* Added optional alarm to my_lock if one has FCNTL_LOCK. Added new
|
||||
defines to my_sys.h.
|
||||
|
||||
Mon Aug 27 22:20:38 1990 Michael Widenius (monty at lynx)
|
||||
|
||||
* my_end() now can print output about executed program.
|
||||
* Added parameter-defines for my_end in my_sys.h
|
||||
|
||||
Sun Apr 1 23:29:47 1990 Monty (monty at monty)
|
||||
|
||||
* Changed mf_keydisk.c to have separate functions for read and write.
|
||||
Read can now return pointer to intern key-buffer to skip
|
||||
unessessary memcpy-s.
|
||||
|
||||
Fri Mar 23 23:03:39 1990 Monty (monty at monty)
|
||||
|
||||
* function test_if_hard_pathname() added in dirname.c
|
||||
* my_getwd now only saves changed current dir if dir is a
|
||||
hard pathname.
|
||||
* changed my_path() to use test_if_hard_pathname()
|
||||
|
||||
Thu Mar 1 14:47:59 1990 Monty (monty at monty)
|
||||
|
||||
* New function my_path().
|
||||
|
||||
Sat Feb 24 02:54:35 1990 Monty (monty at monty)
|
||||
|
||||
* Added print of my_progname in my_mess.c
|
||||
|
||||
Sun Feb 11 17:55:58 1990 David Axmark (davida at isil)
|
||||
|
||||
* Concatenated libarys my_func and my_sys because of to much
|
||||
crosswise dependencies.
|
||||
* Fixed varagrs code in mf_fixadr.c
|
||||
|
||||
Mon Dec 4 17:36:16 1989 Monty (monty at monty)
|
||||
|
||||
* Changed safemalloc() to use my_message() if out of memory and
|
||||
to check MY_WME if we want this error-messages.
|
||||
* Changed my_setwd() to use dos_setdrive() insted of system().
|
||||
|
||||
Wed Oct 25 02:56:07 1989 Monty (monty at monty)
|
||||
|
||||
* Changed my_mktmp1() to work like tempnam() with default dirname.
|
||||
* Changed name of my_mktmp1.c to my_tempnam.c
|
||||
|
||||
Thu Oct 19 16:39:27 1989 David Axmark (davida at isil)
|
||||
|
||||
* Removed libary mysysnc. Instead added a hook to my_error that
|
||||
can call my_message if needed.
|
||||
|
||||
Thu Oct 5 01:33:29 1989 David Axmark (davida at isil)
|
||||
|
||||
* Use MY_SEEK_{SET,CUR,END} as arguments to my_seek
|
||||
|
||||
* Added a a array of structs that holds properties of open files.
|
||||
Removed include file extras.h
|
||||
|
||||
Wed Jun 21 01:34:04 1989 Monty (monty at monty)
|
||||
|
||||
* Added two new malloc-functions: my_once_alloc() and
|
||||
my_once_free(). These give easyer and quicker startup.
|
||||
|
||||
Mon May 22 14:03:44 1989 Monty (monty at monty)
|
||||
|
||||
* Fixed my_getwd and my_setwd so they work.
|
||||
* Added extern variabel curr_char[] with is set to current
|
||||
directory after my_getwd() or my_setwd();
|
||||
|
||||
Mon Jan 23 03:38:50 1989 Monty (monty at monty)
|
||||
|
||||
* Changed my_chsize to check if NO_CHSIZE is defined. If new file
|
||||
should be shorter it fills unused part with null.
|
||||
* Changed my_lock to not check for arg 0 (Functions should use
|
||||
LK_TO_EOF to lock all file.
|
||||
|
||||
Tue Dec 6 15:09:44 1988 Monty (monty at monty)
|
||||
|
||||
* Added DBUG_PRINT if error in my_seek.
|
||||
|
||||
Mon Dec 5 15:58:48 1988 Monty (monty at monty)
|
||||
|
||||
* Added DBUG_PRINT if not all byte read/written in my_read(),
|
||||
my_fread(), my_write() and my_fwrite();
|
||||
|
||||
Sat Dec 3 01:48:03 1988 Monty (monty at monty)
|
||||
|
||||
* Fixed bug in Makefile; quick did't work.
|
||||
* Changed safemalloc to use bmove, bfill and memcpy when handling
|
||||
memoryblocks.
|
||||
|
||||
Fri Dec 2 03:29:21 1988 Monty (monty at monty)
|
||||
|
||||
* Added more defines under MEMORY in my_func.h
|
||||
* Added functions to llib-lmysys.
|
||||
* Removed RCS/* files and installed ewerything as stable.
|
||||
(Because errors in old RCS-files.
|
||||
|
||||
Wed Nov 9 00:32:33 1988 Monty (monty at monty)
|
||||
|
||||
* Changed realloc for MSDOS; Previous version freed old block on
|
||||
* error, new version (of compiler) dosn't.
|
||||
|
||||
Wed Oct 26 21:07:27 1988 Monty (monty at monty)
|
||||
|
||||
* Fixed missing updateing of my_stream_opened;
|
||||
383
deps/mysqllite/mysys/array.c
vendored
Normal file
383
deps/mysqllite/mysys/array.c
vendored
Normal file
@@ -0,0 +1,383 @@
|
||||
/* Copyright (C) 2000 MySQL AB
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
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 */
|
||||
|
||||
/* Handling of arrays that can grow dynamicly. */
|
||||
|
||||
#include "mysys_priv.h"
|
||||
#include "m_string.h"
|
||||
|
||||
/*
|
||||
Initiate dynamic array
|
||||
|
||||
SYNOPSIS
|
||||
init_dynamic_array2()
|
||||
array Pointer to an array
|
||||
element_size Size of element
|
||||
init_buffer Initial buffer pointer
|
||||
init_alloc Number of initial elements
|
||||
alloc_increment Increment for adding new elements
|
||||
|
||||
DESCRIPTION
|
||||
init_dynamic_array() initiates array and allocate space for
|
||||
init_alloc eilements.
|
||||
Array is usable even if space allocation failed, hence, the
|
||||
function never returns TRUE.
|
||||
Static buffers must begin immediately after the array structure.
|
||||
|
||||
RETURN VALUE
|
||||
FALSE Ok
|
||||
*/
|
||||
|
||||
my_bool init_dynamic_array2(DYNAMIC_ARRAY *array, uint element_size,
|
||||
void *init_buffer, uint init_alloc,
|
||||
uint alloc_increment)
|
||||
{
|
||||
DBUG_ENTER("init_dynamic_array");
|
||||
if (!alloc_increment)
|
||||
{
|
||||
alloc_increment=max((8192-MALLOC_OVERHEAD)/element_size,16);
|
||||
if (init_alloc > 8 && alloc_increment > init_alloc * 2)
|
||||
alloc_increment=init_alloc*2;
|
||||
}
|
||||
|
||||
if (!init_alloc)
|
||||
{
|
||||
init_alloc=alloc_increment;
|
||||
init_buffer= 0;
|
||||
}
|
||||
array->elements=0;
|
||||
array->max_element=init_alloc;
|
||||
array->alloc_increment=alloc_increment;
|
||||
array->size_of_element=element_size;
|
||||
if ((array->buffer= init_buffer))
|
||||
DBUG_RETURN(FALSE);
|
||||
/*
|
||||
Since the dynamic array is usable even if allocation fails here malloc
|
||||
should not throw an error
|
||||
*/
|
||||
if (!(array->buffer= (uchar*) my_malloc(element_size*init_alloc, MYF(0))))
|
||||
array->max_element=0;
|
||||
DBUG_RETURN(FALSE);
|
||||
}
|
||||
|
||||
my_bool init_dynamic_array(DYNAMIC_ARRAY *array, uint element_size,
|
||||
uint init_alloc, uint alloc_increment)
|
||||
{
|
||||
/* placeholder to preserve ABI */
|
||||
return my_init_dynamic_array_ci(array, element_size, init_alloc,
|
||||
alloc_increment);
|
||||
}
|
||||
/*
|
||||
Insert element at the end of array. Allocate memory if needed.
|
||||
|
||||
SYNOPSIS
|
||||
insert_dynamic()
|
||||
array
|
||||
element
|
||||
|
||||
RETURN VALUE
|
||||
TRUE Insert failed
|
||||
FALSE Ok
|
||||
*/
|
||||
|
||||
my_bool insert_dynamic(DYNAMIC_ARRAY *array, uchar* element)
|
||||
{
|
||||
uchar* buffer;
|
||||
if (array->elements == array->max_element)
|
||||
{ /* Call only when nessesary */
|
||||
if (!(buffer=alloc_dynamic(array)))
|
||||
return TRUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
buffer=array->buffer+(array->elements * array->size_of_element);
|
||||
array->elements++;
|
||||
}
|
||||
memcpy(buffer,element,(size_t) array->size_of_element);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Alloc space for next element(s)
|
||||
|
||||
SYNOPSIS
|
||||
alloc_dynamic()
|
||||
array
|
||||
|
||||
DESCRIPTION
|
||||
alloc_dynamic() checks if there is empty space for at least
|
||||
one element if not tries to allocate space for alloc_increment
|
||||
elements at the end of array.
|
||||
|
||||
RETURN VALUE
|
||||
pointer Pointer to empty space for element
|
||||
0 Error
|
||||
*/
|
||||
|
||||
uchar *alloc_dynamic(DYNAMIC_ARRAY *array)
|
||||
{
|
||||
if (array->elements == array->max_element)
|
||||
{
|
||||
char *new_ptr;
|
||||
if (array->buffer == (uchar *)(array + 1))
|
||||
{
|
||||
/*
|
||||
In this senerio, the buffer is statically preallocated,
|
||||
so we have to create an all-new malloc since we overflowed
|
||||
*/
|
||||
if (!(new_ptr= (char *) my_malloc((array->max_element+
|
||||
array->alloc_increment) *
|
||||
array->size_of_element,
|
||||
MYF(MY_WME))))
|
||||
return 0;
|
||||
memcpy(new_ptr, array->buffer,
|
||||
array->elements * array->size_of_element);
|
||||
}
|
||||
else
|
||||
if (!(new_ptr=(char*) my_realloc(array->buffer,(array->max_element+
|
||||
array->alloc_increment)*
|
||||
array->size_of_element,
|
||||
MYF(MY_WME | MY_ALLOW_ZERO_PTR))))
|
||||
return 0;
|
||||
array->buffer= (uchar*) new_ptr;
|
||||
array->max_element+=array->alloc_increment;
|
||||
}
|
||||
return array->buffer+(array->elements++ * array->size_of_element);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Pop last element from array.
|
||||
|
||||
SYNOPSIS
|
||||
pop_dynamic()
|
||||
array
|
||||
|
||||
RETURN VALUE
|
||||
pointer Ok
|
||||
0 Array is empty
|
||||
*/
|
||||
|
||||
uchar *pop_dynamic(DYNAMIC_ARRAY *array)
|
||||
{
|
||||
if (array->elements)
|
||||
return array->buffer+(--array->elements * array->size_of_element);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
Replace element in array with given element and index
|
||||
|
||||
SYNOPSIS
|
||||
set_dynamic()
|
||||
array
|
||||
element Element to be inserted
|
||||
idx Index where element is to be inserted
|
||||
|
||||
DESCRIPTION
|
||||
set_dynamic() replaces element in array.
|
||||
If idx > max_element insert new element. Allocate memory if needed.
|
||||
|
||||
RETURN VALUE
|
||||
TRUE Idx was out of range and allocation of new memory failed
|
||||
FALSE Ok
|
||||
*/
|
||||
|
||||
my_bool set_dynamic(DYNAMIC_ARRAY *array, uchar* element, uint idx)
|
||||
{
|
||||
if (idx >= array->elements)
|
||||
{
|
||||
if (idx >= array->max_element && allocate_dynamic(array, idx))
|
||||
return TRUE;
|
||||
bzero((uchar*) (array->buffer+array->elements*array->size_of_element),
|
||||
(idx - array->elements)*array->size_of_element);
|
||||
array->elements=idx+1;
|
||||
}
|
||||
memcpy(array->buffer+(idx * array->size_of_element),element,
|
||||
(size_t) array->size_of_element);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Ensure that dynamic array has enough elements
|
||||
|
||||
SYNOPSIS
|
||||
allocate_dynamic()
|
||||
array
|
||||
max_elements Numbers of elements that is needed
|
||||
|
||||
NOTES
|
||||
Any new allocated element are NOT initialized
|
||||
|
||||
RETURN VALUE
|
||||
FALSE Ok
|
||||
TRUE Allocation of new memory failed
|
||||
*/
|
||||
|
||||
my_bool allocate_dynamic(DYNAMIC_ARRAY *array, uint max_elements)
|
||||
{
|
||||
if (max_elements >= array->max_element)
|
||||
{
|
||||
uint size;
|
||||
uchar *new_ptr;
|
||||
size= (max_elements + array->alloc_increment)/array->alloc_increment;
|
||||
size*= array->alloc_increment;
|
||||
if (array->buffer == (uchar *)(array + 1))
|
||||
{
|
||||
/*
|
||||
In this senerio, the buffer is statically preallocated,
|
||||
so we have to create an all-new malloc since we overflowed
|
||||
*/
|
||||
if (!(new_ptr= (uchar *) my_malloc(size *
|
||||
array->size_of_element,
|
||||
MYF(MY_WME))))
|
||||
return 0;
|
||||
memcpy(new_ptr, array->buffer,
|
||||
array->elements * array->size_of_element);
|
||||
}
|
||||
else
|
||||
|
||||
|
||||
if (!(new_ptr= (uchar*) my_realloc(array->buffer,size*
|
||||
array->size_of_element,
|
||||
MYF(MY_WME | MY_ALLOW_ZERO_PTR))))
|
||||
return TRUE;
|
||||
array->buffer= new_ptr;
|
||||
array->max_element= size;
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Get an element from array by given index
|
||||
|
||||
SYNOPSIS
|
||||
get_dynamic()
|
||||
array
|
||||
uchar* Element to be returned. If idx > elements contain zeroes.
|
||||
idx Index of element wanted.
|
||||
*/
|
||||
|
||||
void get_dynamic(DYNAMIC_ARRAY *array, uchar* element, uint idx)
|
||||
{
|
||||
if (idx >= array->elements)
|
||||
{
|
||||
DBUG_PRINT("warning",("To big array idx: %d, array size is %d",
|
||||
idx,array->elements));
|
||||
bzero(element,array->size_of_element);
|
||||
return;
|
||||
}
|
||||
memcpy(element,array->buffer+idx*array->size_of_element,
|
||||
(size_t) array->size_of_element);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Empty array by freeing all memory
|
||||
|
||||
SYNOPSIS
|
||||
delete_dynamic()
|
||||
array Array to be deleted
|
||||
*/
|
||||
|
||||
void delete_dynamic(DYNAMIC_ARRAY *array)
|
||||
{
|
||||
/*
|
||||
Just mark as empty if we are using a static buffer
|
||||
*/
|
||||
if (array->buffer == (uchar *)(array + 1))
|
||||
array->elements= 0;
|
||||
else
|
||||
if (array->buffer)
|
||||
{
|
||||
my_free(array->buffer);
|
||||
array->buffer=0;
|
||||
array->elements=array->max_element=0;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
Delete element by given index
|
||||
|
||||
SYNOPSIS
|
||||
delete_dynamic_element()
|
||||
array
|
||||
idx Index of element to be deleted
|
||||
*/
|
||||
|
||||
void delete_dynamic_element(DYNAMIC_ARRAY *array, uint idx)
|
||||
{
|
||||
char *ptr= (char*) array->buffer+array->size_of_element*idx;
|
||||
array->elements--;
|
||||
memmove(ptr,ptr+array->size_of_element,
|
||||
(array->elements-idx)*array->size_of_element);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Free unused memory
|
||||
|
||||
SYNOPSIS
|
||||
freeze_size()
|
||||
array Array to be freed
|
||||
|
||||
*/
|
||||
|
||||
void freeze_size(DYNAMIC_ARRAY *array)
|
||||
{
|
||||
uint elements=max(array->elements,1);
|
||||
|
||||
/*
|
||||
Do nothing if we are using a static buffer
|
||||
*/
|
||||
if (array->buffer == (uchar *)(array + 1))
|
||||
return;
|
||||
|
||||
if (array->buffer && array->max_element != elements)
|
||||
{
|
||||
array->buffer=(uchar*) my_realloc(array->buffer,
|
||||
elements*array->size_of_element,
|
||||
MYF(MY_WME));
|
||||
array->max_element=elements;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Get the index of a dynamic element
|
||||
|
||||
SYNOPSIS
|
||||
get_index_dynamic()
|
||||
array Array
|
||||
element Whose element index
|
||||
|
||||
*/
|
||||
|
||||
int get_index_dynamic(DYNAMIC_ARRAY *array, uchar* element)
|
||||
{
|
||||
size_t ret;
|
||||
if (array->buffer > element)
|
||||
return -1;
|
||||
|
||||
ret= (element - array->buffer) / array->size_of_element;
|
||||
if (ret > array->elements)
|
||||
return -1;
|
||||
|
||||
return ret;
|
||||
|
||||
}
|
||||
311
deps/mysqllite/mysys/base64.c
vendored
Normal file
311
deps/mysqllite/mysys/base64.c
vendored
Normal file
@@ -0,0 +1,311 @@
|
||||
/* Copyright (C) 2003 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 */
|
||||
|
||||
#include <my_global.h>
|
||||
#include <m_string.h> /* strchr() */
|
||||
#include <m_ctype.h> /* my_isspace() */
|
||||
#include <base64.h>
|
||||
|
||||
#ifndef MAIN
|
||||
|
||||
static char base64_table[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
||||
"abcdefghijklmnopqrstuvwxyz"
|
||||
"0123456789+/";
|
||||
|
||||
|
||||
int
|
||||
base64_needed_encoded_length(int length_of_data)
|
||||
{
|
||||
int nb_base64_chars;
|
||||
nb_base64_chars= (length_of_data + 2) / 3 * 4;
|
||||
|
||||
return
|
||||
nb_base64_chars + /* base64 char incl padding */
|
||||
(nb_base64_chars - 1)/ 76 + /* newlines */
|
||||
1; /* NUL termination of string */
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
base64_needed_decoded_length(int length_of_encoded_data)
|
||||
{
|
||||
return (int) ceil(length_of_encoded_data * 3 / 4);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Encode a data as base64.
|
||||
|
||||
Note: We require that dst is pre-allocated to correct size.
|
||||
See base64_needed_encoded_length().
|
||||
*/
|
||||
|
||||
int
|
||||
base64_encode(const void *src, size_t src_len, char *dst)
|
||||
{
|
||||
const unsigned char *s= (const unsigned char*)src;
|
||||
size_t i= 0;
|
||||
size_t len= 0;
|
||||
|
||||
for (; i < src_len; len += 4)
|
||||
{
|
||||
unsigned c;
|
||||
|
||||
if (len == 76)
|
||||
{
|
||||
len= 0;
|
||||
*dst++= '\n';
|
||||
}
|
||||
|
||||
c= s[i++];
|
||||
c <<= 8;
|
||||
|
||||
if (i < src_len)
|
||||
c += s[i];
|
||||
c <<= 8;
|
||||
i++;
|
||||
|
||||
if (i < src_len)
|
||||
c += s[i];
|
||||
i++;
|
||||
|
||||
*dst++= base64_table[(c >> 18) & 0x3f];
|
||||
*dst++= base64_table[(c >> 12) & 0x3f];
|
||||
|
||||
if (i > (src_len + 1))
|
||||
*dst++= '=';
|
||||
else
|
||||
*dst++= base64_table[(c >> 6) & 0x3f];
|
||||
|
||||
if (i > src_len)
|
||||
*dst++= '=';
|
||||
else
|
||||
*dst++= base64_table[(c >> 0) & 0x3f];
|
||||
}
|
||||
*dst= '\0';
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static inline uint
|
||||
pos(unsigned char c)
|
||||
{
|
||||
return (uint) (strchr(base64_table, c) - base64_table);
|
||||
}
|
||||
|
||||
|
||||
#define SKIP_SPACE(src, i, size) \
|
||||
{ \
|
||||
while (i < size && my_isspace(&my_charset_latin1, * src)) \
|
||||
{ \
|
||||
i++; \
|
||||
src++; \
|
||||
} \
|
||||
if (i == size) \
|
||||
{ \
|
||||
break; \
|
||||
} \
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Decode a base64 string
|
||||
|
||||
SYNOPSIS
|
||||
base64_decode()
|
||||
src Pointer to base64-encoded string
|
||||
len Length of string at 'src'
|
||||
dst Pointer to location where decoded data will be stored
|
||||
end_ptr Pointer to variable that will refer to the character
|
||||
after the end of the encoded data that were decoded. Can
|
||||
be NULL.
|
||||
|
||||
DESCRIPTION
|
||||
|
||||
The base64-encoded data in the range ['src','*end_ptr') will be
|
||||
decoded and stored starting at 'dst'. The decoding will stop
|
||||
after 'len' characters have been read from 'src', or when padding
|
||||
occurs in the base64-encoded data. In either case: if 'end_ptr' is
|
||||
non-null, '*end_ptr' will be set to point to the character after
|
||||
the last read character, even in the presence of error.
|
||||
|
||||
NOTE
|
||||
We require that 'dst' is pre-allocated to correct size.
|
||||
|
||||
SEE ALSO
|
||||
base64_needed_decoded_length().
|
||||
|
||||
RETURN VALUE
|
||||
Number of bytes written at 'dst' or -1 in case of failure
|
||||
*/
|
||||
int
|
||||
base64_decode(const char *src_base, size_t len,
|
||||
void *dst, const char **end_ptr)
|
||||
{
|
||||
char b[3];
|
||||
size_t i= 0;
|
||||
char *dst_base= (char *)dst;
|
||||
char const *src= src_base;
|
||||
char *d= dst_base;
|
||||
size_t j;
|
||||
|
||||
while (i < len)
|
||||
{
|
||||
unsigned c= 0;
|
||||
size_t mark= 0;
|
||||
|
||||
SKIP_SPACE(src, i, len);
|
||||
|
||||
c += pos(*src++);
|
||||
c <<= 6;
|
||||
i++;
|
||||
|
||||
SKIP_SPACE(src, i, len);
|
||||
|
||||
c += pos(*src++);
|
||||
c <<= 6;
|
||||
i++;
|
||||
|
||||
SKIP_SPACE(src, i, len);
|
||||
|
||||
if (*src != '=')
|
||||
c += pos(*src++);
|
||||
else
|
||||
{
|
||||
src += 2; /* There should be two bytes padding */
|
||||
i= len;
|
||||
mark= 2;
|
||||
c <<= 6;
|
||||
goto end;
|
||||
}
|
||||
c <<= 6;
|
||||
i++;
|
||||
|
||||
SKIP_SPACE(src, i, len);
|
||||
|
||||
if (*src != '=')
|
||||
c += pos(*src++);
|
||||
else
|
||||
{
|
||||
src += 1; /* There should be one byte padding */
|
||||
i= len;
|
||||
mark= 1;
|
||||
goto end;
|
||||
}
|
||||
i++;
|
||||
|
||||
end:
|
||||
b[0]= (c >> 16) & 0xff;
|
||||
b[1]= (c >> 8) & 0xff;
|
||||
b[2]= (c >> 0) & 0xff;
|
||||
|
||||
for (j=0; j<3-mark; j++)
|
||||
*d++= b[j];
|
||||
}
|
||||
|
||||
if (end_ptr != NULL)
|
||||
*end_ptr= src;
|
||||
|
||||
/*
|
||||
The variable 'i' is set to 'len' when padding has been read, so it
|
||||
does not actually reflect the number of bytes read from 'src'.
|
||||
*/
|
||||
return i != len ? -1 : (int) (d - dst_base);
|
||||
}
|
||||
|
||||
|
||||
#else /* MAIN */
|
||||
|
||||
#define require(b) { \
|
||||
if (!(b)) { \
|
||||
printf("Require failed at %s:%d\n", __FILE__, __LINE__); \
|
||||
abort(); \
|
||||
} \
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
main(void)
|
||||
{
|
||||
int i;
|
||||
size_t j;
|
||||
size_t k, l;
|
||||
size_t dst_len;
|
||||
size_t needed_length;
|
||||
|
||||
for (i= 0; i < 500; i++)
|
||||
{
|
||||
/* Create source data */
|
||||
const size_t src_len= rand() % 1000 + 1;
|
||||
|
||||
char * src= (char *) malloc(src_len);
|
||||
char * s= src;
|
||||
char * str;
|
||||
char * dst;
|
||||
|
||||
require(src);
|
||||
for (j= 0; j<src_len; j++)
|
||||
{
|
||||
char c= rand();
|
||||
*s++= c;
|
||||
}
|
||||
|
||||
/* Encode */
|
||||
needed_length= base64_needed_encoded_length(src_len);
|
||||
str= (char *) malloc(needed_length);
|
||||
require(str);
|
||||
for (k= 0; k < needed_length; k++)
|
||||
str[k]= 0xff; /* Fill memory to check correct NUL termination */
|
||||
require(base64_encode(src, src_len, str) == 0);
|
||||
require(needed_length == strlen(str) + 1);
|
||||
|
||||
/* Decode */
|
||||
dst= (char *) malloc(base64_needed_decoded_length(strlen(str)));
|
||||
require(dst);
|
||||
dst_len= base64_decode(str, strlen(str), dst, NULL);
|
||||
require(dst_len == src_len);
|
||||
|
||||
if (memcmp(src, dst, src_len) != 0)
|
||||
{
|
||||
printf(" --------- src --------- --------- dst ---------\n");
|
||||
for (k= 0; k<src_len; k+=8)
|
||||
{
|
||||
printf("%.4x ", (uint) k);
|
||||
for (l=0; l<8 && k+l<src_len; l++)
|
||||
{
|
||||
unsigned char c= src[k+l];
|
||||
printf("%.2x ", (unsigned)c);
|
||||
}
|
||||
|
||||
printf(" ");
|
||||
|
||||
for (l=0; l<8 && k+l<dst_len; l++)
|
||||
{
|
||||
unsigned char c= dst[k+l];
|
||||
printf("%.2x ", (unsigned)c);
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
printf("src length: %.8x, dst length: %.8x\n",
|
||||
(uint) src_len, (uint) dst_len);
|
||||
require(0);
|
||||
}
|
||||
}
|
||||
printf("Test succeeded.\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif
|
||||
354
deps/mysqllite/mysys/charset-def.c
vendored
Normal file
354
deps/mysqllite/mysys/charset-def.c
vendored
Normal file
@@ -0,0 +1,354 @@
|
||||
/* Copyright (C) 2000 MySQL AB
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
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 */
|
||||
|
||||
#include "mysys_priv.h"
|
||||
|
||||
/*
|
||||
Include all compiled character sets into the client
|
||||
If a client don't want to use all of them, he can define his own
|
||||
init_compiled_charsets() that only adds those that he wants
|
||||
*/
|
||||
|
||||
#ifdef HAVE_UCA_COLLATIONS
|
||||
|
||||
#ifdef HAVE_CHARSET_ucs2
|
||||
extern CHARSET_INFO my_charset_ucs2_icelandic_uca_ci;
|
||||
extern CHARSET_INFO my_charset_ucs2_latvian_uca_ci;
|
||||
extern CHARSET_INFO my_charset_ucs2_romanian_uca_ci;
|
||||
extern CHARSET_INFO my_charset_ucs2_slovenian_uca_ci;
|
||||
extern CHARSET_INFO my_charset_ucs2_polish_uca_ci;
|
||||
extern CHARSET_INFO my_charset_ucs2_estonian_uca_ci;
|
||||
extern CHARSET_INFO my_charset_ucs2_spanish_uca_ci;
|
||||
extern CHARSET_INFO my_charset_ucs2_swedish_uca_ci;
|
||||
extern CHARSET_INFO my_charset_ucs2_turkish_uca_ci;
|
||||
extern CHARSET_INFO my_charset_ucs2_czech_uca_ci;
|
||||
extern CHARSET_INFO my_charset_ucs2_danish_uca_ci;
|
||||
extern CHARSET_INFO my_charset_ucs2_lithuanian_uca_ci;
|
||||
extern CHARSET_INFO my_charset_ucs2_slovak_uca_ci;
|
||||
extern CHARSET_INFO my_charset_ucs2_spanish2_uca_ci;
|
||||
extern CHARSET_INFO my_charset_ucs2_roman_uca_ci;
|
||||
extern CHARSET_INFO my_charset_ucs2_persian_uca_ci;
|
||||
extern CHARSET_INFO my_charset_ucs2_esperanto_uca_ci;
|
||||
extern CHARSET_INFO my_charset_ucs2_hungarian_uca_ci;
|
||||
extern CHARSET_INFO my_charset_ucs2_sinhala_uca_ci;
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef HAVE_CHARSET_utf32
|
||||
extern CHARSET_INFO my_charset_utf32_icelandic_uca_ci;
|
||||
extern CHARSET_INFO my_charset_utf32_latvian_uca_ci;
|
||||
extern CHARSET_INFO my_charset_utf32_romanian_uca_ci;
|
||||
extern CHARSET_INFO my_charset_utf32_slovenian_uca_ci;
|
||||
extern CHARSET_INFO my_charset_utf32_polish_uca_ci;
|
||||
extern CHARSET_INFO my_charset_utf32_estonian_uca_ci;
|
||||
extern CHARSET_INFO my_charset_utf32_spanish_uca_ci;
|
||||
extern CHARSET_INFO my_charset_utf32_swedish_uca_ci;
|
||||
extern CHARSET_INFO my_charset_utf32_turkish_uca_ci;
|
||||
extern CHARSET_INFO my_charset_utf32_czech_uca_ci;
|
||||
extern CHARSET_INFO my_charset_utf32_danish_uca_ci;
|
||||
extern CHARSET_INFO my_charset_utf32_lithuanian_uca_ci;
|
||||
extern CHARSET_INFO my_charset_utf32_slovak_uca_ci;
|
||||
extern CHARSET_INFO my_charset_utf32_spanish2_uca_ci;
|
||||
extern CHARSET_INFO my_charset_utf32_roman_uca_ci;
|
||||
extern CHARSET_INFO my_charset_utf32_persian_uca_ci;
|
||||
extern CHARSET_INFO my_charset_utf32_esperanto_uca_ci;
|
||||
extern CHARSET_INFO my_charset_utf32_hungarian_uca_ci;
|
||||
extern CHARSET_INFO my_charset_utf32_sinhala_uca_ci;
|
||||
#endif /* HAVE_CHARSET_utf32 */
|
||||
|
||||
|
||||
#ifdef HAVE_CHARSET_utf16
|
||||
extern CHARSET_INFO my_charset_utf16_icelandic_uca_ci;
|
||||
extern CHARSET_INFO my_charset_utf16_latvian_uca_ci;
|
||||
extern CHARSET_INFO my_charset_utf16_romanian_uca_ci;
|
||||
extern CHARSET_INFO my_charset_utf16_slovenian_uca_ci;
|
||||
extern CHARSET_INFO my_charset_utf16_polish_uca_ci;
|
||||
extern CHARSET_INFO my_charset_utf16_estonian_uca_ci;
|
||||
extern CHARSET_INFO my_charset_utf16_spanish_uca_ci;
|
||||
extern CHARSET_INFO my_charset_utf16_swedish_uca_ci;
|
||||
extern CHARSET_INFO my_charset_utf16_turkish_uca_ci;
|
||||
extern CHARSET_INFO my_charset_utf16_czech_uca_ci;
|
||||
extern CHARSET_INFO my_charset_utf16_danish_uca_ci;
|
||||
extern CHARSET_INFO my_charset_utf16_lithuanian_uca_ci;
|
||||
extern CHARSET_INFO my_charset_utf16_slovak_uca_ci;
|
||||
extern CHARSET_INFO my_charset_utf16_spanish2_uca_ci;
|
||||
extern CHARSET_INFO my_charset_utf16_roman_uca_ci;
|
||||
extern CHARSET_INFO my_charset_utf16_persian_uca_ci;
|
||||
extern CHARSET_INFO my_charset_utf16_esperanto_uca_ci;
|
||||
extern CHARSET_INFO my_charset_utf16_hungarian_uca_ci;
|
||||
extern CHARSET_INFO my_charset_utf16_sinhala_uca_ci;
|
||||
#endif /* HAVE_CHARSET_utf16 */
|
||||
|
||||
|
||||
#ifdef HAVE_CHARSET_utf8
|
||||
extern CHARSET_INFO my_charset_utf8_icelandic_uca_ci;
|
||||
extern CHARSET_INFO my_charset_utf8_latvian_uca_ci;
|
||||
extern CHARSET_INFO my_charset_utf8_romanian_uca_ci;
|
||||
extern CHARSET_INFO my_charset_utf8_slovenian_uca_ci;
|
||||
extern CHARSET_INFO my_charset_utf8_polish_uca_ci;
|
||||
extern CHARSET_INFO my_charset_utf8_estonian_uca_ci;
|
||||
extern CHARSET_INFO my_charset_utf8_spanish_uca_ci;
|
||||
extern CHARSET_INFO my_charset_utf8_swedish_uca_ci;
|
||||
extern CHARSET_INFO my_charset_utf8_turkish_uca_ci;
|
||||
extern CHARSET_INFO my_charset_utf8_czech_uca_ci;
|
||||
extern CHARSET_INFO my_charset_utf8_danish_uca_ci;
|
||||
extern CHARSET_INFO my_charset_utf8_lithuanian_uca_ci;
|
||||
extern CHARSET_INFO my_charset_utf8_slovak_uca_ci;
|
||||
extern CHARSET_INFO my_charset_utf8_spanish2_uca_ci;
|
||||
extern CHARSET_INFO my_charset_utf8_roman_uca_ci;
|
||||
extern CHARSET_INFO my_charset_utf8_persian_uca_ci;
|
||||
extern CHARSET_INFO my_charset_utf8_esperanto_uca_ci;
|
||||
extern CHARSET_INFO my_charset_utf8_hungarian_uca_ci;
|
||||
extern CHARSET_INFO my_charset_utf8_sinhala_uca_ci;
|
||||
#ifdef HAVE_UTF8_GENERAL_CS
|
||||
extern CHARSET_INFO my_charset_utf8_general_cs;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_CHARSET_utf8mb4
|
||||
extern CHARSET_INFO my_charset_utf8mb4_icelandic_uca_ci;
|
||||
extern CHARSET_INFO my_charset_utf8mb4_latvian_uca_ci;
|
||||
extern CHARSET_INFO my_charset_utf8mb4_romanian_uca_ci;
|
||||
extern CHARSET_INFO my_charset_utf8mb4_slovenian_uca_ci;
|
||||
extern CHARSET_INFO my_charset_utf8mb4_polish_uca_ci;
|
||||
extern CHARSET_INFO my_charset_utf8mb4_estonian_uca_ci;
|
||||
extern CHARSET_INFO my_charset_utf8mb4_spanish_uca_ci;
|
||||
extern CHARSET_INFO my_charset_utf8mb4_swedish_uca_ci;
|
||||
extern CHARSET_INFO my_charset_utf8mb4_turkish_uca_ci;
|
||||
extern CHARSET_INFO my_charset_utf8mb4_czech_uca_ci;
|
||||
extern CHARSET_INFO my_charset_utf8mb4_danish_uca_ci;
|
||||
extern CHARSET_INFO my_charset_utf8mb4_lithuanian_uca_ci;
|
||||
extern CHARSET_INFO my_charset_utf8mb4_slovak_uca_ci;
|
||||
extern CHARSET_INFO my_charset_utf8mb4_spanish2_uca_ci;
|
||||
extern CHARSET_INFO my_charset_utf8mb4_roman_uca_ci;
|
||||
extern CHARSET_INFO my_charset_utf8mb4_persian_uca_ci;
|
||||
extern CHARSET_INFO my_charset_utf8mb4_esperanto_uca_ci;
|
||||
extern CHARSET_INFO my_charset_utf8mb4_hungarian_uca_ci;
|
||||
extern CHARSET_INFO my_charset_utf8mb4_sinhala_uca_ci;
|
||||
#endif /* HAVE_CHARSET_utf8mb4 */
|
||||
|
||||
#endif /* HAVE_UCA_COLLATIONS */
|
||||
|
||||
my_bool init_compiled_charsets(myf flags __attribute__((unused)))
|
||||
{
|
||||
CHARSET_INFO *cs;
|
||||
|
||||
add_compiled_collation(&my_charset_bin);
|
||||
add_compiled_collation(&my_charset_filename);
|
||||
|
||||
add_compiled_collation(&my_charset_latin1);
|
||||
add_compiled_collation(&my_charset_latin1_bin);
|
||||
add_compiled_collation(&my_charset_latin1_german2_ci);
|
||||
|
||||
#ifdef HAVE_CHARSET_big5
|
||||
add_compiled_collation(&my_charset_big5_chinese_ci);
|
||||
add_compiled_collation(&my_charset_big5_bin);
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_CHARSET_cp1250
|
||||
add_compiled_collation(&my_charset_cp1250_czech_ci);
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_CHARSET_cp932
|
||||
add_compiled_collation(&my_charset_cp932_japanese_ci);
|
||||
add_compiled_collation(&my_charset_cp932_bin);
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_CHARSET_latin2
|
||||
add_compiled_collation(&my_charset_latin2_czech_ci);
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_CHARSET_eucjpms
|
||||
add_compiled_collation(&my_charset_eucjpms_japanese_ci);
|
||||
add_compiled_collation(&my_charset_eucjpms_bin);
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_CHARSET_euckr
|
||||
add_compiled_collation(&my_charset_euckr_korean_ci);
|
||||
add_compiled_collation(&my_charset_euckr_bin);
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_CHARSET_gb2312
|
||||
add_compiled_collation(&my_charset_gb2312_chinese_ci);
|
||||
add_compiled_collation(&my_charset_gb2312_bin);
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_CHARSET_gbk
|
||||
add_compiled_collation(&my_charset_gbk_chinese_ci);
|
||||
add_compiled_collation(&my_charset_gbk_bin);
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_CHARSET_sjis
|
||||
add_compiled_collation(&my_charset_sjis_japanese_ci);
|
||||
add_compiled_collation(&my_charset_sjis_bin);
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_CHARSET_tis620
|
||||
add_compiled_collation(&my_charset_tis620_thai_ci);
|
||||
add_compiled_collation(&my_charset_tis620_bin);
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_CHARSET_ucs2
|
||||
add_compiled_collation(&my_charset_ucs2_general_ci);
|
||||
add_compiled_collation(&my_charset_ucs2_bin);
|
||||
#ifdef HAVE_UCA_COLLATIONS
|
||||
add_compiled_collation(&my_charset_ucs2_unicode_ci);
|
||||
add_compiled_collation(&my_charset_ucs2_icelandic_uca_ci);
|
||||
add_compiled_collation(&my_charset_ucs2_latvian_uca_ci);
|
||||
add_compiled_collation(&my_charset_ucs2_romanian_uca_ci);
|
||||
add_compiled_collation(&my_charset_ucs2_slovenian_uca_ci);
|
||||
add_compiled_collation(&my_charset_ucs2_polish_uca_ci);
|
||||
add_compiled_collation(&my_charset_ucs2_estonian_uca_ci);
|
||||
add_compiled_collation(&my_charset_ucs2_spanish_uca_ci);
|
||||
add_compiled_collation(&my_charset_ucs2_swedish_uca_ci);
|
||||
add_compiled_collation(&my_charset_ucs2_turkish_uca_ci);
|
||||
add_compiled_collation(&my_charset_ucs2_czech_uca_ci);
|
||||
add_compiled_collation(&my_charset_ucs2_danish_uca_ci);
|
||||
add_compiled_collation(&my_charset_ucs2_lithuanian_uca_ci);
|
||||
add_compiled_collation(&my_charset_ucs2_slovak_uca_ci);
|
||||
add_compiled_collation(&my_charset_ucs2_spanish2_uca_ci);
|
||||
add_compiled_collation(&my_charset_ucs2_roman_uca_ci);
|
||||
add_compiled_collation(&my_charset_ucs2_persian_uca_ci);
|
||||
add_compiled_collation(&my_charset_ucs2_esperanto_uca_ci);
|
||||
add_compiled_collation(&my_charset_ucs2_hungarian_uca_ci);
|
||||
add_compiled_collation(&my_charset_ucs2_sinhala_uca_ci);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_CHARSET_ujis
|
||||
add_compiled_collation(&my_charset_ujis_japanese_ci);
|
||||
add_compiled_collation(&my_charset_ujis_bin);
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_CHARSET_utf8
|
||||
add_compiled_collation(&my_charset_utf8_general_ci);
|
||||
add_compiled_collation(&my_charset_utf8_bin);
|
||||
#ifdef HAVE_UTF8_GENERAL_CS
|
||||
add_compiled_collation(&my_charset_utf8_general_cs);
|
||||
#endif
|
||||
#ifdef HAVE_UCA_COLLATIONS
|
||||
add_compiled_collation(&my_charset_utf8_unicode_ci);
|
||||
add_compiled_collation(&my_charset_utf8_icelandic_uca_ci);
|
||||
add_compiled_collation(&my_charset_utf8_latvian_uca_ci);
|
||||
add_compiled_collation(&my_charset_utf8_romanian_uca_ci);
|
||||
add_compiled_collation(&my_charset_utf8_slovenian_uca_ci);
|
||||
add_compiled_collation(&my_charset_utf8_polish_uca_ci);
|
||||
add_compiled_collation(&my_charset_utf8_estonian_uca_ci);
|
||||
add_compiled_collation(&my_charset_utf8_spanish_uca_ci);
|
||||
add_compiled_collation(&my_charset_utf8_swedish_uca_ci);
|
||||
add_compiled_collation(&my_charset_utf8_turkish_uca_ci);
|
||||
add_compiled_collation(&my_charset_utf8_czech_uca_ci);
|
||||
add_compiled_collation(&my_charset_utf8_danish_uca_ci);
|
||||
add_compiled_collation(&my_charset_utf8_lithuanian_uca_ci);
|
||||
add_compiled_collation(&my_charset_utf8_slovak_uca_ci);
|
||||
add_compiled_collation(&my_charset_utf8_spanish2_uca_ci);
|
||||
add_compiled_collation(&my_charset_utf8_roman_uca_ci);
|
||||
add_compiled_collation(&my_charset_utf8_persian_uca_ci);
|
||||
add_compiled_collation(&my_charset_utf8_esperanto_uca_ci);
|
||||
add_compiled_collation(&my_charset_utf8_hungarian_uca_ci);
|
||||
add_compiled_collation(&my_charset_utf8_sinhala_uca_ci);
|
||||
#endif
|
||||
#endif /* HAVE_CHARSET_utf8 */
|
||||
|
||||
|
||||
#ifdef HAVE_CHARSET_utf8mb4
|
||||
add_compiled_collation(&my_charset_utf8mb4_general_ci);
|
||||
add_compiled_collation(&my_charset_utf8mb4_bin);
|
||||
#ifdef HAVE_UCA_COLLATIONS
|
||||
add_compiled_collation(&my_charset_utf8mb4_unicode_ci);
|
||||
add_compiled_collation(&my_charset_utf8mb4_icelandic_uca_ci);
|
||||
add_compiled_collation(&my_charset_utf8mb4_latvian_uca_ci);
|
||||
add_compiled_collation(&my_charset_utf8mb4_romanian_uca_ci);
|
||||
add_compiled_collation(&my_charset_utf8mb4_slovenian_uca_ci);
|
||||
add_compiled_collation(&my_charset_utf8mb4_polish_uca_ci);
|
||||
add_compiled_collation(&my_charset_utf8mb4_estonian_uca_ci);
|
||||
add_compiled_collation(&my_charset_utf8mb4_spanish_uca_ci);
|
||||
add_compiled_collation(&my_charset_utf8mb4_swedish_uca_ci);
|
||||
add_compiled_collation(&my_charset_utf8mb4_turkish_uca_ci);
|
||||
add_compiled_collation(&my_charset_utf8mb4_czech_uca_ci);
|
||||
add_compiled_collation(&my_charset_utf8mb4_danish_uca_ci);
|
||||
add_compiled_collation(&my_charset_utf8mb4_lithuanian_uca_ci);
|
||||
add_compiled_collation(&my_charset_utf8mb4_slovak_uca_ci);
|
||||
add_compiled_collation(&my_charset_utf8mb4_spanish2_uca_ci);
|
||||
add_compiled_collation(&my_charset_utf8mb4_roman_uca_ci);
|
||||
add_compiled_collation(&my_charset_utf8mb4_persian_uca_ci);
|
||||
add_compiled_collation(&my_charset_utf8mb4_esperanto_uca_ci);
|
||||
add_compiled_collation(&my_charset_utf8mb4_hungarian_uca_ci);
|
||||
add_compiled_collation(&my_charset_utf8mb4_sinhala_uca_ci);
|
||||
#endif /* HAVE_UCA_COLLATIONS */
|
||||
#endif /* HAVE_CHARSET_utf8mb4 */
|
||||
|
||||
|
||||
#ifdef HAVE_CHARSET_utf16
|
||||
add_compiled_collation(&my_charset_utf16_general_ci);
|
||||
add_compiled_collation(&my_charset_utf16_bin);
|
||||
#ifdef HAVE_UCA_COLLATIONS
|
||||
add_compiled_collation(&my_charset_utf16_unicode_ci);
|
||||
add_compiled_collation(&my_charset_utf16_icelandic_uca_ci);
|
||||
add_compiled_collation(&my_charset_utf16_latvian_uca_ci);
|
||||
add_compiled_collation(&my_charset_utf16_romanian_uca_ci);
|
||||
add_compiled_collation(&my_charset_utf16_slovenian_uca_ci);
|
||||
add_compiled_collation(&my_charset_utf16_polish_uca_ci);
|
||||
add_compiled_collation(&my_charset_utf16_estonian_uca_ci);
|
||||
add_compiled_collation(&my_charset_utf16_spanish_uca_ci);
|
||||
add_compiled_collation(&my_charset_utf16_swedish_uca_ci);
|
||||
add_compiled_collation(&my_charset_utf16_turkish_uca_ci);
|
||||
add_compiled_collation(&my_charset_utf16_czech_uca_ci);
|
||||
add_compiled_collation(&my_charset_utf16_danish_uca_ci);
|
||||
add_compiled_collation(&my_charset_utf16_lithuanian_uca_ci);
|
||||
add_compiled_collation(&my_charset_utf16_slovak_uca_ci);
|
||||
add_compiled_collation(&my_charset_utf16_spanish2_uca_ci);
|
||||
add_compiled_collation(&my_charset_utf16_roman_uca_ci);
|
||||
add_compiled_collation(&my_charset_utf16_persian_uca_ci);
|
||||
add_compiled_collation(&my_charset_utf16_esperanto_uca_ci);
|
||||
add_compiled_collation(&my_charset_utf16_hungarian_uca_ci);
|
||||
add_compiled_collation(&my_charset_utf16_sinhala_uca_ci);
|
||||
#endif /* HAVE_UCA_COLLATIOINS */
|
||||
#endif /* HAVE_CHARSET_utf16 */
|
||||
|
||||
|
||||
#ifdef HAVE_CHARSET_utf32
|
||||
add_compiled_collation(&my_charset_utf32_general_ci);
|
||||
add_compiled_collation(&my_charset_utf32_bin);
|
||||
#ifdef HAVE_UCA_COLLATIONS
|
||||
add_compiled_collation(&my_charset_utf32_unicode_ci);
|
||||
add_compiled_collation(&my_charset_utf32_icelandic_uca_ci);
|
||||
add_compiled_collation(&my_charset_utf32_latvian_uca_ci);
|
||||
add_compiled_collation(&my_charset_utf32_romanian_uca_ci);
|
||||
add_compiled_collation(&my_charset_utf32_slovenian_uca_ci);
|
||||
add_compiled_collation(&my_charset_utf32_polish_uca_ci);
|
||||
add_compiled_collation(&my_charset_utf32_estonian_uca_ci);
|
||||
add_compiled_collation(&my_charset_utf32_spanish_uca_ci);
|
||||
add_compiled_collation(&my_charset_utf32_swedish_uca_ci);
|
||||
add_compiled_collation(&my_charset_utf32_turkish_uca_ci);
|
||||
add_compiled_collation(&my_charset_utf32_czech_uca_ci);
|
||||
add_compiled_collation(&my_charset_utf32_danish_uca_ci);
|
||||
add_compiled_collation(&my_charset_utf32_lithuanian_uca_ci);
|
||||
add_compiled_collation(&my_charset_utf32_slovak_uca_ci);
|
||||
add_compiled_collation(&my_charset_utf32_spanish2_uca_ci);
|
||||
add_compiled_collation(&my_charset_utf32_roman_uca_ci);
|
||||
add_compiled_collation(&my_charset_utf32_persian_uca_ci);
|
||||
add_compiled_collation(&my_charset_utf32_esperanto_uca_ci);
|
||||
add_compiled_collation(&my_charset_utf32_hungarian_uca_ci);
|
||||
add_compiled_collation(&my_charset_utf32_sinhala_uca_ci);
|
||||
#endif /* HAVE_UCA_COLLATIONS */
|
||||
#endif /* HAVE_CHARSET_utf32 */
|
||||
|
||||
/* Copy compiled charsets */
|
||||
for (cs=compiled_charsets; cs->name; cs++)
|
||||
add_compiled_collation(cs);
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
937
deps/mysqllite/mysys/charset.c
vendored
Normal file
937
deps/mysqllite/mysys/charset.c
vendored
Normal file
@@ -0,0 +1,937 @@
|
||||
/* Copyright (C) 2000 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 */
|
||||
|
||||
#include "mysys_priv.h"
|
||||
#include "mysys_err.h"
|
||||
#include <m_ctype.h>
|
||||
#include <m_string.h>
|
||||
#include <my_dir.h>
|
||||
#include <my_xml.h>
|
||||
|
||||
|
||||
/*
|
||||
The code below implements this functionality:
|
||||
|
||||
- Initializing charset related structures
|
||||
- Loading dynamic charsets
|
||||
- Searching for a proper CHARSET_INFO
|
||||
using charset name, collation name or collation ID
|
||||
- Setting server default character set
|
||||
*/
|
||||
|
||||
my_bool my_charset_same(CHARSET_INFO *cs1, CHARSET_INFO *cs2)
|
||||
{
|
||||
return ((cs1 == cs2) || !strcmp(cs1->csname,cs2->csname));
|
||||
}
|
||||
|
||||
|
||||
static uint
|
||||
get_collation_number_internal(const char *name)
|
||||
{
|
||||
CHARSET_INFO **cs;
|
||||
for (cs= all_charsets;
|
||||
cs < all_charsets + array_elements(all_charsets);
|
||||
cs++)
|
||||
{
|
||||
if ( cs[0] && cs[0]->name &&
|
||||
!my_strcasecmp(&my_charset_latin1, cs[0]->name, name))
|
||||
return cs[0]->number;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static my_bool init_state_maps(CHARSET_INFO *cs)
|
||||
{
|
||||
uint i;
|
||||
uchar *state_map;
|
||||
uchar *ident_map;
|
||||
|
||||
if (!(cs->state_map= (uchar*) my_once_alloc(256, MYF(MY_WME))))
|
||||
return 1;
|
||||
|
||||
if (!(cs->ident_map= (uchar*) my_once_alloc(256, MYF(MY_WME))))
|
||||
return 1;
|
||||
|
||||
state_map= cs->state_map;
|
||||
ident_map= cs->ident_map;
|
||||
|
||||
/* Fill state_map with states to get a faster parser */
|
||||
for (i=0; i < 256 ; i++)
|
||||
{
|
||||
if (my_isalpha(cs,i))
|
||||
state_map[i]=(uchar) MY_LEX_IDENT;
|
||||
else if (my_isdigit(cs,i))
|
||||
state_map[i]=(uchar) MY_LEX_NUMBER_IDENT;
|
||||
#if defined(USE_MB) && defined(USE_MB_IDENT)
|
||||
else if (my_mbcharlen(cs, i)>1)
|
||||
state_map[i]=(uchar) MY_LEX_IDENT;
|
||||
#endif
|
||||
else if (my_isspace(cs,i))
|
||||
state_map[i]=(uchar) MY_LEX_SKIP;
|
||||
else
|
||||
state_map[i]=(uchar) MY_LEX_CHAR;
|
||||
}
|
||||
state_map[(uchar)'_']=state_map[(uchar)'$']=(uchar) MY_LEX_IDENT;
|
||||
state_map[(uchar)'\'']=(uchar) MY_LEX_STRING;
|
||||
state_map[(uchar)'.']=(uchar) MY_LEX_REAL_OR_POINT;
|
||||
state_map[(uchar)'>']=state_map[(uchar)'=']=state_map[(uchar)'!']= (uchar) MY_LEX_CMP_OP;
|
||||
state_map[(uchar)'<']= (uchar) MY_LEX_LONG_CMP_OP;
|
||||
state_map[(uchar)'&']=state_map[(uchar)'|']=(uchar) MY_LEX_BOOL;
|
||||
state_map[(uchar)'#']=(uchar) MY_LEX_COMMENT;
|
||||
state_map[(uchar)';']=(uchar) MY_LEX_SEMICOLON;
|
||||
state_map[(uchar)':']=(uchar) MY_LEX_SET_VAR;
|
||||
state_map[0]=(uchar) MY_LEX_EOL;
|
||||
state_map[(uchar)'\\']= (uchar) MY_LEX_ESCAPE;
|
||||
state_map[(uchar)'/']= (uchar) MY_LEX_LONG_COMMENT;
|
||||
state_map[(uchar)'*']= (uchar) MY_LEX_END_LONG_COMMENT;
|
||||
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;
|
||||
|
||||
/*
|
||||
Create a second map to make it faster to find identifiers
|
||||
*/
|
||||
for (i=0; i < 256 ; i++)
|
||||
{
|
||||
ident_map[i]= (uchar) (state_map[i] == MY_LEX_IDENT ||
|
||||
state_map[i] == MY_LEX_NUMBER_IDENT);
|
||||
}
|
||||
|
||||
/* Special handling of hex and binary strings */
|
||||
state_map[(uchar)'x']= state_map[(uchar)'X']= (uchar) MY_LEX_IDENT_OR_HEX;
|
||||
state_map[(uchar)'b']= state_map[(uchar)'B']= (uchar) MY_LEX_IDENT_OR_BIN;
|
||||
state_map[(uchar)'n']= state_map[(uchar)'N']= (uchar) MY_LEX_IDENT_OR_NCHAR;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static void simple_cs_init_functions(CHARSET_INFO *cs)
|
||||
{
|
||||
if (cs->state & MY_CS_BINSORT)
|
||||
cs->coll= &my_collation_8bit_bin_handler;
|
||||
else
|
||||
cs->coll= &my_collation_8bit_simple_ci_handler;
|
||||
|
||||
cs->cset= &my_charset_8bit_handler;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static int cs_copy_data(CHARSET_INFO *to, CHARSET_INFO *from)
|
||||
{
|
||||
to->number= from->number ? from->number : to->number;
|
||||
|
||||
if (from->csname)
|
||||
if (!(to->csname= my_once_strdup(from->csname,MYF(MY_WME))))
|
||||
goto err;
|
||||
|
||||
if (from->name)
|
||||
if (!(to->name= my_once_strdup(from->name,MYF(MY_WME))))
|
||||
goto err;
|
||||
|
||||
if (from->comment)
|
||||
if (!(to->comment= my_once_strdup(from->comment,MYF(MY_WME))))
|
||||
goto err;
|
||||
|
||||
if (from->ctype)
|
||||
{
|
||||
if (!(to->ctype= (uchar*) my_once_memdup((char*) from->ctype,
|
||||
MY_CS_CTYPE_TABLE_SIZE,
|
||||
MYF(MY_WME))))
|
||||
goto err;
|
||||
if (init_state_maps(to))
|
||||
goto err;
|
||||
}
|
||||
if (from->to_lower)
|
||||
if (!(to->to_lower= (uchar*) my_once_memdup((char*) from->to_lower,
|
||||
MY_CS_TO_LOWER_TABLE_SIZE,
|
||||
MYF(MY_WME))))
|
||||
goto err;
|
||||
|
||||
if (from->to_upper)
|
||||
if (!(to->to_upper= (uchar*) my_once_memdup((char*) from->to_upper,
|
||||
MY_CS_TO_UPPER_TABLE_SIZE,
|
||||
MYF(MY_WME))))
|
||||
goto err;
|
||||
if (from->sort_order)
|
||||
{
|
||||
if (!(to->sort_order= (uchar*) my_once_memdup((char*) from->sort_order,
|
||||
MY_CS_SORT_ORDER_TABLE_SIZE,
|
||||
MYF(MY_WME))))
|
||||
goto err;
|
||||
|
||||
}
|
||||
if (from->tab_to_uni)
|
||||
{
|
||||
uint sz= MY_CS_TO_UNI_TABLE_SIZE*sizeof(uint16);
|
||||
if (!(to->tab_to_uni= (uint16*) my_once_memdup((char*)from->tab_to_uni,
|
||||
sz, MYF(MY_WME))))
|
||||
goto err;
|
||||
}
|
||||
if (from->tailoring)
|
||||
if (!(to->tailoring= my_once_strdup(from->tailoring,MYF(MY_WME))))
|
||||
goto err;
|
||||
|
||||
return 0;
|
||||
|
||||
err:
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static my_bool simple_cs_is_full(CHARSET_INFO *cs)
|
||||
{
|
||||
return ((cs->csname && cs->tab_to_uni && cs->ctype && cs->to_upper &&
|
||||
cs->to_lower) &&
|
||||
(cs->number && cs->name &&
|
||||
(cs->sort_order || (cs->state & MY_CS_BINSORT) )));
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
copy_uca_collation(CHARSET_INFO *to, CHARSET_INFO *from)
|
||||
{
|
||||
to->cset= from->cset;
|
||||
to->coll= from->coll;
|
||||
to->strxfrm_multiply= from->strxfrm_multiply;
|
||||
to->min_sort_char= from->min_sort_char;
|
||||
to->max_sort_char= from->max_sort_char;
|
||||
to->mbminlen= from->mbminlen;
|
||||
to->mbmaxlen= from->mbmaxlen;
|
||||
to->state|= MY_CS_AVAILABLE | MY_CS_LOADED |
|
||||
MY_CS_STRNXFRM | MY_CS_UNICODE;
|
||||
}
|
||||
|
||||
|
||||
static int add_collation(CHARSET_INFO *cs)
|
||||
{
|
||||
if (cs->name && (cs->number ||
|
||||
(cs->number=get_collation_number_internal(cs->name))) &&
|
||||
cs->number < array_elements(all_charsets))
|
||||
{
|
||||
if (!all_charsets[cs->number])
|
||||
{
|
||||
if (!(all_charsets[cs->number]=
|
||||
(CHARSET_INFO*) my_once_alloc(sizeof(CHARSET_INFO),MYF(0))))
|
||||
return MY_XML_ERROR;
|
||||
bzero((void*)all_charsets[cs->number],sizeof(CHARSET_INFO));
|
||||
}
|
||||
|
||||
if (cs->primary_number == cs->number)
|
||||
cs->state |= MY_CS_PRIMARY;
|
||||
|
||||
if (cs->binary_number == cs->number)
|
||||
cs->state |= MY_CS_BINSORT;
|
||||
|
||||
all_charsets[cs->number]->state|= cs->state;
|
||||
|
||||
if (!(all_charsets[cs->number]->state & MY_CS_COMPILED))
|
||||
{
|
||||
CHARSET_INFO *newcs= all_charsets[cs->number];
|
||||
if (cs_copy_data(all_charsets[cs->number],cs))
|
||||
return MY_XML_ERROR;
|
||||
|
||||
newcs->caseup_multiply= newcs->casedn_multiply= 1;
|
||||
|
||||
if (!strcmp(cs->csname,"ucs2") )
|
||||
{
|
||||
#if defined(HAVE_CHARSET_ucs2) && defined(HAVE_UCA_COLLATIONS)
|
||||
copy_uca_collation(newcs, &my_charset_ucs2_unicode_ci);
|
||||
newcs->state|= MY_CS_AVAILABLE | MY_CS_LOADED | MY_CS_NONASCII;
|
||||
#endif
|
||||
}
|
||||
else if (!strcmp(cs->csname, "utf8") || !strcmp(cs->csname, "utf8mb3"))
|
||||
{
|
||||
#if defined (HAVE_CHARSET_utf8) && defined(HAVE_UCA_COLLATIONS)
|
||||
copy_uca_collation(newcs, &my_charset_utf8_unicode_ci);
|
||||
newcs->ctype= my_charset_utf8_unicode_ci.ctype;
|
||||
if (init_state_maps(newcs))
|
||||
return MY_XML_ERROR;
|
||||
#endif
|
||||
}
|
||||
else if (!strcmp(cs->csname, "utf8mb4"))
|
||||
{
|
||||
#if defined (HAVE_CHARSET_utf8mb4) && defined(HAVE_UCA_COLLATIONS)
|
||||
copy_uca_collation(newcs, &my_charset_utf8mb4_unicode_ci);
|
||||
newcs->ctype= my_charset_utf8mb4_unicode_ci.ctype;
|
||||
newcs->state|= MY_CS_AVAILABLE | MY_CS_LOADED;
|
||||
#endif
|
||||
}
|
||||
else if (!strcmp(cs->csname, "utf16"))
|
||||
{
|
||||
#if defined (HAVE_CHARSET_utf16) && defined(HAVE_UCA_COLLATIONS)
|
||||
copy_uca_collation(newcs, &my_charset_utf16_unicode_ci);
|
||||
newcs->state|= MY_CS_AVAILABLE | MY_CS_LOADED | MY_CS_NONASCII;
|
||||
#endif
|
||||
}
|
||||
else if (!strcmp(cs->csname, "utf32"))
|
||||
{
|
||||
#if defined (HAVE_CHARSET_utf32) && defined(HAVE_UCA_COLLATIONS)
|
||||
copy_uca_collation(newcs, &my_charset_utf32_unicode_ci);
|
||||
newcs->state|= MY_CS_AVAILABLE | MY_CS_LOADED | MY_CS_NONASCII;
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
uchar *sort_order= all_charsets[cs->number]->sort_order;
|
||||
simple_cs_init_functions(all_charsets[cs->number]);
|
||||
newcs->mbminlen= 1;
|
||||
newcs->mbmaxlen= 1;
|
||||
if (simple_cs_is_full(all_charsets[cs->number]))
|
||||
{
|
||||
all_charsets[cs->number]->state |= MY_CS_LOADED;
|
||||
}
|
||||
all_charsets[cs->number]->state|= MY_CS_AVAILABLE;
|
||||
|
||||
/*
|
||||
Check if case sensitive sort order: A < a < B.
|
||||
We need MY_CS_FLAG for regex library, and for
|
||||
case sensitivity flag for 5.0 client protocol,
|
||||
to support isCaseSensitive() method in JDBC driver
|
||||
*/
|
||||
if (sort_order && sort_order['A'] < sort_order['a'] &&
|
||||
sort_order['a'] < sort_order['B'])
|
||||
all_charsets[cs->number]->state|= MY_CS_CSSORT;
|
||||
|
||||
if (my_charset_is_8bit_pure_ascii(all_charsets[cs->number]))
|
||||
all_charsets[cs->number]->state|= MY_CS_PUREASCII;
|
||||
if (!my_charset_is_ascii_compatible(cs))
|
||||
all_charsets[cs->number]->state|= MY_CS_NONASCII;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/*
|
||||
We need the below to make get_charset_name()
|
||||
and get_charset_number() working even if a
|
||||
character set has not been really incompiled.
|
||||
The above functions are used for example
|
||||
in error message compiler extra/comp_err.c.
|
||||
If a character set was compiled, this information
|
||||
will get lost and overwritten in add_compiled_collation().
|
||||
*/
|
||||
CHARSET_INFO *dst= all_charsets[cs->number];
|
||||
dst->number= cs->number;
|
||||
if (cs->comment)
|
||||
if (!(dst->comment= my_once_strdup(cs->comment,MYF(MY_WME))))
|
||||
return MY_XML_ERROR;
|
||||
if (cs->csname)
|
||||
if (!(dst->csname= my_once_strdup(cs->csname,MYF(MY_WME))))
|
||||
return MY_XML_ERROR;
|
||||
if (cs->name)
|
||||
if (!(dst->name= my_once_strdup(cs->name,MYF(MY_WME))))
|
||||
return MY_XML_ERROR;
|
||||
}
|
||||
cs->number= 0;
|
||||
cs->primary_number= 0;
|
||||
cs->binary_number= 0;
|
||||
cs->name= NULL;
|
||||
cs->state= 0;
|
||||
cs->sort_order= NULL;
|
||||
cs->state= 0;
|
||||
}
|
||||
return MY_XML_OK;
|
||||
}
|
||||
|
||||
|
||||
#define MY_MAX_ALLOWED_BUF 1024*1024
|
||||
#define MY_CHARSET_INDEX "Index.xml"
|
||||
|
||||
const char *charsets_dir= NULL;
|
||||
|
||||
|
||||
static my_bool my_read_charset_file(const char *filename, myf myflags)
|
||||
{
|
||||
uchar *buf;
|
||||
int fd;
|
||||
size_t len, tmp_len;
|
||||
MY_STAT stat_info;
|
||||
|
||||
if (!my_stat(filename, &stat_info, MYF(myflags)) ||
|
||||
((len= (uint)stat_info.st_size) > MY_MAX_ALLOWED_BUF) ||
|
||||
!(buf= (uchar*) my_malloc(len,myflags)))
|
||||
return TRUE;
|
||||
|
||||
if ((fd= mysql_file_open(key_file_charset, filename, O_RDONLY, myflags)) < 0)
|
||||
goto error;
|
||||
tmp_len= mysql_file_read(fd, buf, len, myflags);
|
||||
mysql_file_close(fd, myflags);
|
||||
if (tmp_len != len)
|
||||
goto error;
|
||||
|
||||
if (my_parse_charset_xml((char*) buf,len,add_collation))
|
||||
{
|
||||
#ifdef NOT_YET
|
||||
printf("ERROR at line %d pos %d '%s'\n",
|
||||
my_xml_error_lineno(&p)+1,
|
||||
my_xml_error_pos(&p),
|
||||
my_xml_error_string(&p));
|
||||
#endif
|
||||
}
|
||||
|
||||
my_free(buf);
|
||||
return FALSE;
|
||||
|
||||
error:
|
||||
my_free(buf);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
char *get_charsets_dir(char *buf)
|
||||
{
|
||||
const char *sharedir= SHAREDIR;
|
||||
char *res;
|
||||
DBUG_ENTER("get_charsets_dir");
|
||||
|
||||
if (charsets_dir != NULL)
|
||||
strmake(buf, charsets_dir, FN_REFLEN-1);
|
||||
else
|
||||
{
|
||||
if (test_if_hard_path(sharedir) ||
|
||||
is_prefix(sharedir, DEFAULT_CHARSET_HOME))
|
||||
strxmov(buf, sharedir, "/", CHARSET_DIR, NullS);
|
||||
else
|
||||
strxmov(buf, DEFAULT_CHARSET_HOME, "/", sharedir, "/", CHARSET_DIR,
|
||||
NullS);
|
||||
}
|
||||
res= convert_dirname(buf,buf,NullS);
|
||||
DBUG_PRINT("info",("charsets dir: '%s'", buf));
|
||||
DBUG_RETURN(res);
|
||||
}
|
||||
|
||||
CHARSET_INFO *all_charsets[MY_ALL_CHARSETS_SIZE]={NULL};
|
||||
CHARSET_INFO *default_charset_info = &my_charset_latin1;
|
||||
|
||||
void add_compiled_collation(CHARSET_INFO *cs)
|
||||
{
|
||||
all_charsets[cs->number]= cs;
|
||||
cs->state|= MY_CS_AVAILABLE;
|
||||
}
|
||||
|
||||
static void *cs_alloc(size_t size)
|
||||
{
|
||||
return my_once_alloc(size, MYF(MY_WME));
|
||||
}
|
||||
|
||||
|
||||
static my_pthread_once_t charsets_initialized= MY_PTHREAD_ONCE_INIT;
|
||||
static my_pthread_once_t charsets_template= MY_PTHREAD_ONCE_INIT;
|
||||
|
||||
static void init_available_charsets(void)
|
||||
{
|
||||
char fname[FN_REFLEN + sizeof(MY_CHARSET_INDEX)];
|
||||
CHARSET_INFO **cs;
|
||||
|
||||
bzero(&all_charsets,sizeof(all_charsets));
|
||||
init_compiled_charsets(MYF(0));
|
||||
|
||||
/* Copy compiled charsets */
|
||||
for (cs=all_charsets;
|
||||
cs < all_charsets+array_elements(all_charsets)-1 ;
|
||||
cs++)
|
||||
{
|
||||
if (*cs)
|
||||
{
|
||||
if (cs[0]->ctype)
|
||||
if (init_state_maps(*cs))
|
||||
*cs= NULL;
|
||||
}
|
||||
}
|
||||
|
||||
strmov(get_charsets_dir(fname), MY_CHARSET_INDEX);
|
||||
my_read_charset_file(fname, MYF(0));
|
||||
}
|
||||
|
||||
|
||||
void free_charsets(void)
|
||||
{
|
||||
charsets_initialized= charsets_template;
|
||||
}
|
||||
|
||||
|
||||
static const char*
|
||||
get_collation_name_alias(const char *name, char *buf, size_t bufsize)
|
||||
{
|
||||
if (!strncasecmp(name, "utf8mb3_", 8))
|
||||
{
|
||||
my_snprintf(buf, bufsize, "utf8_%s", name + 8);
|
||||
return buf;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
uint get_collation_number(const char *name)
|
||||
{
|
||||
uint id;
|
||||
char alias[64];
|
||||
my_pthread_once(&charsets_initialized, init_available_charsets);
|
||||
if ((id= get_collation_number_internal(name)))
|
||||
return id;
|
||||
if ((name= get_collation_name_alias(name, alias, sizeof(alias))))
|
||||
return get_collation_number_internal(name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static uint
|
||||
get_charset_number_internal(const char *charset_name, uint cs_flags)
|
||||
{
|
||||
CHARSET_INFO **cs;
|
||||
|
||||
for (cs= all_charsets;
|
||||
cs < all_charsets + array_elements(all_charsets);
|
||||
cs++)
|
||||
{
|
||||
if ( cs[0] && cs[0]->csname && (cs[0]->state & cs_flags) &&
|
||||
!my_strcasecmp(&my_charset_latin1, cs[0]->csname, charset_name))
|
||||
return cs[0]->number;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static const char*
|
||||
get_charset_name_alias(const char *name)
|
||||
{
|
||||
if (!my_strcasecmp(&my_charset_latin1, name, "utf8mb3"))
|
||||
return "utf8";
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
uint get_charset_number(const char *charset_name, uint cs_flags)
|
||||
{
|
||||
uint id;
|
||||
my_pthread_once(&charsets_initialized, init_available_charsets);
|
||||
if ((id= get_charset_number_internal(charset_name, cs_flags)))
|
||||
return id;
|
||||
if ((charset_name= get_charset_name_alias(charset_name)))
|
||||
return get_charset_number_internal(charset_name, cs_flags);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
const char *get_charset_name(uint charset_number)
|
||||
{
|
||||
CHARSET_INFO *cs;
|
||||
my_pthread_once(&charsets_initialized, init_available_charsets);
|
||||
|
||||
cs=all_charsets[charset_number];
|
||||
if (cs && (cs->number == charset_number) && cs->name )
|
||||
return (char*) cs->name;
|
||||
|
||||
return (char*) "?"; /* this mimics find_type() */
|
||||
}
|
||||
|
||||
|
||||
static CHARSET_INFO *get_internal_charset(uint cs_number, myf flags)
|
||||
{
|
||||
char buf[FN_REFLEN];
|
||||
CHARSET_INFO *cs;
|
||||
|
||||
if ((cs= all_charsets[cs_number]))
|
||||
{
|
||||
if (cs->state & MY_CS_READY) /* if CS is already initialized */
|
||||
return cs;
|
||||
|
||||
/*
|
||||
To make things thread safe we are not allowing other threads to interfere
|
||||
while we may changing the cs_info_table
|
||||
*/
|
||||
mysql_mutex_lock(&THR_LOCK_charset);
|
||||
|
||||
if (!(cs->state & (MY_CS_COMPILED|MY_CS_LOADED))) /* if CS is not in memory */
|
||||
{
|
||||
strxmov(get_charsets_dir(buf), cs->csname, ".xml", NullS);
|
||||
my_read_charset_file(buf,flags);
|
||||
}
|
||||
|
||||
if (cs->state & MY_CS_AVAILABLE)
|
||||
{
|
||||
if (!(cs->state & MY_CS_READY))
|
||||
{
|
||||
if ((cs->cset->init && cs->cset->init(cs, cs_alloc)) ||
|
||||
(cs->coll->init && cs->coll->init(cs, cs_alloc)))
|
||||
cs= NULL;
|
||||
else
|
||||
cs->state|= MY_CS_READY;
|
||||
}
|
||||
}
|
||||
else
|
||||
cs= NULL;
|
||||
|
||||
mysql_mutex_unlock(&THR_LOCK_charset);
|
||||
}
|
||||
return cs;
|
||||
}
|
||||
|
||||
|
||||
CHARSET_INFO *get_charset(uint cs_number, myf flags)
|
||||
{
|
||||
CHARSET_INFO *cs;
|
||||
if (cs_number == default_charset_info->number)
|
||||
return default_charset_info;
|
||||
|
||||
my_pthread_once(&charsets_initialized, init_available_charsets);
|
||||
|
||||
if (!cs_number || cs_number > array_elements(all_charsets))
|
||||
return NULL;
|
||||
|
||||
cs=get_internal_charset(cs_number, flags);
|
||||
|
||||
if (!cs && (flags & MY_WME))
|
||||
{
|
||||
char index_file[FN_REFLEN + sizeof(MY_CHARSET_INDEX)], cs_string[23];
|
||||
strmov(get_charsets_dir(index_file),MY_CHARSET_INDEX);
|
||||
cs_string[0]='#';
|
||||
int10_to_str(cs_number, cs_string+1, 10);
|
||||
my_error(EE_UNKNOWN_CHARSET, MYF(ME_BELL), cs_string, index_file);
|
||||
}
|
||||
return cs;
|
||||
}
|
||||
|
||||
CHARSET_INFO *get_charset_by_name(const char *cs_name, myf flags)
|
||||
{
|
||||
uint cs_number;
|
||||
CHARSET_INFO *cs;
|
||||
my_pthread_once(&charsets_initialized, init_available_charsets);
|
||||
|
||||
cs_number=get_collation_number(cs_name);
|
||||
cs= cs_number ? get_internal_charset(cs_number,flags) : NULL;
|
||||
|
||||
if (!cs && (flags & MY_WME))
|
||||
{
|
||||
char index_file[FN_REFLEN + sizeof(MY_CHARSET_INDEX)];
|
||||
strmov(get_charsets_dir(index_file),MY_CHARSET_INDEX);
|
||||
my_error(EE_UNKNOWN_COLLATION, MYF(ME_BELL), cs_name, index_file);
|
||||
}
|
||||
|
||||
return cs;
|
||||
}
|
||||
|
||||
|
||||
CHARSET_INFO *get_charset_by_csname(const char *cs_name,
|
||||
uint cs_flags,
|
||||
myf flags)
|
||||
{
|
||||
uint cs_number;
|
||||
CHARSET_INFO *cs;
|
||||
DBUG_ENTER("get_charset_by_csname");
|
||||
DBUG_PRINT("enter",("name: '%s'", cs_name));
|
||||
|
||||
my_pthread_once(&charsets_initialized, init_available_charsets);
|
||||
|
||||
cs_number= get_charset_number(cs_name, cs_flags);
|
||||
cs= cs_number ? get_internal_charset(cs_number, flags) : NULL;
|
||||
|
||||
if (!cs && (flags & MY_WME))
|
||||
{
|
||||
char index_file[FN_REFLEN + sizeof(MY_CHARSET_INDEX)];
|
||||
strmov(get_charsets_dir(index_file),MY_CHARSET_INDEX);
|
||||
my_error(EE_UNKNOWN_CHARSET, MYF(ME_BELL), cs_name, index_file);
|
||||
}
|
||||
|
||||
DBUG_RETURN(cs);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Resolve character set by the character set name (utf8, latin1, ...).
|
||||
|
||||
The function tries to resolve character set by the specified name. If
|
||||
there is character set with the given name, it is assigned to the "cs"
|
||||
parameter and FALSE is returned. If there is no such character set,
|
||||
"default_cs" is assigned to the "cs" and TRUE is returned.
|
||||
|
||||
@param[in] cs_name Character set name.
|
||||
@param[in] default_cs Default character set.
|
||||
@param[out] cs Variable to store character set.
|
||||
|
||||
@return FALSE if character set was resolved successfully; TRUE if there
|
||||
is no character set with given name.
|
||||
*/
|
||||
|
||||
my_bool resolve_charset(const char *cs_name,
|
||||
CHARSET_INFO *default_cs,
|
||||
CHARSET_INFO **cs)
|
||||
{
|
||||
*cs= get_charset_by_csname(cs_name, MY_CS_PRIMARY, MYF(0));
|
||||
|
||||
if (*cs == NULL)
|
||||
{
|
||||
*cs= default_cs;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Resolve collation by the collation name (utf8_general_ci, ...).
|
||||
|
||||
The function tries to resolve collation by the specified name. If there
|
||||
is collation with the given name, it is assigned to the "cl" parameter
|
||||
and FALSE is returned. If there is no such collation, "default_cl" is
|
||||
assigned to the "cl" and TRUE is returned.
|
||||
|
||||
@param[out] cl Variable to store collation.
|
||||
@param[in] cl_name Collation name.
|
||||
@param[in] default_cl Default collation.
|
||||
|
||||
@return FALSE if collation was resolved successfully; TRUE if there is no
|
||||
collation with given name.
|
||||
*/
|
||||
|
||||
my_bool resolve_collation(const char *cl_name,
|
||||
CHARSET_INFO *default_cl,
|
||||
CHARSET_INFO **cl)
|
||||
{
|
||||
*cl= get_charset_by_name(cl_name, MYF(0));
|
||||
|
||||
if (*cl == NULL)
|
||||
{
|
||||
*cl= default_cl;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Escape string with backslashes (\)
|
||||
|
||||
SYNOPSIS
|
||||
escape_string_for_mysql()
|
||||
charset_info Charset of the strings
|
||||
to Buffer for escaped string
|
||||
to_length Length of destination buffer, or 0
|
||||
from The string to escape
|
||||
length The length of the string to escape
|
||||
|
||||
DESCRIPTION
|
||||
This escapes the contents of a string by adding backslashes before special
|
||||
characters, and turning others into specific escape sequences, such as
|
||||
turning newlines into \n and null bytes into \0.
|
||||
|
||||
NOTE
|
||||
To maintain compatibility with the old C API, to_length may be 0 to mean
|
||||
"big enough"
|
||||
|
||||
RETURN VALUES
|
||||
(size_t) -1 The escaped string did not fit in the to buffer
|
||||
# The length of the escaped string
|
||||
*/
|
||||
|
||||
size_t escape_string_for_mysql(CHARSET_INFO *charset_info,
|
||||
char *to, size_t to_length,
|
||||
const char *from, size_t length)
|
||||
{
|
||||
const char *to_start= to;
|
||||
const char *end, *to_end=to_start + (to_length ? to_length-1 : 2*length);
|
||||
my_bool overflow= FALSE;
|
||||
#ifdef USE_MB
|
||||
my_bool use_mb_flag= use_mb(charset_info);
|
||||
#endif
|
||||
for (end= from + length; from < end; from++)
|
||||
{
|
||||
char escape= 0;
|
||||
#ifdef USE_MB
|
||||
int tmp_length;
|
||||
if (use_mb_flag && (tmp_length= my_ismbchar(charset_info, from, end)))
|
||||
{
|
||||
if (to + tmp_length > to_end)
|
||||
{
|
||||
overflow= TRUE;
|
||||
break;
|
||||
}
|
||||
while (tmp_length--)
|
||||
*to++= *from++;
|
||||
from--;
|
||||
continue;
|
||||
}
|
||||
/*
|
||||
If the next character appears to begin a multi-byte character, we
|
||||
escape that first byte of that apparent multi-byte character. (The
|
||||
character just looks like a multi-byte character -- if it were actually
|
||||
a multi-byte character, it would have been passed through in the test
|
||||
above.)
|
||||
|
||||
Without this check, we can create a problem by converting an invalid
|
||||
multi-byte character into a valid one. For example, 0xbf27 is not
|
||||
a valid GBK character, but 0xbf5c is. (0x27 = ', 0x5c = \)
|
||||
*/
|
||||
if (use_mb_flag && (tmp_length= my_mbcharlen(charset_info, *from)) > 1)
|
||||
escape= *from;
|
||||
else
|
||||
#endif
|
||||
switch (*from) {
|
||||
case 0: /* Must be escaped for 'mysql' */
|
||||
escape= '0';
|
||||
break;
|
||||
case '\n': /* Must be escaped for logs */
|
||||
escape= 'n';
|
||||
break;
|
||||
case '\r':
|
||||
escape= 'r';
|
||||
break;
|
||||
case '\\':
|
||||
escape= '\\';
|
||||
break;
|
||||
case '\'':
|
||||
escape= '\'';
|
||||
break;
|
||||
case '"': /* Better safe than sorry */
|
||||
escape= '"';
|
||||
break;
|
||||
case '\032': /* This gives problems on Win32 */
|
||||
escape= 'Z';
|
||||
break;
|
||||
}
|
||||
if (escape)
|
||||
{
|
||||
if (to + 2 > to_end)
|
||||
{
|
||||
overflow= TRUE;
|
||||
break;
|
||||
}
|
||||
*to++= '\\';
|
||||
*to++= escape;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (to + 1 > to_end)
|
||||
{
|
||||
overflow= TRUE;
|
||||
break;
|
||||
}
|
||||
*to++= *from;
|
||||
}
|
||||
}
|
||||
*to= 0;
|
||||
return overflow ? (size_t) -1 : (size_t) (to - to_start);
|
||||
}
|
||||
|
||||
|
||||
#ifdef BACKSLASH_MBTAIL
|
||||
static CHARSET_INFO *fs_cset_cache= NULL;
|
||||
|
||||
CHARSET_INFO *fs_character_set()
|
||||
{
|
||||
if (!fs_cset_cache)
|
||||
{
|
||||
char buf[10]= "cp";
|
||||
GetLocaleInfo(LOCALE_SYSTEM_DEFAULT, LOCALE_IDEFAULTANSICODEPAGE,
|
||||
buf+2, sizeof(buf)-3);
|
||||
/*
|
||||
We cannot call get_charset_by_name here
|
||||
because fs_character_set() is executed before
|
||||
LOCK_THD_charset mutex initialization, which
|
||||
is used inside get_charset_by_name.
|
||||
As we're now interested in cp932 only,
|
||||
let's just detect it using strcmp().
|
||||
*/
|
||||
fs_cset_cache= !strcmp(buf, "cp932") ?
|
||||
&my_charset_cp932_japanese_ci : &my_charset_bin;
|
||||
}
|
||||
return fs_cset_cache;
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
Escape apostrophes by doubling them up
|
||||
|
||||
SYNOPSIS
|
||||
escape_quotes_for_mysql()
|
||||
charset_info Charset of the strings
|
||||
to Buffer for escaped string
|
||||
to_length Length of destination buffer, or 0
|
||||
from The string to escape
|
||||
length The length of the string to escape
|
||||
|
||||
DESCRIPTION
|
||||
This escapes the contents of a string by doubling up any apostrophes that
|
||||
it contains. This is used when the NO_BACKSLASH_ESCAPES SQL_MODE is in
|
||||
effect on the server.
|
||||
|
||||
NOTE
|
||||
To be consistent with escape_string_for_mysql(), to_length may be 0 to
|
||||
mean "big enough"
|
||||
|
||||
RETURN VALUES
|
||||
~0 The escaped string did not fit in the to buffer
|
||||
>=0 The length of the escaped string
|
||||
*/
|
||||
|
||||
size_t escape_quotes_for_mysql(CHARSET_INFO *charset_info,
|
||||
char *to, size_t to_length,
|
||||
const char *from, size_t length)
|
||||
{
|
||||
const char *to_start= to;
|
||||
const char *end, *to_end=to_start + (to_length ? to_length-1 : 2*length);
|
||||
my_bool overflow= FALSE;
|
||||
#ifdef USE_MB
|
||||
my_bool use_mb_flag= use_mb(charset_info);
|
||||
#endif
|
||||
for (end= from + length; from < end; from++)
|
||||
{
|
||||
#ifdef USE_MB
|
||||
int tmp_length;
|
||||
if (use_mb_flag && (tmp_length= my_ismbchar(charset_info, from, end)))
|
||||
{
|
||||
if (to + tmp_length > to_end)
|
||||
{
|
||||
overflow= TRUE;
|
||||
break;
|
||||
}
|
||||
while (tmp_length--)
|
||||
*to++= *from++;
|
||||
from--;
|
||||
continue;
|
||||
}
|
||||
/*
|
||||
We don't have the same issue here with a non-multi-byte character being
|
||||
turned into a multi-byte character by the addition of an escaping
|
||||
character, because we are only escaping the ' character with itself.
|
||||
*/
|
||||
#endif
|
||||
if (*from == '\'')
|
||||
{
|
||||
if (to + 2 > to_end)
|
||||
{
|
||||
overflow= TRUE;
|
||||
break;
|
||||
}
|
||||
*to++= '\'';
|
||||
*to++= '\'';
|
||||
}
|
||||
else
|
||||
{
|
||||
if (to + 1 > to_end)
|
||||
{
|
||||
overflow= TRUE;
|
||||
break;
|
||||
}
|
||||
*to++= *from;
|
||||
}
|
||||
}
|
||||
*to= 0;
|
||||
return overflow ? (ulong)~0 : (ulong) (to - to_start);
|
||||
}
|
||||
35
deps/mysqllite/mysys/checksum.c
vendored
Normal file
35
deps/mysqllite/mysys/checksum.c
vendored
Normal file
@@ -0,0 +1,35 @@
|
||||
/* Copyright (C) 2000 MySQL AB
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
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 */
|
||||
|
||||
|
||||
#include <my_global.h>
|
||||
#include <my_sys.h>
|
||||
#include <zlib.h>
|
||||
|
||||
/*
|
||||
Calculate a long checksum for a memoryblock.
|
||||
|
||||
SYNOPSIS
|
||||
my_checksum()
|
||||
crc start value for crc
|
||||
pos pointer to memory block
|
||||
length length of the block
|
||||
*/
|
||||
|
||||
ha_checksum my_checksum(ha_checksum crc, const uchar *pos, size_t length)
|
||||
{
|
||||
return (ha_checksum)crc32((uint)crc, pos, (uint)length);
|
||||
}
|
||||
|
||||
1217
deps/mysqllite/mysys/default.c
vendored
Normal file
1217
deps/mysqllite/mysys/default.c
vendored
Normal file
File diff suppressed because it is too large
Load Diff
119
deps/mysqllite/mysys/errors.c
vendored
Normal file
119
deps/mysqllite/mysys/errors.c
vendored
Normal file
@@ -0,0 +1,119 @@
|
||||
/* Copyright (C) 2000 MySQL AB
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
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 */
|
||||
|
||||
#include "mysys_priv.h"
|
||||
#include "mysys_err.h"
|
||||
|
||||
#ifndef SHARED_LIBRARY
|
||||
|
||||
const char *globerrs[GLOBERRS]=
|
||||
{
|
||||
"Can't create/write to file '%s' (Errcode: %d)",
|
||||
"Error reading file '%s' (Errcode: %d)",
|
||||
"Error writing file '%s' (Errcode: %d)",
|
||||
"Error on close of '%s' (Errcode: %d)",
|
||||
"Out of memory (Needed %u bytes)",
|
||||
"Error on delete of '%s' (Errcode: %d)",
|
||||
"Error on rename of '%s' to '%s' (Errcode: %d)",
|
||||
"",
|
||||
"Unexpected eof found when reading file '%s' (Errcode: %d)",
|
||||
"Can't lock file (Errcode: %d)",
|
||||
"Can't unlock file (Errcode: %d)",
|
||||
"Can't read dir of '%s' (Errcode: %d)",
|
||||
"Can't get stat of '%s' (Errcode: %d)",
|
||||
"Can't change size of file (Errcode: %d)",
|
||||
"Can't open stream from handle (Errcode: %d)",
|
||||
"Can't get working dirctory (Errcode: %d)",
|
||||
"Can't change dir to '%s' (Errcode: %d)",
|
||||
"Warning: '%s' had %d links",
|
||||
"Warning: %d files and %d streams is left open\n",
|
||||
"Disk is full writing '%s' (Errcode: %d). Waiting for someone to free space... (Expect up to %d secs delay for server to continue after freeing disk space)",
|
||||
"Can't create directory '%s' (Errcode: %d)",
|
||||
"Character set '%s' is not a compiled character set and is not specified in the '%s' file",
|
||||
"Out of resources when opening file '%s' (Errcode: %d)",
|
||||
"Can't read value for symlink '%s' (Error %d)",
|
||||
"Can't create symlink '%s' pointing at '%s' (Error %d)",
|
||||
"Error on realpath() on '%s' (Error %d)",
|
||||
"Can't sync file '%s' to disk (Errcode: %d)",
|
||||
"Collation '%s' is not a compiled collation and is not specified in the '%s' file",
|
||||
"File '%s' not found (Errcode: %d)",
|
||||
"File '%s' (fileno: %d) was not closed",
|
||||
"Can't change ownership of the file '%s' (Errcode: %d)",
|
||||
"Can't change permissions of the file '%s' (Errcode: %d)",
|
||||
"Can't seek in file '%s' (Errcode: %d)"
|
||||
};
|
||||
|
||||
void init_glob_errs(void)
|
||||
{
|
||||
/* This is now done statically. */
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
void init_glob_errs()
|
||||
{
|
||||
EE(EE_CANTCREATEFILE) = "Can't create/write to file '%s' (Errcode: %d)";
|
||||
EE(EE_READ) = "Error reading file '%s' (Errcode: %d)";
|
||||
EE(EE_WRITE) = "Error writing file '%s' (Errcode: %d)";
|
||||
EE(EE_BADCLOSE) = "Error on close of '%'s (Errcode: %d)";
|
||||
EE(EE_OUTOFMEMORY) = "Out of memory (Needed %u bytes)";
|
||||
EE(EE_DELETE) = "Error on delete of '%s' (Errcode: %d)";
|
||||
EE(EE_LINK) = "Error on rename of '%s' to '%s' (Errcode: %d)";
|
||||
EE(EE_EOFERR) = "Unexpected eof found when reading file '%s' (Errcode: %d)";
|
||||
EE(EE_CANTLOCK) = "Can't lock file (Errcode: %d)";
|
||||
EE(EE_CANTUNLOCK) = "Can't unlock file (Errcode: %d)";
|
||||
EE(EE_DIR) = "Can't read dir of '%s' (Errcode: %d)";
|
||||
EE(EE_STAT) = "Can't get stat of '%s' (Errcode: %d)";
|
||||
EE(EE_CANT_CHSIZE) = "Can't change size of file (Errcode: %d)";
|
||||
EE(EE_CANT_OPEN_STREAM)= "Can't open stream from handle (Errcode: %d)";
|
||||
EE(EE_GETWD) = "Can't get working directory (Errcode: %d)";
|
||||
EE(EE_SETWD) = "Can't change dir to '%s' (Errcode: %d)";
|
||||
EE(EE_LINK_WARNING) = "Warning: '%s' had %d links";
|
||||
EE(EE_OPEN_WARNING) = "Warning: %d files and %d streams is left open\n";
|
||||
EE(EE_DISK_FULL) = "Disk is full writing '%s'. Waiting for someone to free space...";
|
||||
EE(EE_CANT_MKDIR) ="Can't create directory '%s' (Errcode: %d)";
|
||||
EE(EE_UNKNOWN_CHARSET)= "Character set '%s' is not a compiled character set and is not specified in the %s file";
|
||||
EE(EE_OUT_OF_FILERESOURCES)="Out of resources when opening file '%s' (Errcode: %d)";
|
||||
EE(EE_CANT_READLINK)= "Can't read value for symlink '%s' (Error %d)";
|
||||
EE(EE_CANT_SYMLINK)= "Can't create symlink '%s' pointing at '%s' (Error %d)";
|
||||
EE(EE_REALPATH)= "Error on realpath() on '%s' (Error %d)";
|
||||
EE(EE_SYNC)= "Can't sync file '%s' to disk (Errcode: %d)";
|
||||
EE(EE_UNKNOWN_COLLATION)= "Collation '%s' is not a compiled collation and is not specified in the %s file";
|
||||
EE(EE_FILENOTFOUND) = "File '%s' not found (Errcode: %d)";
|
||||
EE(EE_FILE_NOT_CLOSED) = "File '%s' (fileno: %d) was not closed";
|
||||
EE(EE_CHANGE_OWNERSHIP) = "Can't change ownership of the file '%s' (Errcode: %d)";
|
||||
EE(EE_CHANGE_PERMISSIONS) = "Can't change permissions of the file '%s' (Errcode: %d)";
|
||||
EE(EE_CANT_SEEK) = "Can't seek in file '%s' (Errcode: %d)";
|
||||
}
|
||||
#endif
|
||||
|
||||
void wait_for_free_space(const char *filename, int errors)
|
||||
{
|
||||
if (errors == 0)
|
||||
my_error(EE_DISK_FULL,MYF(ME_BELL | ME_NOREFRESH),
|
||||
filename,my_errno,MY_WAIT_FOR_USER_TO_FIX_PANIC);
|
||||
if (!(errors % MY_WAIT_GIVE_USER_A_MESSAGE))
|
||||
my_printf_error(EE_DISK_FULL,
|
||||
"Retry in %d secs. Message reprinted in %d secs",
|
||||
MYF(ME_BELL | ME_NOREFRESH),
|
||||
MY_WAIT_FOR_USER_TO_FIX_PANIC,
|
||||
MY_WAIT_GIVE_USER_A_MESSAGE * MY_WAIT_FOR_USER_TO_FIX_PANIC );
|
||||
(void) sleep(MY_WAIT_FOR_USER_TO_FIX_PANIC);
|
||||
}
|
||||
|
||||
const char **get_global_errmsgs()
|
||||
{
|
||||
return globerrs;
|
||||
}
|
||||
769
deps/mysqllite/mysys/hash.c
vendored
Normal file
769
deps/mysqllite/mysys/hash.c
vendored
Normal file
@@ -0,0 +1,769 @@
|
||||
/* Copyright 2000-2008 MySQL AB, 2008 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 hash functions used for saveing keys */
|
||||
/* One of key_length or key_length_offset must be given */
|
||||
/* Key length of 0 isn't allowed */
|
||||
|
||||
#include "mysys_priv.h"
|
||||
#include <m_string.h>
|
||||
#include <m_ctype.h>
|
||||
#include "hash.h"
|
||||
|
||||
#define NO_RECORD ((uint) -1)
|
||||
#define LOWFIND 1
|
||||
#define LOWUSED 2
|
||||
#define HIGHFIND 4
|
||||
#define HIGHUSED 8
|
||||
|
||||
typedef struct st_hash_info {
|
||||
uint next; /* index to next key */
|
||||
uchar *data; /* data for current entry */
|
||||
} HASH_LINK;
|
||||
|
||||
static uint my_hash_mask(my_hash_value_type hashnr,
|
||||
size_t buffmax, size_t maxlength);
|
||||
static void movelink(HASH_LINK *array,uint pos,uint next_link,uint newlink);
|
||||
static int hashcmp(const HASH *hash, HASH_LINK *pos, const uchar *key,
|
||||
size_t length);
|
||||
|
||||
static my_hash_value_type calc_hash(const HASH *hash,
|
||||
const uchar *key, size_t length)
|
||||
{
|
||||
ulong nr1=1, nr2=4;
|
||||
hash->charset->coll->hash_sort(hash->charset,(uchar*) key,length,&nr1,&nr2);
|
||||
return (my_hash_value_type)nr1;
|
||||
}
|
||||
|
||||
/**
|
||||
@brief Initialize the hash
|
||||
|
||||
@details
|
||||
|
||||
Initialize the hash, by defining and giving valid values for
|
||||
its elements. The failure to allocate memory for the
|
||||
hash->array element will not result in a fatal failure. The
|
||||
dynamic array that is part of the hash will allocate memory
|
||||
as required during insertion.
|
||||
|
||||
@param[in,out] hash The hash that is initialized
|
||||
@param[in] charset The charater set information
|
||||
@param[in] size The hash size
|
||||
@param[in] key_offest The key offset for the hash
|
||||
@param[in] key_length The length of the key used in
|
||||
the hash
|
||||
@param[in] get_key get the key for the hash
|
||||
@param[in] free_element pointer to the function that
|
||||
does cleanup
|
||||
@return inidicates success or failure of initialization
|
||||
@retval 0 success
|
||||
@retval 1 failure
|
||||
*/
|
||||
my_bool
|
||||
_my_hash_init(HASH *hash, uint growth_size, CHARSET_INFO *charset,
|
||||
ulong size, size_t key_offset, size_t key_length,
|
||||
my_hash_get_key get_key,
|
||||
void (*free_element)(void*), uint flags)
|
||||
{
|
||||
DBUG_ENTER("my_hash_init");
|
||||
DBUG_PRINT("enter",("hash: 0x%lx size: %u", (long) hash, (uint) size));
|
||||
|
||||
hash->records=0;
|
||||
hash->key_offset=key_offset;
|
||||
hash->key_length=key_length;
|
||||
hash->blength=1;
|
||||
hash->get_key=get_key;
|
||||
hash->free=free_element;
|
||||
hash->flags=flags;
|
||||
hash->charset=charset;
|
||||
DBUG_RETURN(my_init_dynamic_array_ci(&hash->array,
|
||||
sizeof(HASH_LINK), size, growth_size));
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Call hash->free on all elements in hash.
|
||||
|
||||
SYNOPSIS
|
||||
my_hash_free_elements()
|
||||
hash hash table
|
||||
|
||||
NOTES:
|
||||
Sets records to 0
|
||||
*/
|
||||
|
||||
static inline void my_hash_free_elements(HASH *hash)
|
||||
{
|
||||
if (hash->free)
|
||||
{
|
||||
HASH_LINK *data=dynamic_element(&hash->array,0,HASH_LINK*);
|
||||
HASH_LINK *end= data + hash->records;
|
||||
while (data < end)
|
||||
(*hash->free)((data++)->data);
|
||||
}
|
||||
hash->records=0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Free memory used by hash.
|
||||
|
||||
SYNOPSIS
|
||||
my_hash_free()
|
||||
hash the hash to delete elements of
|
||||
|
||||
NOTES: Hash can't be reused without calling my_hash_init again.
|
||||
*/
|
||||
|
||||
void my_hash_free(HASH *hash)
|
||||
{
|
||||
DBUG_ENTER("my_hash_free");
|
||||
DBUG_PRINT("enter",("hash: 0x%lx", (long) hash));
|
||||
|
||||
my_hash_free_elements(hash);
|
||||
hash->free= 0;
|
||||
delete_dynamic(&hash->array);
|
||||
hash->blength= 0;
|
||||
DBUG_VOID_RETURN;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Delete all elements from the hash (the hash itself is to be reused).
|
||||
|
||||
SYNOPSIS
|
||||
my_hash_reset()
|
||||
hash the hash to delete elements of
|
||||
*/
|
||||
|
||||
void my_hash_reset(HASH *hash)
|
||||
{
|
||||
DBUG_ENTER("my_hash_reset");
|
||||
DBUG_PRINT("enter",("hash: 0x%lxd", (long) hash));
|
||||
|
||||
my_hash_free_elements(hash);
|
||||
reset_dynamic(&hash->array);
|
||||
/* Set row pointers so that the hash can be reused at once */
|
||||
hash->blength= 1;
|
||||
DBUG_VOID_RETURN;
|
||||
}
|
||||
|
||||
/* some helper functions */
|
||||
|
||||
/*
|
||||
This function is char* instead of uchar* as HPUX11 compiler can't
|
||||
handle inline functions that are not defined as native types
|
||||
*/
|
||||
|
||||
static inline char*
|
||||
my_hash_key(const HASH *hash, const uchar *record, size_t *length,
|
||||
my_bool first)
|
||||
{
|
||||
if (hash->get_key)
|
||||
return (char*) (*hash->get_key)(record,length,first);
|
||||
*length=hash->key_length;
|
||||
return (char*) record+hash->key_offset;
|
||||
}
|
||||
|
||||
/* Calculate pos according to keys */
|
||||
|
||||
static uint my_hash_mask(my_hash_value_type hashnr, size_t buffmax,
|
||||
size_t maxlength)
|
||||
{
|
||||
if ((hashnr & (buffmax-1)) < maxlength) return (hashnr & (buffmax-1));
|
||||
return (hashnr & ((buffmax >> 1) -1));
|
||||
}
|
||||
|
||||
static uint my_hash_rec_mask(const HASH *hash, HASH_LINK *pos,
|
||||
size_t buffmax, size_t maxlength)
|
||||
{
|
||||
size_t length;
|
||||
uchar *key= (uchar*) my_hash_key(hash, pos->data, &length, 0);
|
||||
return my_hash_mask(calc_hash(hash, key, length), buffmax, maxlength);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* for compilers which can not handle inline */
|
||||
static
|
||||
#if !defined(__USLC__) && !defined(__sgi)
|
||||
inline
|
||||
#endif
|
||||
my_hash_value_type rec_hashnr(HASH *hash,const uchar *record)
|
||||
{
|
||||
size_t length;
|
||||
uchar *key= (uchar*) my_hash_key(hash, record, &length, 0);
|
||||
return calc_hash(hash,key,length);
|
||||
}
|
||||
|
||||
|
||||
uchar* my_hash_search(const HASH *hash, const uchar *key, size_t length)
|
||||
{
|
||||
HASH_SEARCH_STATE state;
|
||||
return my_hash_first(hash, key, length, &state);
|
||||
}
|
||||
|
||||
uchar* my_hash_search_using_hash_value(const HASH *hash,
|
||||
my_hash_value_type hash_value,
|
||||
const uchar *key,
|
||||
size_t length)
|
||||
{
|
||||
HASH_SEARCH_STATE state;
|
||||
return my_hash_first_from_hash_value(hash, hash_value,
|
||||
key, length, &state);
|
||||
}
|
||||
|
||||
my_hash_value_type my_calc_hash(const HASH *hash,
|
||||
const uchar *key, size_t length)
|
||||
{
|
||||
return calc_hash(hash, key, length ? length : hash->key_length);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Search after a record based on a key
|
||||
|
||||
NOTE
|
||||
Assigns the number of the found record to HASH_SEARCH_STATE state
|
||||
*/
|
||||
|
||||
uchar* my_hash_first(const HASH *hash, const uchar *key, size_t length,
|
||||
HASH_SEARCH_STATE *current_record)
|
||||
{
|
||||
uchar *res;
|
||||
if (my_hash_inited(hash))
|
||||
res= my_hash_first_from_hash_value(hash,
|
||||
calc_hash(hash, key, length ? length : hash->key_length),
|
||||
key, length, current_record);
|
||||
else
|
||||
res= 0;
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
uchar* my_hash_first_from_hash_value(const HASH *hash,
|
||||
my_hash_value_type hash_value,
|
||||
const uchar *key,
|
||||
size_t length,
|
||||
HASH_SEARCH_STATE *current_record)
|
||||
{
|
||||
HASH_LINK *pos;
|
||||
uint flag,idx;
|
||||
DBUG_ENTER("my_hash_first_from_hash_value");
|
||||
|
||||
flag=1;
|
||||
if (hash->records)
|
||||
{
|
||||
idx= my_hash_mask(hash_value,
|
||||
hash->blength, hash->records);
|
||||
do
|
||||
{
|
||||
pos= dynamic_element(&hash->array,idx,HASH_LINK*);
|
||||
if (!hashcmp(hash,pos,key,length))
|
||||
{
|
||||
DBUG_PRINT("exit",("found key at %d",idx));
|
||||
*current_record= idx;
|
||||
DBUG_RETURN (pos->data);
|
||||
}
|
||||
if (flag)
|
||||
{
|
||||
flag=0; /* Reset flag */
|
||||
if (my_hash_rec_mask(hash, pos, hash->blength, hash->records) != idx)
|
||||
break; /* Wrong link */
|
||||
}
|
||||
}
|
||||
while ((idx=pos->next) != NO_RECORD);
|
||||
}
|
||||
*current_record= NO_RECORD;
|
||||
DBUG_RETURN(0);
|
||||
}
|
||||
|
||||
/* Get next record with identical key */
|
||||
/* Can only be called if previous calls was my_hash_search */
|
||||
|
||||
uchar* my_hash_next(const HASH *hash, const uchar *key, size_t length,
|
||||
HASH_SEARCH_STATE *current_record)
|
||||
{
|
||||
HASH_LINK *pos;
|
||||
uint idx;
|
||||
|
||||
if (*current_record != NO_RECORD)
|
||||
{
|
||||
HASH_LINK *data=dynamic_element(&hash->array,0,HASH_LINK*);
|
||||
for (idx=data[*current_record].next; idx != NO_RECORD ; idx=pos->next)
|
||||
{
|
||||
pos=data+idx;
|
||||
if (!hashcmp(hash,pos,key,length))
|
||||
{
|
||||
*current_record= idx;
|
||||
return pos->data;
|
||||
}
|
||||
}
|
||||
*current_record= NO_RECORD;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* Change link from pos to new_link */
|
||||
|
||||
static void movelink(HASH_LINK *array,uint find,uint next_link,uint newlink)
|
||||
{
|
||||
HASH_LINK *old_link;
|
||||
do
|
||||
{
|
||||
old_link=array+next_link;
|
||||
}
|
||||
while ((next_link=old_link->next) != find);
|
||||
old_link->next= newlink;
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
Compare a key in a record to a whole key. Return 0 if identical
|
||||
|
||||
SYNOPSIS
|
||||
hashcmp()
|
||||
hash hash table
|
||||
pos position of hash record to use in comparison
|
||||
key key for comparison
|
||||
length length of key
|
||||
|
||||
NOTES:
|
||||
If length is 0, comparison is done using the length of the
|
||||
record being compared against.
|
||||
|
||||
RETURN
|
||||
= 0 key of record == key
|
||||
!= 0 key of record != key
|
||||
*/
|
||||
|
||||
static int hashcmp(const HASH *hash, HASH_LINK *pos, const uchar *key,
|
||||
size_t length)
|
||||
{
|
||||
size_t rec_keylength;
|
||||
uchar *rec_key= (uchar*) my_hash_key(hash, pos->data, &rec_keylength, 1);
|
||||
return ((length && length != rec_keylength) ||
|
||||
my_strnncoll(hash->charset, (uchar*) rec_key, rec_keylength,
|
||||
(uchar*) key, rec_keylength));
|
||||
}
|
||||
|
||||
|
||||
/* Write a hash-key to the hash-index */
|
||||
|
||||
my_bool my_hash_insert(HASH *info, const uchar *record)
|
||||
{
|
||||
int flag;
|
||||
size_t idx,halfbuff,first_index;
|
||||
my_hash_value_type hash_nr;
|
||||
uchar *UNINIT_VAR(ptr_to_rec),*UNINIT_VAR(ptr_to_rec2);
|
||||
HASH_LINK *data,*empty,*UNINIT_VAR(gpos),*UNINIT_VAR(gpos2),*pos;
|
||||
|
||||
if (HASH_UNIQUE & info->flags)
|
||||
{
|
||||
uchar *key= (uchar*) my_hash_key(info, record, &idx, 1);
|
||||
if (my_hash_search(info, key, idx))
|
||||
return(TRUE); /* Duplicate entry */
|
||||
}
|
||||
|
||||
flag=0;
|
||||
if (!(empty=(HASH_LINK*) alloc_dynamic(&info->array)))
|
||||
return(TRUE); /* No more memory */
|
||||
|
||||
data=dynamic_element(&info->array,0,HASH_LINK*);
|
||||
halfbuff= info->blength >> 1;
|
||||
|
||||
idx=first_index=info->records-halfbuff;
|
||||
if (idx != info->records) /* If some records */
|
||||
{
|
||||
do
|
||||
{
|
||||
pos=data+idx;
|
||||
hash_nr=rec_hashnr(info,pos->data);
|
||||
if (flag == 0) /* First loop; Check if ok */
|
||||
if (my_hash_mask(hash_nr, info->blength, info->records) != first_index)
|
||||
break;
|
||||
if (!(hash_nr & halfbuff))
|
||||
{ /* Key will not move */
|
||||
if (!(flag & LOWFIND))
|
||||
{
|
||||
if (flag & HIGHFIND)
|
||||
{
|
||||
flag=LOWFIND | HIGHFIND;
|
||||
/* key shall be moved to the current empty position */
|
||||
gpos=empty;
|
||||
ptr_to_rec=pos->data;
|
||||
empty=pos; /* This place is now free */
|
||||
}
|
||||
else
|
||||
{
|
||||
flag=LOWFIND | LOWUSED; /* key isn't changed */
|
||||
gpos=pos;
|
||||
ptr_to_rec=pos->data;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!(flag & LOWUSED))
|
||||
{
|
||||
/* Change link of previous LOW-key */
|
||||
gpos->data=ptr_to_rec;
|
||||
gpos->next= (uint) (pos-data);
|
||||
flag= (flag & HIGHFIND) | (LOWFIND | LOWUSED);
|
||||
}
|
||||
gpos=pos;
|
||||
ptr_to_rec=pos->data;
|
||||
}
|
||||
}
|
||||
else
|
||||
{ /* key will be moved */
|
||||
if (!(flag & HIGHFIND))
|
||||
{
|
||||
flag= (flag & LOWFIND) | HIGHFIND;
|
||||
/* key shall be moved to the last (empty) position */
|
||||
gpos2 = empty; empty=pos;
|
||||
ptr_to_rec2=pos->data;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!(flag & HIGHUSED))
|
||||
{
|
||||
/* Change link of previous hash-key and save */
|
||||
gpos2->data=ptr_to_rec2;
|
||||
gpos2->next=(uint) (pos-data);
|
||||
flag= (flag & LOWFIND) | (HIGHFIND | HIGHUSED);
|
||||
}
|
||||
gpos2=pos;
|
||||
ptr_to_rec2=pos->data;
|
||||
}
|
||||
}
|
||||
}
|
||||
while ((idx=pos->next) != NO_RECORD);
|
||||
|
||||
if ((flag & (LOWFIND | LOWUSED)) == LOWFIND)
|
||||
{
|
||||
gpos->data=ptr_to_rec;
|
||||
gpos->next=NO_RECORD;
|
||||
}
|
||||
if ((flag & (HIGHFIND | HIGHUSED)) == HIGHFIND)
|
||||
{
|
||||
gpos2->data=ptr_to_rec2;
|
||||
gpos2->next=NO_RECORD;
|
||||
}
|
||||
}
|
||||
/* Check if we are at the empty position */
|
||||
|
||||
idx= my_hash_mask(rec_hashnr(info, record), info->blength, info->records + 1);
|
||||
pos=data+idx;
|
||||
if (pos == empty)
|
||||
{
|
||||
pos->data=(uchar*) record;
|
||||
pos->next=NO_RECORD;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Check if more records in same hash-nr family */
|
||||
empty[0]=pos[0];
|
||||
gpos= data + my_hash_rec_mask(info, pos, info->blength, info->records + 1);
|
||||
if (pos == gpos)
|
||||
{
|
||||
pos->data=(uchar*) record;
|
||||
pos->next=(uint) (empty - data);
|
||||
}
|
||||
else
|
||||
{
|
||||
pos->data=(uchar*) record;
|
||||
pos->next=NO_RECORD;
|
||||
movelink(data,(uint) (pos-data),(uint) (gpos-data),(uint) (empty-data));
|
||||
}
|
||||
}
|
||||
if (++info->records == info->blength)
|
||||
info->blength+= info->blength;
|
||||
return(0);
|
||||
}
|
||||
|
||||
|
||||
/******************************************************************************
|
||||
** Remove one record from hash-table. The record with the same record
|
||||
** ptr is removed.
|
||||
** if there is a free-function it's called for record if found
|
||||
******************************************************************************/
|
||||
|
||||
my_bool my_hash_delete(HASH *hash, uchar *record)
|
||||
{
|
||||
uint blength,pos2,idx,empty_index;
|
||||
my_hash_value_type pos_hashnr, lastpos_hashnr;
|
||||
HASH_LINK *data,*lastpos,*gpos,*pos,*pos3,*empty;
|
||||
DBUG_ENTER("my_hash_delete");
|
||||
if (!hash->records)
|
||||
DBUG_RETURN(1);
|
||||
|
||||
blength=hash->blength;
|
||||
data=dynamic_element(&hash->array,0,HASH_LINK*);
|
||||
/* Search after record with key */
|
||||
pos= data + my_hash_mask(rec_hashnr(hash, record), blength, hash->records);
|
||||
gpos = 0;
|
||||
|
||||
while (pos->data != record)
|
||||
{
|
||||
gpos=pos;
|
||||
if (pos->next == NO_RECORD)
|
||||
DBUG_RETURN(1); /* Key not found */
|
||||
pos=data+pos->next;
|
||||
}
|
||||
|
||||
if ( --(hash->records) < hash->blength >> 1) hash->blength>>=1;
|
||||
lastpos=data+hash->records;
|
||||
|
||||
/* Remove link to record */
|
||||
empty=pos; empty_index=(uint) (empty-data);
|
||||
if (gpos)
|
||||
gpos->next=pos->next; /* unlink current ptr */
|
||||
else if (pos->next != NO_RECORD)
|
||||
{
|
||||
empty=data+(empty_index=pos->next);
|
||||
pos->data=empty->data;
|
||||
pos->next=empty->next;
|
||||
}
|
||||
|
||||
if (empty == lastpos) /* last key at wrong pos or no next link */
|
||||
goto exit;
|
||||
|
||||
/* Move the last key (lastpos) */
|
||||
lastpos_hashnr=rec_hashnr(hash,lastpos->data);
|
||||
/* pos is where lastpos should be */
|
||||
pos= data + my_hash_mask(lastpos_hashnr, hash->blength, hash->records);
|
||||
if (pos == empty) /* Move to empty position. */
|
||||
{
|
||||
empty[0]=lastpos[0];
|
||||
goto exit;
|
||||
}
|
||||
pos_hashnr=rec_hashnr(hash,pos->data);
|
||||
/* pos3 is where the pos should be */
|
||||
pos3= data + my_hash_mask(pos_hashnr, hash->blength, hash->records);
|
||||
if (pos != pos3)
|
||||
{ /* pos is on wrong posit */
|
||||
empty[0]=pos[0]; /* Save it here */
|
||||
pos[0]=lastpos[0]; /* This should be here */
|
||||
movelink(data,(uint) (pos-data),(uint) (pos3-data),empty_index);
|
||||
goto exit;
|
||||
}
|
||||
pos2= my_hash_mask(lastpos_hashnr, blength, hash->records + 1);
|
||||
if (pos2 == my_hash_mask(pos_hashnr, blength, hash->records + 1))
|
||||
{ /* Identical key-positions */
|
||||
if (pos2 != hash->records)
|
||||
{
|
||||
empty[0]=lastpos[0];
|
||||
movelink(data,(uint) (lastpos-data),(uint) (pos-data),empty_index);
|
||||
goto exit;
|
||||
}
|
||||
idx= (uint) (pos-data); /* Link pos->next after lastpos */
|
||||
}
|
||||
else idx= NO_RECORD; /* Different positions merge */
|
||||
|
||||
empty[0]=lastpos[0];
|
||||
movelink(data,idx,empty_index,pos->next);
|
||||
pos->next=empty_index;
|
||||
|
||||
exit:
|
||||
(void) pop_dynamic(&hash->array);
|
||||
if (hash->free)
|
||||
(*hash->free)((uchar*) record);
|
||||
DBUG_RETURN(0);
|
||||
}
|
||||
|
||||
/*
|
||||
Update keys when record has changed.
|
||||
This is much more efficent than using a delete & insert.
|
||||
*/
|
||||
|
||||
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;
|
||||
HASH_LINK org_link,*data,*previous,*pos;
|
||||
DBUG_ENTER("my_hash_update");
|
||||
|
||||
if (HASH_UNIQUE & hash->flags)
|
||||
{
|
||||
HASH_SEARCH_STATE state;
|
||||
uchar *found, *new_key= (uchar*) my_hash_key(hash, record, &idx, 1);
|
||||
if ((found= my_hash_first(hash, new_key, idx, &state)))
|
||||
{
|
||||
do
|
||||
{
|
||||
if (found != record)
|
||||
DBUG_RETURN(1); /* Duplicate entry */
|
||||
}
|
||||
while ((found= my_hash_next(hash, new_key, idx, &state)));
|
||||
}
|
||||
}
|
||||
|
||||
data=dynamic_element(&hash->array,0,HASH_LINK*);
|
||||
blength=hash->blength; records=hash->records;
|
||||
|
||||
/* Search after record with key */
|
||||
|
||||
idx= my_hash_mask(calc_hash(hash, old_key, (old_key_length ?
|
||||
old_key_length :
|
||||
hash->key_length)),
|
||||
blength, records);
|
||||
new_index= my_hash_mask(rec_hashnr(hash, record), blength, records);
|
||||
if (idx == new_index)
|
||||
DBUG_RETURN(0); /* Nothing to do (No record check) */
|
||||
previous=0;
|
||||
for (;;)
|
||||
{
|
||||
|
||||
if ((pos= data+idx)->data == record)
|
||||
break;
|
||||
previous=pos;
|
||||
if ((idx=pos->next) == NO_RECORD)
|
||||
DBUG_RETURN(1); /* Not found in links */
|
||||
}
|
||||
org_link= *pos;
|
||||
empty=idx;
|
||||
|
||||
/* Relink record from current chain */
|
||||
|
||||
if (!previous)
|
||||
{
|
||||
if (pos->next != NO_RECORD)
|
||||
{
|
||||
empty=pos->next;
|
||||
*pos= data[pos->next];
|
||||
}
|
||||
}
|
||||
else
|
||||
previous->next=pos->next; /* unlink pos */
|
||||
|
||||
/* Move data to correct position */
|
||||
if (new_index == empty)
|
||||
{
|
||||
/*
|
||||
At this point record is unlinked from the old chain, thus it holds
|
||||
random position. By the chance this position is equal to position
|
||||
for the first element in the new chain. That means updated record
|
||||
is the only record in the new chain.
|
||||
*/
|
||||
if (empty != idx)
|
||||
{
|
||||
/*
|
||||
Record was moved while unlinking it from the old chain.
|
||||
Copy data to a new position.
|
||||
*/
|
||||
data[empty]= org_link;
|
||||
}
|
||||
data[empty].next= NO_RECORD;
|
||||
DBUG_RETURN(0);
|
||||
}
|
||||
pos=data+new_index;
|
||||
new_pos_index= my_hash_rec_mask(hash, pos, blength, records);
|
||||
if (new_index != new_pos_index)
|
||||
{ /* Other record in wrong position */
|
||||
data[empty] = *pos;
|
||||
movelink(data,new_index,new_pos_index,empty);
|
||||
org_link.next=NO_RECORD;
|
||||
data[new_index]= org_link;
|
||||
}
|
||||
else
|
||||
{ /* Link in chain at right position */
|
||||
org_link.next=data[new_index].next;
|
||||
data[empty]=org_link;
|
||||
data[new_index].next=empty;
|
||||
}
|
||||
DBUG_RETURN(0);
|
||||
}
|
||||
|
||||
|
||||
uchar *my_hash_element(HASH *hash, ulong idx)
|
||||
{
|
||||
if (idx < hash->records)
|
||||
return dynamic_element(&hash->array,idx,HASH_LINK*)->data;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Replace old row with new row. This should only be used when key
|
||||
isn't changed
|
||||
*/
|
||||
|
||||
void my_hash_replace(HASH *hash, HASH_SEARCH_STATE *current_record,
|
||||
uchar *new_row)
|
||||
{
|
||||
if (*current_record != NO_RECORD) /* Safety */
|
||||
dynamic_element(&hash->array, *current_record, HASH_LINK*)->data= new_row;
|
||||
}
|
||||
|
||||
|
||||
#ifndef DBUG_OFF
|
||||
|
||||
my_bool my_hash_check(HASH *hash)
|
||||
{
|
||||
int error;
|
||||
uint i,rec_link,found,max_links,seek,links,idx;
|
||||
uint records,blength;
|
||||
HASH_LINK *data,*hash_info;
|
||||
|
||||
records=hash->records; blength=hash->blength;
|
||||
data=dynamic_element(&hash->array,0,HASH_LINK*);
|
||||
error=0;
|
||||
|
||||
for (i=found=max_links=seek=0 ; i < records ; i++)
|
||||
{
|
||||
if (my_hash_rec_mask(hash, data + i, blength, records) == i)
|
||||
{
|
||||
found++; seek++; links=1;
|
||||
for (idx=data[i].next ;
|
||||
idx != NO_RECORD && found < records + 1;
|
||||
idx=hash_info->next)
|
||||
{
|
||||
if (idx >= records)
|
||||
{
|
||||
DBUG_PRINT("error",
|
||||
("Found pointer outside array to %d from link starting at %d",
|
||||
idx,i));
|
||||
error=1;
|
||||
}
|
||||
hash_info=data+idx;
|
||||
seek+= ++links;
|
||||
if ((rec_link= my_hash_rec_mask(hash, hash_info,
|
||||
blength, records)) != i)
|
||||
{
|
||||
DBUG_PRINT("error", ("Record in wrong link at %d: Start %d "
|
||||
"Record: 0x%lx Record-link %d",
|
||||
idx, i, (long) hash_info->data, rec_link));
|
||||
error=1;
|
||||
}
|
||||
else
|
||||
found++;
|
||||
}
|
||||
if (links > max_links) max_links=links;
|
||||
}
|
||||
}
|
||||
if (found != records)
|
||||
{
|
||||
DBUG_PRINT("error",("Found %u of %u records", found, records));
|
||||
error=1;
|
||||
}
|
||||
if (records)
|
||||
DBUG_PRINT("info",
|
||||
("records: %u seeks: %d max links: %d hitrate: %.2f",
|
||||
records,seek,max_links,(float) seek / (float) records));
|
||||
return error;
|
||||
}
|
||||
#endif
|
||||
527
deps/mysqllite/mysys/lf_alloc-pin.c
vendored
Normal file
527
deps/mysqllite/mysys/lf_alloc-pin.c
vendored
Normal file
@@ -0,0 +1,527 @@
|
||||
/* QQ: TODO multi-pinbox */
|
||||
/* Copyright (C) 2006-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 */
|
||||
|
||||
/*
|
||||
wait-free concurrent allocator based on pinning addresses
|
||||
|
||||
It works as follows: every thread (strictly speaking - every CPU, but
|
||||
it's too difficult to do) has a small array of pointers. They're called
|
||||
"pins". Before using an object its address must be stored in this array
|
||||
(pinned). When an object is no longer necessary its address must be
|
||||
removed from this array (unpinned). When a thread wants to free() an
|
||||
object it scans all pins of all threads to see if somebody has this
|
||||
object pinned. If yes - the object is not freed (but stored in a
|
||||
"purgatory"). To reduce the cost of a single free() pins are not scanned
|
||||
on every free() but only added to (thread-local) purgatory. On every
|
||||
LF_PURGATORY_SIZE free() purgatory is scanned and all unpinned objects
|
||||
are freed.
|
||||
|
||||
Pins are used to solve ABA problem. To use pins one must obey
|
||||
a pinning protocol:
|
||||
|
||||
1. Let's assume that PTR is a shared pointer to an object. Shared means
|
||||
that any thread may modify it anytime to point to a different object
|
||||
and free the old object. Later the freed object may be potentially
|
||||
allocated by another thread. If we're unlucky that other thread may
|
||||
set PTR to point to this object again. This is ABA problem.
|
||||
2. Create a local pointer LOCAL_PTR.
|
||||
3. Pin the PTR in a loop:
|
||||
do
|
||||
{
|
||||
LOCAL_PTR= PTR;
|
||||
pin(PTR, PIN_NUMBER);
|
||||
} while (LOCAL_PTR != PTR)
|
||||
4. It is guaranteed that after the loop has ended, LOCAL_PTR
|
||||
points to an object (or NULL, if PTR may be NULL), that
|
||||
will never be freed. It is not guaranteed though
|
||||
that LOCAL_PTR == PTR (as PTR can change any time)
|
||||
5. When done working with the object, remove the pin:
|
||||
unpin(PIN_NUMBER)
|
||||
6. When copying pins (as in the list traversing loop:
|
||||
pin(CUR, 1);
|
||||
while ()
|
||||
{
|
||||
do // standard
|
||||
{ // pinning
|
||||
NEXT=CUR->next; // loop
|
||||
pin(NEXT, 0); // see #3
|
||||
} while (NEXT != CUR->next); // above
|
||||
...
|
||||
...
|
||||
CUR=NEXT;
|
||||
pin(CUR, 1); // copy pin[0] to pin[1]
|
||||
}
|
||||
which keeps CUR address constantly pinned), note than pins may be
|
||||
copied only upwards (!!!), that is pin[N] to pin[M], M > N.
|
||||
7. Don't keep the object pinned longer than necessary - the number of
|
||||
pins you have is limited (and small), keeping an object pinned
|
||||
prevents its reuse and cause unnecessary mallocs.
|
||||
|
||||
Explanations:
|
||||
|
||||
3. The loop is important. The following can occur:
|
||||
thread1> LOCAL_PTR= PTR
|
||||
thread2> free(PTR); PTR=0;
|
||||
thread1> pin(PTR, PIN_NUMBER);
|
||||
now thread1 cannot access LOCAL_PTR, even if it's pinned,
|
||||
because it points to a freed memory. That is, it *must*
|
||||
verify that it has indeed pinned PTR, the shared pointer.
|
||||
|
||||
6. When a thread wants to free some LOCAL_PTR, and it scans
|
||||
all lists of pins to see whether it's pinned, it does it
|
||||
upwards, from low pin numbers to high. Thus another thread
|
||||
must copy an address from one pin to another in the same
|
||||
direction - upwards, otherwise the scanning thread may
|
||||
miss it.
|
||||
|
||||
Implementation details:
|
||||
|
||||
Pins are given away from a "pinbox". Pinbox is stack-based allocator.
|
||||
It used dynarray for storing pins, new elements are allocated by dynarray
|
||||
as necessary, old are pushed in the stack for reuse. ABA is solved by
|
||||
versioning a pointer - because we use an array, a pointer to pins is 16 bit,
|
||||
upper 16 bits are used for a version.
|
||||
|
||||
It is assumed that pins belong to a THD and are not transferable
|
||||
between THD's (LF_PINS::stack_ends_here being a primary reason
|
||||
for this limitation).
|
||||
*/
|
||||
#include <my_global.h>
|
||||
#include <my_sys.h>
|
||||
#include <lf.h>
|
||||
|
||||
#define LF_PINBOX_MAX_PINS 65536
|
||||
|
||||
static void _lf_pinbox_real_free(LF_PINS *pins);
|
||||
|
||||
/*
|
||||
Initialize a pinbox. Normally called from lf_alloc_init.
|
||||
See the latter for details.
|
||||
*/
|
||||
void lf_pinbox_init(LF_PINBOX *pinbox, uint free_ptr_offset,
|
||||
lf_pinbox_free_func *free_func, void *free_func_arg)
|
||||
{
|
||||
DBUG_ASSERT(free_ptr_offset % sizeof(void *) == 0);
|
||||
compile_time_assert(sizeof(LF_PINS) == 64);
|
||||
lf_dynarray_init(&pinbox->pinarray, sizeof(LF_PINS));
|
||||
pinbox->pinstack_top_ver= 0;
|
||||
pinbox->pins_in_array= 0;
|
||||
pinbox->free_ptr_offset= free_ptr_offset;
|
||||
pinbox->free_func= free_func;
|
||||
pinbox->free_func_arg= free_func_arg;
|
||||
}
|
||||
|
||||
void lf_pinbox_destroy(LF_PINBOX *pinbox)
|
||||
{
|
||||
lf_dynarray_destroy(&pinbox->pinarray);
|
||||
}
|
||||
|
||||
/*
|
||||
Get pins from a pinbox. Usually called via lf_alloc_get_pins() or
|
||||
lf_hash_get_pins().
|
||||
|
||||
SYNOPSYS
|
||||
pinbox -
|
||||
|
||||
DESCRIPTION
|
||||
get a new LF_PINS structure from a stack of unused pins,
|
||||
or allocate a new one out of dynarray.
|
||||
|
||||
NOTE
|
||||
It is assumed that pins belong to a thread and are not transferable
|
||||
between threads.
|
||||
*/
|
||||
LF_PINS *_lf_pinbox_get_pins(LF_PINBOX *pinbox)
|
||||
{
|
||||
uint32 pins, next, top_ver;
|
||||
LF_PINS *el;
|
||||
/*
|
||||
We have an array of max. 64k elements.
|
||||
The highest index currently allocated is pinbox->pins_in_array.
|
||||
Freed elements are in a lifo stack, pinstack_top_ver.
|
||||
pinstack_top_ver is 32 bits; 16 low bits are the index in the
|
||||
array, to the first element of the list. 16 high bits are a version
|
||||
(every time the 16 low bits are updated, the 16 high bits are
|
||||
incremented). Versioniong prevents the ABA problem.
|
||||
*/
|
||||
top_ver= pinbox->pinstack_top_ver;
|
||||
do
|
||||
{
|
||||
if (!(pins= top_ver % LF_PINBOX_MAX_PINS))
|
||||
{
|
||||
/* the stack of free elements is empty */
|
||||
pins= my_atomic_add32((int32 volatile*) &pinbox->pins_in_array, 1)+1;
|
||||
if (unlikely(pins >= LF_PINBOX_MAX_PINS))
|
||||
return 0;
|
||||
/*
|
||||
note that the first allocated element has index 1 (pins==1).
|
||||
index 0 is reserved to mean "NULL pointer"
|
||||
*/
|
||||
el= (LF_PINS *)_lf_dynarray_lvalue(&pinbox->pinarray, pins);
|
||||
if (unlikely(!el))
|
||||
return 0;
|
||||
break;
|
||||
}
|
||||
el= (LF_PINS *)_lf_dynarray_value(&pinbox->pinarray, pins);
|
||||
next= el->link;
|
||||
} while (!my_atomic_cas32((int32 volatile*) &pinbox->pinstack_top_ver,
|
||||
(int32*) &top_ver,
|
||||
top_ver-pins+next+LF_PINBOX_MAX_PINS));
|
||||
/*
|
||||
set el->link to the index of el in the dynarray (el->link has two usages:
|
||||
- if element is allocated, it's its own index
|
||||
- if element is free, it's its next element in the free stack
|
||||
*/
|
||||
el->link= pins;
|
||||
el->purgatory_count= 0;
|
||||
el->pinbox= pinbox;
|
||||
el->stack_ends_here= & my_thread_var->stack_ends_here;
|
||||
return el;
|
||||
}
|
||||
|
||||
/*
|
||||
Put pins back to a pinbox. Usually called via lf_alloc_put_pins() or
|
||||
lf_hash_put_pins().
|
||||
|
||||
DESCRIPTION
|
||||
empty the purgatory (XXX deadlock warning below!),
|
||||
push LF_PINS structure to a stack
|
||||
*/
|
||||
void _lf_pinbox_put_pins(LF_PINS *pins)
|
||||
{
|
||||
LF_PINBOX *pinbox= pins->pinbox;
|
||||
uint32 top_ver, nr;
|
||||
nr= pins->link;
|
||||
#ifdef MY_LF_EXTRA_DEBUG
|
||||
{
|
||||
int i;
|
||||
for (i= 0; i < LF_PINBOX_PINS; i++)
|
||||
DBUG_ASSERT(pins->pin[i] == 0);
|
||||
}
|
||||
#endif
|
||||
/*
|
||||
XXX this will deadlock if other threads will wait for
|
||||
the caller to do something after _lf_pinbox_put_pins(),
|
||||
and they would have pinned addresses that the caller wants to free.
|
||||
Thus: only free pins when all work is done and nobody can wait for you!!!
|
||||
*/
|
||||
while (pins->purgatory_count)
|
||||
{
|
||||
_lf_pinbox_real_free(pins);
|
||||
if (pins->purgatory_count)
|
||||
{
|
||||
my_atomic_rwlock_wrunlock(&pins->pinbox->pinarray.lock);
|
||||
pthread_yield();
|
||||
my_atomic_rwlock_wrlock(&pins->pinbox->pinarray.lock);
|
||||
}
|
||||
}
|
||||
top_ver= pinbox->pinstack_top_ver;
|
||||
do
|
||||
{
|
||||
pins->link= top_ver % LF_PINBOX_MAX_PINS;
|
||||
} while (!my_atomic_cas32((int32 volatile*) &pinbox->pinstack_top_ver,
|
||||
(int32*) &top_ver,
|
||||
top_ver-pins->link+nr+LF_PINBOX_MAX_PINS));
|
||||
return;
|
||||
}
|
||||
|
||||
static int ptr_cmp(void **a, void **b)
|
||||
{
|
||||
return *a < *b ? -1 : *a == *b ? 0 : 1;
|
||||
}
|
||||
|
||||
#define add_to_purgatory(PINS, ADDR) \
|
||||
do \
|
||||
{ \
|
||||
*(void **)((char *)(ADDR)+(PINS)->pinbox->free_ptr_offset)= \
|
||||
(PINS)->purgatory; \
|
||||
(PINS)->purgatory= (ADDR); \
|
||||
(PINS)->purgatory_count++; \
|
||||
} while (0)
|
||||
|
||||
/*
|
||||
Free an object allocated via pinbox allocator
|
||||
|
||||
DESCRIPTION
|
||||
add an object to purgatory. if necessary, call _lf_pinbox_real_free()
|
||||
to actually free something.
|
||||
*/
|
||||
void _lf_pinbox_free(LF_PINS *pins, void *addr)
|
||||
{
|
||||
add_to_purgatory(pins, addr);
|
||||
if (pins->purgatory_count % LF_PURGATORY_SIZE)
|
||||
_lf_pinbox_real_free(pins);
|
||||
}
|
||||
|
||||
struct st_harvester {
|
||||
void **granary;
|
||||
int npins;
|
||||
};
|
||||
|
||||
/*
|
||||
callback for _lf_dynarray_iterate:
|
||||
scan all pins of all threads and accumulate all pins
|
||||
*/
|
||||
static int harvest_pins(LF_PINS *el, struct st_harvester *hv)
|
||||
{
|
||||
int i;
|
||||
LF_PINS *el_end= el+min(hv->npins, LF_DYNARRAY_LEVEL_LENGTH);
|
||||
for (; el < el_end; el++)
|
||||
{
|
||||
for (i= 0; i < LF_PINBOX_PINS; i++)
|
||||
{
|
||||
void *p= el->pin[i];
|
||||
if (p)
|
||||
*hv->granary++= p;
|
||||
}
|
||||
}
|
||||
/*
|
||||
hv->npins may become negative below, but it means that
|
||||
we're on the last dynarray page and harvest_pins() won't be
|
||||
called again. We don't bother to make hv->npins() correct
|
||||
(that is 0) in this case.
|
||||
*/
|
||||
hv->npins-= LF_DYNARRAY_LEVEL_LENGTH;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
callback for _lf_dynarray_iterate:
|
||||
scan all pins of all threads and see if addr is present there
|
||||
*/
|
||||
static int match_pins(LF_PINS *el, void *addr)
|
||||
{
|
||||
int i;
|
||||
LF_PINS *el_end= el+LF_DYNARRAY_LEVEL_LENGTH;
|
||||
for (; el < el_end; el++)
|
||||
for (i= 0; i < LF_PINBOX_PINS; i++)
|
||||
if (el->pin[i] == addr)
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if STACK_DIRECTION < 0
|
||||
#define available_stack_size(CUR,END) (long) ((char*)(CUR) - (char*)(END))
|
||||
#else
|
||||
#define available_stack_size(CUR,END) (long) ((char*)(END) - (char*)(CUR))
|
||||
#endif
|
||||
|
||||
#define next_node(P, X) (*((uchar * volatile *)(((uchar *)(X)) + (P)->free_ptr_offset)))
|
||||
#define anext_node(X) next_node(&allocator->pinbox, (X))
|
||||
|
||||
/*
|
||||
Scan the purgatory and free everything that can be freed
|
||||
*/
|
||||
static void _lf_pinbox_real_free(LF_PINS *pins)
|
||||
{
|
||||
int npins, alloca_size;
|
||||
void *list, **addr;
|
||||
void *first= NULL, *last= NULL;
|
||||
LF_PINBOX *pinbox= pins->pinbox;
|
||||
|
||||
npins= pinbox->pins_in_array+1;
|
||||
|
||||
#ifdef HAVE_ALLOCA
|
||||
alloca_size= sizeof(void *)*LF_PINBOX_PINS*npins;
|
||||
/* create a sorted list of pinned addresses, to speed up searches */
|
||||
if (available_stack_size(&pinbox, *pins->stack_ends_here) > alloca_size)
|
||||
{
|
||||
struct st_harvester hv;
|
||||
addr= (void **) alloca(alloca_size);
|
||||
hv.granary= addr;
|
||||
hv.npins= npins;
|
||||
/* scan the dynarray and accumulate all pinned addresses */
|
||||
_lf_dynarray_iterate(&pinbox->pinarray,
|
||||
(lf_dynarray_func)harvest_pins, &hv);
|
||||
|
||||
npins= hv.granary-addr;
|
||||
/* and sort them */
|
||||
if (npins)
|
||||
qsort(addr, npins, sizeof(void *), (qsort_cmp)ptr_cmp);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
addr= 0;
|
||||
|
||||
list= pins->purgatory;
|
||||
pins->purgatory= 0;
|
||||
pins->purgatory_count= 0;
|
||||
while (list)
|
||||
{
|
||||
void *cur= list;
|
||||
list= *(void **)((char *)cur+pinbox->free_ptr_offset);
|
||||
if (npins)
|
||||
{
|
||||
if (addr) /* use binary search */
|
||||
{
|
||||
void **a, **b, **c;
|
||||
for (a= addr, b= addr+npins-1, c= a+(b-a)/2; (b-a) > 1; c= a+(b-a)/2)
|
||||
if (cur == *c)
|
||||
a= b= c;
|
||||
else if (cur > *c)
|
||||
a= c;
|
||||
else
|
||||
b= c;
|
||||
if (cur == *a || cur == *b)
|
||||
goto found;
|
||||
}
|
||||
else /* no alloca - no cookie. linear search here */
|
||||
{
|
||||
if (_lf_dynarray_iterate(&pinbox->pinarray,
|
||||
(lf_dynarray_func)match_pins, cur))
|
||||
goto found;
|
||||
}
|
||||
}
|
||||
/* not pinned - freeing */
|
||||
if (last)
|
||||
last= next_node(pinbox, last)= (uchar *)cur;
|
||||
else
|
||||
first= last= (uchar *)cur;
|
||||
continue;
|
||||
found:
|
||||
/* pinned - keeping */
|
||||
add_to_purgatory(pins, cur);
|
||||
}
|
||||
if (last)
|
||||
pinbox->free_func(first, last, pinbox->free_func_arg);
|
||||
}
|
||||
|
||||
/* lock-free memory allocator for fixed-size objects */
|
||||
|
||||
LF_REQUIRE_PINS(1)
|
||||
|
||||
/*
|
||||
callback for _lf_pinbox_real_free to free a list of unpinned objects -
|
||||
add it back to the allocator stack
|
||||
|
||||
DESCRIPTION
|
||||
'first' and 'last' are the ends of the linked list of nodes:
|
||||
first->el->el->....->el->last. Use first==last to free only one element.
|
||||
*/
|
||||
static void alloc_free(uchar *first,
|
||||
uchar volatile *last,
|
||||
LF_ALLOCATOR *allocator)
|
||||
{
|
||||
/*
|
||||
we need a union here to access type-punned pointer reliably.
|
||||
otherwise gcc -fstrict-aliasing will not see 'tmp' changed in the loop
|
||||
*/
|
||||
union { uchar * node; void *ptr; } tmp;
|
||||
tmp.node= allocator->top;
|
||||
do
|
||||
{
|
||||
anext_node(last)= tmp.node;
|
||||
} while (!my_atomic_casptr((void **)(char *)&allocator->top,
|
||||
(void **)&tmp.ptr, first) && LF_BACKOFF);
|
||||
}
|
||||
|
||||
/*
|
||||
initialize lock-free allocator
|
||||
|
||||
SYNOPSYS
|
||||
allocator -
|
||||
size a size of an object to allocate
|
||||
free_ptr_offset an offset inside the object to a sizeof(void *)
|
||||
memory that is guaranteed to be unused after
|
||||
the object is put in the purgatory. Unused by ANY
|
||||
thread, not only the purgatory owner.
|
||||
This memory will be used to link waiting-to-be-freed
|
||||
objects in a purgatory list.
|
||||
*/
|
||||
void lf_alloc_init(LF_ALLOCATOR *allocator, uint size, uint free_ptr_offset)
|
||||
{
|
||||
lf_pinbox_init(&allocator->pinbox, free_ptr_offset,
|
||||
(lf_pinbox_free_func *)alloc_free, allocator);
|
||||
allocator->top= 0;
|
||||
allocator->mallocs= 0;
|
||||
allocator->element_size= size;
|
||||
DBUG_ASSERT(size >= sizeof(void*) + free_ptr_offset);
|
||||
}
|
||||
|
||||
/*
|
||||
destroy the allocator, free everything that's in it
|
||||
|
||||
NOTE
|
||||
As every other init/destroy function here and elsewhere it
|
||||
is not thread safe. No, this function is no different, ensure
|
||||
that no thread needs the allocator before destroying it.
|
||||
We are not responsible for any damage that may be caused by
|
||||
accessing the allocator when it is being or has been destroyed.
|
||||
Oh yes, and don't put your cat in a microwave.
|
||||
*/
|
||||
void lf_alloc_destroy(LF_ALLOCATOR *allocator)
|
||||
{
|
||||
uchar *node= allocator->top;
|
||||
while (node)
|
||||
{
|
||||
uchar *tmp= anext_node(node);
|
||||
my_free(node);
|
||||
node= tmp;
|
||||
}
|
||||
lf_pinbox_destroy(&allocator->pinbox);
|
||||
allocator->top= 0;
|
||||
}
|
||||
|
||||
/*
|
||||
Allocate and return an new object.
|
||||
|
||||
DESCRIPTION
|
||||
Pop an unused object from the stack or malloc it is the stack is empty.
|
||||
pin[0] is used, it's removed on return.
|
||||
*/
|
||||
void *_lf_alloc_new(LF_PINS *pins)
|
||||
{
|
||||
LF_ALLOCATOR *allocator= (LF_ALLOCATOR *)(pins->pinbox->free_func_arg);
|
||||
uchar *node;
|
||||
for (;;)
|
||||
{
|
||||
do
|
||||
{
|
||||
node= allocator->top;
|
||||
_lf_pin(pins, 0, node);
|
||||
} while (node != allocator->top && LF_BACKOFF);
|
||||
if (!node)
|
||||
{
|
||||
node= (void *)my_malloc(allocator->element_size, MYF(MY_WME));
|
||||
#ifdef MY_LF_EXTRA_DEBUG
|
||||
if (likely(node != 0))
|
||||
my_atomic_add32(&allocator->mallocs, 1);
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
if (my_atomic_casptr((void **)(char *)&allocator->top,
|
||||
(void *)&node, anext_node(node)))
|
||||
break;
|
||||
}
|
||||
_lf_unpin(pins, 0);
|
||||
return node;
|
||||
}
|
||||
|
||||
/*
|
||||
count the number of objects in a pool.
|
||||
|
||||
NOTE
|
||||
This is NOT thread-safe !!!
|
||||
*/
|
||||
uint lf_alloc_pool_count(LF_ALLOCATOR *allocator)
|
||||
{
|
||||
uint i;
|
||||
uchar *node;
|
||||
for (node= allocator->top, i= 0; node; node= anext_node(node), i++)
|
||||
/* no op */;
|
||||
return i;
|
||||
}
|
||||
|
||||
207
deps/mysqllite/mysys/lf_dynarray.c
vendored
Normal file
207
deps/mysqllite/mysys/lf_dynarray.c
vendored
Normal file
@@ -0,0 +1,207 @@
|
||||
/* Copyright (C) 2006 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 */
|
||||
|
||||
/*
|
||||
Analog of DYNAMIC_ARRAY that never reallocs
|
||||
(so no pointer into the array may ever become invalid).
|
||||
|
||||
Memory is allocated in non-contiguous chunks.
|
||||
This data structure is not space efficient for sparse arrays.
|
||||
|
||||
Every element is aligned to sizeof(element) boundary
|
||||
(to avoid false sharing if element is big enough).
|
||||
|
||||
LF_DYNARRAY is a recursive structure. On the zero level
|
||||
LF_DYNARRAY::level[0] it's an array of LF_DYNARRAY_LEVEL_LENGTH elements,
|
||||
on the first level it's an array of LF_DYNARRAY_LEVEL_LENGTH pointers
|
||||
to arrays of elements, on the second level it's an array of pointers
|
||||
to arrays of pointers to arrays of elements. And so on.
|
||||
|
||||
With four levels the number of elements is limited to 4311810304
|
||||
(but as in all functions index is uint, the real limit is 2^32-1)
|
||||
|
||||
Actually, it's wait-free, not lock-free ;-)
|
||||
*/
|
||||
|
||||
#include <my_global.h>
|
||||
#include <m_string.h>
|
||||
#include <my_sys.h>
|
||||
#include <lf.h>
|
||||
|
||||
void lf_dynarray_init(LF_DYNARRAY *array, uint element_size)
|
||||
{
|
||||
bzero(array, sizeof(*array));
|
||||
array->size_of_element= element_size;
|
||||
my_atomic_rwlock_init(&array->lock);
|
||||
}
|
||||
|
||||
static void recursive_free(void **alloc, int level)
|
||||
{
|
||||
if (!alloc)
|
||||
return;
|
||||
|
||||
if (level)
|
||||
{
|
||||
int i;
|
||||
for (i= 0; i < LF_DYNARRAY_LEVEL_LENGTH; i++)
|
||||
recursive_free(alloc[i], level-1);
|
||||
my_free(alloc);
|
||||
}
|
||||
else
|
||||
my_free(alloc[-1]);
|
||||
}
|
||||
|
||||
void lf_dynarray_destroy(LF_DYNARRAY *array)
|
||||
{
|
||||
int i;
|
||||
for (i= 0; i < LF_DYNARRAY_LEVELS; i++)
|
||||
recursive_free(array->level[i], i);
|
||||
my_atomic_rwlock_destroy(&array->lock);
|
||||
}
|
||||
|
||||
static const ulong dynarray_idxes_in_prev_levels[LF_DYNARRAY_LEVELS]=
|
||||
{
|
||||
0, /* +1 here to to avoid -1's below */
|
||||
LF_DYNARRAY_LEVEL_LENGTH,
|
||||
LF_DYNARRAY_LEVEL_LENGTH * LF_DYNARRAY_LEVEL_LENGTH +
|
||||
LF_DYNARRAY_LEVEL_LENGTH,
|
||||
LF_DYNARRAY_LEVEL_LENGTH * LF_DYNARRAY_LEVEL_LENGTH *
|
||||
LF_DYNARRAY_LEVEL_LENGTH + LF_DYNARRAY_LEVEL_LENGTH *
|
||||
LF_DYNARRAY_LEVEL_LENGTH + LF_DYNARRAY_LEVEL_LENGTH
|
||||
};
|
||||
|
||||
static const ulong dynarray_idxes_in_prev_level[LF_DYNARRAY_LEVELS]=
|
||||
{
|
||||
0, /* +1 here to to avoid -1's below */
|
||||
LF_DYNARRAY_LEVEL_LENGTH,
|
||||
LF_DYNARRAY_LEVEL_LENGTH * LF_DYNARRAY_LEVEL_LENGTH,
|
||||
LF_DYNARRAY_LEVEL_LENGTH * LF_DYNARRAY_LEVEL_LENGTH *
|
||||
LF_DYNARRAY_LEVEL_LENGTH,
|
||||
};
|
||||
|
||||
/*
|
||||
Returns a valid lvalue pointer to the element number 'idx'.
|
||||
Allocates memory if necessary.
|
||||
*/
|
||||
void *_lf_dynarray_lvalue(LF_DYNARRAY *array, uint idx)
|
||||
{
|
||||
void * ptr, * volatile * ptr_ptr= 0;
|
||||
int i;
|
||||
|
||||
for (i= LF_DYNARRAY_LEVELS-1; idx < dynarray_idxes_in_prev_levels[i]; i--)
|
||||
/* no-op */;
|
||||
ptr_ptr= &array->level[i];
|
||||
idx-= dynarray_idxes_in_prev_levels[i];
|
||||
for (; i > 0; i--)
|
||||
{
|
||||
if (!(ptr= *ptr_ptr))
|
||||
{
|
||||
void *alloc= my_malloc(LF_DYNARRAY_LEVEL_LENGTH * sizeof(void *),
|
||||
MYF(MY_WME|MY_ZEROFILL));
|
||||
if (unlikely(!alloc))
|
||||
return(NULL);
|
||||
if (my_atomic_casptr(ptr_ptr, &ptr, alloc))
|
||||
ptr= alloc;
|
||||
else
|
||||
my_free(alloc);
|
||||
}
|
||||
ptr_ptr= ((void **)ptr) + idx / dynarray_idxes_in_prev_level[i];
|
||||
idx%= dynarray_idxes_in_prev_level[i];
|
||||
}
|
||||
if (!(ptr= *ptr_ptr))
|
||||
{
|
||||
uchar *alloc, *data;
|
||||
alloc= my_malloc(LF_DYNARRAY_LEVEL_LENGTH * array->size_of_element +
|
||||
max(array->size_of_element, sizeof(void *)),
|
||||
MYF(MY_WME|MY_ZEROFILL));
|
||||
if (unlikely(!alloc))
|
||||
return(NULL);
|
||||
/* reserve the space for free() address */
|
||||
data= alloc + sizeof(void *);
|
||||
{ /* alignment */
|
||||
intptr mod= ((intptr)data) % array->size_of_element;
|
||||
if (mod)
|
||||
data+= array->size_of_element - mod;
|
||||
}
|
||||
((void **)data)[-1]= alloc; /* free() will need the original pointer */
|
||||
if (my_atomic_casptr(ptr_ptr, &ptr, data))
|
||||
ptr= data;
|
||||
else
|
||||
my_free(alloc);
|
||||
}
|
||||
return ((uchar*)ptr) + array->size_of_element * idx;
|
||||
}
|
||||
|
||||
/*
|
||||
Returns a pointer to the element number 'idx'
|
||||
or NULL if an element does not exists
|
||||
*/
|
||||
void *_lf_dynarray_value(LF_DYNARRAY *array, uint idx)
|
||||
{
|
||||
void * ptr, * volatile * ptr_ptr= 0;
|
||||
int i;
|
||||
|
||||
for (i= LF_DYNARRAY_LEVELS-1; idx < dynarray_idxes_in_prev_levels[i]; i--)
|
||||
/* no-op */;
|
||||
ptr_ptr= &array->level[i];
|
||||
idx-= dynarray_idxes_in_prev_levels[i];
|
||||
for (; i > 0; i--)
|
||||
{
|
||||
if (!(ptr= *ptr_ptr))
|
||||
return(NULL);
|
||||
ptr_ptr= ((void **)ptr) + idx / dynarray_idxes_in_prev_level[i];
|
||||
idx %= dynarray_idxes_in_prev_level[i];
|
||||
}
|
||||
if (!(ptr= *ptr_ptr))
|
||||
return(NULL);
|
||||
return ((uchar*)ptr) + array->size_of_element * idx;
|
||||
}
|
||||
|
||||
static int recursive_iterate(LF_DYNARRAY *array, void *ptr, int level,
|
||||
lf_dynarray_func func, void *arg)
|
||||
{
|
||||
int res, i;
|
||||
if (!ptr)
|
||||
return 0;
|
||||
if (!level)
|
||||
return func(ptr, arg);
|
||||
for (i= 0; i < LF_DYNARRAY_LEVEL_LENGTH; i++)
|
||||
if ((res= recursive_iterate(array, ((void **)ptr)[i], level-1, func, arg)))
|
||||
return res;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
Calls func(array, arg) on every array of LF_DYNARRAY_LEVEL_LENGTH elements
|
||||
in lf_dynarray.
|
||||
|
||||
DESCRIPTION
|
||||
lf_dynarray consists of a set of arrays, LF_DYNARRAY_LEVEL_LENGTH elements
|
||||
each. _lf_dynarray_iterate() calls user-supplied function on every array
|
||||
from the set. It is the fastest way to scan the array, faster than
|
||||
for (i=0; i < N; i++) { func(_lf_dynarray_value(dynarray, i)); }
|
||||
|
||||
NOTE
|
||||
if func() returns non-zero, the scan is aborted
|
||||
*/
|
||||
int _lf_dynarray_iterate(LF_DYNARRAY *array, lf_dynarray_func func, void *arg)
|
||||
{
|
||||
int i, res;
|
||||
for (i= 0; i < LF_DYNARRAY_LEVELS; i++)
|
||||
if ((res= recursive_iterate(array, array->level[i], i, func, arg)))
|
||||
return res;
|
||||
return 0;
|
||||
}
|
||||
|
||||
503
deps/mysqllite/mysys/lf_hash.c
vendored
Normal file
503
deps/mysqllite/mysys/lf_hash.c
vendored
Normal file
@@ -0,0 +1,503 @@
|
||||
/* Copyright (C) 2006-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 */
|
||||
|
||||
/*
|
||||
extensible hash
|
||||
|
||||
TODO
|
||||
try to get rid of dummy nodes ?
|
||||
for non-unique hash, count only _distinct_ values
|
||||
(but how to do it in lf_hash_delete ?)
|
||||
*/
|
||||
#include <my_global.h>
|
||||
#include <m_string.h>
|
||||
#include <my_sys.h>
|
||||
#include <my_bit.h>
|
||||
#include <lf.h>
|
||||
|
||||
LF_REQUIRE_PINS(3)
|
||||
|
||||
/* An element of the list */
|
||||
typedef struct {
|
||||
intptr volatile link; /* a pointer to the next element in a listand a flag */
|
||||
uint32 hashnr; /* reversed hash number, for sorting */
|
||||
const uchar *key;
|
||||
size_t keylen;
|
||||
/*
|
||||
data is stored here, directly after the keylen.
|
||||
thus the pointer to data is (void*)(slist_element_ptr+1)
|
||||
*/
|
||||
} LF_SLIST;
|
||||
|
||||
/*
|
||||
a structure to pass the context (pointers two the three successive elements
|
||||
in a list) from lfind to linsert/ldelete
|
||||
*/
|
||||
typedef struct {
|
||||
intptr volatile *prev;
|
||||
LF_SLIST *curr, *next;
|
||||
} CURSOR;
|
||||
|
||||
/*
|
||||
the last bit in LF_SLIST::link is a "deleted" flag.
|
||||
the helper macros below convert it to a pure pointer or a pure flag
|
||||
*/
|
||||
#define PTR(V) (LF_SLIST *)((V) & (~(intptr)1))
|
||||
#define DELETED(V) ((V) & 1)
|
||||
|
||||
/*
|
||||
DESCRIPTION
|
||||
Search for hashnr/key/keylen in the list starting from 'head' and
|
||||
position the cursor. The list is ORDER BY hashnr, key
|
||||
|
||||
RETURN
|
||||
0 - not found
|
||||
1 - found
|
||||
|
||||
NOTE
|
||||
cursor is positioned in either case
|
||||
pins[0..2] are used, they are NOT removed on return
|
||||
*/
|
||||
static int lfind(LF_SLIST * volatile *head, CHARSET_INFO *cs, uint32 hashnr,
|
||||
const uchar *key, uint keylen, CURSOR *cursor, LF_PINS *pins)
|
||||
{
|
||||
uint32 cur_hashnr;
|
||||
const uchar *cur_key;
|
||||
uint cur_keylen;
|
||||
intptr link;
|
||||
|
||||
retry:
|
||||
cursor->prev= (intptr *)head;
|
||||
do { /* PTR() isn't necessary below, head is a dummy node */
|
||||
cursor->curr= (LF_SLIST *)(*cursor->prev);
|
||||
_lf_pin(pins, 1, cursor->curr);
|
||||
} while (*cursor->prev != (intptr)cursor->curr && LF_BACKOFF);
|
||||
for (;;)
|
||||
{
|
||||
if (unlikely(!cursor->curr))
|
||||
return 0; /* end of the list */
|
||||
do {
|
||||
/* QQ: XXX or goto retry ? */
|
||||
link= cursor->curr->link;
|
||||
cursor->next= PTR(link);
|
||||
_lf_pin(pins, 0, cursor->next);
|
||||
} while (link != cursor->curr->link && LF_BACKOFF);
|
||||
cur_hashnr= cursor->curr->hashnr;
|
||||
cur_key= cursor->curr->key;
|
||||
cur_keylen= cursor->curr->keylen;
|
||||
if (*cursor->prev != (intptr)cursor->curr)
|
||||
{
|
||||
(void)LF_BACKOFF;
|
||||
goto retry;
|
||||
}
|
||||
if (!DELETED(link))
|
||||
{
|
||||
if (cur_hashnr >= hashnr)
|
||||
{
|
||||
int r= 1;
|
||||
if (cur_hashnr > hashnr ||
|
||||
(r= my_strnncoll(cs, (uchar*) cur_key, cur_keylen, (uchar*) key,
|
||||
keylen)) >= 0)
|
||||
return !r;
|
||||
}
|
||||
cursor->prev= &(cursor->curr->link);
|
||||
_lf_pin(pins, 2, cursor->curr);
|
||||
}
|
||||
else
|
||||
{
|
||||
/*
|
||||
we found a deleted node - be nice, help the other thread
|
||||
and remove this deleted node
|
||||
*/
|
||||
if (my_atomic_casptr((void **)cursor->prev,
|
||||
(void **)&cursor->curr, cursor->next))
|
||||
_lf_alloc_free(pins, cursor->curr);
|
||||
else
|
||||
{
|
||||
(void)LF_BACKOFF;
|
||||
goto retry;
|
||||
}
|
||||
}
|
||||
cursor->curr= cursor->next;
|
||||
_lf_pin(pins, 1, cursor->curr);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
DESCRIPTION
|
||||
insert a 'node' in the list that starts from 'head' in the correct
|
||||
position (as found by lfind)
|
||||
|
||||
RETURN
|
||||
0 - inserted
|
||||
not 0 - a pointer to a duplicate (not pinned and thus unusable)
|
||||
|
||||
NOTE
|
||||
it uses pins[0..2], on return all pins are removed.
|
||||
if there're nodes with the same key value, a new node is added before them.
|
||||
*/
|
||||
static LF_SLIST *linsert(LF_SLIST * volatile *head, CHARSET_INFO *cs,
|
||||
LF_SLIST *node, LF_PINS *pins, uint flags)
|
||||
{
|
||||
CURSOR cursor;
|
||||
int res;
|
||||
|
||||
for (;;)
|
||||
{
|
||||
if (lfind(head, cs, node->hashnr, node->key, node->keylen,
|
||||
&cursor, pins) &&
|
||||
(flags & LF_HASH_UNIQUE))
|
||||
{
|
||||
res= 0; /* duplicate found */
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
node->link= (intptr)cursor.curr;
|
||||
DBUG_ASSERT(node->link != (intptr)node); /* no circular references */
|
||||
DBUG_ASSERT(cursor.prev != &node->link); /* no circular references */
|
||||
if (my_atomic_casptr((void **)cursor.prev, (void **)&cursor.curr, node))
|
||||
{
|
||||
res= 1; /* inserted ok */
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
_lf_unpin(pins, 0);
|
||||
_lf_unpin(pins, 1);
|
||||
_lf_unpin(pins, 2);
|
||||
/*
|
||||
Note that cursor.curr is not pinned here and the pointer is unreliable,
|
||||
the object may dissapear anytime. But if it points to a dummy node, the
|
||||
pointer is safe, because dummy nodes are never freed - initialize_bucket()
|
||||
uses this fact.
|
||||
*/
|
||||
return res ? 0 : cursor.curr;
|
||||
}
|
||||
|
||||
/*
|
||||
DESCRIPTION
|
||||
deletes a node as identified by hashnr/keey/keylen from the list
|
||||
that starts from 'head'
|
||||
|
||||
RETURN
|
||||
0 - ok
|
||||
1 - not found
|
||||
|
||||
NOTE
|
||||
it uses pins[0..2], on return all pins are removed.
|
||||
*/
|
||||
static int ldelete(LF_SLIST * volatile *head, CHARSET_INFO *cs, uint32 hashnr,
|
||||
const uchar *key, uint keylen, LF_PINS *pins)
|
||||
{
|
||||
CURSOR cursor;
|
||||
int res;
|
||||
|
||||
for (;;)
|
||||
{
|
||||
if (!lfind(head, cs, hashnr, key, keylen, &cursor, pins))
|
||||
{
|
||||
res= 1; /* not found */
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* mark the node deleted */
|
||||
if (my_atomic_casptr((void **)&(cursor.curr->link),
|
||||
(void **)&cursor.next,
|
||||
(void *)(((intptr)cursor.next) | 1)))
|
||||
{
|
||||
/* and remove it from the list */
|
||||
if (my_atomic_casptr((void **)cursor.prev,
|
||||
(void **)&cursor.curr, cursor.next))
|
||||
_lf_alloc_free(pins, cursor.curr);
|
||||
else
|
||||
{
|
||||
/*
|
||||
somebody already "helped" us and removed the node ?
|
||||
Let's check if we need to help that someone too!
|
||||
(to ensure the number of "set DELETED flag" actions
|
||||
is equal to the number of "remove from the list" actions)
|
||||
*/
|
||||
lfind(head, cs, hashnr, key, keylen, &cursor, pins);
|
||||
}
|
||||
res= 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
_lf_unpin(pins, 0);
|
||||
_lf_unpin(pins, 1);
|
||||
_lf_unpin(pins, 2);
|
||||
return res;
|
||||
}
|
||||
|
||||
/*
|
||||
DESCRIPTION
|
||||
searches for a node as identified by hashnr/keey/keylen in the list
|
||||
that starts from 'head'
|
||||
|
||||
RETURN
|
||||
0 - not found
|
||||
node - found
|
||||
|
||||
NOTE
|
||||
it uses pins[0..2], on return the pin[2] keeps the node found
|
||||
all other pins are removed.
|
||||
*/
|
||||
static LF_SLIST *lsearch(LF_SLIST * volatile *head, CHARSET_INFO *cs,
|
||||
uint32 hashnr, const uchar *key, uint keylen,
|
||||
LF_PINS *pins)
|
||||
{
|
||||
CURSOR cursor;
|
||||
int res= lfind(head, cs, hashnr, key, keylen, &cursor, pins);
|
||||
if (res)
|
||||
_lf_pin(pins, 2, cursor.curr);
|
||||
_lf_unpin(pins, 0);
|
||||
_lf_unpin(pins, 1);
|
||||
return res ? cursor.curr : 0;
|
||||
}
|
||||
|
||||
static inline const uchar* hash_key(const LF_HASH *hash,
|
||||
const uchar *record, size_t *length)
|
||||
{
|
||||
if (hash->get_key)
|
||||
return (*hash->get_key)(record, length, 0);
|
||||
*length= hash->key_length;
|
||||
return record + hash->key_offset;
|
||||
}
|
||||
|
||||
/*
|
||||
Compute the hash key value from the raw key.
|
||||
|
||||
@note, that the hash value is limited to 2^31, because we need one
|
||||
bit to distinguish between normal and dummy nodes.
|
||||
*/
|
||||
static inline uint calc_hash(LF_HASH *hash, const uchar *key, uint keylen)
|
||||
{
|
||||
ulong nr1= 1, nr2= 4;
|
||||
hash->charset->coll->hash_sort(hash->charset, (uchar*) key, keylen,
|
||||
&nr1, &nr2);
|
||||
return nr1 & INT_MAX32;
|
||||
}
|
||||
|
||||
#define MAX_LOAD 1.0 /* average number of elements in a bucket */
|
||||
|
||||
static int initialize_bucket(LF_HASH *, LF_SLIST * volatile*, uint, LF_PINS *);
|
||||
|
||||
/*
|
||||
Initializes lf_hash, the arguments are compatible with hash_init
|
||||
|
||||
@note element_size sets both the size of allocated memory block for
|
||||
lf_alloc and a size of memcpy'ed block size in lf_hash_insert. Typically
|
||||
they are the same, indeed. But LF_HASH::element_size can be decreased
|
||||
after lf_hash_init, and then lf_alloc will allocate larger block that
|
||||
lf_hash_insert will copy over. It is desireable if part of the element
|
||||
is expensive to initialize - for example if there is a mutex or
|
||||
DYNAMIC_ARRAY. In this case they should be initialize in the
|
||||
LF_ALLOCATOR::constructor, and lf_hash_insert should not overwrite them.
|
||||
See wt_init() for example.
|
||||
*/
|
||||
void lf_hash_init(LF_HASH *hash, uint element_size, uint flags,
|
||||
uint key_offset, uint key_length, my_hash_get_key get_key,
|
||||
CHARSET_INFO *charset)
|
||||
{
|
||||
lf_alloc_init(&hash->alloc, sizeof(LF_SLIST)+element_size,
|
||||
offsetof(LF_SLIST, key));
|
||||
lf_dynarray_init(&hash->array, sizeof(LF_SLIST *));
|
||||
hash->size= 1;
|
||||
hash->count= 0;
|
||||
hash->element_size= element_size;
|
||||
hash->flags= flags;
|
||||
hash->charset= charset ? charset : &my_charset_bin;
|
||||
hash->key_offset= key_offset;
|
||||
hash->key_length= key_length;
|
||||
hash->get_key= get_key;
|
||||
DBUG_ASSERT(get_key ? !key_offset && !key_length : key_length);
|
||||
}
|
||||
|
||||
void lf_hash_destroy(LF_HASH *hash)
|
||||
{
|
||||
LF_SLIST *el, **head= (LF_SLIST **)_lf_dynarray_value(&hash->array, 0);
|
||||
|
||||
if (unlikely(!head))
|
||||
return;
|
||||
el= *head;
|
||||
|
||||
while (el)
|
||||
{
|
||||
intptr next= el->link;
|
||||
if (el->hashnr & 1)
|
||||
lf_alloc_direct_free(&hash->alloc, el); /* normal node */
|
||||
else
|
||||
my_free(el); /* dummy node */
|
||||
el= (LF_SLIST *)next;
|
||||
}
|
||||
lf_alloc_destroy(&hash->alloc);
|
||||
lf_dynarray_destroy(&hash->array);
|
||||
}
|
||||
|
||||
/*
|
||||
DESCRIPTION
|
||||
inserts a new element to a hash. it will have a _copy_ of
|
||||
data, not a pointer to it.
|
||||
|
||||
RETURN
|
||||
0 - inserted
|
||||
1 - didn't (unique key conflict)
|
||||
-1 - out of memory
|
||||
|
||||
NOTE
|
||||
see linsert() for pin usage notes
|
||||
*/
|
||||
int lf_hash_insert(LF_HASH *hash, LF_PINS *pins, const void *data)
|
||||
{
|
||||
int csize, bucket, hashnr;
|
||||
LF_SLIST *node, * volatile *el;
|
||||
|
||||
lf_rwlock_by_pins(pins);
|
||||
node= (LF_SLIST *)_lf_alloc_new(pins);
|
||||
if (unlikely(!node))
|
||||
return -1;
|
||||
memcpy(node+1, data, hash->element_size);
|
||||
node->key= hash_key(hash, (uchar *)(node+1), &node->keylen);
|
||||
hashnr= calc_hash(hash, node->key, node->keylen);
|
||||
bucket= hashnr % hash->size;
|
||||
el= _lf_dynarray_lvalue(&hash->array, bucket);
|
||||
if (unlikely(!el))
|
||||
return -1;
|
||||
if (*el == NULL && unlikely(initialize_bucket(hash, el, bucket, pins)))
|
||||
return -1;
|
||||
node->hashnr= my_reverse_bits(hashnr) | 1; /* normal node */
|
||||
if (linsert(el, hash->charset, node, pins, hash->flags))
|
||||
{
|
||||
_lf_alloc_free(pins, node);
|
||||
lf_rwunlock_by_pins(pins);
|
||||
return 1;
|
||||
}
|
||||
csize= hash->size;
|
||||
if ((my_atomic_add32(&hash->count, 1)+1.0) / csize > MAX_LOAD)
|
||||
my_atomic_cas32(&hash->size, &csize, csize*2);
|
||||
lf_rwunlock_by_pins(pins);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
DESCRIPTION
|
||||
deletes an element with the given key from the hash (if a hash is
|
||||
not unique and there're many elements with this key - the "first"
|
||||
matching element is deleted)
|
||||
RETURN
|
||||
0 - deleted
|
||||
1 - didn't (not found)
|
||||
-1 - out of memory
|
||||
NOTE
|
||||
see ldelete() for pin usage notes
|
||||
*/
|
||||
int lf_hash_delete(LF_HASH *hash, LF_PINS *pins, const void *key, uint keylen)
|
||||
{
|
||||
LF_SLIST * volatile *el;
|
||||
uint bucket, hashnr= calc_hash(hash, (uchar *)key, keylen);
|
||||
|
||||
bucket= hashnr % hash->size;
|
||||
lf_rwlock_by_pins(pins);
|
||||
el= _lf_dynarray_lvalue(&hash->array, bucket);
|
||||
if (unlikely(!el))
|
||||
return -1;
|
||||
/*
|
||||
note that we still need to initialize_bucket here,
|
||||
we cannot return "node not found", because an old bucket of that
|
||||
node may've been split and the node was assigned to a new bucket
|
||||
that was never accessed before and thus is not initialized.
|
||||
*/
|
||||
if (*el == NULL && unlikely(initialize_bucket(hash, el, bucket, pins)))
|
||||
return -1;
|
||||
if (ldelete(el, hash->charset, my_reverse_bits(hashnr) | 1,
|
||||
(uchar *)key, keylen, pins))
|
||||
{
|
||||
lf_rwunlock_by_pins(pins);
|
||||
return 1;
|
||||
}
|
||||
my_atomic_add32(&hash->count, -1);
|
||||
lf_rwunlock_by_pins(pins);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
RETURN
|
||||
a pointer to an element with the given key (if a hash is not unique and
|
||||
there're many elements with this key - the "first" matching element)
|
||||
NULL if nothing is found
|
||||
MY_ERRPTR if OOM
|
||||
|
||||
NOTE
|
||||
see lsearch() for pin usage notes
|
||||
*/
|
||||
void *lf_hash_search(LF_HASH *hash, LF_PINS *pins, const void *key, uint keylen)
|
||||
{
|
||||
LF_SLIST * volatile *el, *found;
|
||||
uint bucket, hashnr= calc_hash(hash, (uchar *)key, keylen);
|
||||
|
||||
bucket= hashnr % hash->size;
|
||||
lf_rwlock_by_pins(pins);
|
||||
el= _lf_dynarray_lvalue(&hash->array, bucket);
|
||||
if (unlikely(!el))
|
||||
return MY_ERRPTR;
|
||||
if (*el == NULL && unlikely(initialize_bucket(hash, el, bucket, pins)))
|
||||
return MY_ERRPTR;
|
||||
found= lsearch(el, hash->charset, my_reverse_bits(hashnr) | 1,
|
||||
(uchar *)key, keylen, pins);
|
||||
lf_rwunlock_by_pins(pins);
|
||||
return found ? found+1 : 0;
|
||||
}
|
||||
|
||||
static const uchar *dummy_key= (uchar*)"";
|
||||
|
||||
/*
|
||||
RETURN
|
||||
0 - ok
|
||||
-1 - out of memory
|
||||
*/
|
||||
static int initialize_bucket(LF_HASH *hash, LF_SLIST * volatile *node,
|
||||
uint bucket, LF_PINS *pins)
|
||||
{
|
||||
uint parent= my_clear_highest_bit(bucket);
|
||||
LF_SLIST *dummy= (LF_SLIST *)my_malloc(sizeof(LF_SLIST), MYF(MY_WME));
|
||||
LF_SLIST **tmp= 0, *cur;
|
||||
LF_SLIST * volatile *el= _lf_dynarray_lvalue(&hash->array, parent);
|
||||
if (unlikely(!el || !dummy))
|
||||
return -1;
|
||||
if (*el == NULL && bucket &&
|
||||
unlikely(initialize_bucket(hash, el, parent, pins)))
|
||||
return -1;
|
||||
dummy->hashnr= my_reverse_bits(bucket) | 0; /* dummy node */
|
||||
dummy->key= dummy_key;
|
||||
dummy->keylen= 0;
|
||||
if ((cur= linsert(el, hash->charset, dummy, pins, LF_HASH_UNIQUE)))
|
||||
{
|
||||
my_free(dummy);
|
||||
dummy= cur;
|
||||
}
|
||||
my_atomic_casptr((void **)node, (void **)&tmp, dummy);
|
||||
/*
|
||||
note that if the CAS above failed (after linsert() succeeded),
|
||||
it would mean that some other thread has executed linsert() for
|
||||
the same dummy node, its linsert() failed, it picked up our
|
||||
dummy node (in "dummy= cur") and executed the same CAS as above.
|
||||
Which means that even if CAS above failed we don't need to retry,
|
||||
and we should not free(dummy) - there's no memory leak here
|
||||
*/
|
||||
return 0;
|
||||
}
|
||||
114
deps/mysqllite/mysys/list.c
vendored
Normal file
114
deps/mysqllite/mysys/list.c
vendored
Normal file
@@ -0,0 +1,114 @@
|
||||
/* Copyright (C) 2000 MySQL AB
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
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 */
|
||||
|
||||
/*
|
||||
Code for handling dubble-linked lists in C
|
||||
*/
|
||||
|
||||
#include "mysys_priv.h"
|
||||
#include <my_list.h>
|
||||
|
||||
|
||||
|
||||
/* Add a element to start of list */
|
||||
|
||||
LIST *list_add(LIST *root, LIST *element)
|
||||
{
|
||||
DBUG_ENTER("list_add");
|
||||
DBUG_PRINT("enter",("root: 0x%lx element: 0x%lx", (long) root, (long) element));
|
||||
if (root)
|
||||
{
|
||||
if (root->prev) /* If add in mid of list */
|
||||
root->prev->next= element;
|
||||
element->prev=root->prev;
|
||||
root->prev=element;
|
||||
}
|
||||
else
|
||||
element->prev=0;
|
||||
element->next=root;
|
||||
DBUG_RETURN(element); /* New root */
|
||||
}
|
||||
|
||||
|
||||
LIST *list_delete(LIST *root, LIST *element)
|
||||
{
|
||||
if (element->prev)
|
||||
element->prev->next=element->next;
|
||||
else
|
||||
root=element->next;
|
||||
if (element->next)
|
||||
element->next->prev=element->prev;
|
||||
return root;
|
||||
}
|
||||
|
||||
|
||||
void list_free(LIST *root, uint free_data)
|
||||
{
|
||||
LIST *next;
|
||||
while (root)
|
||||
{
|
||||
next=root->next;
|
||||
if (free_data)
|
||||
my_free(root->data);
|
||||
my_free(root);
|
||||
root=next;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
LIST *list_cons(void *data, LIST *list)
|
||||
{
|
||||
LIST *new_charset=(LIST*) my_malloc(sizeof(LIST),MYF(MY_FAE));
|
||||
if (!new_charset)
|
||||
return 0;
|
||||
new_charset->data=data;
|
||||
return list_add(list,new_charset);
|
||||
}
|
||||
|
||||
|
||||
LIST *list_reverse(LIST *root)
|
||||
{
|
||||
LIST *last;
|
||||
|
||||
last=root;
|
||||
while (root)
|
||||
{
|
||||
last=root;
|
||||
root=root->next;
|
||||
last->next=last->prev;
|
||||
last->prev=root;
|
||||
}
|
||||
return last;
|
||||
}
|
||||
|
||||
uint list_length(LIST *list)
|
||||
{
|
||||
uint count;
|
||||
for (count=0 ; list ; list=list->next, count++) ;
|
||||
return count;
|
||||
}
|
||||
|
||||
|
||||
int list_walk(LIST *list, list_walk_action action, uchar* argument)
|
||||
{
|
||||
int error=0;
|
||||
while (list)
|
||||
{
|
||||
if ((error = (*action)(list->data,argument)))
|
||||
return error;
|
||||
list=list_rest(list);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
325
deps/mysqllite/mysys/md5.c
vendored
Normal file
325
deps/mysqllite/mysys/md5.c
vendored
Normal file
@@ -0,0 +1,325 @@
|
||||
/* Copyright (C) 2000 MySQL AB
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
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 */
|
||||
|
||||
/*
|
||||
* This code implements the MD5 message-digest algorithm.
|
||||
* The algorithm is due to Ron Rivest. This code was
|
||||
* written by Colin Plumb in 1993, no copyright is claimed.
|
||||
* This code is in the public domain; do with it what you wish.
|
||||
*
|
||||
* Equivalent code is available from RSA Data Security, Inc.
|
||||
* This code has been tested against that, and is equivalent,
|
||||
* except that you don't need to include two pages of legalese
|
||||
* with every copy.
|
||||
*
|
||||
* To compute the message digest of a chunk of bytes, declare an
|
||||
* MD5Context structure, pass it to MD5Init, call MD5Update as
|
||||
* needed on buffers full of bytes, and then call MD5Final, which
|
||||
* will fill a supplied 16-byte array with the digest.
|
||||
*/
|
||||
|
||||
/* This code was modified in 1997 by Jim Kingdon of Cyclic Software to
|
||||
not require an integer type which is exactly 32 bits. This work
|
||||
draws on the changes for the same purpose by Tatu Ylonen
|
||||
<ylo@cs.hut.fi> as part of SSH, but since I didn't actually use
|
||||
that code, there is no copyright issue. I hereby disclaim
|
||||
copyright in any changes I have made; this code remains in the
|
||||
public domain. */
|
||||
|
||||
#include <my_global.h>
|
||||
#include <m_string.h>
|
||||
#include "my_md5.h"
|
||||
|
||||
#include <string.h> /* for memcpy() and memset() */
|
||||
|
||||
|
||||
static void
|
||||
my_MD5Transform (cvs_uint32 buf[4], const unsigned char in[64]);
|
||||
|
||||
/* Little-endian byte-swapping routines. Note that these do not
|
||||
depend on the size of datatypes such as uint32, nor do they require
|
||||
us to detect the endianness of the machine we are running on. It
|
||||
is possible they should be macros for speed, but I would be
|
||||
surprised if they were a performance bottleneck for MD5. */
|
||||
|
||||
static uint32 getu32 (const unsigned char *addr)
|
||||
{
|
||||
return (((((unsigned long)addr[3] << 8) | addr[2]) << 8)
|
||||
| addr[1]) << 8 | addr[0];
|
||||
}
|
||||
|
||||
static void
|
||||
putu32 (uint32 data, unsigned char *addr)
|
||||
{
|
||||
addr[0] = (unsigned char)data;
|
||||
addr[1] = (unsigned char)(data >> 8);
|
||||
addr[2] = (unsigned char)(data >> 16);
|
||||
addr[3] = (unsigned char)(data >> 24);
|
||||
}
|
||||
|
||||
/*
|
||||
Start MD5 accumulation. Set bit count to 0 and buffer to mysterious
|
||||
initialization constants.
|
||||
*/
|
||||
void
|
||||
my_MD5Init (my_MD5Context *ctx)
|
||||
{
|
||||
ctx->buf[0] = 0x67452301;
|
||||
ctx->buf[1] = 0xefcdab89;
|
||||
ctx->buf[2] = 0x98badcfe;
|
||||
ctx->buf[3] = 0x10325476;
|
||||
|
||||
ctx->bits[0] = 0;
|
||||
ctx->bits[1] = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
Update context to reflect the concatenation of another buffer full
|
||||
of bytes.
|
||||
*/
|
||||
void
|
||||
my_MD5Update (my_MD5Context *ctx, unsigned char const *buf, unsigned len)
|
||||
{
|
||||
uint32 t;
|
||||
|
||||
/* Update bitcount */
|
||||
|
||||
t = ctx->bits[0];
|
||||
if ((ctx->bits[0] = (t + ((uint32)len << 3)) & 0xffffffff) < t)
|
||||
ctx->bits[1]++; /* Carry from low to high */
|
||||
ctx->bits[1] += len >> 29;
|
||||
|
||||
t = (t >> 3) & 0x3f; /* Bytes already in shsInfo->data */
|
||||
|
||||
/* Handle any leading odd-sized chunks */
|
||||
|
||||
if ( t ) {
|
||||
unsigned char *p = ctx->in + t;
|
||||
|
||||
t = 64-t;
|
||||
if (len < t) {
|
||||
memcpy(p, buf, len);
|
||||
return;
|
||||
}
|
||||
memcpy(p, buf, t);
|
||||
my_MD5Transform (ctx->buf, ctx->in);
|
||||
buf += t;
|
||||
len -= t;
|
||||
}
|
||||
|
||||
/* Process data in 64-byte chunks */
|
||||
|
||||
while (len >= 64) {
|
||||
memcpy(ctx->in, buf, 64);
|
||||
my_MD5Transform (ctx->buf, ctx->in);
|
||||
buf += 64;
|
||||
len -= 64;
|
||||
}
|
||||
|
||||
/* Handle any remaining bytes of data. */
|
||||
|
||||
memcpy(ctx->in, buf, len);
|
||||
}
|
||||
|
||||
/*
|
||||
Final wrapup - pad to 64-byte boundary with the bit pattern
|
||||
1 0* (64-bit count of bits processed, MSB-first)
|
||||
*/
|
||||
void
|
||||
my_MD5Final (unsigned char digest[16], my_MD5Context *ctx)
|
||||
{
|
||||
unsigned count;
|
||||
unsigned char *p;
|
||||
|
||||
/* Compute number of bytes mod 64 */
|
||||
count = (ctx->bits[0] >> 3) & 0x3F;
|
||||
|
||||
/* Set the first char of padding to 0x80. This is safe since there is
|
||||
always at least one byte free */
|
||||
p = ctx->in + count;
|
||||
*p++ = 0x80;
|
||||
|
||||
/* Bytes of padding needed to make 64 bytes */
|
||||
count = 64 - 1 - count;
|
||||
|
||||
/* Pad out to 56 mod 64 */
|
||||
if (count < 8) {
|
||||
/* Two lots of padding: Pad the first block to 64 bytes */
|
||||
memset(p, 0, count);
|
||||
my_MD5Transform (ctx->buf, ctx->in);
|
||||
|
||||
/* Now fill the next block with 56 bytes */
|
||||
memset(ctx->in, 0, 56);
|
||||
} else {
|
||||
/* Pad block to 56 bytes */
|
||||
memset(p, 0, count-8);
|
||||
}
|
||||
|
||||
/* Append length in bits and transform */
|
||||
putu32(ctx->bits[0], ctx->in + 56);
|
||||
putu32(ctx->bits[1], ctx->in + 60);
|
||||
|
||||
my_MD5Transform (ctx->buf, ctx->in);
|
||||
putu32(ctx->buf[0], digest);
|
||||
putu32(ctx->buf[1], digest + 4);
|
||||
putu32(ctx->buf[2], digest + 8);
|
||||
putu32(ctx->buf[3], digest + 12);
|
||||
memset(ctx, 0, sizeof(ctx)); /* In case it's sensitive */
|
||||
}
|
||||
|
||||
#ifndef ASM_MD5
|
||||
|
||||
/* The four core functions - F1 is optimized somewhat */
|
||||
|
||||
/* #define F1(x, y, z) (x & y | ~x & z) */
|
||||
#define F1(x, y, z) (z ^ (x & (y ^ z)))
|
||||
#define F2(x, y, z) F1(z, x, y)
|
||||
#define F3(x, y, z) (x ^ y ^ z)
|
||||
#define F4(x, y, z) (y ^ (x | ~z))
|
||||
|
||||
/* This is the central step in the MD5 algorithm. */
|
||||
#define MD5STEP(f, w, x, y, z, data, s) \
|
||||
( w += f(x, y, z) + data, w &= 0xffffffff, w = w<<s | w>>(32-s), w += x )
|
||||
|
||||
/*
|
||||
* The core of the MD5 algorithm, this alters an existing MD5 hash to
|
||||
* reflect the addition of 16 longwords of new data. MD5Update blocks
|
||||
* the data and converts bytes into longwords for this routine.
|
||||
*/
|
||||
static void
|
||||
my_MD5Transform (uint32 buf[4], const unsigned char inraw[64])
|
||||
{
|
||||
register uint32 a, b, c, d;
|
||||
uint32 in[16];
|
||||
int i;
|
||||
|
||||
for (i = 0; i < 16; ++i)
|
||||
in[i] = getu32 (inraw + 4 * i);
|
||||
|
||||
a = buf[0];
|
||||
b = buf[1];
|
||||
c = buf[2];
|
||||
d = buf[3];
|
||||
|
||||
MD5STEP(F1, a, b, c, d, in[ 0]+0xd76aa478, 7);
|
||||
MD5STEP(F1, d, a, b, c, in[ 1]+0xe8c7b756, 12);
|
||||
MD5STEP(F1, c, d, a, b, in[ 2]+0x242070db, 17);
|
||||
MD5STEP(F1, b, c, d, a, in[ 3]+0xc1bdceee, 22);
|
||||
MD5STEP(F1, a, b, c, d, in[ 4]+0xf57c0faf, 7);
|
||||
MD5STEP(F1, d, a, b, c, in[ 5]+0x4787c62a, 12);
|
||||
MD5STEP(F1, c, d, a, b, in[ 6]+0xa8304613, 17);
|
||||
MD5STEP(F1, b, c, d, a, in[ 7]+0xfd469501, 22);
|
||||
MD5STEP(F1, a, b, c, d, in[ 8]+0x698098d8, 7);
|
||||
MD5STEP(F1, d, a, b, c, in[ 9]+0x8b44f7af, 12);
|
||||
MD5STEP(F1, c, d, a, b, in[10]+0xffff5bb1, 17);
|
||||
MD5STEP(F1, b, c, d, a, in[11]+0x895cd7be, 22);
|
||||
MD5STEP(F1, a, b, c, d, in[12]+0x6b901122, 7);
|
||||
MD5STEP(F1, d, a, b, c, in[13]+0xfd987193, 12);
|
||||
MD5STEP(F1, c, d, a, b, in[14]+0xa679438e, 17);
|
||||
MD5STEP(F1, b, c, d, a, in[15]+0x49b40821, 22);
|
||||
|
||||
MD5STEP(F2, a, b, c, d, in[ 1]+0xf61e2562, 5);
|
||||
MD5STEP(F2, d, a, b, c, in[ 6]+0xc040b340, 9);
|
||||
MD5STEP(F2, c, d, a, b, in[11]+0x265e5a51, 14);
|
||||
MD5STEP(F2, b, c, d, a, in[ 0]+0xe9b6c7aa, 20);
|
||||
MD5STEP(F2, a, b, c, d, in[ 5]+0xd62f105d, 5);
|
||||
MD5STEP(F2, d, a, b, c, in[10]+0x02441453, 9);
|
||||
MD5STEP(F2, c, d, a, b, in[15]+0xd8a1e681, 14);
|
||||
MD5STEP(F2, b, c, d, a, in[ 4]+0xe7d3fbc8, 20);
|
||||
MD5STEP(F2, a, b, c, d, in[ 9]+0x21e1cde6, 5);
|
||||
MD5STEP(F2, d, a, b, c, in[14]+0xc33707d6, 9);
|
||||
MD5STEP(F2, c, d, a, b, in[ 3]+0xf4d50d87, 14);
|
||||
MD5STEP(F2, b, c, d, a, in[ 8]+0x455a14ed, 20);
|
||||
MD5STEP(F2, a, b, c, d, in[13]+0xa9e3e905, 5);
|
||||
MD5STEP(F2, d, a, b, c, in[ 2]+0xfcefa3f8, 9);
|
||||
MD5STEP(F2, c, d, a, b, in[ 7]+0x676f02d9, 14);
|
||||
MD5STEP(F2, b, c, d, a, in[12]+0x8d2a4c8a, 20);
|
||||
|
||||
MD5STEP(F3, a, b, c, d, in[ 5]+0xfffa3942, 4);
|
||||
MD5STEP(F3, d, a, b, c, in[ 8]+0x8771f681, 11);
|
||||
MD5STEP(F3, c, d, a, b, in[11]+0x6d9d6122, 16);
|
||||
MD5STEP(F3, b, c, d, a, in[14]+0xfde5380c, 23);
|
||||
MD5STEP(F3, a, b, c, d, in[ 1]+0xa4beea44, 4);
|
||||
MD5STEP(F3, d, a, b, c, in[ 4]+0x4bdecfa9, 11);
|
||||
MD5STEP(F3, c, d, a, b, in[ 7]+0xf6bb4b60, 16);
|
||||
MD5STEP(F3, b, c, d, a, in[10]+0xbebfbc70, 23);
|
||||
MD5STEP(F3, a, b, c, d, in[13]+0x289b7ec6, 4);
|
||||
MD5STEP(F3, d, a, b, c, in[ 0]+0xeaa127fa, 11);
|
||||
MD5STEP(F3, c, d, a, b, in[ 3]+0xd4ef3085, 16);
|
||||
MD5STEP(F3, b, c, d, a, in[ 6]+0x04881d05, 23);
|
||||
MD5STEP(F3, a, b, c, d, in[ 9]+0xd9d4d039, 4);
|
||||
MD5STEP(F3, d, a, b, c, in[12]+0xe6db99e5, 11);
|
||||
MD5STEP(F3, c, d, a, b, in[15]+0x1fa27cf8, 16);
|
||||
MD5STEP(F3, b, c, d, a, in[ 2]+0xc4ac5665, 23);
|
||||
|
||||
MD5STEP(F4, a, b, c, d, in[ 0]+0xf4292244, 6);
|
||||
MD5STEP(F4, d, a, b, c, in[ 7]+0x432aff97, 10);
|
||||
MD5STEP(F4, c, d, a, b, in[14]+0xab9423a7, 15);
|
||||
MD5STEP(F4, b, c, d, a, in[ 5]+0xfc93a039, 21);
|
||||
MD5STEP(F4, a, b, c, d, in[12]+0x655b59c3, 6);
|
||||
MD5STEP(F4, d, a, b, c, in[ 3]+0x8f0ccc92, 10);
|
||||
MD5STEP(F4, c, d, a, b, in[10]+0xffeff47d, 15);
|
||||
MD5STEP(F4, b, c, d, a, in[ 1]+0x85845dd1, 21);
|
||||
MD5STEP(F4, a, b, c, d, in[ 8]+0x6fa87e4f, 6);
|
||||
MD5STEP(F4, d, a, b, c, in[15]+0xfe2ce6e0, 10);
|
||||
MD5STEP(F4, c, d, a, b, in[ 6]+0xa3014314, 15);
|
||||
MD5STEP(F4, b, c, d, a, in[13]+0x4e0811a1, 21);
|
||||
MD5STEP(F4, a, b, c, d, in[ 4]+0xf7537e82, 6);
|
||||
MD5STEP(F4, d, a, b, c, in[11]+0xbd3af235, 10);
|
||||
MD5STEP(F4, c, d, a, b, in[ 2]+0x2ad7d2bb, 15);
|
||||
MD5STEP(F4, b, c, d, a, in[ 9]+0xeb86d391, 21);
|
||||
|
||||
buf[0] += a;
|
||||
buf[1] += b;
|
||||
buf[2] += c;
|
||||
buf[3] += d;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef TEST
|
||||
/*
|
||||
Simple test program. Can use it to manually run the tests from
|
||||
RFC1321 for example.
|
||||
*/
|
||||
#include <stdio.h>
|
||||
|
||||
int
|
||||
main (int argc, char **argv)
|
||||
{
|
||||
my_MD5Context context;
|
||||
unsigned char checksum[16];
|
||||
int i;
|
||||
int j;
|
||||
|
||||
if (argc < 2)
|
||||
{
|
||||
fprintf (stderr, "usage: %s string-to-hash\n", argv[0]);
|
||||
exit (1);
|
||||
}
|
||||
for (j = 1; j < argc; ++j)
|
||||
{
|
||||
printf ("MD5 (\"%s\") = ", argv[j]);
|
||||
my_MD5Init (&context);
|
||||
my_MD5Update (&context, argv[j], strlen (argv[j]));
|
||||
my_MD5Final (checksum, &context);
|
||||
for (i = 0; i < 16; i++)
|
||||
{
|
||||
printf ("%02x", (unsigned int) checksum[i]);
|
||||
}
|
||||
printf ("\n");
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
#endif /* TEST */
|
||||
61
deps/mysqllite/mysys/mf_arr_appstr.c
vendored
Normal file
61
deps/mysqllite/mysys/mf_arr_appstr.c
vendored
Normal file
@@ -0,0 +1,61 @@
|
||||
/* Copyright (C) 2007 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 */
|
||||
|
||||
#include "mysys_priv.h"
|
||||
#include <m_string.h> /* strcmp() */
|
||||
|
||||
|
||||
/**
|
||||
Append str to array, or move to the end if it already exists
|
||||
|
||||
@param str String to be appended
|
||||
@param array The array, terminated by a NULL element, all unused elements
|
||||
pre-initialized to NULL
|
||||
@param size Size of the array; array must be terminated by a NULL
|
||||
pointer, so can hold size - 1 elements
|
||||
|
||||
@retval FALSE Success
|
||||
@retval TRUE Failure, array is full
|
||||
*/
|
||||
|
||||
my_bool array_append_string_unique(const char *str,
|
||||
const char **array, size_t size)
|
||||
{
|
||||
const char **p;
|
||||
/* end points at the terminating NULL element */
|
||||
const char **end= array + size - 1;
|
||||
DBUG_ASSERT(*end == NULL);
|
||||
|
||||
for (p= array; *p; ++p)
|
||||
{
|
||||
if (strcmp(*p, str) == 0)
|
||||
break;
|
||||
}
|
||||
if (p >= end)
|
||||
return TRUE; /* Array is full */
|
||||
|
||||
DBUG_ASSERT(*p == NULL || strcmp(*p, str) == 0);
|
||||
|
||||
while (*(p + 1))
|
||||
{
|
||||
*p= *(p + 1);
|
||||
++p;
|
||||
}
|
||||
|
||||
DBUG_ASSERT(p < end);
|
||||
*p= str;
|
||||
|
||||
return FALSE; /* Success */
|
||||
}
|
||||
121
deps/mysqllite/mysys/mf_cache.c
vendored
Normal file
121
deps/mysqllite/mysys/mf_cache.c
vendored
Normal file
@@ -0,0 +1,121 @@
|
||||
/* Copyright (C) 2000 MySQL AB
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
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 */
|
||||
|
||||
/* Open a temporary file and cache it with io_cache. Delete it on close */
|
||||
|
||||
#include "mysys_priv.h"
|
||||
#include <m_string.h>
|
||||
#include "my_static.h"
|
||||
#include "mysys_err.h"
|
||||
|
||||
/*
|
||||
Remove an open tempfile so that it doesn't survive
|
||||
if we crash; If the operating system doesn't support
|
||||
this, just remember the file name for later removal
|
||||
*/
|
||||
|
||||
static my_bool cache_remove_open_tmp(IO_CACHE *cache __attribute__((unused)),
|
||||
const char *name)
|
||||
{
|
||||
#if O_TEMPORARY == 0
|
||||
#if !defined(CANT_DELETE_OPEN_FILES)
|
||||
/* The following should always succeed */
|
||||
(void) my_delete(name,MYF(MY_WME | ME_NOINPUT));
|
||||
#else
|
||||
int length;
|
||||
if (!(cache->file_name=
|
||||
(char*) my_malloc((length=strlen(name)+1),MYF(MY_WME))))
|
||||
{
|
||||
my_close(cache->file,MYF(0));
|
||||
cache->file = -1;
|
||||
errno=my_errno=ENOMEM;
|
||||
return 1;
|
||||
}
|
||||
memcpy(cache->file_name,name,length);
|
||||
#endif
|
||||
#endif /* O_TEMPORARY == 0 */
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
** Open tempfile cached by IO_CACHE
|
||||
** Should be used when no seeks are done (only reinit_io_buff)
|
||||
** Return 0 if cache is inited ok
|
||||
** The actual file is created when the IO_CACHE buffer gets filled
|
||||
** If dir is not given, use TMPDIR.
|
||||
*/
|
||||
|
||||
my_bool open_cached_file(IO_CACHE *cache, const char* dir, const char *prefix,
|
||||
size_t cache_size, myf cache_myflags)
|
||||
{
|
||||
DBUG_ENTER("open_cached_file");
|
||||
cache->dir= dir ? my_strdup(dir,MYF(cache_myflags & MY_WME)) : (char*) 0;
|
||||
cache->prefix= (prefix ? my_strdup(prefix,MYF(cache_myflags & MY_WME)) :
|
||||
(char*) 0);
|
||||
cache->file_name=0;
|
||||
cache->buffer=0; /* Mark that not open */
|
||||
if (!init_io_cache(cache,-1,cache_size,WRITE_CACHE,0L,0,
|
||||
MYF(cache_myflags | MY_NABP)))
|
||||
{
|
||||
DBUG_RETURN(0);
|
||||
}
|
||||
my_free(cache->dir);
|
||||
my_free(cache->prefix);
|
||||
DBUG_RETURN(1);
|
||||
}
|
||||
|
||||
/* Create the temporary file */
|
||||
|
||||
my_bool real_open_cached_file(IO_CACHE *cache)
|
||||
{
|
||||
char name_buff[FN_REFLEN];
|
||||
int error=1;
|
||||
DBUG_ENTER("real_open_cached_file");
|
||||
if ((cache->file=create_temp_file(name_buff, cache->dir, cache->prefix,
|
||||
(O_RDWR | O_BINARY | O_TRUNC |
|
||||
O_TEMPORARY | O_SHORT_LIVED),
|
||||
MYF(MY_WME))) >= 0)
|
||||
{
|
||||
error=0;
|
||||
cache_remove_open_tmp(cache, name_buff);
|
||||
}
|
||||
DBUG_RETURN(error);
|
||||
}
|
||||
|
||||
|
||||
void close_cached_file(IO_CACHE *cache)
|
||||
{
|
||||
DBUG_ENTER("close_cached_file");
|
||||
if (my_b_inited(cache))
|
||||
{
|
||||
File file=cache->file;
|
||||
cache->file= -1; /* Don't flush data */
|
||||
(void) end_io_cache(cache);
|
||||
if (file >= 0)
|
||||
{
|
||||
(void) my_close(file,MYF(0));
|
||||
#ifdef CANT_DELETE_OPEN_FILES
|
||||
if (cache->file_name)
|
||||
{
|
||||
(void) my_delete(cache->file_name,MYF(MY_WME | ME_NOINPUT));
|
||||
my_free(cache->file_name);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
my_free(cache->dir);
|
||||
my_free(cache->prefix);
|
||||
}
|
||||
DBUG_VOID_RETURN;
|
||||
}
|
||||
154
deps/mysqllite/mysys/mf_dirname.c
vendored
Normal file
154
deps/mysqllite/mysys/mf_dirname.c
vendored
Normal file
@@ -0,0 +1,154 @@
|
||||
/* Copyright (C) 2000 MySQL AB
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
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 */
|
||||
|
||||
#include "mysys_priv.h"
|
||||
#include <m_string.h>
|
||||
|
||||
/* Functions definied in this file */
|
||||
|
||||
size_t dirname_length(const char *name)
|
||||
{
|
||||
register char *pos, *gpos;
|
||||
#ifdef BASKSLASH_MBTAIL
|
||||
CHARSET_INFO *fs= fs_character_set();
|
||||
#endif
|
||||
#ifdef FN_DEVCHAR
|
||||
if ((pos=(char*)strrchr(name,FN_DEVCHAR)) == 0)
|
||||
#endif
|
||||
pos=(char*) name-1;
|
||||
|
||||
gpos= pos++;
|
||||
for ( ; *pos ; pos++) /* Find last FN_LIBCHAR */
|
||||
{
|
||||
#ifdef BASKSLASH_MBTAIL
|
||||
uint l;
|
||||
if (use_mb(fs) && (l= my_ismbchar(fs, pos, pos + 3)))
|
||||
{
|
||||
pos+= l - 1;
|
||||
continue;
|
||||
}
|
||||
#endif
|
||||
if (*pos == FN_LIBCHAR || *pos == '/')
|
||||
gpos=pos;
|
||||
}
|
||||
return (size_t) (gpos+1-(char*) name);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Gives directory part of filename. Directory ends with '/'
|
||||
|
||||
SYNOPSIS
|
||||
dirname_part()
|
||||
to Store directory name here
|
||||
name Original name
|
||||
to_length Store length of 'to' here
|
||||
|
||||
RETURN
|
||||
# Length of directory part in 'name'
|
||||
*/
|
||||
|
||||
size_t dirname_part(char *to, const char *name, size_t *to_res_length)
|
||||
{
|
||||
size_t length;
|
||||
DBUG_ENTER("dirname_part");
|
||||
DBUG_PRINT("enter",("'%s'",name));
|
||||
|
||||
length=dirname_length(name);
|
||||
*to_res_length= (size_t) (convert_dirname(to, name, name+length) - to);
|
||||
DBUG_RETURN(length);
|
||||
} /* dirname */
|
||||
|
||||
|
||||
/*
|
||||
Convert directory name to use under this system
|
||||
|
||||
SYNPOSIS
|
||||
convert_dirname()
|
||||
to Store result here. Must be at least of size
|
||||
min(FN_REFLEN, strlen(from) + 1) to make room
|
||||
for adding FN_LIBCHAR at the end.
|
||||
from Original filename. May be == to
|
||||
from_end Pointer at end of filename (normally end \0)
|
||||
|
||||
IMPLEMENTATION
|
||||
If Windows converts '/' to '\'
|
||||
Adds a FN_LIBCHAR to end if the result string if there isn't one
|
||||
and the last isn't dev_char.
|
||||
Copies data from 'from' until ASCII(0) for until from == from_end
|
||||
If you want to use the whole 'from' string, just send NullS as the
|
||||
last argument.
|
||||
|
||||
If the result string is larger than FN_REFLEN -1, then it's cut.
|
||||
|
||||
RETURN
|
||||
Returns pointer to end \0 in to
|
||||
*/
|
||||
|
||||
#ifndef FN_DEVCHAR
|
||||
#define FN_DEVCHAR '\0' /* For easier code */
|
||||
#endif
|
||||
|
||||
char *convert_dirname(char *to, const char *from, const char *from_end)
|
||||
{
|
||||
char *to_org=to;
|
||||
#ifdef BACKSLASH_MBTAIL
|
||||
CHARSET_INFO *fs= fs_character_set();
|
||||
#endif
|
||||
DBUG_ENTER("convert_dirname");
|
||||
|
||||
/* We use -2 here, becasue we need place for the last FN_LIBCHAR */
|
||||
if (!from_end || (from_end - from) > FN_REFLEN-2)
|
||||
from_end=from+FN_REFLEN -2;
|
||||
|
||||
#if FN_LIBCHAR != '/'
|
||||
{
|
||||
for (; from != from_end && *from ; from++)
|
||||
{
|
||||
if (*from == '/')
|
||||
*to++= FN_LIBCHAR;
|
||||
else
|
||||
{
|
||||
#ifdef BACKSLASH_MBTAIL
|
||||
uint l;
|
||||
if (use_mb(fs) && (l= my_ismbchar(fs, from, from + 3)))
|
||||
{
|
||||
memmove(to, from, l);
|
||||
to+= l;
|
||||
from+= l - 1;
|
||||
to_org= to; /* Don't look inside mbchar */
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
*to++= *from;
|
||||
}
|
||||
}
|
||||
}
|
||||
*to=0;
|
||||
}
|
||||
#else
|
||||
/* This is ok even if to == from, becasue we need to cut the string */
|
||||
to= strmake(to, from, (size_t) (from_end-from));
|
||||
#endif
|
||||
|
||||
/* Add FN_LIBCHAR to the end of directory path */
|
||||
if (to != to_org && (to[-1] != FN_LIBCHAR && to[-1] != FN_DEVCHAR))
|
||||
{
|
||||
*to++=FN_LIBCHAR;
|
||||
*to=0;
|
||||
}
|
||||
DBUG_RETURN(to); /* Pointer to end of dir */
|
||||
} /* convert_dirname */
|
||||
54
deps/mysqllite/mysys/mf_fn_ext.c
vendored
Normal file
54
deps/mysqllite/mysys/mf_fn_ext.c
vendored
Normal file
@@ -0,0 +1,54 @@
|
||||
/* Copyright (C) 2000 MySQL AB
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
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 */
|
||||
|
||||
|
||||
#include "mysys_priv.h"
|
||||
#include <m_string.h>
|
||||
|
||||
/*
|
||||
Return a pointer to the extension of the filename.
|
||||
|
||||
SYNOPSIS
|
||||
fn_ext()
|
||||
name Name of file
|
||||
|
||||
DESCRIPTION
|
||||
The extension is defined as everything after the first extension character
|
||||
(normally '.') after the directory name.
|
||||
|
||||
RETURN VALUES
|
||||
Pointer to to the extension character. If there isn't any extension,
|
||||
points at the end ASCII(0) of the filename.
|
||||
*/
|
||||
|
||||
char *fn_ext(const char *name)
|
||||
{
|
||||
register const char *pos, *gpos;
|
||||
DBUG_ENTER("fn_ext");
|
||||
DBUG_PRINT("mfunkt",("name: '%s'",name));
|
||||
|
||||
#if defined(FN_DEVCHAR) || defined(BASKSLASH_MBTAIL)
|
||||
{
|
||||
char buff[FN_REFLEN];
|
||||
size_t res_length;
|
||||
gpos= name+ dirname_part(buff,(char*) name, &res_length);
|
||||
}
|
||||
#else
|
||||
if (!(gpos= strrchr(name, FN_LIBCHAR)))
|
||||
gpos= name;
|
||||
#endif
|
||||
pos=strchr(gpos,FN_EXTCHAR);
|
||||
DBUG_RETURN((char*) (pos ? pos : strend(gpos)));
|
||||
} /* fn_ext */
|
||||
142
deps/mysqllite/mysys/mf_format.c
vendored
Normal file
142
deps/mysqllite/mysys/mf_format.c
vendored
Normal file
@@ -0,0 +1,142 @@
|
||||
/* Copyright (C) 2000 MySQL AB
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
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 */
|
||||
|
||||
#include "mysys_priv.h"
|
||||
#include <m_string.h>
|
||||
|
||||
/*
|
||||
Formats a filename with possible replace of directory of extension
|
||||
Function can handle the case where 'to' == 'name'
|
||||
For a description of the flag values, consult my_sys.h
|
||||
The arguments should be in unix format.
|
||||
*/
|
||||
|
||||
char * fn_format(char * to, const char *name, const char *dir,
|
||||
const char *extension, uint flag)
|
||||
{
|
||||
char dev[FN_REFLEN], buff[FN_REFLEN], *pos, *startpos;
|
||||
const char *ext;
|
||||
reg1 size_t length;
|
||||
size_t dev_length;
|
||||
DBUG_ENTER("fn_format");
|
||||
DBUG_PRINT("enter",("name: %s dir: %s extension: %s flag: %d",
|
||||
name,dir,extension,flag));
|
||||
|
||||
/* Copy and skip directory */
|
||||
name+=(length=dirname_part(dev, (startpos=(char *) name), &dev_length));
|
||||
if (length == 0 || (flag & MY_REPLACE_DIR))
|
||||
{
|
||||
/* Use given directory */
|
||||
convert_dirname(dev,dir,NullS); /* Fix to this OS */
|
||||
}
|
||||
else if ((flag & MY_RELATIVE_PATH) && !test_if_hard_path(dev))
|
||||
{
|
||||
/* Put 'dir' before the given path */
|
||||
strmake(buff,dev,sizeof(buff)-1);
|
||||
pos=convert_dirname(dev,dir,NullS);
|
||||
strmake(pos,buff,sizeof(buff)-1- (int) (pos-dev));
|
||||
}
|
||||
|
||||
if (flag & MY_PACK_FILENAME)
|
||||
pack_dirname(dev,dev); /* Put in ./.. and ~/.. */
|
||||
if (flag & MY_UNPACK_FILENAME)
|
||||
(void) unpack_dirname(dev,dev); /* Replace ~/.. with dir */
|
||||
|
||||
if (!(flag & MY_APPEND_EXT) &&
|
||||
(pos= (char*) strchr(name,FN_EXTCHAR)) != NullS)
|
||||
{
|
||||
if ((flag & MY_REPLACE_EXT) == 0) /* If we should keep old ext */
|
||||
{
|
||||
length=strlength(name); /* Use old extension */
|
||||
ext = "";
|
||||
}
|
||||
else
|
||||
{
|
||||
length= (size_t) (pos-(char*) name); /* Change extension */
|
||||
ext= extension;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
length=strlength(name); /* No ext, use the now one */
|
||||
ext=extension;
|
||||
}
|
||||
|
||||
if (strlen(dev)+length+strlen(ext) >= FN_REFLEN || length >= FN_LEN )
|
||||
{
|
||||
/* To long path, return original or NULL */
|
||||
size_t tmp_length;
|
||||
if (flag & MY_SAFE_PATH)
|
||||
DBUG_RETURN(NullS);
|
||||
tmp_length= strlength(startpos);
|
||||
DBUG_PRINT("error",("dev: '%s' ext: '%s' length: %u",dev,ext,
|
||||
(uint) length));
|
||||
(void) strmake(to,startpos,min(tmp_length,FN_REFLEN-1));
|
||||
}
|
||||
else
|
||||
{
|
||||
if (to == startpos)
|
||||
{
|
||||
bmove(buff,(uchar*) name,length); /* Save name for last copy */
|
||||
name=buff;
|
||||
}
|
||||
pos=strmake(strmov(to,dev),name,length);
|
||||
(void) strmov(pos,ext); /* Don't convert extension */
|
||||
}
|
||||
/*
|
||||
If MY_RETURN_REAL_PATH and MY_RESOLVE_SYMLINK is given, only do
|
||||
realpath if the file is a symbolic link
|
||||
*/
|
||||
if (flag & MY_RETURN_REAL_PATH)
|
||||
(void) my_realpath(to, to, MYF(flag & MY_RESOLVE_SYMLINKS ?
|
||||
MY_RESOLVE_LINK: 0));
|
||||
else if (flag & MY_RESOLVE_SYMLINKS)
|
||||
{
|
||||
strmov(buff,to);
|
||||
(void) my_readlink(to, buff, MYF(0));
|
||||
}
|
||||
DBUG_RETURN(to);
|
||||
} /* fn_format */
|
||||
|
||||
|
||||
/*
|
||||
strlength(const string str)
|
||||
Return length of string with end-space:s not counted.
|
||||
*/
|
||||
|
||||
size_t strlength(const char *str)
|
||||
{
|
||||
reg1 const char * pos;
|
||||
reg2 const char * found;
|
||||
DBUG_ENTER("strlength");
|
||||
|
||||
pos= found= str;
|
||||
|
||||
while (*pos)
|
||||
{
|
||||
if (*pos != ' ')
|
||||
{
|
||||
while (*++pos && *pos != ' ') {};
|
||||
if (!*pos)
|
||||
{
|
||||
found=pos; /* String ends here */
|
||||
break;
|
||||
}
|
||||
}
|
||||
found=pos;
|
||||
while (*++pos == ' ') {};
|
||||
}
|
||||
DBUG_RETURN((size_t) (found - str));
|
||||
} /* strlength */
|
||||
81
deps/mysqllite/mysys/mf_getdate.c
vendored
Normal file
81
deps/mysqllite/mysys/mf_getdate.c
vendored
Normal file
@@ -0,0 +1,81 @@
|
||||
/* Copyright (C) 2000 MySQL AB
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
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 */
|
||||
|
||||
/* Get date in a printable form: yyyy-mm-dd hh:mm:ss */
|
||||
|
||||
#include "mysys_priv.h"
|
||||
#include <m_string.h>
|
||||
|
||||
/*
|
||||
get date as string
|
||||
|
||||
SYNOPSIS
|
||||
get_date()
|
||||
to - string where date will be written
|
||||
flag - format of date:
|
||||
If flag & GETDATE_TIME Return date and time
|
||||
If flag & GETDATE_SHORT_DATE Return short date format YYMMDD
|
||||
If flag & GETDATE_HHMMSSTIME Return time in HHMMDD format.
|
||||
If flag & GETDATE_GMT Date/time in GMT
|
||||
If flag & GETDATE_FIXEDLENGTH Return fixed length date/time
|
||||
date - for conversion
|
||||
*/
|
||||
|
||||
|
||||
void get_date(register char * to, int flag, time_t date)
|
||||
{
|
||||
reg2 struct tm *start_time;
|
||||
time_t skr;
|
||||
#if defined(HAVE_LOCALTIME_R) && defined(_REENTRANT)
|
||||
struct tm tm_tmp;
|
||||
#endif
|
||||
|
||||
skr=date ? (time_t) date : my_time(0);
|
||||
#if defined(HAVE_LOCALTIME_R) && defined(_REENTRANT)
|
||||
if (flag & GETDATE_GMT)
|
||||
gmtime_r(&skr,&tm_tmp);
|
||||
else
|
||||
localtime_r(&skr,&tm_tmp);
|
||||
start_time= &tm_tmp;
|
||||
#else
|
||||
if (flag & GETDATE_GMT)
|
||||
start_time= gmtime(&skr);
|
||||
else
|
||||
start_time= localtime(&skr);
|
||||
#endif
|
||||
if (flag & GETDATE_SHORT_DATE)
|
||||
sprintf(to,"%02d%02d%02d",
|
||||
start_time->tm_year % 100,
|
||||
start_time->tm_mon+1,
|
||||
start_time->tm_mday);
|
||||
else
|
||||
sprintf(to, ((flag & GETDATE_FIXEDLENGTH) ?
|
||||
"%4d-%02d-%02d" : "%d-%02d-%02d"),
|
||||
start_time->tm_year+1900,
|
||||
start_time->tm_mon+1,
|
||||
start_time->tm_mday);
|
||||
if (flag & GETDATE_DATE_TIME)
|
||||
sprintf(strend(to),
|
||||
((flag & GETDATE_FIXEDLENGTH) ?
|
||||
" %02d:%02d:%02d" : " %2d:%02d:%02d"),
|
||||
start_time->tm_hour,
|
||||
start_time->tm_min,
|
||||
start_time->tm_sec);
|
||||
else if (flag & GETDATE_HHMMSSTIME)
|
||||
sprintf(strend(to),"%02d%02d%02d",
|
||||
start_time->tm_hour,
|
||||
start_time->tm_min,
|
||||
start_time->tm_sec);
|
||||
} /* get_date */
|
||||
1949
deps/mysqllite/mysys/mf_iocache.c
vendored
Normal file
1949
deps/mysqllite/mysys/mf_iocache.c
vendored
Normal file
File diff suppressed because it is too large
Load Diff
472
deps/mysqllite/mysys/mf_iocache2.c
vendored
Normal file
472
deps/mysqllite/mysys/mf_iocache2.c
vendored
Normal file
@@ -0,0 +1,472 @@
|
||||
/* Copyright (C) 2000 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 */
|
||||
|
||||
/*
|
||||
More functions to be used with IO_CACHE files
|
||||
*/
|
||||
|
||||
#include "mysys_priv.h"
|
||||
#include <m_string.h>
|
||||
#include <stdarg.h>
|
||||
#include <m_ctype.h>
|
||||
|
||||
/*
|
||||
Copy contents of an IO_CACHE to a file.
|
||||
|
||||
SYNOPSIS
|
||||
my_b_copy_to_file()
|
||||
cache IO_CACHE to copy from
|
||||
file File to copy to
|
||||
|
||||
DESCRIPTION
|
||||
Copy the contents of the cache to the file. The cache will be
|
||||
re-inited to a read cache and will read from the beginning of the
|
||||
cache.
|
||||
|
||||
If a failure to write fully occurs, the cache is only copied
|
||||
partially.
|
||||
|
||||
TODO
|
||||
Make this function solid by handling partial reads from the cache
|
||||
in a correct manner: it should be atomic.
|
||||
|
||||
RETURN VALUE
|
||||
0 All OK
|
||||
1 An error occured
|
||||
*/
|
||||
int
|
||||
my_b_copy_to_file(IO_CACHE *cache, FILE *file)
|
||||
{
|
||||
size_t bytes_in_cache;
|
||||
DBUG_ENTER("my_b_copy_to_file");
|
||||
|
||||
/* Reinit the cache to read from the beginning of the cache */
|
||||
if (reinit_io_cache(cache, READ_CACHE, 0L, FALSE, FALSE))
|
||||
DBUG_RETURN(1);
|
||||
bytes_in_cache= my_b_bytes_in_cache(cache);
|
||||
do
|
||||
{
|
||||
if (my_fwrite(file, cache->read_pos, bytes_in_cache,
|
||||
MYF(MY_WME | MY_NABP)) == (size_t) -1)
|
||||
DBUG_RETURN(1);
|
||||
cache->read_pos= cache->read_end;
|
||||
} while ((bytes_in_cache= my_b_fill(cache)));
|
||||
DBUG_RETURN(0);
|
||||
}
|
||||
|
||||
|
||||
my_off_t my_b_append_tell(IO_CACHE* info)
|
||||
{
|
||||
/*
|
||||
Sometimes we want to make sure that the variable is not put into
|
||||
a register in debugging mode so we can see its value in the core
|
||||
*/
|
||||
#ifndef DBUG_OFF
|
||||
# define dbug_volatile volatile
|
||||
#else
|
||||
# define dbug_volatile
|
||||
#endif
|
||||
|
||||
/*
|
||||
Prevent optimizer from putting res in a register when debugging
|
||||
we need this to be able to see the value of res when the assert fails
|
||||
*/
|
||||
dbug_volatile my_off_t res;
|
||||
|
||||
/*
|
||||
We need to lock the append buffer mutex to keep flush_io_cache()
|
||||
from messing with the variables that we need in order to provide the
|
||||
answer to the question.
|
||||
*/
|
||||
mysql_mutex_lock(&info->append_buffer_lock);
|
||||
|
||||
#ifndef DBUG_OFF
|
||||
/*
|
||||
Make sure EOF is where we think it is. Note that we cannot just use
|
||||
my_tell() because we have a reader thread that could have left the
|
||||
file offset in a non-EOF location
|
||||
*/
|
||||
{
|
||||
volatile my_off_t save_pos;
|
||||
save_pos = my_tell(info->file,MYF(0));
|
||||
my_seek(info->file,(my_off_t)0,MY_SEEK_END,MYF(0));
|
||||
/*
|
||||
Save the value of my_tell in res so we can see it when studying coredump
|
||||
*/
|
||||
DBUG_ASSERT(info->end_of_file - (info->append_read_pos-info->write_buffer)
|
||||
== (res=my_tell(info->file,MYF(0))));
|
||||
my_seek(info->file,save_pos,MY_SEEK_SET,MYF(0));
|
||||
}
|
||||
#endif
|
||||
res = info->end_of_file + (info->write_pos-info->append_read_pos);
|
||||
mysql_mutex_unlock(&info->append_buffer_lock);
|
||||
return res;
|
||||
}
|
||||
|
||||
my_off_t my_b_safe_tell(IO_CACHE *info)
|
||||
{
|
||||
if (unlikely(info->type == SEQ_READ_APPEND))
|
||||
return my_b_append_tell(info);
|
||||
return my_b_tell(info);
|
||||
}
|
||||
|
||||
/*
|
||||
Make next read happen at the given position
|
||||
For write cache, make next write happen at the given position
|
||||
*/
|
||||
|
||||
void my_b_seek(IO_CACHE *info,my_off_t pos)
|
||||
{
|
||||
my_off_t offset;
|
||||
DBUG_ENTER("my_b_seek");
|
||||
DBUG_PRINT("enter",("pos: %lu", (ulong) pos));
|
||||
|
||||
/*
|
||||
TODO:
|
||||
Verify that it is OK to do seek in the non-append
|
||||
area in SEQ_READ_APPEND cache
|
||||
a) see if this always works
|
||||
b) see if there is a better way to make it work
|
||||
*/
|
||||
if (info->type == SEQ_READ_APPEND)
|
||||
(void) flush_io_cache(info);
|
||||
|
||||
offset=(pos - info->pos_in_file);
|
||||
|
||||
if (info->type == READ_CACHE || info->type == SEQ_READ_APPEND)
|
||||
{
|
||||
/* TODO: explain why this works if pos < info->pos_in_file */
|
||||
if ((ulonglong) offset < (ulonglong) (info->read_end - info->buffer))
|
||||
{
|
||||
/* The read is in the current buffer; Reuse it */
|
||||
info->read_pos = info->buffer + offset;
|
||||
DBUG_VOID_RETURN;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Force a new read on next my_b_read */
|
||||
info->read_pos=info->read_end=info->buffer;
|
||||
}
|
||||
}
|
||||
else if (info->type == WRITE_CACHE)
|
||||
{
|
||||
/* If write is in current buffer, reuse it */
|
||||
if ((ulonglong) offset <
|
||||
(ulonglong) (info->write_end - info->write_buffer))
|
||||
{
|
||||
info->write_pos = info->write_buffer + offset;
|
||||
DBUG_VOID_RETURN;
|
||||
}
|
||||
(void) flush_io_cache(info);
|
||||
/* Correct buffer end so that we write in increments of IO_SIZE */
|
||||
info->write_end=(info->write_buffer+info->buffer_length-
|
||||
(pos & (IO_SIZE-1)));
|
||||
}
|
||||
info->pos_in_file=pos;
|
||||
info->seek_not_done=1;
|
||||
DBUG_VOID_RETURN;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Fill buffer of the cache.
|
||||
|
||||
NOTES
|
||||
This assumes that you have already used all characters in the CACHE,
|
||||
independent of the read_pos value!
|
||||
|
||||
RETURN
|
||||
0 On error or EOF (info->error = -1 on error)
|
||||
# Number of characters
|
||||
*/
|
||||
|
||||
|
||||
size_t my_b_fill(IO_CACHE *info)
|
||||
{
|
||||
my_off_t pos_in_file=(info->pos_in_file+
|
||||
(size_t) (info->read_end - info->buffer));
|
||||
size_t diff_length, length, max_length;
|
||||
|
||||
if (info->seek_not_done)
|
||||
{ /* File touched, do seek */
|
||||
if (my_seek(info->file,pos_in_file,MY_SEEK_SET,MYF(0)) ==
|
||||
MY_FILEPOS_ERROR)
|
||||
{
|
||||
info->error= 0;
|
||||
return 0;
|
||||
}
|
||||
info->seek_not_done=0;
|
||||
}
|
||||
diff_length=(size_t) (pos_in_file & (IO_SIZE-1));
|
||||
max_length=(info->read_length-diff_length);
|
||||
if (max_length >= (info->end_of_file - pos_in_file))
|
||||
max_length= (size_t) (info->end_of_file - pos_in_file);
|
||||
|
||||
if (!max_length)
|
||||
{
|
||||
info->error= 0;
|
||||
return 0; /* EOF */
|
||||
}
|
||||
if ((length= my_read(info->file,info->buffer,max_length,
|
||||
info->myflags)) == (size_t) -1)
|
||||
{
|
||||
info->error= -1;
|
||||
return 0;
|
||||
}
|
||||
info->read_pos=info->buffer;
|
||||
info->read_end=info->buffer+length;
|
||||
info->pos_in_file=pos_in_file;
|
||||
return length;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Read a string ended by '\n' into a buffer of 'max_length' size.
|
||||
Returns number of characters read, 0 on error.
|
||||
last byte is set to '\0'
|
||||
If buffer is full then to[max_length-1] will be set to \0.
|
||||
*/
|
||||
|
||||
size_t my_b_gets(IO_CACHE *info, char *to, size_t max_length)
|
||||
{
|
||||
char *start = to;
|
||||
size_t length;
|
||||
max_length--; /* Save place for end \0 */
|
||||
|
||||
/* Calculate number of characters in buffer */
|
||||
if (!(length= my_b_bytes_in_cache(info)) &&
|
||||
!(length= my_b_fill(info)))
|
||||
return 0;
|
||||
|
||||
for (;;)
|
||||
{
|
||||
uchar *pos, *end;
|
||||
if (length > max_length)
|
||||
length=max_length;
|
||||
for (pos=info->read_pos,end=pos+length ; pos < end ;)
|
||||
{
|
||||
if ((*to++ = *pos++) == '\n')
|
||||
{
|
||||
info->read_pos=pos;
|
||||
*to='\0';
|
||||
return (size_t) (to-start);
|
||||
}
|
||||
}
|
||||
if (!(max_length-=length))
|
||||
{
|
||||
/* Found enough charcters; Return found string */
|
||||
info->read_pos=pos;
|
||||
*to='\0';
|
||||
return (size_t) (to-start);
|
||||
}
|
||||
if (!(length=my_b_fill(info)))
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
my_off_t my_b_filelength(IO_CACHE *info)
|
||||
{
|
||||
if (info->type == WRITE_CACHE)
|
||||
return my_b_tell(info);
|
||||
|
||||
info->seek_not_done= 1;
|
||||
return my_seek(info->file, 0L, MY_SEEK_END, MYF(0));
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Simple printf version. Supports '%s', '%d', '%u', "%ld" and "%lu"
|
||||
Used for logging in MySQL
|
||||
returns number of written character, or (size_t) -1 on error
|
||||
*/
|
||||
|
||||
size_t my_b_printf(IO_CACHE *info, const char* fmt, ...)
|
||||
{
|
||||
size_t result;
|
||||
va_list args;
|
||||
va_start(args,fmt);
|
||||
result=my_b_vprintf(info, fmt, args);
|
||||
va_end(args);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
size_t my_b_vprintf(IO_CACHE *info, const char* fmt, va_list args)
|
||||
{
|
||||
size_t out_length= 0;
|
||||
uint minimum_width; /* as yet unimplemented */
|
||||
uint minimum_width_sign;
|
||||
uint precision; /* as yet unimplemented for anything but %b */
|
||||
my_bool is_zero_padded;
|
||||
|
||||
/*
|
||||
Store the location of the beginning of a format directive, for the
|
||||
case where we learn we shouldn't have been parsing a format string
|
||||
at all, and we don't want to lose the flag/precision/width/size
|
||||
information.
|
||||
*/
|
||||
const char* backtrack;
|
||||
|
||||
for (; *fmt != '\0'; fmt++)
|
||||
{
|
||||
/* Copy everything until '%' or end of string */
|
||||
const char *start=fmt;
|
||||
size_t length;
|
||||
|
||||
for (; (*fmt != '\0') && (*fmt != '%'); fmt++) ;
|
||||
|
||||
length= (size_t) (fmt - start);
|
||||
out_length+=length;
|
||||
if (my_b_write(info, (const uchar*) start, length))
|
||||
goto err;
|
||||
|
||||
if (*fmt == '\0') /* End of format */
|
||||
return out_length;
|
||||
|
||||
/*
|
||||
By this point, *fmt must be a percent; Keep track of this location and
|
||||
skip over the percent character.
|
||||
*/
|
||||
DBUG_ASSERT(*fmt == '%');
|
||||
backtrack= fmt;
|
||||
fmt++;
|
||||
|
||||
is_zero_padded= FALSE;
|
||||
minimum_width_sign= 1;
|
||||
minimum_width= 0;
|
||||
precision= 0;
|
||||
/* Skip if max size is used (to be compatible with printf) */
|
||||
|
||||
process_flags:
|
||||
switch (*fmt)
|
||||
{
|
||||
case '-':
|
||||
minimum_width_sign= -1; fmt++; goto process_flags;
|
||||
case '0':
|
||||
is_zero_padded= TRUE; fmt++; goto process_flags;
|
||||
case '#':
|
||||
/** @todo Implement "#" conversion flag. */ fmt++; goto process_flags;
|
||||
case ' ':
|
||||
/** @todo Implement " " conversion flag. */ fmt++; goto process_flags;
|
||||
case '+':
|
||||
/** @todo Implement "+" conversion flag. */ fmt++; goto process_flags;
|
||||
}
|
||||
|
||||
if (*fmt == '*')
|
||||
{
|
||||
precision= (int) va_arg(args, int);
|
||||
fmt++;
|
||||
}
|
||||
else
|
||||
{
|
||||
while (my_isdigit(&my_charset_latin1, *fmt)) {
|
||||
minimum_width=(minimum_width * 10) + (*fmt - '0');
|
||||
fmt++;
|
||||
}
|
||||
}
|
||||
minimum_width*= minimum_width_sign;
|
||||
|
||||
if (*fmt == '.')
|
||||
{
|
||||
fmt++;
|
||||
if (*fmt == '*') {
|
||||
precision= (int) va_arg(args, int);
|
||||
fmt++;
|
||||
}
|
||||
else
|
||||
{
|
||||
while (my_isdigit(&my_charset_latin1, *fmt)) {
|
||||
precision=(precision * 10) + (*fmt - '0');
|
||||
fmt++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (*fmt == 's') /* String parameter */
|
||||
{
|
||||
reg2 char *par = va_arg(args, char *);
|
||||
size_t length2 = strlen(par);
|
||||
/* TODO: implement precision */
|
||||
out_length+= length2;
|
||||
if (my_b_write(info, (uchar*) par, length2))
|
||||
goto err;
|
||||
}
|
||||
else if (*fmt == 'b') /* Sized buffer parameter, only precision makes sense */
|
||||
{
|
||||
char *par = va_arg(args, char *);
|
||||
out_length+= precision;
|
||||
if (my_b_write(info, (uchar*) par, precision))
|
||||
goto err;
|
||||
}
|
||||
else if (*fmt == 'd' || *fmt == 'u') /* Integer parameter */
|
||||
{
|
||||
register int iarg;
|
||||
size_t length2;
|
||||
char buff[17];
|
||||
|
||||
iarg = va_arg(args, int);
|
||||
if (*fmt == 'd')
|
||||
length2= (size_t) (int10_to_str((long) iarg,buff, -10) - buff);
|
||||
else
|
||||
length2= (uint) (int10_to_str((long) (uint) iarg,buff,10)- buff);
|
||||
|
||||
/* minimum width padding */
|
||||
if (minimum_width > length2)
|
||||
{
|
||||
char *buffz;
|
||||
|
||||
buffz= my_alloca(minimum_width - length2);
|
||||
if (is_zero_padded)
|
||||
memset(buffz, '0', minimum_width - length2);
|
||||
else
|
||||
memset(buffz, ' ', minimum_width - length2);
|
||||
my_b_write(info, buffz, minimum_width - length2);
|
||||
my_afree(buffz);
|
||||
}
|
||||
|
||||
out_length+= length2;
|
||||
if (my_b_write(info, (uchar*) buff, length2))
|
||||
goto err;
|
||||
}
|
||||
else if ((*fmt == 'l' && fmt[1] == 'd') || fmt[1] == 'u')
|
||||
/* long parameter */
|
||||
{
|
||||
register long iarg;
|
||||
size_t length2;
|
||||
char buff[17];
|
||||
|
||||
iarg = va_arg(args, long);
|
||||
if (*++fmt == 'd')
|
||||
length2= (size_t) (int10_to_str(iarg,buff, -10) - buff);
|
||||
else
|
||||
length2= (size_t) (int10_to_str(iarg,buff,10)- buff);
|
||||
out_length+= length2;
|
||||
if (my_b_write(info, (uchar*) buff, length2))
|
||||
goto err;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* %% or unknown code */
|
||||
if (my_b_write(info, (uchar*) backtrack, (size_t) (fmt-backtrack)))
|
||||
goto err;
|
||||
out_length+= fmt-backtrack;
|
||||
}
|
||||
}
|
||||
return out_length;
|
||||
|
||||
err:
|
||||
return (size_t) -1;
|
||||
}
|
||||
4523
deps/mysqllite/mysys/mf_keycache.c
vendored
Normal file
4523
deps/mysqllite/mysys/mf_keycache.c
vendored
Normal file
File diff suppressed because it is too large
Load Diff
361
deps/mysqllite/mysys/mf_keycaches.c
vendored
Normal file
361
deps/mysqllite/mysys/mf_keycaches.c
vendored
Normal file
@@ -0,0 +1,361 @@
|
||||
/* Copyright (C) 2003 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 */
|
||||
|
||||
/*
|
||||
Handling of multiple key caches
|
||||
|
||||
The idea is to have a thread safe hash on the table name,
|
||||
with a default key cache value that is returned if the table name is not in
|
||||
the cache.
|
||||
*/
|
||||
|
||||
#include "mysys_priv.h"
|
||||
#include <keycache.h>
|
||||
#include <hash.h>
|
||||
#include <m_string.h>
|
||||
|
||||
/*****************************************************************************
|
||||
General functions to handle SAFE_HASH objects.
|
||||
|
||||
A SAFE_HASH object is used to store the hash, the mutex and default value
|
||||
needed by the rest of the key cache code.
|
||||
This is a separate struct to make it easy to later reuse the code for other
|
||||
purposes
|
||||
|
||||
All entries are linked in a list to allow us to traverse all elements
|
||||
and delete selected ones. (HASH doesn't allow any easy ways to do this).
|
||||
*****************************************************************************/
|
||||
|
||||
/*
|
||||
Struct to store a key and pointer to object
|
||||
*/
|
||||
|
||||
typedef struct st_safe_hash_entry
|
||||
{
|
||||
uchar *key;
|
||||
uint length;
|
||||
uchar *data;
|
||||
struct st_safe_hash_entry *next, **prev;
|
||||
} SAFE_HASH_ENTRY;
|
||||
|
||||
|
||||
typedef struct st_safe_hash_with_default
|
||||
{
|
||||
rw_lock_t mutex;
|
||||
HASH hash;
|
||||
uchar *default_value;
|
||||
SAFE_HASH_ENTRY *root;
|
||||
} SAFE_HASH;
|
||||
|
||||
|
||||
/*
|
||||
Free a SAFE_HASH_ENTRY
|
||||
|
||||
This function is called by the hash object on delete
|
||||
*/
|
||||
|
||||
static void safe_hash_entry_free(SAFE_HASH_ENTRY *entry)
|
||||
{
|
||||
DBUG_ENTER("free_assign_entry");
|
||||
my_free(entry);
|
||||
DBUG_VOID_RETURN;
|
||||
}
|
||||
|
||||
|
||||
/* Get key and length for a SAFE_HASH_ENTRY */
|
||||
|
||||
static uchar *safe_hash_entry_get(SAFE_HASH_ENTRY *entry, size_t *length,
|
||||
my_bool not_used __attribute__((unused)))
|
||||
{
|
||||
*length=entry->length;
|
||||
return (uchar*) entry->key;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Init a SAFE_HASH object
|
||||
|
||||
SYNOPSIS
|
||||
safe_hash_init()
|
||||
hash safe_hash handler
|
||||
elements Expected max number of elements
|
||||
default_value default value
|
||||
|
||||
NOTES
|
||||
In case of error we set hash->default_value to 0 to allow one to call
|
||||
safe_hash_free on an object that couldn't be initialized.
|
||||
|
||||
RETURN
|
||||
0 ok
|
||||
1 error
|
||||
*/
|
||||
|
||||
static my_bool safe_hash_init(SAFE_HASH *hash, uint elements,
|
||||
uchar *default_value)
|
||||
{
|
||||
DBUG_ENTER("safe_hash");
|
||||
if (my_hash_init(&hash->hash, &my_charset_bin, elements,
|
||||
0, 0, (my_hash_get_key) safe_hash_entry_get,
|
||||
(void (*)(void*)) safe_hash_entry_free, 0))
|
||||
{
|
||||
hash->default_value= 0;
|
||||
DBUG_RETURN(1);
|
||||
}
|
||||
my_rwlock_init(&hash->mutex, 0);
|
||||
hash->default_value= default_value;
|
||||
hash->root= 0;
|
||||
DBUG_RETURN(0);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Free a SAFE_HASH object
|
||||
|
||||
NOTES
|
||||
This is safe to call on any object that has been sent to safe_hash_init()
|
||||
*/
|
||||
|
||||
static void safe_hash_free(SAFE_HASH *hash)
|
||||
{
|
||||
/*
|
||||
Test if safe_hash_init succeeded. This will also guard us against multiple
|
||||
free calls.
|
||||
*/
|
||||
if (hash->default_value)
|
||||
{
|
||||
my_hash_free(&hash->hash);
|
||||
rwlock_destroy(&hash->mutex);
|
||||
hash->default_value=0;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
Return the value stored for a key or default value if no key
|
||||
*/
|
||||
|
||||
static uchar *safe_hash_search(SAFE_HASH *hash, const uchar *key, uint length)
|
||||
{
|
||||
uchar *result;
|
||||
DBUG_ENTER("safe_hash_search");
|
||||
rw_rdlock(&hash->mutex);
|
||||
result= my_hash_search(&hash->hash, key, length);
|
||||
rw_unlock(&hash->mutex);
|
||||
if (!result)
|
||||
result= hash->default_value;
|
||||
else
|
||||
result= ((SAFE_HASH_ENTRY*) result)->data;
|
||||
DBUG_PRINT("exit",("data: 0x%lx", (long) result));
|
||||
DBUG_RETURN(result);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Associate a key with some data
|
||||
|
||||
SYONOPSIS
|
||||
safe_hash_set()
|
||||
hash Hash handle
|
||||
key key (path to table etc..)
|
||||
length Length of key
|
||||
data data to to associate with the data
|
||||
|
||||
NOTES
|
||||
This can be used both to insert a new entry and change an existing
|
||||
entry.
|
||||
If one associates a key with the default key cache, the key is deleted
|
||||
|
||||
RETURN
|
||||
0 ok
|
||||
1 error (Can only be EOM). In this case my_message() is called.
|
||||
*/
|
||||
|
||||
static my_bool safe_hash_set(SAFE_HASH *hash, const uchar *key, uint length,
|
||||
uchar *data)
|
||||
{
|
||||
SAFE_HASH_ENTRY *entry;
|
||||
my_bool error= 0;
|
||||
DBUG_ENTER("safe_hash_set");
|
||||
DBUG_PRINT("enter",("key: %.*s data: 0x%lx", length, key, (long) data));
|
||||
|
||||
rw_wrlock(&hash->mutex);
|
||||
entry= (SAFE_HASH_ENTRY*) my_hash_search(&hash->hash, key, length);
|
||||
|
||||
if (data == hash->default_value)
|
||||
{
|
||||
/*
|
||||
The key is to be associated with the default entry. In this case
|
||||
we can just delete the entry (if it existed) from the hash as a
|
||||
search will return the default entry
|
||||
*/
|
||||
if (!entry) /* nothing to do */
|
||||
goto end;
|
||||
/* unlink entry from list */
|
||||
if ((*entry->prev= entry->next))
|
||||
entry->next->prev= entry->prev;
|
||||
my_hash_delete(&hash->hash, (uchar*) entry);
|
||||
goto end;
|
||||
}
|
||||
if (entry)
|
||||
{
|
||||
/* Entry existed; Just change the pointer to point at the new data */
|
||||
entry->data= data;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!(entry= (SAFE_HASH_ENTRY *) my_malloc(sizeof(*entry) + length,
|
||||
MYF(MY_WME))))
|
||||
{
|
||||
error= 1;
|
||||
goto end;
|
||||
}
|
||||
entry->key= (uchar*) (entry +1);
|
||||
memcpy((char*) entry->key, (char*) key, length);
|
||||
entry->length= length;
|
||||
entry->data= data;
|
||||
/* Link entry to list */
|
||||
if ((entry->next= hash->root))
|
||||
entry->next->prev= &entry->next;
|
||||
entry->prev= &hash->root;
|
||||
hash->root= entry;
|
||||
if (my_hash_insert(&hash->hash, (uchar*) entry))
|
||||
{
|
||||
/* This can only happen if hash got out of memory */
|
||||
my_free(entry);
|
||||
error= 1;
|
||||
goto end;
|
||||
}
|
||||
}
|
||||
|
||||
end:
|
||||
rw_unlock(&hash->mutex);
|
||||
DBUG_RETURN(error);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Change all entres with one data value to another data value
|
||||
|
||||
SYONOPSIS
|
||||
safe_hash_change()
|
||||
hash Hash handle
|
||||
old_data Old data
|
||||
new_data Change all 'old_data' to this
|
||||
|
||||
NOTES
|
||||
We use the linked list to traverse all elements in the hash as
|
||||
this allows us to delete elements in the case where 'new_data' is the
|
||||
default value.
|
||||
*/
|
||||
|
||||
static void safe_hash_change(SAFE_HASH *hash, uchar *old_data, uchar *new_data)
|
||||
{
|
||||
SAFE_HASH_ENTRY *entry, *next;
|
||||
DBUG_ENTER("safe_hash_set");
|
||||
|
||||
rw_wrlock(&hash->mutex);
|
||||
|
||||
for (entry= hash->root ; entry ; entry= next)
|
||||
{
|
||||
next= entry->next;
|
||||
if (entry->data == old_data)
|
||||
{
|
||||
if (new_data == hash->default_value)
|
||||
{
|
||||
if ((*entry->prev= entry->next))
|
||||
entry->next->prev= entry->prev;
|
||||
my_hash_delete(&hash->hash, (uchar*) entry);
|
||||
}
|
||||
else
|
||||
entry->data= new_data;
|
||||
}
|
||||
}
|
||||
|
||||
rw_unlock(&hash->mutex);
|
||||
DBUG_VOID_RETURN;
|
||||
}
|
||||
|
||||
|
||||
/*****************************************************************************
|
||||
Functions to handle the key cache objects
|
||||
*****************************************************************************/
|
||||
|
||||
/* Variable to store all key cache objects */
|
||||
static SAFE_HASH key_cache_hash;
|
||||
|
||||
|
||||
my_bool multi_keycache_init(void)
|
||||
{
|
||||
return safe_hash_init(&key_cache_hash, 16, (uchar*) dflt_key_cache);
|
||||
}
|
||||
|
||||
|
||||
void multi_keycache_free(void)
|
||||
{
|
||||
safe_hash_free(&key_cache_hash);
|
||||
}
|
||||
|
||||
/*
|
||||
Get a key cache to be used for a specific table.
|
||||
|
||||
SYNOPSIS
|
||||
multi_key_cache_search()
|
||||
key key to find (usually table path)
|
||||
uint length Length of key.
|
||||
|
||||
NOTES
|
||||
This function is coded in such a way that we will return the
|
||||
default key cache even if one never called multi_keycache_init.
|
||||
This will ensure that it works with old MyISAM clients.
|
||||
|
||||
RETURN
|
||||
key cache to use
|
||||
*/
|
||||
|
||||
KEY_CACHE *multi_key_cache_search(uchar *key, uint length)
|
||||
{
|
||||
if (!key_cache_hash.hash.records)
|
||||
return dflt_key_cache;
|
||||
return (KEY_CACHE*) safe_hash_search(&key_cache_hash, key, length);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Assosiate a key cache with a key
|
||||
|
||||
|
||||
SYONOPSIS
|
||||
multi_key_cache_set()
|
||||
key key (path to table etc..)
|
||||
length Length of key
|
||||
key_cache cache to assococite with the table
|
||||
|
||||
NOTES
|
||||
This can be used both to insert a new entry and change an existing
|
||||
entry
|
||||
*/
|
||||
|
||||
|
||||
my_bool multi_key_cache_set(const uchar *key, uint length,
|
||||
KEY_CACHE *key_cache)
|
||||
{
|
||||
return safe_hash_set(&key_cache_hash, key, length, (uchar*) key_cache);
|
||||
}
|
||||
|
||||
|
||||
void multi_key_cache_change(KEY_CACHE *old_data,
|
||||
KEY_CACHE *new_data)
|
||||
{
|
||||
safe_hash_change(&key_cache_hash, (uchar*) old_data, (uchar*) new_data);
|
||||
}
|
||||
55
deps/mysqllite/mysys/mf_loadpath.c
vendored
Normal file
55
deps/mysqllite/mysys/mf_loadpath.c
vendored
Normal file
@@ -0,0 +1,55 @@
|
||||
/* Copyright (C) 2000 MySQL AB
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
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 */
|
||||
|
||||
#include "mysys_priv.h"
|
||||
#include <m_string.h>
|
||||
|
||||
/* Returns full load-path for a file. to may be = path */
|
||||
/* if path is a hard-path return path */
|
||||
/* if path starts with home-dir return path */
|
||||
/* if path starts with current dir or parent-dir unpack path */
|
||||
/* if there is no path, prepend with own_path_prefix if given */
|
||||
/* else unpack path according to current dir */
|
||||
|
||||
char * my_load_path(char * to, const char *path,
|
||||
const char *own_path_prefix)
|
||||
{
|
||||
char buff[FN_REFLEN];
|
||||
int is_cur;
|
||||
DBUG_ENTER("my_load_path");
|
||||
DBUG_PRINT("enter",("path: %s prefix: %s",path,
|
||||
own_path_prefix ? own_path_prefix : ""));
|
||||
|
||||
if ((path[0] == FN_HOMELIB && path[1] == FN_LIBCHAR) ||
|
||||
test_if_hard_path(path))
|
||||
(void) strnmov(buff, path, FN_REFLEN);
|
||||
else if ((is_cur=(path[0] == FN_CURLIB && path[1] == FN_LIBCHAR)) ||
|
||||
(is_prefix(path,FN_PARENTDIR)) ||
|
||||
! own_path_prefix)
|
||||
{
|
||||
if (is_cur)
|
||||
is_cur=2; /* Remove current dir */
|
||||
if (! my_getwd(buff,(uint) (FN_REFLEN-strlen(path)+is_cur),MYF(0)))
|
||||
(void) strncat(buff, path+is_cur, FN_REFLEN-1);
|
||||
else
|
||||
(void) strnmov(buff, path, FN_REFLEN); /* Return org file name */
|
||||
}
|
||||
else
|
||||
(void) strxnmov(buff, FN_REFLEN, own_path_prefix, path, NullS);
|
||||
strnmov(to, buff, FN_REFLEN);
|
||||
to[FN_REFLEN-1]= '\0';
|
||||
DBUG_PRINT("exit",("to: %s",to));
|
||||
DBUG_RETURN(to);
|
||||
} /* my_load_path */
|
||||
460
deps/mysqllite/mysys/mf_pack.c
vendored
Normal file
460
deps/mysqllite/mysys/mf_pack.c
vendored
Normal file
@@ -0,0 +1,460 @@
|
||||
/* Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved.
|
||||
|
||||
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 */
|
||||
|
||||
#include "mysys_priv.h"
|
||||
#include <m_string.h>
|
||||
#ifdef HAVE_PWD_H
|
||||
#include <pwd.h>
|
||||
#endif
|
||||
|
||||
static char * expand_tilde(char **path);
|
||||
|
||||
/* Pack a dirname ; Changes HOME to ~/ and current dev to ./ */
|
||||
/* from is a dirname (from dirname() ?) ending with FN_LIBCHAR */
|
||||
/* to may be == from */
|
||||
|
||||
void pack_dirname(char * to, const char *from)
|
||||
{
|
||||
int cwd_err;
|
||||
size_t d_length,length,UNINIT_VAR(buff_length);
|
||||
char * start;
|
||||
char buff[FN_REFLEN];
|
||||
DBUG_ENTER("pack_dirname");
|
||||
|
||||
(void) intern_filename(to,from); /* Change to intern name */
|
||||
|
||||
#ifdef FN_DEVCHAR
|
||||
if ((start=strrchr(to,FN_DEVCHAR)) != 0) /* Skip device part */
|
||||
start++;
|
||||
else
|
||||
#endif
|
||||
start=to;
|
||||
|
||||
if (!(cwd_err= my_getwd(buff,FN_REFLEN,MYF(0))))
|
||||
{
|
||||
buff_length= strlen(buff);
|
||||
d_length= (size_t) (start-to);
|
||||
if ((start == to ||
|
||||
(buff_length == d_length && !memcmp(buff,start,d_length))) &&
|
||||
*start != FN_LIBCHAR && *start)
|
||||
{ /* Put current dir before */
|
||||
bchange((uchar*) to, d_length, (uchar*) buff, buff_length, strlen(to)+1);
|
||||
}
|
||||
}
|
||||
|
||||
if ((d_length= cleanup_dirname(to,to)) != 0)
|
||||
{
|
||||
length=0;
|
||||
if (home_dir)
|
||||
{
|
||||
length= strlen(home_dir);
|
||||
if (home_dir[length-1] == FN_LIBCHAR)
|
||||
length--; /* Don't test last '/' */
|
||||
}
|
||||
if (length > 1 && length < d_length)
|
||||
{ /* test if /xx/yy -> ~/yy */
|
||||
if (memcmp(to,home_dir,length) == 0 && to[length] == FN_LIBCHAR)
|
||||
{
|
||||
to[0]=FN_HOMELIB; /* Filename begins with ~ */
|
||||
(void) strmov_overlapp(to+1,to+length);
|
||||
}
|
||||
}
|
||||
if (! cwd_err)
|
||||
{ /* Test if cwd is ~/... */
|
||||
if (length > 1 && length < buff_length)
|
||||
{
|
||||
if (memcmp(buff,home_dir,length) == 0 && buff[length] == FN_LIBCHAR)
|
||||
{
|
||||
buff[0]=FN_HOMELIB;
|
||||
(void) strmov_overlapp(buff+1,buff+length);
|
||||
}
|
||||
}
|
||||
if (is_prefix(to,buff))
|
||||
{
|
||||
length= strlen(buff);
|
||||
if (to[length])
|
||||
(void) strmov_overlapp(to,to+length); /* Remove everything before */
|
||||
else
|
||||
{
|
||||
to[0]= FN_CURLIB; /* Put ./ instead of cwd */
|
||||
to[1]= FN_LIBCHAR;
|
||||
to[2]= '\0';
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
DBUG_PRINT("exit",("to: '%s'",to));
|
||||
DBUG_VOID_RETURN;
|
||||
} /* pack_dirname */
|
||||
|
||||
|
||||
/*
|
||||
remove unwanted chars from dirname
|
||||
|
||||
SYNOPSIS
|
||||
cleanup_dirname()
|
||||
to Store result here
|
||||
from Dirname to fix. May be same as to
|
||||
|
||||
IMPLEMENTATION
|
||||
"/../" removes prev dir
|
||||
"/~/" removes all before ~
|
||||
//" is same as "/", except on Win32 at start of a file
|
||||
"/./" is removed
|
||||
Unpacks home_dir if "~/.." used
|
||||
Unpacks current dir if if "./.." used
|
||||
|
||||
RETURN
|
||||
# length of new name
|
||||
*/
|
||||
|
||||
size_t cleanup_dirname(register char *to, const char *from)
|
||||
{
|
||||
reg5 size_t length;
|
||||
reg2 char * pos;
|
||||
reg3 char * from_ptr;
|
||||
reg4 char * start;
|
||||
char parent[5], /* for "FN_PARENTDIR" */
|
||||
buff[FN_REFLEN+1],*end_parentdir;
|
||||
#ifdef BACKSLASH_MBTAIL
|
||||
CHARSET_INFO *fs= fs_character_set();
|
||||
#endif
|
||||
DBUG_ENTER("cleanup_dirname");
|
||||
DBUG_PRINT("enter",("from: '%s'",from));
|
||||
|
||||
start=buff;
|
||||
from_ptr=(char *) from;
|
||||
#ifdef FN_DEVCHAR
|
||||
if ((pos=strrchr(from_ptr,FN_DEVCHAR)) != 0)
|
||||
{ /* Skip device part */
|
||||
length=(size_t) (pos-from_ptr)+1;
|
||||
start=strnmov(buff,from_ptr,length); from_ptr+=length;
|
||||
}
|
||||
#endif
|
||||
|
||||
parent[0]=FN_LIBCHAR;
|
||||
length=(size_t) (strmov(parent+1,FN_PARENTDIR)-parent);
|
||||
for (pos=start ; (*pos= *from_ptr++) != 0 ; pos++)
|
||||
{
|
||||
#ifdef BACKSLASH_MBTAIL
|
||||
uint l;
|
||||
if (use_mb(fs) && (l= my_ismbchar(fs, from_ptr - 1, from_ptr + 2)))
|
||||
{
|
||||
for (l-- ; l ; *++pos= *from_ptr++, l--);
|
||||
start= pos + 1; /* Don't look inside multi-byte char */
|
||||
continue;
|
||||
}
|
||||
#endif
|
||||
if (*pos == '/')
|
||||
*pos = FN_LIBCHAR;
|
||||
if (*pos == FN_LIBCHAR)
|
||||
{
|
||||
if ((size_t) (pos-start) > length && memcmp(pos-length,parent,length) == 0)
|
||||
{ /* If .../../; skip prev */
|
||||
pos-=length;
|
||||
if (pos != start)
|
||||
{ /* not /../ */
|
||||
pos--;
|
||||
if (*pos == FN_HOMELIB && (pos == start || pos[-1] == FN_LIBCHAR))
|
||||
{
|
||||
if (!home_dir)
|
||||
{
|
||||
pos+=length+1; /* Don't unpack ~/.. */
|
||||
continue;
|
||||
}
|
||||
pos=strmov(buff,home_dir)-1; /* Unpacks ~/.. */
|
||||
if (*pos == FN_LIBCHAR)
|
||||
pos--; /* home ended with '/' */
|
||||
}
|
||||
if (*pos == FN_CURLIB && (pos == start || pos[-1] == FN_LIBCHAR))
|
||||
{
|
||||
if (my_getwd(curr_dir,FN_REFLEN,MYF(0)))
|
||||
{
|
||||
pos+=length+1; /* Don't unpack ./.. */
|
||||
continue;
|
||||
}
|
||||
pos=strmov(buff,curr_dir)-1; /* Unpacks ./.. */
|
||||
if (*pos == FN_LIBCHAR)
|
||||
pos--; /* home ended with '/' */
|
||||
}
|
||||
end_parentdir=pos;
|
||||
while (pos >= start && *pos != FN_LIBCHAR) /* remove prev dir */
|
||||
pos--;
|
||||
if (pos[1] == FN_HOMELIB ||
|
||||
(pos > start && memcmp(pos, parent, length) == 0))
|
||||
{ /* Don't remove ~user/ */
|
||||
pos=strmov(end_parentdir+1,parent);
|
||||
*pos=FN_LIBCHAR;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if ((size_t) (pos-start) == length-1 &&
|
||||
!memcmp(start,parent+1,length-1))
|
||||
start=pos; /* Starts with "../" */
|
||||
else if (pos-start > 0 && pos[-1] == FN_LIBCHAR)
|
||||
{
|
||||
#ifdef FN_NETWORK_DRIVES
|
||||
if (pos-start != 1)
|
||||
#endif
|
||||
pos--; /* Remove dupplicate '/' */
|
||||
}
|
||||
else if (pos-start > 1 && pos[-1] == FN_CURLIB && pos[-2] == FN_LIBCHAR)
|
||||
pos-=2; /* Skip /./ */
|
||||
else if (pos > buff+1 && pos[-1] == FN_HOMELIB && pos[-2] == FN_LIBCHAR)
|
||||
{ /* Found ..../~/ */
|
||||
buff[0]=FN_HOMELIB;
|
||||
buff[1]=FN_LIBCHAR;
|
||||
start=buff; pos=buff+1;
|
||||
}
|
||||
}
|
||||
}
|
||||
(void) strmov(to,buff);
|
||||
DBUG_PRINT("exit",("to: '%s'",to));
|
||||
DBUG_RETURN((size_t) (pos-buff));
|
||||
} /* cleanup_dirname */
|
||||
|
||||
|
||||
/*
|
||||
On system where you don't have symbolic links, the following
|
||||
code will allow you to create a file:
|
||||
directory-name.sym that should contain the real path
|
||||
to the directory. This will be used if the directory name
|
||||
doesn't exists
|
||||
*/
|
||||
|
||||
|
||||
my_bool my_use_symdir=0; /* Set this if you want to use symdirs */
|
||||
|
||||
#ifdef USE_SYMDIR
|
||||
void symdirget(char *dir)
|
||||
{
|
||||
char buff[FN_REFLEN+1];
|
||||
char *pos=strend(dir);
|
||||
if (dir[0] && pos[-1] != FN_DEVCHAR && my_access(dir, F_OK))
|
||||
{
|
||||
File file;
|
||||
size_t length;
|
||||
char temp= *(--pos); /* May be "/" or "\" */
|
||||
strmov(pos,".sym");
|
||||
file= my_open(dir, O_RDONLY, MYF(0));
|
||||
*pos++=temp; *pos=0; /* Restore old filename */
|
||||
if (file >= 0)
|
||||
{
|
||||
if ((length= my_read(file, buff, sizeof(buff) - 1, MYF(0))) > 0)
|
||||
{
|
||||
for (pos= buff + length ;
|
||||
pos > buff && (iscntrl(pos[-1]) || isspace(pos[-1])) ;
|
||||
pos --);
|
||||
|
||||
/* Ensure that the symlink ends with the directory symbol */
|
||||
if (pos == buff || pos[-1] != FN_LIBCHAR)
|
||||
*pos++=FN_LIBCHAR;
|
||||
|
||||
strmake(dir,buff, (size_t) (pos-buff));
|
||||
}
|
||||
my_close(file, MYF(0));
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif /* USE_SYMDIR */
|
||||
|
||||
|
||||
/**
|
||||
Convert a directory name to a format which can be compared as strings
|
||||
|
||||
@param to result buffer, FN_REFLEN chars in length; may be == from
|
||||
@param from 'packed' directory name, in whatever format
|
||||
@returns size of the normalized name
|
||||
|
||||
@details
|
||||
- Ensures that last char is FN_LIBCHAR, unless it is FN_DEVCHAR
|
||||
- Uses cleanup_dirname
|
||||
|
||||
It does *not* expand ~/ (although, see cleanup_dirname). Nor does it do
|
||||
any case folding. All case-insensitive normalization should be done by
|
||||
the caller.
|
||||
*/
|
||||
|
||||
size_t normalize_dirname(char *to, const char *from)
|
||||
{
|
||||
size_t length;
|
||||
char buff[FN_REFLEN];
|
||||
DBUG_ENTER("normalize_dirname");
|
||||
|
||||
/*
|
||||
Despite the name, this actually converts the name to the system's
|
||||
format (TODO: name this properly).
|
||||
*/
|
||||
(void) intern_filename(buff, from);
|
||||
length= strlen(buff); /* Fix that '/' is last */
|
||||
if (length &&
|
||||
#ifdef FN_DEVCHAR
|
||||
buff[length - 1] != FN_DEVCHAR &&
|
||||
#endif
|
||||
buff[length - 1] != FN_LIBCHAR && buff[length - 1] != '/')
|
||||
{
|
||||
/* we need reserve 2 bytes for the trailing slash and the zero */
|
||||
if (length >= sizeof (buff) - 1)
|
||||
length= sizeof (buff) - 2;
|
||||
buff[length]= FN_LIBCHAR;
|
||||
buff[length + 1]= '\0';
|
||||
}
|
||||
|
||||
length=cleanup_dirname(to, buff);
|
||||
|
||||
DBUG_RETURN(length);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Fixes a directory name so that can be used by open()
|
||||
|
||||
@param to Result buffer, FN_REFLEN characters. May be == from
|
||||
@param from 'Packed' directory name (may contain ~)
|
||||
|
||||
@details
|
||||
- Uses normalize_dirname()
|
||||
- Expands ~/... to home_dir/...
|
||||
- Resolves MySQL's fake "foo.sym" symbolic directory names (if USE_SYMDIR)
|
||||
- Changes a UNIX filename to system filename (replaces / with \ on windows)
|
||||
|
||||
@returns
|
||||
Length of new directory name (= length of to)
|
||||
*/
|
||||
|
||||
size_t unpack_dirname(char * to, const char *from)
|
||||
{
|
||||
size_t length, h_length;
|
||||
char buff[FN_REFLEN+1+4],*suffix,*tilde_expansion;
|
||||
DBUG_ENTER("unpack_dirname");
|
||||
|
||||
length= normalize_dirname(buff, from);
|
||||
|
||||
if (buff[0] == FN_HOMELIB)
|
||||
{
|
||||
suffix=buff+1; tilde_expansion=expand_tilde(&suffix);
|
||||
if (tilde_expansion)
|
||||
{
|
||||
length-= (size_t) (suffix-buff)-1;
|
||||
if (length+(h_length= strlen(tilde_expansion)) <= FN_REFLEN)
|
||||
{
|
||||
if ((h_length > 0) && (tilde_expansion[h_length-1] == FN_LIBCHAR))
|
||||
h_length--;
|
||||
if (buff+h_length < suffix)
|
||||
bmove(buff+h_length,suffix,length);
|
||||
else
|
||||
bmove_upp((uchar*) buff+h_length+length, (uchar*) suffix+length, length);
|
||||
bmove(buff,tilde_expansion,h_length);
|
||||
}
|
||||
}
|
||||
}
|
||||
#ifdef USE_SYMDIR
|
||||
if (my_use_symdir)
|
||||
symdirget(buff);
|
||||
#endif
|
||||
DBUG_RETURN(system_filename(to,buff)); /* Fix for open */
|
||||
} /* unpack_dirname */
|
||||
|
||||
|
||||
/* Expand tilde to home or user-directory */
|
||||
/* Path is reset to point at FN_LIBCHAR after ~xxx */
|
||||
|
||||
static char * expand_tilde(char **path)
|
||||
{
|
||||
if (path[0][0] == FN_LIBCHAR)
|
||||
return home_dir; /* ~/ expanded to home */
|
||||
#ifdef HAVE_GETPWNAM
|
||||
{
|
||||
char *str,save;
|
||||
struct passwd *user_entry;
|
||||
|
||||
if (!(str=strchr(*path,FN_LIBCHAR)))
|
||||
str=strend(*path);
|
||||
save= *str; *str= '\0';
|
||||
user_entry=getpwnam(*path);
|
||||
*str=save;
|
||||
endpwent();
|
||||
if (user_entry)
|
||||
{
|
||||
*path=str;
|
||||
return user_entry->pw_dir;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
return (char *) 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Fix filename so it can be used by open, create
|
||||
|
||||
SYNOPSIS
|
||||
unpack_filename()
|
||||
to Store result here. Must be at least of size FN_REFLEN.
|
||||
from Filename in unix format (with ~)
|
||||
|
||||
RETURN
|
||||
# length of to
|
||||
|
||||
NOTES
|
||||
to may be == from
|
||||
~ will only be expanded if total length < FN_REFLEN
|
||||
*/
|
||||
|
||||
|
||||
size_t unpack_filename(char * to, const char *from)
|
||||
{
|
||||
size_t length, n_length, buff_length;
|
||||
char buff[FN_REFLEN];
|
||||
DBUG_ENTER("unpack_filename");
|
||||
|
||||
length=dirname_part(buff, from, &buff_length);/* copy & convert dirname */
|
||||
n_length=unpack_dirname(buff,buff);
|
||||
if (n_length+strlen(from+length) < FN_REFLEN)
|
||||
{
|
||||
(void) strmov(buff+n_length,from+length);
|
||||
length= system_filename(to,buff); /* Fix to usably filename */
|
||||
}
|
||||
else
|
||||
length= system_filename(to,from); /* Fix to usably filename */
|
||||
DBUG_RETURN(length);
|
||||
} /* unpack_filename */
|
||||
|
||||
|
||||
/* Convert filename (unix standard) to system standard */
|
||||
/* Used before system command's like open(), create() .. */
|
||||
/* Returns used length of to; total length should be FN_REFLEN */
|
||||
|
||||
size_t system_filename(char *to, const char *from)
|
||||
{
|
||||
return (size_t) (strmake(to,from,FN_REFLEN-1)-to);
|
||||
}
|
||||
|
||||
/* Fix a filename to intern (UNIX format) */
|
||||
|
||||
char *intern_filename(char *to, const char *from)
|
||||
{
|
||||
size_t length, to_length;
|
||||
char buff[FN_REFLEN];
|
||||
if (from == to)
|
||||
{ /* Dirname may destroy from */
|
||||
strmov(buff,from);
|
||||
from=buff;
|
||||
}
|
||||
length= dirname_part(to, from, &to_length); /* Copy dirname & fix chars */
|
||||
(void) strmov(to + to_length,from+length);
|
||||
return (to);
|
||||
} /* intern_filename */
|
||||
120
deps/mysqllite/mysys/mf_path.c
vendored
Normal file
120
deps/mysqllite/mysys/mf_path.c
vendored
Normal file
@@ -0,0 +1,120 @@
|
||||
/* Copyright (C) 2000 MySQL AB
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
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 */
|
||||
|
||||
#include "mysys_priv.h"
|
||||
#include <m_string.h>
|
||||
|
||||
static char *find_file_in_path(char *to,const char *name);
|
||||
|
||||
/* Finds where program can find it's files.
|
||||
pre_pathname is found by first locking at progname (argv[0]).
|
||||
if progname contains path the path is returned.
|
||||
else if progname is found in path, return it
|
||||
else if progname is given and POSIX environment variable "_" is set
|
||||
then path is taken from "_".
|
||||
If filename doesn't contain a path append MY_BASEDIR_VERSION or
|
||||
MY_BASEDIR if defined, else append "/my/running".
|
||||
own_path_name_part is concatinated to result.
|
||||
my_path puts result in to and returns to */
|
||||
|
||||
char * my_path(char * to, const char *progname,
|
||||
const char *own_pathname_part)
|
||||
{
|
||||
char *start, *end, *prog;
|
||||
size_t to_length;
|
||||
DBUG_ENTER("my_path");
|
||||
|
||||
start=to; /* Return this */
|
||||
if (progname && (dirname_part(to, progname, &to_length) ||
|
||||
find_file_in_path(to,progname) ||
|
||||
((prog=getenv("_")) != 0 &&
|
||||
dirname_part(to, prog, &to_length))))
|
||||
{
|
||||
(void) intern_filename(to,to);
|
||||
if (!test_if_hard_path(to))
|
||||
{
|
||||
if (!my_getwd(curr_dir,FN_REFLEN,MYF(0)))
|
||||
bchange((uchar*) to, 0, (uchar*) curr_dir, strlen(curr_dir), strlen(to)+1);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if ((end = getenv("MY_BASEDIR_VERSION")) == 0 &&
|
||||
(end = getenv("MY_BASEDIR")) == 0)
|
||||
{
|
||||
#ifdef DEFAULT_BASEDIR
|
||||
end= (char*) DEFAULT_BASEDIR;
|
||||
#else
|
||||
end= (char*) "/my/";
|
||||
#endif
|
||||
}
|
||||
(void) intern_filename(to,end);
|
||||
to=strend(to);
|
||||
if (to != start && to[-1] != FN_LIBCHAR)
|
||||
*to++ = FN_LIBCHAR;
|
||||
(void) strmov(to,own_pathname_part);
|
||||
}
|
||||
DBUG_PRINT("exit",("to: '%s'",start));
|
||||
DBUG_RETURN(start);
|
||||
} /* my_path */
|
||||
|
||||
|
||||
/* test if file without filename is found in path */
|
||||
/* Returns to if found and to has dirpart if found, else NullS */
|
||||
|
||||
#if defined(__WIN__)
|
||||
#define F_OK 0
|
||||
#define PATH_SEP ';'
|
||||
#define PROGRAM_EXTENSION ".exe"
|
||||
#else
|
||||
#define PATH_SEP ':'
|
||||
#endif
|
||||
|
||||
static char *find_file_in_path(char *to, const char *name)
|
||||
{
|
||||
char *path,*pos,dir[2];
|
||||
const char *ext="";
|
||||
|
||||
if (!(path=getenv("PATH")))
|
||||
return NullS;
|
||||
dir[0]=FN_LIBCHAR; dir[1]=0;
|
||||
#ifdef PROGRAM_EXTENSION
|
||||
if (!fn_ext(name)[0])
|
||||
ext=PROGRAM_EXTENSION;
|
||||
#endif
|
||||
|
||||
for (pos=path ; (pos=strchr(pos,PATH_SEP)) ; path= ++pos)
|
||||
{
|
||||
if (path != pos)
|
||||
{
|
||||
strxmov(strnmov(to,path,(uint) (pos-path)),dir,name,ext,NullS);
|
||||
if (!access(to,F_OK))
|
||||
{
|
||||
to[(uint) (pos-path)+1]=0; /* Return path only */
|
||||
return to;
|
||||
}
|
||||
}
|
||||
}
|
||||
#ifdef __WIN__
|
||||
to[0]=FN_CURLIB;
|
||||
strxmov(to+1,dir,name,ext,NullS);
|
||||
if (!access(to,F_OK)) /* Test in current dir */
|
||||
{
|
||||
to[2]=0; /* Leave ".\" */
|
||||
return to;
|
||||
}
|
||||
#endif
|
||||
return NullS; /* File not found */
|
||||
}
|
||||
216
deps/mysqllite/mysys/mf_qsort.c
vendored
Normal file
216
deps/mysqllite/mysys/mf_qsort.c
vendored
Normal file
@@ -0,0 +1,216 @@
|
||||
/* Copyright (C) 2000 MySQL AB
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
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 */
|
||||
|
||||
/*
|
||||
qsort implementation optimized for comparison of pointers
|
||||
Inspired by the qsort implementations by Douglas C. Schmidt,
|
||||
and Bentley & McIlroy's "Engineering a Sort Function".
|
||||
*/
|
||||
|
||||
|
||||
#include "mysys_priv.h"
|
||||
#ifndef SCO
|
||||
#include <m_string.h>
|
||||
#endif
|
||||
|
||||
/* We need to use qsort with 2 different compare functions */
|
||||
#ifdef QSORT_EXTRA_CMP_ARGUMENT
|
||||
#define CMP(A,B) ((*cmp)(cmp_argument,(A),(B)))
|
||||
#else
|
||||
#define CMP(A,B) ((*cmp)((A),(B)))
|
||||
#endif
|
||||
|
||||
#define SWAP(A, B, size,swap_ptrs) \
|
||||
do { \
|
||||
if (swap_ptrs) \
|
||||
{ \
|
||||
reg1 char **a = (char**) (A), **b = (char**) (B); \
|
||||
char *tmp = *a; *a++ = *b; *b++ = tmp; \
|
||||
} \
|
||||
else \
|
||||
{ \
|
||||
reg1 char *a = (A), *b = (B); \
|
||||
reg3 char *end= a+size; \
|
||||
do \
|
||||
{ \
|
||||
char tmp = *a; *a++ = *b; *b++ = tmp; \
|
||||
} while (a < end); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
/* Put the median in the middle argument */
|
||||
#define MEDIAN(low, mid, high) \
|
||||
{ \
|
||||
if (CMP(high,low) < 0) \
|
||||
SWAP(high, low, size, ptr_cmp); \
|
||||
if (CMP(mid, low) < 0) \
|
||||
SWAP(mid, low, size, ptr_cmp); \
|
||||
else if (CMP(high, mid) < 0) \
|
||||
SWAP(mid, high, size, ptr_cmp); \
|
||||
}
|
||||
|
||||
/* The following node is used to store ranges to avoid recursive calls */
|
||||
|
||||
typedef struct st_stack
|
||||
{
|
||||
char *low,*high;
|
||||
} stack_node;
|
||||
|
||||
#define PUSH(LOW,HIGH) {stack_ptr->low = LOW; stack_ptr++->high = HIGH;}
|
||||
#define POP(LOW,HIGH) {LOW = (--stack_ptr)->low; HIGH = stack_ptr->high;}
|
||||
|
||||
/* The following stack size is enough for ulong ~0 elements */
|
||||
#define STACK_SIZE (8 * sizeof(unsigned long int))
|
||||
#define THRESHOLD_FOR_INSERT_SORT 10
|
||||
#if defined(QSORT_TYPE_IS_VOID)
|
||||
#define SORT_RETURN return
|
||||
#else
|
||||
#define SORT_RETURN return 0
|
||||
#endif
|
||||
|
||||
/****************************************************************************
|
||||
** 'standard' quicksort with the following extensions:
|
||||
**
|
||||
** Can be compiled with the qsort2_cmp compare function
|
||||
** Store ranges on stack to avoid recursion
|
||||
** Use insert sort on small ranges
|
||||
** Optimize for sorting of pointers (used often by MySQL)
|
||||
** Use median comparison to find partition element
|
||||
*****************************************************************************/
|
||||
|
||||
#ifdef QSORT_EXTRA_CMP_ARGUMENT
|
||||
qsort_t my_qsort2(void *base_ptr, size_t count, size_t size, qsort2_cmp cmp,
|
||||
void *cmp_argument)
|
||||
#else
|
||||
qsort_t my_qsort(void *base_ptr, size_t count, size_t size, qsort_cmp cmp)
|
||||
#endif
|
||||
{
|
||||
char *low, *high, *pivot;
|
||||
stack_node stack[STACK_SIZE], *stack_ptr;
|
||||
my_bool ptr_cmp;
|
||||
/* Handle the simple case first */
|
||||
/* This will also make the rest of the code simpler */
|
||||
if (count <= 1)
|
||||
SORT_RETURN;
|
||||
|
||||
low = (char*) base_ptr;
|
||||
high = low+ size * (count - 1);
|
||||
stack_ptr = stack + 1;
|
||||
#ifdef HAVE_purify
|
||||
/* The first element in the stack will be accessed for the last POP */
|
||||
stack[0].low=stack[0].high=0;
|
||||
#endif
|
||||
pivot = (char *) my_alloca((int) size);
|
||||
ptr_cmp= size == sizeof(char*) && !((low - (char*) 0)& (sizeof(char*)-1));
|
||||
|
||||
/* The following loop sorts elements between high and low */
|
||||
do
|
||||
{
|
||||
char *low_ptr, *high_ptr, *mid;
|
||||
|
||||
count=((size_t) (high - low) / size)+1;
|
||||
/* If count is small, then an insert sort is faster than qsort */
|
||||
if (count < THRESHOLD_FOR_INSERT_SORT)
|
||||
{
|
||||
for (low_ptr = low + size; low_ptr <= high; low_ptr += size)
|
||||
{
|
||||
char *ptr;
|
||||
for (ptr = low_ptr; ptr > low && CMP(ptr - size, ptr) > 0;
|
||||
ptr -= size)
|
||||
SWAP(ptr, ptr - size, size, ptr_cmp);
|
||||
}
|
||||
POP(low, high);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Try to find a good middle element */
|
||||
mid= low + size * (count >> 1);
|
||||
if (count > 40) /* Must be bigger than 24 */
|
||||
{
|
||||
size_t step = size* (count / 8);
|
||||
MEDIAN(low, low + step, low+step*2);
|
||||
MEDIAN(mid - step, mid, mid+step);
|
||||
MEDIAN(high - 2 * step, high-step, high);
|
||||
/* Put best median in 'mid' */
|
||||
MEDIAN(low+step, mid, high-step);
|
||||
low_ptr = low;
|
||||
high_ptr = high;
|
||||
}
|
||||
else
|
||||
{
|
||||
MEDIAN(low, mid, high);
|
||||
/* The low and high argument are already in sorted against 'pivot' */
|
||||
low_ptr = low + size;
|
||||
high_ptr = high - size;
|
||||
}
|
||||
memcpy(pivot, mid, size);
|
||||
|
||||
do
|
||||
{
|
||||
while (CMP(low_ptr, pivot) < 0)
|
||||
low_ptr += size;
|
||||
while (CMP(pivot, high_ptr) < 0)
|
||||
high_ptr -= size;
|
||||
|
||||
if (low_ptr < high_ptr)
|
||||
{
|
||||
SWAP(low_ptr, high_ptr, size, ptr_cmp);
|
||||
low_ptr += size;
|
||||
high_ptr -= size;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (low_ptr == high_ptr)
|
||||
{
|
||||
low_ptr += size;
|
||||
high_ptr -= size;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
while (low_ptr <= high_ptr);
|
||||
|
||||
/*
|
||||
Prepare for next iteration.
|
||||
Skip partitions of size 1 as these doesn't have to be sorted
|
||||
Push the larger partition and sort the smaller one first.
|
||||
This ensures that the stack is keept small.
|
||||
*/
|
||||
|
||||
if ((int) (high_ptr - low) <= 0)
|
||||
{
|
||||
if ((int) (high - low_ptr) <= 0)
|
||||
{
|
||||
POP(low, high); /* Nothing more to sort */
|
||||
}
|
||||
else
|
||||
low = low_ptr; /* Ignore small left part. */
|
||||
}
|
||||
else if ((int) (high - low_ptr) <= 0)
|
||||
high = high_ptr; /* Ignore small right part. */
|
||||
else if ((high_ptr - low) > (high - low_ptr))
|
||||
{
|
||||
PUSH(low, high_ptr); /* Push larger left part */
|
||||
low = low_ptr;
|
||||
}
|
||||
else
|
||||
{
|
||||
PUSH(low_ptr, high); /* Push larger right part */
|
||||
high = high_ptr;
|
||||
}
|
||||
} while (stack_ptr > stack);
|
||||
my_afree(pivot);
|
||||
SORT_RETURN;
|
||||
}
|
||||
19
deps/mysqllite/mysys/mf_qsort2.c
vendored
Normal file
19
deps/mysqllite/mysys/mf_qsort2.c
vendored
Normal file
@@ -0,0 +1,19 @@
|
||||
/* Copyright (C) 2000 MySQL AB
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
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 */
|
||||
|
||||
/* qsort that sends one extra argument to the compare subrutine */
|
||||
|
||||
#define QSORT_EXTRA_CMP_ARGUMENT
|
||||
#include "mf_qsort.c"
|
||||
54
deps/mysqllite/mysys/mf_radix.c
vendored
Normal file
54
deps/mysqllite/mysys/mf_radix.c
vendored
Normal file
@@ -0,0 +1,54 @@
|
||||
/* Copyright (C) 2000 MySQL AB
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
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 */
|
||||
|
||||
/*
|
||||
Radixsort for pointers to fixed length strings.
|
||||
A very quick sort for not to long (< 20 char) strings.
|
||||
Neads a extra buffers of number_of_elements pointers but is
|
||||
2-3 times faster than quicksort
|
||||
*/
|
||||
|
||||
#include "mysys_priv.h"
|
||||
#include <m_string.h>
|
||||
|
||||
/* Radixsort */
|
||||
|
||||
void radixsort_for_str_ptr(uchar **base, uint number_of_elements, size_t size_of_element, uchar **buffer)
|
||||
{
|
||||
uchar **end,**ptr,**buffer_ptr;
|
||||
uint32 *count_ptr,*count_end,count[256];
|
||||
int pass;
|
||||
|
||||
end=base+number_of_elements; count_end=count+256;
|
||||
for (pass=(int) size_of_element-1 ; pass >= 0 ; pass--)
|
||||
{
|
||||
bzero((uchar*) count,sizeof(uint32)*256);
|
||||
for (ptr= base ; ptr < end ; ptr++)
|
||||
count[ptr[0][pass]]++;
|
||||
if (count[0] == number_of_elements)
|
||||
goto next;
|
||||
for (count_ptr=count+1 ; count_ptr < count_end ; count_ptr++)
|
||||
{
|
||||
if (*count_ptr == number_of_elements)
|
||||
goto next;
|
||||
(*count_ptr)+= *(count_ptr-1);
|
||||
}
|
||||
for (ptr= end ; ptr-- != base ;)
|
||||
buffer[--count[ptr[0][pass]]]= *ptr;
|
||||
for (ptr=base, buffer_ptr=buffer ; ptr < end ;)
|
||||
(*ptr++) = *buffer_ptr++;
|
||||
next:;
|
||||
}
|
||||
}
|
||||
40
deps/mysqllite/mysys/mf_same.c
vendored
Normal file
40
deps/mysqllite/mysys/mf_same.c
vendored
Normal file
@@ -0,0 +1,40 @@
|
||||
/* Copyright (C) 2000 MySQL AB
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
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 */
|
||||
|
||||
/* Kopierar biblioteksstrukturen och extensionen fr}n ett filnamn */
|
||||
|
||||
#include "mysys_priv.h"
|
||||
#include <m_string.h>
|
||||
|
||||
/*
|
||||
Copy directory and/or extension between filenames.
|
||||
(For the meaning of 'flag', check mf_format.c)
|
||||
'to' may be equal to 'name'.
|
||||
Returns 'to'.
|
||||
*/
|
||||
|
||||
char * fn_same(char *to, const char *name, int flag)
|
||||
{
|
||||
char dev[FN_REFLEN];
|
||||
const char *ext;
|
||||
size_t dev_length;
|
||||
DBUG_ENTER("fn_same");
|
||||
DBUG_PRINT("enter",("to: %s name: %s flag: %d",to,name,flag));
|
||||
|
||||
if ((ext=strrchr(name+dirname_part(dev, name, &dev_length),FN_EXTCHAR)) == 0)
|
||||
ext="";
|
||||
|
||||
DBUG_RETURN(fn_format(to,to,dev,ext,flag));
|
||||
} /* fn_same */
|
||||
41
deps/mysqllite/mysys/mf_sort.c
vendored
Normal file
41
deps/mysqllite/mysys/mf_sort.c
vendored
Normal file
@@ -0,0 +1,41 @@
|
||||
/* Copyright (C) 2000 MySQL AB
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
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 */
|
||||
|
||||
/* Sort of string pointers in string-order with radix or qsort */
|
||||
|
||||
#include "mysys_priv.h"
|
||||
#include <m_string.h>
|
||||
|
||||
void my_string_ptr_sort(uchar *base, uint items, size_t size)
|
||||
{
|
||||
#if INT_MAX > 65536L
|
||||
uchar **ptr=0;
|
||||
|
||||
if (size <= 20 && items >= 1000 && items < 100000 &&
|
||||
(ptr= (uchar**) my_malloc(items*sizeof(char*),MYF(0))))
|
||||
{
|
||||
radixsort_for_str_ptr((uchar**) base,items,size,ptr);
|
||||
my_free(ptr);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
if (size && items)
|
||||
{
|
||||
my_qsort2(base,items, sizeof(uchar*), get_ptr_compare(size),
|
||||
(void*) &size);
|
||||
}
|
||||
}
|
||||
}
|
||||
105
deps/mysqllite/mysys/mf_soundex.c
vendored
Normal file
105
deps/mysqllite/mysys/mf_soundex.c
vendored
Normal file
@@ -0,0 +1,105 @@
|
||||
/* Copyright (C) 2000 MySQL AB
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
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 */
|
||||
|
||||
/****************************************************************
|
||||
* SOUNDEX ALGORITHM in C *
|
||||
* *
|
||||
* The basic Algorithm source is taken from EDN Nov. *
|
||||
* 14, 1985 pg. 36. *
|
||||
* *
|
||||
* As a test Those in Illinois will find that the *
|
||||
* first group of numbers in their drivers license *
|
||||
* number is the soundex number for their last name. *
|
||||
* *
|
||||
* RHW PC-IBBS ID. #1230 *
|
||||
* *
|
||||
* As an extension if remove_garbage is set then all non- *
|
||||
* alpha characters are skipped *
|
||||
* *
|
||||
* Note, that this implementation corresponds to the *
|
||||
* original version of the algorithm, not to the more *
|
||||
* popular "enhanced" version, described by Knuth. *
|
||||
****************************************************************/
|
||||
|
||||
#include "mysys_priv.h"
|
||||
#include <m_ctype.h>
|
||||
#include "my_static.h"
|
||||
|
||||
static char get_scode(CHARSET_INFO * cs, char **ptr,pbool remove_garbage);
|
||||
|
||||
/* outputed string is 4 byte long */
|
||||
/* out_pntr can be == in_pntr */
|
||||
|
||||
void soundex(CHARSET_INFO * cs,register char * out_pntr, char * in_pntr,
|
||||
pbool remove_garbage)
|
||||
{
|
||||
char ch,last_ch;
|
||||
reg3 char * end;
|
||||
register uchar *map=cs->to_upper;
|
||||
|
||||
if (remove_garbage)
|
||||
{
|
||||
while (*in_pntr && !my_isalpha(cs,*in_pntr)) /* Skip pre-space */
|
||||
in_pntr++;
|
||||
}
|
||||
*out_pntr++ = map[(uchar)*in_pntr]; /* Copy first letter */
|
||||
last_ch = get_scode(cs,&in_pntr,0); /* code of the first letter */
|
||||
/* for the first 'double-letter */
|
||||
/* check. */
|
||||
end=out_pntr+3; /* Loop on input letters until */
|
||||
/* end of input (null) or output */
|
||||
/* letter code count = 3 */
|
||||
|
||||
in_pntr++;
|
||||
while (out_pntr < end && (ch = get_scode(cs,&in_pntr,remove_garbage)) != 0)
|
||||
{
|
||||
in_pntr++;
|
||||
if ((ch != '0') && (ch != last_ch)) /* if not skipped or double */
|
||||
{
|
||||
*out_pntr++ = ch; /* letter, copy to output */
|
||||
} /* for next double-letter check */
|
||||
last_ch = ch; /* save code of last input letter */
|
||||
}
|
||||
while (out_pntr < end)
|
||||
*out_pntr++ = '0';
|
||||
*out_pntr=0; /* end string */
|
||||
return;
|
||||
} /* soundex */
|
||||
|
||||
|
||||
/*
|
||||
If alpha, map input letter to soundex code.
|
||||
If not alpha and remove_garbage is set then skip to next char
|
||||
else return 0
|
||||
*/
|
||||
|
||||
static char get_scode(CHARSET_INFO * cs,char **ptr, pbool remove_garbage)
|
||||
{
|
||||
uchar ch;
|
||||
|
||||
if (remove_garbage)
|
||||
{
|
||||
while (**ptr && !my_isalpha(cs,**ptr))
|
||||
(*ptr)++;
|
||||
}
|
||||
ch=my_toupper(cs,**ptr);
|
||||
if (ch < 'A' || ch > 'Z')
|
||||
{
|
||||
if (my_isalpha(cs,ch)) /* If extended alfa (country spec) */
|
||||
return '0'; /* threat as vokal */
|
||||
return 0; /* Can't map */
|
||||
}
|
||||
return(soundex_map[ch-'A']);
|
||||
} /* get_scode */
|
||||
95
deps/mysqllite/mysys/mf_tempdir.c
vendored
Normal file
95
deps/mysqllite/mysys/mf_tempdir.c
vendored
Normal file
@@ -0,0 +1,95 @@
|
||||
/* Copyright (C) 2000 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 */
|
||||
|
||||
#include "mysys_priv.h"
|
||||
#include <m_string.h>
|
||||
|
||||
#if defined(__WIN__)
|
||||
#define DELIM ';'
|
||||
#else
|
||||
#define DELIM ':'
|
||||
#endif
|
||||
|
||||
my_bool init_tmpdir(MY_TMPDIR *tmpdir, const char *pathlist)
|
||||
{
|
||||
char *end, *copy;
|
||||
char buff[FN_REFLEN];
|
||||
DBUG_ENTER("init_tmpdir");
|
||||
DBUG_PRINT("enter", ("pathlist: %s", pathlist ? pathlist : "NULL"));
|
||||
|
||||
mysql_mutex_init(key_TMPDIR_mutex, &tmpdir->mutex, MY_MUTEX_INIT_FAST);
|
||||
if (my_init_dynamic_array(&tmpdir->full_list, sizeof(char*), 1, 5))
|
||||
goto err;
|
||||
if (!pathlist || !pathlist[0])
|
||||
{
|
||||
/* Get default temporary directory */
|
||||
pathlist=getenv("TMPDIR"); /* Use this if possible */
|
||||
#if defined(__WIN__)
|
||||
if (!pathlist)
|
||||
pathlist=getenv("TEMP");
|
||||
if (!pathlist)
|
||||
pathlist=getenv("TMP");
|
||||
#endif
|
||||
if (!pathlist || !pathlist[0])
|
||||
pathlist=(char*) P_tmpdir;
|
||||
}
|
||||
do
|
||||
{
|
||||
size_t length;
|
||||
end=strcend(pathlist, DELIM);
|
||||
strmake(buff, pathlist, (uint) (end-pathlist));
|
||||
length= cleanup_dirname(buff, buff);
|
||||
if (!(copy= my_strndup(buff, length, MYF(MY_WME))) ||
|
||||
insert_dynamic(&tmpdir->full_list, (uchar*) ©))
|
||||
DBUG_RETURN(TRUE);
|
||||
pathlist=end+1;
|
||||
}
|
||||
while (*end);
|
||||
freeze_size(&tmpdir->full_list);
|
||||
tmpdir->list=(char **)tmpdir->full_list.buffer;
|
||||
tmpdir->max=tmpdir->full_list.elements-1;
|
||||
tmpdir->cur=0;
|
||||
DBUG_RETURN(FALSE);
|
||||
|
||||
err:
|
||||
delete_dynamic(&tmpdir->full_list); /* Safe to free */
|
||||
mysql_mutex_destroy(&tmpdir->mutex);
|
||||
DBUG_RETURN(TRUE);
|
||||
}
|
||||
|
||||
|
||||
char *my_tmpdir(MY_TMPDIR *tmpdir)
|
||||
{
|
||||
char *dir;
|
||||
if (!tmpdir->max)
|
||||
return tmpdir->list[0];
|
||||
mysql_mutex_lock(&tmpdir->mutex);
|
||||
dir=tmpdir->list[tmpdir->cur];
|
||||
tmpdir->cur= (tmpdir->cur == tmpdir->max) ? 0 : tmpdir->cur+1;
|
||||
mysql_mutex_unlock(&tmpdir->mutex);
|
||||
return dir;
|
||||
}
|
||||
|
||||
void free_tmpdir(MY_TMPDIR *tmpdir)
|
||||
{
|
||||
uint i;
|
||||
if (!tmpdir->full_list.elements)
|
||||
return;
|
||||
for (i=0; i<=tmpdir->max; i++)
|
||||
my_free(tmpdir->list[i]);
|
||||
delete_dynamic(&tmpdir->full_list);
|
||||
mysql_mutex_destroy(&tmpdir->mutex);
|
||||
}
|
||||
|
||||
177
deps/mysqllite/mysys/mf_tempfile.c
vendored
Normal file
177
deps/mysqllite/mysys/mf_tempfile.c
vendored
Normal file
@@ -0,0 +1,177 @@
|
||||
/* Copyright (C) 2000 MySQL AB
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
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 */
|
||||
|
||||
#include "mysys_priv.h"
|
||||
#include <m_string.h>
|
||||
#include "my_static.h"
|
||||
#include "mysys_err.h"
|
||||
#include <errno.h>
|
||||
#ifdef HAVE_PATHS_H
|
||||
#include <paths.h>
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
/*
|
||||
@brief
|
||||
Create a temporary file with unique name in a given directory
|
||||
|
||||
@details
|
||||
create_temp_file
|
||||
to pointer to buffer where temporary filename will be stored
|
||||
dir directory where to create the file
|
||||
prefix prefix the filename with this
|
||||
mode Flags to use for my_create/my_open
|
||||
MyFlags Magic flags
|
||||
|
||||
@return
|
||||
File descriptor of opened file if success
|
||||
-1 and sets errno if fails.
|
||||
|
||||
@note
|
||||
The behaviour of this function differs a lot between
|
||||
implementation, it's main use is to generate a file with
|
||||
a name that does not already exist.
|
||||
|
||||
When passing O_TEMPORARY flag in "mode" the file should
|
||||
be automatically deleted
|
||||
|
||||
The implementation using mkstemp should be considered the
|
||||
reference implementation when adding a new or modifying an
|
||||
existing one
|
||||
|
||||
*/
|
||||
|
||||
File create_temp_file(char *to, const char *dir, const char *prefix,
|
||||
int mode __attribute__((unused)),
|
||||
myf MyFlags __attribute__((unused)))
|
||||
{
|
||||
File file= -1;
|
||||
#ifdef __WIN__
|
||||
TCHAR path_buf[MAX_PATH-14];
|
||||
#endif
|
||||
|
||||
DBUG_ENTER("create_temp_file");
|
||||
DBUG_PRINT("enter", ("dir: %s, prefix: %s", dir, prefix));
|
||||
#if defined (__WIN__)
|
||||
|
||||
/*
|
||||
Use GetTempPath to determine path for temporary files.
|
||||
This is because the documentation for GetTempFileName
|
||||
has the following to say about this parameter:
|
||||
"If this parameter is NULL, the function fails."
|
||||
*/
|
||||
if (!dir)
|
||||
{
|
||||
if(GetTempPath(sizeof(path_buf), path_buf) > 0)
|
||||
dir = path_buf;
|
||||
}
|
||||
/*
|
||||
Use GetTempFileName to generate a unique filename, create
|
||||
the file and release it's handle
|
||||
- uses up to the first three letters from prefix
|
||||
*/
|
||||
if (GetTempFileName(dir, prefix, 0, to) == 0)
|
||||
DBUG_RETURN(-1);
|
||||
|
||||
DBUG_PRINT("info", ("name: %s", to));
|
||||
|
||||
/*
|
||||
Open the file without the "open only if file doesn't already exist"
|
||||
since the file has already been created by GetTempFileName
|
||||
*/
|
||||
if ((file= my_open(to, (mode & ~O_EXCL), MyFlags)) < 0)
|
||||
{
|
||||
/* Open failed, remove the file created by GetTempFileName */
|
||||
int tmp= my_errno;
|
||||
(void) my_delete(to, MYF(0));
|
||||
my_errno= tmp;
|
||||
}
|
||||
|
||||
#elif defined(HAVE_MKSTEMP)
|
||||
{
|
||||
char prefix_buff[30];
|
||||
uint pfx_len;
|
||||
File org_file;
|
||||
|
||||
pfx_len= (uint) (strmov(strnmov(prefix_buff,
|
||||
prefix ? prefix : "tmp.",
|
||||
sizeof(prefix_buff)-7),"XXXXXX") -
|
||||
prefix_buff);
|
||||
if (!dir && ! (dir =getenv("TMPDIR")))
|
||||
dir=P_tmpdir;
|
||||
if (strlen(dir)+ pfx_len > FN_REFLEN-2)
|
||||
{
|
||||
errno=my_errno= ENAMETOOLONG;
|
||||
DBUG_RETURN(file);
|
||||
}
|
||||
strmov(convert_dirname(to,dir,NullS),prefix_buff);
|
||||
org_file=mkstemp(to);
|
||||
if (mode & O_TEMPORARY)
|
||||
(void) my_delete(to, MYF(MY_WME | ME_NOINPUT));
|
||||
file=my_register_filename(org_file, to, FILE_BY_MKSTEMP,
|
||||
EE_CANTCREATEFILE, MyFlags);
|
||||
/* If we didn't manage to register the name, remove the temp file */
|
||||
if (org_file >= 0 && file < 0)
|
||||
{
|
||||
int tmp=my_errno;
|
||||
close(org_file);
|
||||
(void) my_delete(to, MYF(MY_WME | ME_NOINPUT));
|
||||
my_errno=tmp;
|
||||
}
|
||||
}
|
||||
#elif defined(HAVE_TEMPNAM)
|
||||
{
|
||||
extern char **environ;
|
||||
|
||||
char *res,**old_env,*temp_env[1];
|
||||
if (dir && !dir[0])
|
||||
{ /* Change empty string to current dir */
|
||||
to[0]= FN_CURLIB;
|
||||
to[1]= 0;
|
||||
dir=to;
|
||||
}
|
||||
|
||||
old_env= (char**) environ;
|
||||
if (dir)
|
||||
{ /* Don't use TMPDIR if dir is given */
|
||||
environ=(const char**) temp_env;
|
||||
temp_env[0]=0;
|
||||
}
|
||||
|
||||
if ((res=tempnam((char*) dir, (char*) prefix)))
|
||||
{
|
||||
strmake(to,res,FN_REFLEN-1);
|
||||
(*free)(res);
|
||||
file=my_create(to,0,
|
||||
(int) (O_RDWR | O_BINARY | O_TRUNC | O_EXCL | O_NOFOLLOW |
|
||||
O_TEMPORARY | O_SHORT_LIVED),
|
||||
MYF(MY_WME));
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
DBUG_PRINT("error",("Got error: %d from tempnam",errno));
|
||||
}
|
||||
|
||||
environ=(const char**) old_env;
|
||||
}
|
||||
#else
|
||||
#error No implementation found for create_temp_file
|
||||
#endif
|
||||
if (file >= 0)
|
||||
thread_safe_increment(my_tmp_file_created,&THR_LOCK_open);
|
||||
DBUG_RETURN(file);
|
||||
}
|
||||
36
deps/mysqllite/mysys/mf_unixpath.c
vendored
Normal file
36
deps/mysqllite/mysys/mf_unixpath.c
vendored
Normal file
@@ -0,0 +1,36 @@
|
||||
/* Copyright (C) 2000 MySQL AB
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
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 */
|
||||
|
||||
#include "mysys_priv.h"
|
||||
#include <m_string.h>
|
||||
|
||||
/**
|
||||
Convert filename to unix style filename.
|
||||
|
||||
@remark On Windows, converts '\' to '/'.
|
||||
|
||||
@param to A pathname.
|
||||
*/
|
||||
|
||||
void to_unix_path(char *to __attribute__((unused)))
|
||||
{
|
||||
#if FN_LIBCHAR != '/'
|
||||
{
|
||||
to--;
|
||||
while ((to=strchr(to+1,FN_LIBCHAR)) != 0)
|
||||
*to='/';
|
||||
}
|
||||
#endif
|
||||
}
|
||||
89
deps/mysqllite/mysys/mf_wcomp.c
vendored
Normal file
89
deps/mysqllite/mysys/mf_wcomp.c
vendored
Normal file
@@ -0,0 +1,89 @@
|
||||
/* Copyright (C) 2000 MySQL AB
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
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 */
|
||||
|
||||
/* Funktions for comparing with wild-cards */
|
||||
|
||||
#include "mysys_priv.h"
|
||||
|
||||
/* Test if a string is "comparable" to a wild-card string */
|
||||
/* returns 0 if the strings are "comparable" */
|
||||
|
||||
char wild_many='*';
|
||||
char wild_one='?';
|
||||
char wild_prefix=0; /* QQ this can potentially cause a SIGSEGV */
|
||||
|
||||
int wild_compare(register const char *str, register const char *wildstr,
|
||||
pbool str_is_pattern)
|
||||
{
|
||||
char cmp;
|
||||
DBUG_ENTER("wild_compare");
|
||||
|
||||
while (*wildstr)
|
||||
{
|
||||
while (*wildstr && *wildstr != wild_many && *wildstr != wild_one)
|
||||
{
|
||||
if (*wildstr == wild_prefix && wildstr[1])
|
||||
{
|
||||
wildstr++;
|
||||
if (str_is_pattern && *str++ != wild_prefix)
|
||||
DBUG_RETURN(1);
|
||||
}
|
||||
if (*wildstr++ != *str++)
|
||||
DBUG_RETURN(1);
|
||||
}
|
||||
if (! *wildstr )
|
||||
DBUG_RETURN(*str != 0);
|
||||
if (*wildstr++ == wild_one)
|
||||
{
|
||||
if (! *str || (str_is_pattern && *str == wild_many))
|
||||
DBUG_RETURN(1); /* One char; skip */
|
||||
if (*str++ == wild_prefix && str_is_pattern && *str)
|
||||
str++;
|
||||
}
|
||||
else
|
||||
{ /* Found '*' */
|
||||
while (str_is_pattern && *str == wild_many)
|
||||
str++;
|
||||
for (; *wildstr == wild_many || *wildstr == wild_one; wildstr++)
|
||||
if (*wildstr == wild_many)
|
||||
{
|
||||
while (str_is_pattern && *str == wild_many)
|
||||
str++;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (str_is_pattern && *str == wild_prefix && str[1])
|
||||
str+=2;
|
||||
else if (! *str++)
|
||||
DBUG_RETURN (1);
|
||||
}
|
||||
if (!*wildstr)
|
||||
DBUG_RETURN(0); /* '*' as last char: OK */
|
||||
if ((cmp= *wildstr) == wild_prefix && wildstr[1] && !str_is_pattern)
|
||||
cmp=wildstr[1];
|
||||
for (;;str++)
|
||||
{
|
||||
while (*str && *str != cmp)
|
||||
str++;
|
||||
if (!*str)
|
||||
DBUG_RETURN (1);
|
||||
if (wild_compare(str,wildstr,str_is_pattern) == 0)
|
||||
DBUG_RETURN (0);
|
||||
}
|
||||
/* We will never come here */
|
||||
}
|
||||
}
|
||||
DBUG_RETURN (*str != 0);
|
||||
} /* wild_compare */
|
||||
63
deps/mysqllite/mysys/mulalloc.c
vendored
Normal file
63
deps/mysqllite/mysys/mulalloc.c
vendored
Normal file
@@ -0,0 +1,63 @@
|
||||
/* Copyright (C) 2000 MySQL AB
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
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 */
|
||||
|
||||
#include "mysys_priv.h"
|
||||
#include <stdarg.h>
|
||||
|
||||
/*
|
||||
Malloc many pointers at the same time
|
||||
Only ptr1 can be free'd, and doing this will free all
|
||||
the memory allocated. ptr2, etc all point inside big allocated
|
||||
memory area.
|
||||
|
||||
SYNOPSIS
|
||||
my_multi_malloc()
|
||||
myFlags Flags
|
||||
ptr1, length1 Multiple arguments terminated by null ptr
|
||||
ptr2, length2 ...
|
||||
...
|
||||
NULL
|
||||
*/
|
||||
|
||||
void* my_multi_malloc(myf myFlags, ...)
|
||||
{
|
||||
va_list args;
|
||||
char **ptr,*start,*res;
|
||||
size_t tot_length,length;
|
||||
DBUG_ENTER("my_multi_malloc");
|
||||
|
||||
va_start(args,myFlags);
|
||||
tot_length=0;
|
||||
while ((ptr=va_arg(args, char **)))
|
||||
{
|
||||
length=va_arg(args,uint);
|
||||
tot_length+=ALIGN_SIZE(length);
|
||||
}
|
||||
va_end(args);
|
||||
|
||||
if (!(start=(char *) my_malloc(tot_length,myFlags)))
|
||||
DBUG_RETURN(0); /* purecov: inspected */
|
||||
|
||||
va_start(args,myFlags);
|
||||
res=start;
|
||||
while ((ptr=va_arg(args, char **)))
|
||||
{
|
||||
*ptr=res;
|
||||
length=va_arg(args,uint);
|
||||
res+=ALIGN_SIZE(length);
|
||||
}
|
||||
va_end(args);
|
||||
DBUG_RETURN((void*) start);
|
||||
}
|
||||
201
deps/mysqllite/mysys/my_access.c
vendored
Normal file
201
deps/mysqllite/mysys/my_access.c
vendored
Normal file
@@ -0,0 +1,201 @@
|
||||
/* Copyright (C) 2000 MySQL AB
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
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 */
|
||||
|
||||
#include "mysys_priv.h"
|
||||
#include <m_string.h>
|
||||
|
||||
#ifdef __WIN__
|
||||
|
||||
/*
|
||||
Check a file or path for accessability.
|
||||
|
||||
SYNOPSIS
|
||||
file_access()
|
||||
path Path to file
|
||||
amode Access method
|
||||
|
||||
DESCRIPTION
|
||||
This function wraps the normal access method because the access
|
||||
available in MSVCRT> +reports that filenames such as LPT1 and
|
||||
COM1 are valid (they are but should not be so for us).
|
||||
|
||||
RETURN VALUES
|
||||
0 ok
|
||||
-1 error (We use -1 as my_access is mapped to access on other platforms)
|
||||
*/
|
||||
|
||||
int my_access(const char *path, int amode)
|
||||
{
|
||||
WIN32_FILE_ATTRIBUTE_DATA fileinfo;
|
||||
BOOL result;
|
||||
|
||||
result= GetFileAttributesEx(path, GetFileExInfoStandard, &fileinfo);
|
||||
if (! result ||
|
||||
(fileinfo.dwFileAttributes & FILE_ATTRIBUTE_READONLY) && (amode & W_OK))
|
||||
{
|
||||
my_errno= errno= EACCES;
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif /* __WIN__ */
|
||||
|
||||
|
||||
/*
|
||||
List of file names that causes problem on windows
|
||||
|
||||
NOTE that one can also not have file names of type CON.TXT
|
||||
|
||||
NOTE: it is important to keep "CLOCK$" on the first place,
|
||||
we skip it in check_if_legal_tablename.
|
||||
*/
|
||||
static const char *reserved_names[]=
|
||||
{
|
||||
"CLOCK$",
|
||||
"CON", "PRN", "AUX", "NUL",
|
||||
"COM1", "COM2", "COM3", "COM4", "COM5", "COM6", "COM7", "COM8", "COM9",
|
||||
"LPT1", "LPT2", "LPT3", "LPT4", "LPT5", "LPT6", "LPT7", "LPT8", "LPT9",
|
||||
NullS
|
||||
};
|
||||
|
||||
#define MAX_RESERVED_NAME_LENGTH 6
|
||||
|
||||
|
||||
/*
|
||||
Looks up a null-terminated string in a list,
|
||||
case insensitively.
|
||||
|
||||
SYNOPSIS
|
||||
str_list_find()
|
||||
list list of items
|
||||
str item to find
|
||||
|
||||
RETURN
|
||||
0 ok
|
||||
1 reserved file name
|
||||
*/
|
||||
static int str_list_find(const char **list, const char *str)
|
||||
{
|
||||
const char **name;
|
||||
for (name= list; *name; name++)
|
||||
{
|
||||
if (!my_strcasecmp(&my_charset_latin1, *name, str))
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
A map for faster reserved_names lookup,
|
||||
helps to avoid loops in many cases.
|
||||
1 - can be the first letter
|
||||
2 - can be the second letter
|
||||
4 - can be the third letter
|
||||
*/
|
||||
static char reserved_map[256]=
|
||||
{
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* ................ */
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* ................ */
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* !"#$%&'()*+,-./ */
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0123456789:;<=>? */
|
||||
0,1,0,1,0,0,0,0,0,0,0,0,7,4,5,2, /* @ABCDEFGHIJKLMNO */
|
||||
3,0,2,0,4,2,0,0,4,0,0,0,0,0,0,0, /* PQRSTUVWXYZ[\]^_ */
|
||||
0,1,0,1,0,0,0,0,0,0,0,0,7,4,5,2, /* bcdefghijklmno */
|
||||
3,0,2,0,4,2,0,0,4,0,0,0,0,0,0,0, /* pqrstuvwxyz{|}~. */
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* ................ */
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* ................ */
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* ................ */
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* ................ */
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* ................ */
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* ................ */
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* ................ */
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 /* ................ */
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
Check if a table name may cause problems
|
||||
|
||||
SYNOPSIS
|
||||
check_if_legal_tablename
|
||||
name Table name (without any extensions)
|
||||
|
||||
DESCRIPTION
|
||||
We don't check 'CLOCK$' because dollar sign is encoded as @0024,
|
||||
making table file name 'CLOCK@0024', which is safe.
|
||||
This is why we start lookup from the second element
|
||||
(i.e. &reserver_name[1])
|
||||
|
||||
RETURN
|
||||
0 ok
|
||||
1 reserved file name
|
||||
*/
|
||||
|
||||
int check_if_legal_tablename(const char *name)
|
||||
{
|
||||
DBUG_ENTER("check_if_legal_tablename");
|
||||
DBUG_RETURN((reserved_map[(uchar) name[0]] & 1) &&
|
||||
(reserved_map[(uchar) name[1]] & 2) &&
|
||||
(reserved_map[(uchar) name[2]] & 4) &&
|
||||
str_list_find(&reserved_names[1], name));
|
||||
}
|
||||
|
||||
|
||||
#if defined(__WIN__) || defined(__EMX__)
|
||||
|
||||
|
||||
/*
|
||||
Check if a path will access a reserverd file name that may cause problems
|
||||
|
||||
SYNOPSIS
|
||||
check_if_legal_filename
|
||||
path Path to file
|
||||
|
||||
RETURN
|
||||
0 ok
|
||||
1 reserved file name
|
||||
*/
|
||||
|
||||
int check_if_legal_filename(const char *path)
|
||||
{
|
||||
const char *end;
|
||||
const char **reserved_name;
|
||||
DBUG_ENTER("check_if_legal_filename");
|
||||
|
||||
path+= dirname_length(path); /* To start of filename */
|
||||
if (!(end= strchr(path, FN_EXTCHAR)))
|
||||
end= strend(path);
|
||||
if (path == end || (uint) (end - path) > MAX_RESERVED_NAME_LENGTH)
|
||||
DBUG_RETURN(0); /* Simplify inner loop */
|
||||
|
||||
for (reserved_name= reserved_names; *reserved_name; reserved_name++)
|
||||
{
|
||||
const char *reserved= *reserved_name; /* never empty */
|
||||
const char *name= path;
|
||||
|
||||
do
|
||||
{
|
||||
if (*reserved != my_toupper(&my_charset_latin1, *name))
|
||||
break;
|
||||
if (++name == end && !reserved[1])
|
||||
DBUG_RETURN(1); /* Found wrong path */
|
||||
} while (*++reserved);
|
||||
}
|
||||
DBUG_RETURN(0);
|
||||
}
|
||||
|
||||
#endif /* defined(__WIN__) || defined(__EMX__) */
|
||||
227
deps/mysqllite/mysys/my_aes.c
vendored
Normal file
227
deps/mysqllite/mysys/my_aes.c
vendored
Normal file
@@ -0,0 +1,227 @@
|
||||
/* Copyright (C) 2002 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 */
|
||||
|
||||
|
||||
/*
|
||||
Implementation of AES Encryption for MySQL
|
||||
Initial version by Peter Zaitsev June 2002
|
||||
*/
|
||||
|
||||
|
||||
#include <my_global.h>
|
||||
#include <m_string.h>
|
||||
#include "my_aes.h"
|
||||
|
||||
enum encrypt_dir { AES_ENCRYPT, AES_DECRYPT };
|
||||
|
||||
#define AES_BLOCK_SIZE 16 /* Block size in bytes */
|
||||
|
||||
#define AES_BAD_DATA -1 /* If bad data discovered during decoding */
|
||||
|
||||
|
||||
/* The structure for key information */
|
||||
typedef struct {
|
||||
int nr; /* Number of rounds */
|
||||
uint32 rk[4*(AES_MAXNR + 1)]; /* key schedule */
|
||||
} KEYINSTANCE;
|
||||
|
||||
|
||||
/*
|
||||
This is internal function just keeps joint code of Key generation
|
||||
|
||||
SYNOPSIS
|
||||
my_aes_create_key()
|
||||
aes_key Address of Key Instance to be created
|
||||
direction Direction (are we encoding or decoding)
|
||||
key Key to use for real key creation
|
||||
key_length Length of the key
|
||||
|
||||
DESCRIPTION
|
||||
|
||||
RESULT
|
||||
0 ok
|
||||
-1 Error Note: The current impementation never returns this
|
||||
*/
|
||||
|
||||
static int my_aes_create_key(KEYINSTANCE *aes_key,
|
||||
enum encrypt_dir direction, const char *key,
|
||||
int key_length)
|
||||
{
|
||||
uint8 rkey[AES_KEY_LENGTH/8]; /* The real key to be used for encryption */
|
||||
uint8 *rkey_end=rkey+AES_KEY_LENGTH/8; /* Real key boundary */
|
||||
uint8 *ptr; /* Start of the real key*/
|
||||
const char *sptr; /* Start of the working key */
|
||||
const char *key_end=key+key_length; /* Working key boundary*/
|
||||
|
||||
bzero((char*) rkey,AES_KEY_LENGTH/8); /* Set initial key */
|
||||
|
||||
for (ptr= rkey, sptr= key; sptr < key_end; ptr++,sptr++)
|
||||
{
|
||||
if (ptr == rkey_end)
|
||||
ptr= rkey; /* Just loop over tmp_key until we used all key */
|
||||
*ptr^= (uint8) *sptr;
|
||||
}
|
||||
#ifdef AES_USE_KEY_BITS
|
||||
/*
|
||||
This block is intended to allow more weak encryption if application
|
||||
build with libmysqld needs to correspond to export regulations
|
||||
It should be never used in normal distribution as does not give
|
||||
any speed improvement.
|
||||
To get worse security define AES_USE_KEY_BITS to number of bits
|
||||
you want key to be. It should be divisible by 8
|
||||
|
||||
WARNING: Changing this value results in changing of enryption for
|
||||
all key lengths so altering this value will result in impossibility
|
||||
to decrypt data encrypted with previous value
|
||||
*/
|
||||
#define AES_USE_KEY_BYTES (AES_USE_KEY_BITS/8)
|
||||
/*
|
||||
To get weaker key we use first AES_USE_KEY_BYTES bytes of created key
|
||||
and cyclically copy them until we created all required key length
|
||||
*/
|
||||
for (ptr= rkey+AES_USE_KEY_BYTES, sptr=rkey ; ptr < rkey_end;
|
||||
ptr++,sptr++)
|
||||
{
|
||||
if (sptr == rkey+AES_USE_KEY_BYTES)
|
||||
sptr=rkey;
|
||||
*ptr=*sptr;
|
||||
}
|
||||
#endif
|
||||
if (direction == AES_DECRYPT)
|
||||
aes_key->nr = rijndaelKeySetupDec(aes_key->rk, rkey, AES_KEY_LENGTH);
|
||||
else
|
||||
aes_key->nr = rijndaelKeySetupEnc(aes_key->rk, rkey, AES_KEY_LENGTH);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Crypt buffer with AES encryption algorithm.
|
||||
|
||||
SYNOPSIS
|
||||
my_aes_encrypt()
|
||||
source Pointer to data for encryption
|
||||
source_length Size of encryption data
|
||||
dest Buffer to place encrypted data (must be large enough)
|
||||
key Key to be used for encryption
|
||||
key_length Length of the key. Will handle keys of any length
|
||||
|
||||
RETURN
|
||||
>= 0 Size of encrypted data
|
||||
< 0 Error
|
||||
*/
|
||||
|
||||
int my_aes_encrypt(const char* source, int source_length, char* dest,
|
||||
const char* key, int key_length)
|
||||
{
|
||||
KEYINSTANCE aes_key;
|
||||
uint8 block[AES_BLOCK_SIZE]; /* 128 bit block used for padding */
|
||||
int rc; /* result codes */
|
||||
int num_blocks; /* number of complete blocks */
|
||||
char pad_len; /* pad size for the last block */
|
||||
int i;
|
||||
|
||||
if ((rc= my_aes_create_key(&aes_key,AES_ENCRYPT,key,key_length)))
|
||||
return rc;
|
||||
|
||||
num_blocks = source_length/AES_BLOCK_SIZE;
|
||||
|
||||
for (i = num_blocks; i > 0; i--) /* Encode complete blocks */
|
||||
{
|
||||
rijndaelEncrypt(aes_key.rk, aes_key.nr, (const uint8*) source,
|
||||
(uint8*) dest);
|
||||
source+= AES_BLOCK_SIZE;
|
||||
dest+= AES_BLOCK_SIZE;
|
||||
}
|
||||
|
||||
/* Encode the rest. We always have incomplete block */
|
||||
pad_len = AES_BLOCK_SIZE - (source_length - AES_BLOCK_SIZE*num_blocks);
|
||||
memcpy(block, source, 16 - pad_len);
|
||||
bfill(block + AES_BLOCK_SIZE - pad_len, pad_len, pad_len);
|
||||
rijndaelEncrypt(aes_key.rk, aes_key.nr, block, (uint8*) dest);
|
||||
return AES_BLOCK_SIZE*(num_blocks + 1);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
DeCrypt buffer with AES encryption algorithm.
|
||||
|
||||
SYNOPSIS
|
||||
my_aes_decrypt()
|
||||
source Pointer to data for decryption
|
||||
source_length Size of encrypted data
|
||||
dest Buffer to place decrypted data (must be large enough)
|
||||
key Key to be used for decryption
|
||||
key_length Length of the key. Will handle keys of any length
|
||||
|
||||
RETURN
|
||||
>= 0 Size of encrypted data
|
||||
< 0 Error
|
||||
*/
|
||||
|
||||
int my_aes_decrypt(const char *source, int source_length, char *dest,
|
||||
const char *key, int key_length)
|
||||
{
|
||||
KEYINSTANCE aes_key;
|
||||
uint8 block[AES_BLOCK_SIZE]; /* 128 bit block used for padding */
|
||||
int rc; /* Result codes */
|
||||
int num_blocks; /* Number of complete blocks */
|
||||
uint pad_len; /* Pad size for the last block */
|
||||
int i;
|
||||
|
||||
if ((rc=my_aes_create_key(&aes_key,AES_DECRYPT,key,key_length)))
|
||||
return rc;
|
||||
|
||||
num_blocks = source_length/AES_BLOCK_SIZE;
|
||||
|
||||
if ((source_length != num_blocks*AES_BLOCK_SIZE) || num_blocks ==0 )
|
||||
return AES_BAD_DATA; /* Input size has to be even and at least one block */
|
||||
|
||||
for (i = num_blocks-1; i > 0; i--) /* Decode all but last blocks */
|
||||
{
|
||||
rijndaelDecrypt(aes_key.rk, aes_key.nr, (const uint8*) source,
|
||||
(uint8*) dest);
|
||||
source+= AES_BLOCK_SIZE;
|
||||
dest+= AES_BLOCK_SIZE;
|
||||
}
|
||||
|
||||
rijndaelDecrypt(aes_key.rk, aes_key.nr, (const uint8*) source, block);
|
||||
/* Use last char in the block as size */
|
||||
pad_len = (uint) (uchar) block[AES_BLOCK_SIZE-1];
|
||||
|
||||
if (pad_len > AES_BLOCK_SIZE)
|
||||
return AES_BAD_DATA;
|
||||
/* We could also check whole padding but we do not really need this */
|
||||
|
||||
memcpy(dest, block, AES_BLOCK_SIZE - pad_len);
|
||||
return AES_BLOCK_SIZE*num_blocks - pad_len;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Get size of buffer which will be large enough for encrypted data
|
||||
|
||||
SYNOPSIS
|
||||
my_aes_get_size()
|
||||
source_length Length of data to be encrypted
|
||||
|
||||
RETURN
|
||||
Size of buffer required to store encrypted data
|
||||
*/
|
||||
|
||||
int my_aes_get_size(int source_length)
|
||||
{
|
||||
return AES_BLOCK_SIZE*(source_length/AES_BLOCK_SIZE)+AES_BLOCK_SIZE;
|
||||
}
|
||||
32
deps/mysqllite/mysys/my_alarm.c
vendored
Normal file
32
deps/mysqllite/mysys/my_alarm.c
vendored
Normal file
@@ -0,0 +1,32 @@
|
||||
/* Copyright (C) 2000 MySQL AB
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
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 */
|
||||
|
||||
/* Function to set a varible when we got a alarm */
|
||||
/* Used by my_lock samt functions in m_alarm.h */
|
||||
|
||||
|
||||
#include "mysys_priv.h"
|
||||
#include "my_alarm.h"
|
||||
|
||||
#ifdef HAVE_ALARM
|
||||
|
||||
/* ARGSUSED */
|
||||
sig_handler my_set_alarm_variable(int signo __attribute__((unused)))
|
||||
{
|
||||
my_have_got_alarm=1; /* Tell program that time expired */
|
||||
return;
|
||||
}
|
||||
|
||||
#endif /* HAVE_ALARM */
|
||||
436
deps/mysqllite/mysys/my_alloc.c
vendored
Normal file
436
deps/mysqllite/mysys/my_alloc.c
vendored
Normal file
@@ -0,0 +1,436 @@
|
||||
/* Copyright (C) 2000 MySQL AB
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
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 */
|
||||
|
||||
/* Routines to handle mallocing of results which will be freed the same time */
|
||||
|
||||
#include <my_global.h>
|
||||
#include <my_sys.h>
|
||||
#include <m_string.h>
|
||||
#undef EXTRA_DEBUG
|
||||
#define EXTRA_DEBUG
|
||||
|
||||
|
||||
/*
|
||||
Initialize memory root
|
||||
|
||||
SYNOPSIS
|
||||
init_alloc_root()
|
||||
mem_root - memory root to initialize
|
||||
block_size - size of chunks (blocks) used for memory allocation
|
||||
(It is external size of chunk i.e. it should include
|
||||
memory required for internal structures, thus it
|
||||
should be no less than ALLOC_ROOT_MIN_BLOCK_SIZE)
|
||||
pre_alloc_size - if non-0, then size of block that should be
|
||||
pre-allocated during memory root initialization.
|
||||
|
||||
DESCRIPTION
|
||||
This function prepares memory root for further use, sets initial size of
|
||||
chunk for memory allocation and pre-allocates first block if specified.
|
||||
Altough error can happen during execution of this function if
|
||||
pre_alloc_size is non-0 it won't be reported. Instead it will be
|
||||
reported as error in first alloc_root() on this memory root.
|
||||
*/
|
||||
|
||||
void init_alloc_root(MEM_ROOT *mem_root, size_t block_size,
|
||||
size_t pre_alloc_size __attribute__((unused)))
|
||||
{
|
||||
DBUG_ENTER("init_alloc_root");
|
||||
DBUG_PRINT("enter",("root: 0x%lx", (long) mem_root));
|
||||
|
||||
mem_root->free= mem_root->used= mem_root->pre_alloc= 0;
|
||||
mem_root->min_malloc= 32;
|
||||
mem_root->block_size= block_size - ALLOC_ROOT_MIN_BLOCK_SIZE;
|
||||
mem_root->error_handler= 0;
|
||||
mem_root->block_num= 4; /* We shift this with >>2 */
|
||||
mem_root->first_block_usage= 0;
|
||||
|
||||
#if !(defined(HAVE_purify) && defined(EXTRA_DEBUG))
|
||||
if (pre_alloc_size)
|
||||
{
|
||||
if ((mem_root->free= mem_root->pre_alloc=
|
||||
(USED_MEM*) my_malloc(pre_alloc_size+ ALIGN_SIZE(sizeof(USED_MEM)),
|
||||
MYF(0))))
|
||||
{
|
||||
mem_root->free->size= pre_alloc_size+ALIGN_SIZE(sizeof(USED_MEM));
|
||||
mem_root->free->left= pre_alloc_size;
|
||||
mem_root->free->next= 0;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
DBUG_VOID_RETURN;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
SYNOPSIS
|
||||
reset_root_defaults()
|
||||
mem_root memory root to change defaults of
|
||||
block_size new value of block size. Must be greater or equal
|
||||
than ALLOC_ROOT_MIN_BLOCK_SIZE (this value is about
|
||||
68 bytes and depends on platform and compilation flags)
|
||||
pre_alloc_size new size of preallocated block. If not zero,
|
||||
must be equal to or greater than block size,
|
||||
otherwise means 'no prealloc'.
|
||||
DESCRIPTION
|
||||
Function aligns and assigns new value to block size; then it tries to
|
||||
reuse one of existing blocks as prealloc block, or malloc new one of
|
||||
requested size. If no blocks can be reused, all unused blocks are freed
|
||||
before allocation.
|
||||
*/
|
||||
|
||||
void reset_root_defaults(MEM_ROOT *mem_root, size_t block_size,
|
||||
size_t pre_alloc_size __attribute__((unused)))
|
||||
{
|
||||
DBUG_ASSERT(alloc_root_inited(mem_root));
|
||||
|
||||
mem_root->block_size= block_size - ALLOC_ROOT_MIN_BLOCK_SIZE;
|
||||
#if !(defined(HAVE_purify) && defined(EXTRA_DEBUG))
|
||||
if (pre_alloc_size)
|
||||
{
|
||||
size_t size= pre_alloc_size + ALIGN_SIZE(sizeof(USED_MEM));
|
||||
if (!mem_root->pre_alloc || mem_root->pre_alloc->size != size)
|
||||
{
|
||||
USED_MEM *mem, **prev= &mem_root->free;
|
||||
/*
|
||||
Free unused blocks, so that consequent calls
|
||||
to reset_root_defaults won't eat away memory.
|
||||
*/
|
||||
while (*prev)
|
||||
{
|
||||
mem= *prev;
|
||||
if (mem->size == size)
|
||||
{
|
||||
/* We found a suitable block, no need to do anything else */
|
||||
mem_root->pre_alloc= mem;
|
||||
return;
|
||||
}
|
||||
if (mem->left + ALIGN_SIZE(sizeof(USED_MEM)) == mem->size)
|
||||
{
|
||||
/* remove block from the list and free it */
|
||||
*prev= mem->next;
|
||||
my_free(mem);
|
||||
}
|
||||
else
|
||||
prev= &mem->next;
|
||||
}
|
||||
/* Allocate new prealloc block and add it to the end of free list */
|
||||
if ((mem= (USED_MEM *) my_malloc(size, MYF(0))))
|
||||
{
|
||||
mem->size= size;
|
||||
mem->left= pre_alloc_size;
|
||||
mem->next= *prev;
|
||||
*prev= mem_root->pre_alloc= mem;
|
||||
}
|
||||
else
|
||||
{
|
||||
mem_root->pre_alloc= 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
#endif
|
||||
mem_root->pre_alloc= 0;
|
||||
}
|
||||
|
||||
|
||||
void *alloc_root(MEM_ROOT *mem_root, size_t length)
|
||||
{
|
||||
#if defined(HAVE_purify) && defined(EXTRA_DEBUG)
|
||||
reg1 USED_MEM *next;
|
||||
DBUG_ENTER("alloc_root");
|
||||
DBUG_PRINT("enter",("root: 0x%lx", (long) mem_root));
|
||||
|
||||
DBUG_ASSERT(alloc_root_inited(mem_root));
|
||||
|
||||
DBUG_EXECUTE_IF("simulate_out_of_memory",
|
||||
{
|
||||
if (mem_root->error_handler)
|
||||
(*mem_root->error_handler)();
|
||||
DBUG_SET("-d,simulate_out_of_memory");
|
||||
DBUG_RETURN((void*) 0); /* purecov: inspected */
|
||||
});
|
||||
|
||||
length+=ALIGN_SIZE(sizeof(USED_MEM));
|
||||
if (!(next = (USED_MEM*) my_malloc(length,MYF(MY_WME | ME_FATALERROR))))
|
||||
{
|
||||
if (mem_root->error_handler)
|
||||
(*mem_root->error_handler)();
|
||||
DBUG_RETURN((uchar*) 0); /* purecov: inspected */
|
||||
}
|
||||
next->next= mem_root->used;
|
||||
next->size= length;
|
||||
mem_root->used= next;
|
||||
DBUG_PRINT("exit",("ptr: 0x%lx", (long) (((char*) next)+
|
||||
ALIGN_SIZE(sizeof(USED_MEM)))));
|
||||
DBUG_RETURN((uchar*) (((char*) next)+ALIGN_SIZE(sizeof(USED_MEM))));
|
||||
#else
|
||||
size_t get_size, block_size;
|
||||
uchar* point;
|
||||
reg1 USED_MEM *next= 0;
|
||||
reg2 USED_MEM **prev;
|
||||
DBUG_ENTER("alloc_root");
|
||||
DBUG_PRINT("enter",("root: 0x%lx", (long) mem_root));
|
||||
DBUG_ASSERT(alloc_root_inited(mem_root));
|
||||
|
||||
DBUG_EXECUTE_IF("simulate_out_of_memory",
|
||||
{
|
||||
/* Avoid reusing an already allocated block */
|
||||
if (mem_root->error_handler)
|
||||
(*mem_root->error_handler)();
|
||||
DBUG_SET("-d,simulate_out_of_memory");
|
||||
DBUG_RETURN((void*) 0); /* purecov: inspected */
|
||||
});
|
||||
length= ALIGN_SIZE(length);
|
||||
if ((*(prev= &mem_root->free)) != NULL)
|
||||
{
|
||||
if ((*prev)->left < length &&
|
||||
mem_root->first_block_usage++ >= ALLOC_MAX_BLOCK_USAGE_BEFORE_DROP &&
|
||||
(*prev)->left < ALLOC_MAX_BLOCK_TO_DROP)
|
||||
{
|
||||
next= *prev;
|
||||
*prev= next->next; /* Remove block from list */
|
||||
next->next= mem_root->used;
|
||||
mem_root->used= next;
|
||||
mem_root->first_block_usage= 0;
|
||||
}
|
||||
for (next= *prev ; next && next->left < length ; next= next->next)
|
||||
prev= &next->next;
|
||||
}
|
||||
if (! next)
|
||||
{ /* Time to alloc new block */
|
||||
block_size= mem_root->block_size * (mem_root->block_num >> 2);
|
||||
get_size= length+ALIGN_SIZE(sizeof(USED_MEM));
|
||||
get_size= max(get_size, block_size);
|
||||
|
||||
if (!(next = (USED_MEM*) my_malloc(get_size,MYF(MY_WME | ME_FATALERROR))))
|
||||
{
|
||||
if (mem_root->error_handler)
|
||||
(*mem_root->error_handler)();
|
||||
DBUG_RETURN((void*) 0); /* purecov: inspected */
|
||||
}
|
||||
mem_root->block_num++;
|
||||
next->next= *prev;
|
||||
next->size= get_size;
|
||||
next->left= get_size-ALIGN_SIZE(sizeof(USED_MEM));
|
||||
*prev=next;
|
||||
}
|
||||
|
||||
point= (uchar*) ((char*) next+ (next->size-next->left));
|
||||
/*TODO: next part may be unneded due to mem_root->first_block_usage counter*/
|
||||
if ((next->left-= length) < mem_root->min_malloc)
|
||||
{ /* Full block */
|
||||
*prev= next->next; /* Remove block from list */
|
||||
next->next= mem_root->used;
|
||||
mem_root->used= next;
|
||||
mem_root->first_block_usage= 0;
|
||||
}
|
||||
DBUG_PRINT("exit",("ptr: 0x%lx", (ulong) point));
|
||||
DBUG_RETURN((void*) point);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Allocate many pointers at the same time.
|
||||
|
||||
DESCRIPTION
|
||||
ptr1, ptr2, etc all point into big allocated memory area.
|
||||
|
||||
SYNOPSIS
|
||||
multi_alloc_root()
|
||||
root Memory root
|
||||
ptr1, length1 Multiple arguments terminated by a NULL pointer
|
||||
ptr2, length2 ...
|
||||
...
|
||||
NULL
|
||||
|
||||
RETURN VALUE
|
||||
A pointer to the beginning of the allocated memory block
|
||||
in case of success or NULL if out of memory.
|
||||
*/
|
||||
|
||||
void *multi_alloc_root(MEM_ROOT *root, ...)
|
||||
{
|
||||
va_list args;
|
||||
char **ptr, *start, *res;
|
||||
size_t tot_length, length;
|
||||
DBUG_ENTER("multi_alloc_root");
|
||||
|
||||
va_start(args, root);
|
||||
tot_length= 0;
|
||||
while ((ptr= va_arg(args, char **)))
|
||||
{
|
||||
length= va_arg(args, uint);
|
||||
tot_length+= ALIGN_SIZE(length);
|
||||
}
|
||||
va_end(args);
|
||||
|
||||
if (!(start= (char*) alloc_root(root, tot_length)))
|
||||
DBUG_RETURN(0); /* purecov: inspected */
|
||||
|
||||
va_start(args, root);
|
||||
res= start;
|
||||
while ((ptr= va_arg(args, char **)))
|
||||
{
|
||||
*ptr= res;
|
||||
length= va_arg(args, uint);
|
||||
res+= ALIGN_SIZE(length);
|
||||
}
|
||||
va_end(args);
|
||||
DBUG_RETURN((void*) start);
|
||||
}
|
||||
|
||||
#define TRASH_MEM(X) TRASH(((char*)(X) + ((X)->size-(X)->left)), (X)->left)
|
||||
|
||||
/* Mark all data in blocks free for reusage */
|
||||
|
||||
static inline void mark_blocks_free(MEM_ROOT* root)
|
||||
{
|
||||
reg1 USED_MEM *next;
|
||||
reg2 USED_MEM **last;
|
||||
|
||||
/* iterate through (partially) free blocks, mark them free */
|
||||
last= &root->free;
|
||||
for (next= root->free; next; next= *(last= &next->next))
|
||||
{
|
||||
next->left= next->size - ALIGN_SIZE(sizeof(USED_MEM));
|
||||
TRASH_MEM(next);
|
||||
}
|
||||
|
||||
/* Combine the free and the used list */
|
||||
*last= next=root->used;
|
||||
|
||||
/* now go through the used blocks and mark them free */
|
||||
for (; next; next= next->next)
|
||||
{
|
||||
next->left= next->size - ALIGN_SIZE(sizeof(USED_MEM));
|
||||
TRASH_MEM(next);
|
||||
}
|
||||
|
||||
/* Now everything is set; Indicate that nothing is used anymore */
|
||||
root->used= 0;
|
||||
root->first_block_usage= 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Deallocate everything used by alloc_root or just move
|
||||
used blocks to free list if called with MY_USED_TO_FREE
|
||||
|
||||
SYNOPSIS
|
||||
free_root()
|
||||
root Memory root
|
||||
MyFlags Flags for what should be freed:
|
||||
|
||||
MY_MARK_BLOCKS_FREED Don't free blocks, just mark them free
|
||||
MY_KEEP_PREALLOC If this is not set, then free also the
|
||||
preallocated block
|
||||
|
||||
NOTES
|
||||
One can call this function either with root block initialised with
|
||||
init_alloc_root() or with a bzero()-ed block.
|
||||
It's also safe to call this multiple times with the same mem_root.
|
||||
*/
|
||||
|
||||
void free_root(MEM_ROOT *root, myf MyFlags)
|
||||
{
|
||||
reg1 USED_MEM *next,*old;
|
||||
DBUG_ENTER("free_root");
|
||||
DBUG_PRINT("enter",("root: 0x%lx flags: %u", (long) root, (uint) MyFlags));
|
||||
|
||||
if (MyFlags & MY_MARK_BLOCKS_FREE)
|
||||
{
|
||||
mark_blocks_free(root);
|
||||
DBUG_VOID_RETURN;
|
||||
}
|
||||
if (!(MyFlags & MY_KEEP_PREALLOC))
|
||||
root->pre_alloc=0;
|
||||
|
||||
for (next=root->used; next ;)
|
||||
{
|
||||
old=next; next= next->next ;
|
||||
if (old != root->pre_alloc)
|
||||
my_free(old);
|
||||
}
|
||||
for (next=root->free ; next ;)
|
||||
{
|
||||
old=next; next= next->next;
|
||||
if (old != root->pre_alloc)
|
||||
my_free(old);
|
||||
}
|
||||
root->used=root->free=0;
|
||||
if (root->pre_alloc)
|
||||
{
|
||||
root->free=root->pre_alloc;
|
||||
root->free->left=root->pre_alloc->size-ALIGN_SIZE(sizeof(USED_MEM));
|
||||
TRASH_MEM(root->pre_alloc);
|
||||
root->free->next=0;
|
||||
}
|
||||
root->block_num= 4;
|
||||
root->first_block_usage= 0;
|
||||
DBUG_VOID_RETURN;
|
||||
}
|
||||
|
||||
/*
|
||||
Find block that contains an object and set the pre_alloc to it
|
||||
*/
|
||||
|
||||
void set_prealloc_root(MEM_ROOT *root, char *ptr)
|
||||
{
|
||||
USED_MEM *next;
|
||||
for (next=root->used; next ; next=next->next)
|
||||
{
|
||||
if ((char*) next <= ptr && (char*) next + next->size > ptr)
|
||||
{
|
||||
root->pre_alloc=next;
|
||||
return;
|
||||
}
|
||||
}
|
||||
for (next=root->free ; next ; next=next->next)
|
||||
{
|
||||
if ((char*) next <= ptr && (char*) next + next->size > ptr)
|
||||
{
|
||||
root->pre_alloc=next;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
char *strdup_root(MEM_ROOT *root, const char *str)
|
||||
{
|
||||
return strmake_root(root, str, strlen(str));
|
||||
}
|
||||
|
||||
|
||||
char *strmake_root(MEM_ROOT *root, const char *str, size_t len)
|
||||
{
|
||||
char *pos;
|
||||
if ((pos=alloc_root(root,len+1)))
|
||||
{
|
||||
memcpy(pos,str,len);
|
||||
pos[len]=0;
|
||||
}
|
||||
return pos;
|
||||
}
|
||||
|
||||
|
||||
void *memdup_root(MEM_ROOT *root, const void *str, size_t len)
|
||||
{
|
||||
char *pos;
|
||||
if ((pos=alloc_root(root,len)))
|
||||
memcpy(pos,str,len);
|
||||
return pos;
|
||||
}
|
||||
67
deps/mysqllite/mysys/my_atomic.c
vendored
Normal file
67
deps/mysqllite/mysys/my_atomic.c
vendored
Normal file
@@ -0,0 +1,67 @@
|
||||
/* Copyright (C) 2006 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 */
|
||||
|
||||
#include <my_global.h>
|
||||
#include <my_sys.h>
|
||||
|
||||
#include <my_atomic.h>
|
||||
|
||||
/*
|
||||
checks that the current build of atomic ops
|
||||
can run on this machine
|
||||
|
||||
RETURN
|
||||
ATOMIC_xxx values, see my_atomic.h
|
||||
*/
|
||||
int my_atomic_initialize()
|
||||
{
|
||||
compile_time_assert(sizeof(intptr) == sizeof(void *));
|
||||
/* currently the only thing worth checking is SMP/UP issue */
|
||||
#ifdef MY_ATOMIC_MODE_DUMMY
|
||||
return my_getncpus() == 1 ? MY_ATOMIC_OK : MY_ATOMIC_NOT_1CPU;
|
||||
#else
|
||||
return MY_ATOMIC_OK;
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef SAFE_MUTEX
|
||||
#undef pthread_mutex_init
|
||||
#undef pthread_mutex_destroy
|
||||
#undef pthread_mutex_lock
|
||||
#undef pthread_mutex_unlock
|
||||
|
||||
void plain_pthread_mutex_init(safe_mutex_t *m)
|
||||
{
|
||||
pthread_mutex_init(& m->mutex, NULL);
|
||||
}
|
||||
|
||||
void plain_pthread_mutex_destroy(safe_mutex_t *m)
|
||||
{
|
||||
pthread_mutex_destroy(& m->mutex);
|
||||
}
|
||||
|
||||
void plain_pthread_mutex_lock(safe_mutex_t *m)
|
||||
{
|
||||
pthread_mutex_lock(& m->mutex);
|
||||
}
|
||||
|
||||
void plain_pthread_mutex_unlock(safe_mutex_t *m)
|
||||
{
|
||||
pthread_mutex_unlock(& m->mutex);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
64
deps/mysqllite/mysys/my_bit.c
vendored
Normal file
64
deps/mysqllite/mysys/my_bit.c
vendored
Normal file
@@ -0,0 +1,64 @@
|
||||
/* Copyright (C) 2000 MySQL AB
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
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 */
|
||||
|
||||
#include <my_global.h>
|
||||
|
||||
#include <my_bit.h>
|
||||
|
||||
const char _my_bits_nbits[256] = {
|
||||
0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4,
|
||||
1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
|
||||
1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
|
||||
2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
|
||||
1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
|
||||
2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
|
||||
2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
|
||||
3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
|
||||
1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
|
||||
2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
|
||||
2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
|
||||
3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
|
||||
2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
|
||||
3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
|
||||
3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
|
||||
4, 5, 5, 6, 5, 6, 6, 7, 5, 6, 6, 7, 6, 7, 7, 8,
|
||||
};
|
||||
|
||||
/*
|
||||
perl -e 'print map{", 0x".unpack H2,pack B8,unpack b8,chr$_}(0..255)'
|
||||
*/
|
||||
const uchar _my_bits_reverse_table[256]={
|
||||
0x00, 0x80, 0x40, 0xC0, 0x20, 0xA0, 0x60, 0xE0, 0x10, 0x90, 0x50, 0xD0, 0x30,
|
||||
0xB0, 0x70, 0xF0, 0x08, 0x88, 0x48, 0xC8, 0x28, 0xA8, 0x68, 0xE8, 0x18, 0x98,
|
||||
0x58, 0xD8, 0x38, 0xB8, 0x78, 0xF8, 0x04, 0x84, 0x44, 0xC4, 0x24, 0xA4, 0x64,
|
||||
0xE4, 0x14, 0x94, 0x54, 0xD4, 0x34, 0xB4, 0x74, 0xF4, 0x0C, 0x8C, 0x4C, 0xCC,
|
||||
0x2C, 0xAC, 0x6C, 0xEC, 0x1C, 0x9C, 0x5C, 0xDC, 0x3C, 0xBC, 0x7C, 0xFC, 0x02,
|
||||
0x82, 0x42, 0xC2, 0x22, 0xA2, 0x62, 0xE2, 0x12, 0x92, 0x52, 0xD2, 0x32, 0xB2,
|
||||
0x72, 0xF2, 0x0A, 0x8A, 0x4A, 0xCA, 0x2A, 0xAA, 0x6A, 0xEA, 0x1A, 0x9A, 0x5A,
|
||||
0xDA, 0x3A, 0xBA, 0x7A, 0xFA, 0x06, 0x86, 0x46, 0xC6, 0x26, 0xA6, 0x66, 0xE6,
|
||||
0x16, 0x96, 0x56, 0xD6, 0x36, 0xB6, 0x76, 0xF6, 0x0E, 0x8E, 0x4E, 0xCE, 0x2E,
|
||||
0xAE, 0x6E, 0xEE, 0x1E, 0x9E, 0x5E, 0xDE, 0x3E, 0xBE, 0x7E, 0xFE, 0x01, 0x81,
|
||||
0x41, 0xC1, 0x21, 0xA1, 0x61, 0xE1, 0x11, 0x91, 0x51, 0xD1, 0x31, 0xB1, 0x71,
|
||||
0xF1, 0x09, 0x89, 0x49, 0xC9, 0x29, 0xA9, 0x69, 0xE9, 0x19, 0x99, 0x59, 0xD9,
|
||||
0x39, 0xB9, 0x79, 0xF9, 0x05, 0x85, 0x45, 0xC5, 0x25, 0xA5, 0x65, 0xE5, 0x15,
|
||||
0x95, 0x55, 0xD5, 0x35, 0xB5, 0x75, 0xF5, 0x0D, 0x8D, 0x4D, 0xCD, 0x2D, 0xAD,
|
||||
0x6D, 0xED, 0x1D, 0x9D, 0x5D, 0xDD, 0x3D, 0xBD, 0x7D, 0xFD, 0x03, 0x83, 0x43,
|
||||
0xC3, 0x23, 0xA3, 0x63, 0xE3, 0x13, 0x93, 0x53, 0xD3, 0x33, 0xB3, 0x73, 0xF3,
|
||||
0x0B, 0x8B, 0x4B, 0xCB, 0x2B, 0xAB, 0x6B, 0xEB, 0x1B, 0x9B, 0x5B, 0xDB, 0x3B,
|
||||
0xBB, 0x7B, 0xFB, 0x07, 0x87, 0x47, 0xC7, 0x27, 0xA7, 0x67, 0xE7, 0x17, 0x97,
|
||||
0x57, 0xD7, 0x37, 0xB7, 0x77, 0xF7, 0x0F, 0x8F, 0x4F, 0xCF, 0x2F, 0xAF, 0x6F,
|
||||
0xEF, 0x1F, 0x9F, 0x5F, 0xDF, 0x3F, 0xBF, 0x7F, 0xFF
|
||||
};
|
||||
|
||||
932
deps/mysqllite/mysys/my_bitmap.c
vendored
Normal file
932
deps/mysqllite/mysys/my_bitmap.c
vendored
Normal file
@@ -0,0 +1,932 @@
|
||||
/* Copyright (C) 2000 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 */
|
||||
|
||||
/*
|
||||
Handling of uchar arrays as large bitmaps.
|
||||
|
||||
API limitations (or, rather asserted safety assumptions,
|
||||
to encourage correct programming)
|
||||
|
||||
* the internal size is a set of 32 bit words
|
||||
* the number of bits specified in creation can be any number > 0
|
||||
* there are THREAD safe versions of most calls called bitmap_lock_*
|
||||
|
||||
TODO:
|
||||
Make assembler THREAD safe versions of these using test-and-set instructions
|
||||
|
||||
Original version created by Sergei Golubchik 2001 - 2004.
|
||||
New version written and test program added and some changes to the interface
|
||||
was made by Mikael Ronström 2005, with assistance of Tomas Ulin and Mats
|
||||
Kindahl.
|
||||
*/
|
||||
|
||||
#include "mysys_priv.h"
|
||||
#include <my_bitmap.h>
|
||||
#include <m_string.h>
|
||||
#include <my_bit.h>
|
||||
|
||||
void create_last_word_mask(MY_BITMAP *map)
|
||||
{
|
||||
/* Get the number of used bits (1..8) in the last byte */
|
||||
unsigned int const used= 1U + ((map->n_bits-1U) & 0x7U);
|
||||
|
||||
/*
|
||||
Create a mask with the upper 'unused' bits set and the lower 'used'
|
||||
bits clear. The bits within each byte is stored in big-endian order.
|
||||
*/
|
||||
unsigned char const mask= (~((1 << used) - 1)) & 255;
|
||||
|
||||
/*
|
||||
The first bytes are to be set to zero since they represent real bits
|
||||
in the bitvector. The last bytes are set to 0xFF since they represent
|
||||
bytes not used by the bitvector. Finally the last byte contains bits
|
||||
as set by the mask above.
|
||||
*/
|
||||
unsigned char *ptr= (unsigned char*)&map->last_word_mask;
|
||||
|
||||
map->last_word_ptr= map->bitmap + no_words_in_map(map)-1;
|
||||
switch (no_bytes_in_map(map) & 3) {
|
||||
case 1:
|
||||
map->last_word_mask= ~0U;
|
||||
ptr[0]= mask;
|
||||
return;
|
||||
case 2:
|
||||
map->last_word_mask= ~0U;
|
||||
ptr[0]= 0;
|
||||
ptr[1]= mask;
|
||||
return;
|
||||
case 3:
|
||||
map->last_word_mask= 0U;
|
||||
ptr[2]= mask;
|
||||
ptr[3]= 0xFFU;
|
||||
return;
|
||||
case 0:
|
||||
map->last_word_mask= 0U;
|
||||
ptr[3]= mask;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static inline void bitmap_lock(MY_BITMAP *map __attribute__((unused)))
|
||||
{
|
||||
if (map->mutex)
|
||||
mysql_mutex_lock(map->mutex);
|
||||
}
|
||||
|
||||
static inline void bitmap_unlock(MY_BITMAP *map __attribute__((unused)))
|
||||
{
|
||||
if (map->mutex)
|
||||
mysql_mutex_unlock(map->mutex);
|
||||
}
|
||||
|
||||
|
||||
my_bool bitmap_init(MY_BITMAP *map, my_bitmap_map *buf, uint n_bits,
|
||||
my_bool thread_safe __attribute__((unused)))
|
||||
{
|
||||
DBUG_ENTER("bitmap_init");
|
||||
if (!buf)
|
||||
{
|
||||
uint size_in_bytes= bitmap_buffer_size(n_bits);
|
||||
uint extra= 0;
|
||||
|
||||
if (thread_safe)
|
||||
{
|
||||
size_in_bytes= ALIGN_SIZE(size_in_bytes);
|
||||
extra= sizeof(mysql_mutex_t);
|
||||
}
|
||||
map->mutex= 0;
|
||||
|
||||
if (!(buf= (my_bitmap_map*) my_malloc(size_in_bytes+extra, MYF(MY_WME))))
|
||||
DBUG_RETURN(1);
|
||||
|
||||
if (thread_safe)
|
||||
{
|
||||
map->mutex= (mysql_mutex_t *) ((char*) buf + size_in_bytes);
|
||||
mysql_mutex_init(key_BITMAP_mutex, map->mutex, MY_MUTEX_INIT_FAST);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
DBUG_ASSERT(thread_safe == 0);
|
||||
}
|
||||
|
||||
|
||||
map->bitmap= buf;
|
||||
map->n_bits= n_bits;
|
||||
create_last_word_mask(map);
|
||||
bitmap_clear_all(map);
|
||||
DBUG_RETURN(0);
|
||||
}
|
||||
|
||||
|
||||
void bitmap_free(MY_BITMAP *map)
|
||||
{
|
||||
DBUG_ENTER("bitmap_free");
|
||||
if (map->bitmap)
|
||||
{
|
||||
if (map->mutex)
|
||||
mysql_mutex_destroy(map->mutex);
|
||||
|
||||
my_free(map->bitmap);
|
||||
map->bitmap=0;
|
||||
}
|
||||
DBUG_VOID_RETURN;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
test if bit already set and set it if it was not (thread unsafe method)
|
||||
|
||||
SYNOPSIS
|
||||
bitmap_fast_test_and_set()
|
||||
MAP bit map struct
|
||||
BIT bit number
|
||||
|
||||
RETURN
|
||||
0 bit was not set
|
||||
!=0 bit was set
|
||||
*/
|
||||
|
||||
my_bool bitmap_fast_test_and_set(MY_BITMAP *map, uint bitmap_bit)
|
||||
{
|
||||
uchar *value= ((uchar*) map->bitmap) + (bitmap_bit / 8);
|
||||
uchar bit= 1 << ((bitmap_bit) & 7);
|
||||
uchar res= (*value) & bit;
|
||||
*value|= bit;
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
test if bit already set and set it if it was not (thread safe method)
|
||||
|
||||
SYNOPSIS
|
||||
bitmap_fast_test_and_set()
|
||||
map bit map struct
|
||||
bitmap_bit bit number
|
||||
|
||||
RETURN
|
||||
0 bit was not set
|
||||
!=0 bit was set
|
||||
*/
|
||||
|
||||
my_bool bitmap_test_and_set(MY_BITMAP *map, uint bitmap_bit)
|
||||
{
|
||||
my_bool res;
|
||||
DBUG_ASSERT(map->bitmap && bitmap_bit < map->n_bits);
|
||||
bitmap_lock(map);
|
||||
res= bitmap_fast_test_and_set(map, bitmap_bit);
|
||||
bitmap_unlock(map);
|
||||
return res;
|
||||
}
|
||||
|
||||
/*
|
||||
test if bit already set and clear it if it was set(thread unsafe method)
|
||||
|
||||
SYNOPSIS
|
||||
bitmap_fast_test_and_set()
|
||||
MAP bit map struct
|
||||
BIT bit number
|
||||
|
||||
RETURN
|
||||
0 bit was not set
|
||||
!=0 bit was set
|
||||
*/
|
||||
|
||||
my_bool bitmap_fast_test_and_clear(MY_BITMAP *map, uint bitmap_bit)
|
||||
{
|
||||
uchar *byte= (uchar*) map->bitmap + (bitmap_bit / 8);
|
||||
uchar bit= 1 << ((bitmap_bit) & 7);
|
||||
uchar res= (*byte) & bit;
|
||||
*byte&= ~bit;
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
my_bool bitmap_test_and_clear(MY_BITMAP *map, uint bitmap_bit)
|
||||
{
|
||||
my_bool res;
|
||||
DBUG_ASSERT(map->bitmap && bitmap_bit < map->n_bits);
|
||||
bitmap_lock(map);
|
||||
res= bitmap_fast_test_and_clear(map, bitmap_bit);
|
||||
bitmap_unlock(map);
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
uint bitmap_set_next(MY_BITMAP *map)
|
||||
{
|
||||
uint bit_found;
|
||||
DBUG_ASSERT(map->bitmap);
|
||||
if ((bit_found= bitmap_get_first(map)) != MY_BIT_NONE)
|
||||
bitmap_set_bit(map, bit_found);
|
||||
return bit_found;
|
||||
}
|
||||
|
||||
|
||||
void bitmap_set_prefix(MY_BITMAP *map, uint prefix_size)
|
||||
{
|
||||
uint prefix_bytes, prefix_bits, d;
|
||||
uchar *m= (uchar *)map->bitmap;
|
||||
|
||||
DBUG_ASSERT(map->bitmap &&
|
||||
(prefix_size <= map->n_bits || prefix_size == (uint) ~0));
|
||||
set_if_smaller(prefix_size, map->n_bits);
|
||||
if ((prefix_bytes= prefix_size / 8))
|
||||
memset(m, 0xff, prefix_bytes);
|
||||
m+= prefix_bytes;
|
||||
if ((prefix_bits= prefix_size & 7))
|
||||
*m++= (1 << prefix_bits)-1;
|
||||
if ((d= no_bytes_in_map(map)-prefix_bytes))
|
||||
bzero(m, d);
|
||||
}
|
||||
|
||||
|
||||
my_bool bitmap_is_prefix(const MY_BITMAP *map, uint prefix_size)
|
||||
{
|
||||
uint prefix_bits= prefix_size & 0x7, res;
|
||||
uchar *m= (uchar*)map->bitmap;
|
||||
uchar *end_prefix= m+prefix_size/8;
|
||||
uchar *end;
|
||||
DBUG_ASSERT(m && prefix_size <= map->n_bits);
|
||||
end= m+no_bytes_in_map(map);
|
||||
|
||||
while (m < end_prefix)
|
||||
if (*m++ != 0xff)
|
||||
return 0;
|
||||
|
||||
*map->last_word_ptr&= ~map->last_word_mask; /*Clear bits*/
|
||||
res= 0;
|
||||
if (prefix_bits && *m++ != (1 << prefix_bits)-1)
|
||||
goto ret;
|
||||
|
||||
while (m < end)
|
||||
if (*m++ != 0)
|
||||
goto ret;
|
||||
res= 1;
|
||||
ret:
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
my_bool bitmap_is_set_all(const MY_BITMAP *map)
|
||||
{
|
||||
my_bitmap_map *data_ptr= map->bitmap;
|
||||
my_bitmap_map *end= map->last_word_ptr;
|
||||
*map->last_word_ptr |= map->last_word_mask;
|
||||
for (; data_ptr <= end; data_ptr++)
|
||||
if (*data_ptr != 0xFFFFFFFF)
|
||||
return FALSE;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
my_bool bitmap_is_clear_all(const MY_BITMAP *map)
|
||||
{
|
||||
my_bitmap_map *data_ptr= map->bitmap;
|
||||
my_bitmap_map *end;
|
||||
if (*map->last_word_ptr & ~map->last_word_mask)
|
||||
return FALSE;
|
||||
end= map->last_word_ptr;
|
||||
for (; data_ptr < end; data_ptr++)
|
||||
if (*data_ptr)
|
||||
return FALSE;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/* Return TRUE if map1 is a subset of map2 */
|
||||
|
||||
my_bool bitmap_is_subset(const MY_BITMAP *map1, const MY_BITMAP *map2)
|
||||
{
|
||||
my_bitmap_map *m1= map1->bitmap, *m2= map2->bitmap, *end;
|
||||
|
||||
DBUG_ASSERT(map1->bitmap && map2->bitmap &&
|
||||
map1->n_bits==map2->n_bits);
|
||||
|
||||
end= map1->last_word_ptr;
|
||||
*map1->last_word_ptr &= ~map1->last_word_mask;
|
||||
*map2->last_word_ptr &= ~map2->last_word_mask;
|
||||
while (m1 <= end)
|
||||
{
|
||||
if ((*m1++) & ~(*m2++))
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* True if bitmaps has any common bits */
|
||||
|
||||
my_bool bitmap_is_overlapping(const MY_BITMAP *map1, const MY_BITMAP *map2)
|
||||
{
|
||||
my_bitmap_map *m1= map1->bitmap, *m2= map2->bitmap, *end;
|
||||
|
||||
DBUG_ASSERT(map1->bitmap && map2->bitmap &&
|
||||
map1->n_bits==map2->n_bits);
|
||||
|
||||
end= map1->last_word_ptr;
|
||||
*map1->last_word_ptr &= ~map1->last_word_mask;
|
||||
*map2->last_word_ptr &= ~map2->last_word_mask;
|
||||
while (m1 <= end)
|
||||
{
|
||||
if ((*m1++) & (*m2++))
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void bitmap_intersect(MY_BITMAP *map, const MY_BITMAP *map2)
|
||||
{
|
||||
my_bitmap_map *to= map->bitmap, *from= map2->bitmap, *end;
|
||||
uint len= no_words_in_map(map), len2 = no_words_in_map(map2);
|
||||
|
||||
DBUG_ASSERT(map->bitmap && map2->bitmap);
|
||||
|
||||
end= to+min(len,len2);
|
||||
*map2->last_word_ptr&= ~map2->last_word_mask; /*Clear last bits in map2*/
|
||||
while (to < end)
|
||||
*to++ &= *from++;
|
||||
|
||||
if (len2 < len)
|
||||
{
|
||||
end+=len-len2;
|
||||
while (to < end)
|
||||
*to++=0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Set/clear all bits above a bit.
|
||||
|
||||
SYNOPSIS
|
||||
bitmap_set_above()
|
||||
map RETURN The bitmap to change.
|
||||
from_byte The bitmap buffer byte offset to start with.
|
||||
use_bit The bit value (1/0) to use for all upper bits.
|
||||
|
||||
NOTE
|
||||
You can only set/clear full bytes.
|
||||
The function is meant for the situation that you copy a smaller bitmap
|
||||
to a bigger bitmap. Bitmap lengths are always multiple of eigth (the
|
||||
size of a byte). Using 'from_byte' saves multiplication and division
|
||||
by eight during parameter passing.
|
||||
|
||||
RETURN
|
||||
void
|
||||
*/
|
||||
|
||||
void bitmap_set_above(MY_BITMAP *map, uint from_byte, uint use_bit)
|
||||
{
|
||||
uchar use_byte= use_bit ? 0xff : 0;
|
||||
uchar *to= (uchar *)map->bitmap + from_byte;
|
||||
uchar *end= (uchar *)map->bitmap + (map->n_bits+7)/8;
|
||||
|
||||
while (to < end)
|
||||
*to++= use_byte;
|
||||
}
|
||||
|
||||
|
||||
void bitmap_subtract(MY_BITMAP *map, const MY_BITMAP *map2)
|
||||
{
|
||||
my_bitmap_map *to= map->bitmap, *from= map2->bitmap, *end;
|
||||
DBUG_ASSERT(map->bitmap && map2->bitmap &&
|
||||
map->n_bits==map2->n_bits);
|
||||
|
||||
end= map->last_word_ptr;
|
||||
|
||||
while (to <= end)
|
||||
*to++ &= ~(*from++);
|
||||
}
|
||||
|
||||
|
||||
void bitmap_union(MY_BITMAP *map, const MY_BITMAP *map2)
|
||||
{
|
||||
my_bitmap_map *to= map->bitmap, *from= map2->bitmap, *end;
|
||||
|
||||
DBUG_ASSERT(map->bitmap && map2->bitmap &&
|
||||
map->n_bits==map2->n_bits);
|
||||
end= map->last_word_ptr;
|
||||
|
||||
while (to <= end)
|
||||
*to++ |= *from++;
|
||||
}
|
||||
|
||||
|
||||
void bitmap_xor(MY_BITMAP *map, const MY_BITMAP *map2)
|
||||
{
|
||||
my_bitmap_map *to= map->bitmap, *from= map2->bitmap, *end= map->last_word_ptr;
|
||||
DBUG_ASSERT(map->bitmap && map2->bitmap &&
|
||||
map->n_bits==map2->n_bits);
|
||||
while (to <= end)
|
||||
*to++ ^= *from++;
|
||||
}
|
||||
|
||||
|
||||
void bitmap_invert(MY_BITMAP *map)
|
||||
{
|
||||
my_bitmap_map *to= map->bitmap, *end;
|
||||
|
||||
DBUG_ASSERT(map->bitmap);
|
||||
end= map->last_word_ptr;
|
||||
|
||||
while (to <= end)
|
||||
*to++ ^= 0xFFFFFFFF;
|
||||
}
|
||||
|
||||
|
||||
uint bitmap_bits_set(const MY_BITMAP *map)
|
||||
{
|
||||
uchar *m= (uchar*)map->bitmap;
|
||||
uchar *end= m + no_bytes_in_map(map);
|
||||
uint res= 0;
|
||||
|
||||
DBUG_ASSERT(map->bitmap);
|
||||
*map->last_word_ptr&= ~map->last_word_mask; /*Reset last bits to zero*/
|
||||
while (m < end)
|
||||
res+= my_count_bits_ushort(*m++);
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
void bitmap_copy(MY_BITMAP *map, const MY_BITMAP *map2)
|
||||
{
|
||||
my_bitmap_map *to= map->bitmap, *from= map2->bitmap, *end;
|
||||
|
||||
DBUG_ASSERT(map->bitmap && map2->bitmap &&
|
||||
map->n_bits==map2->n_bits);
|
||||
end= map->last_word_ptr;
|
||||
while (to <= end)
|
||||
*to++ = *from++;
|
||||
}
|
||||
|
||||
|
||||
uint bitmap_get_first_set(const MY_BITMAP *map)
|
||||
{
|
||||
uchar *byte_ptr;
|
||||
uint i,j,k;
|
||||
my_bitmap_map *data_ptr, *end= map->last_word_ptr;
|
||||
|
||||
DBUG_ASSERT(map->bitmap);
|
||||
data_ptr= map->bitmap;
|
||||
*map->last_word_ptr &= ~map->last_word_mask;
|
||||
|
||||
for (i=0; data_ptr <= end; data_ptr++, i++)
|
||||
{
|
||||
if (*data_ptr)
|
||||
{
|
||||
byte_ptr= (uchar*)data_ptr;
|
||||
for (j=0; ; j++, byte_ptr++)
|
||||
{
|
||||
if (*byte_ptr)
|
||||
{
|
||||
for (k=0; ; k++)
|
||||
{
|
||||
if (*byte_ptr & (1 << k))
|
||||
return (i*32) + (j*8) + k;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return MY_BIT_NONE;
|
||||
}
|
||||
|
||||
|
||||
uint bitmap_get_first(const MY_BITMAP *map)
|
||||
{
|
||||
uchar *byte_ptr;
|
||||
uint i,j,k;
|
||||
my_bitmap_map *data_ptr, *end= map->last_word_ptr;
|
||||
|
||||
DBUG_ASSERT(map->bitmap);
|
||||
data_ptr= map->bitmap;
|
||||
*map->last_word_ptr|= map->last_word_mask;
|
||||
|
||||
for (i=0; data_ptr <= end; data_ptr++, i++)
|
||||
{
|
||||
if (*data_ptr != 0xFFFFFFFF)
|
||||
{
|
||||
byte_ptr= (uchar*)data_ptr;
|
||||
for (j=0; ; j++, byte_ptr++)
|
||||
{
|
||||
if (*byte_ptr != 0xFF)
|
||||
{
|
||||
for (k=0; ; k++)
|
||||
{
|
||||
if (!(*byte_ptr & (1 << k)))
|
||||
return (i*32) + (j*8) + k;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return MY_BIT_NONE;
|
||||
}
|
||||
|
||||
|
||||
uint bitmap_lock_set_next(MY_BITMAP *map)
|
||||
{
|
||||
uint bit_found;
|
||||
bitmap_lock(map);
|
||||
bit_found= bitmap_set_next(map);
|
||||
bitmap_unlock(map);
|
||||
return bit_found;
|
||||
}
|
||||
|
||||
|
||||
void bitmap_lock_clear_bit(MY_BITMAP *map, uint bitmap_bit)
|
||||
{
|
||||
bitmap_lock(map);
|
||||
DBUG_ASSERT(map->bitmap && bitmap_bit < map->n_bits);
|
||||
bitmap_clear_bit(map, bitmap_bit);
|
||||
bitmap_unlock(map);
|
||||
}
|
||||
|
||||
#ifdef MAIN
|
||||
|
||||
uint get_rand_bit(uint bitsize)
|
||||
{
|
||||
return (rand() % bitsize);
|
||||
}
|
||||
|
||||
bool test_set_get_clear_bit(MY_BITMAP *map, uint bitsize)
|
||||
{
|
||||
uint i, test_bit;
|
||||
uint no_loops= bitsize > 128 ? 128 : bitsize;
|
||||
for (i=0; i < no_loops; i++)
|
||||
{
|
||||
test_bit= get_rand_bit(bitsize);
|
||||
bitmap_set_bit(map, test_bit);
|
||||
if (!bitmap_is_set(map, test_bit))
|
||||
goto error1;
|
||||
bitmap_clear_bit(map, test_bit);
|
||||
if (bitmap_is_set(map, test_bit))
|
||||
goto error2;
|
||||
}
|
||||
return FALSE;
|
||||
error1:
|
||||
printf("Error in set bit, bit %u, bitsize = %u", test_bit, bitsize);
|
||||
return TRUE;
|
||||
error2:
|
||||
printf("Error in clear bit, bit %u, bitsize = %u", test_bit, bitsize);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
bool test_flip_bit(MY_BITMAP *map, uint bitsize)
|
||||
{
|
||||
uint i, test_bit;
|
||||
uint no_loops= bitsize > 128 ? 128 : bitsize;
|
||||
for (i=0; i < no_loops; i++)
|
||||
{
|
||||
test_bit= get_rand_bit(bitsize);
|
||||
bitmap_flip_bit(map, test_bit);
|
||||
if (!bitmap_is_set(map, test_bit))
|
||||
goto error1;
|
||||
bitmap_flip_bit(map, test_bit);
|
||||
if (bitmap_is_set(map, test_bit))
|
||||
goto error2;
|
||||
}
|
||||
return FALSE;
|
||||
error1:
|
||||
printf("Error in flip bit 1, bit %u, bitsize = %u", test_bit, bitsize);
|
||||
return TRUE;
|
||||
error2:
|
||||
printf("Error in flip bit 2, bit %u, bitsize = %u", test_bit, bitsize);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
bool test_operators(MY_BITMAP *map __attribute__((unused)),
|
||||
uint bitsize __attribute__((unused)))
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
bool test_get_all_bits(MY_BITMAP *map, uint bitsize)
|
||||
{
|
||||
uint i;
|
||||
bitmap_set_all(map);
|
||||
if (!bitmap_is_set_all(map))
|
||||
goto error1;
|
||||
if (!bitmap_is_prefix(map, bitsize))
|
||||
goto error5;
|
||||
bitmap_clear_all(map);
|
||||
if (!bitmap_is_clear_all(map))
|
||||
goto error2;
|
||||
if (!bitmap_is_prefix(map, 0))
|
||||
goto error6;
|
||||
for (i=0; i<bitsize;i++)
|
||||
bitmap_set_bit(map, i);
|
||||
if (!bitmap_is_set_all(map))
|
||||
goto error3;
|
||||
for (i=0; i<bitsize;i++)
|
||||
bitmap_clear_bit(map, i);
|
||||
if (!bitmap_is_clear_all(map))
|
||||
goto error4;
|
||||
return FALSE;
|
||||
error1:
|
||||
printf("Error in set_all, bitsize = %u", bitsize);
|
||||
return TRUE;
|
||||
error2:
|
||||
printf("Error in clear_all, bitsize = %u", bitsize);
|
||||
return TRUE;
|
||||
error3:
|
||||
printf("Error in bitmap_is_set_all, bitsize = %u", bitsize);
|
||||
return TRUE;
|
||||
error4:
|
||||
printf("Error in bitmap_is_clear_all, bitsize = %u", bitsize);
|
||||
return TRUE;
|
||||
error5:
|
||||
printf("Error in set_all through set_prefix, bitsize = %u", bitsize);
|
||||
return TRUE;
|
||||
error6:
|
||||
printf("Error in clear_all through set_prefix, bitsize = %u", bitsize);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
bool test_compare_operators(MY_BITMAP *map, uint bitsize)
|
||||
{
|
||||
uint i, j, test_bit1, test_bit2, test_bit3,test_bit4;
|
||||
uint no_loops= bitsize > 128 ? 128 : bitsize;
|
||||
MY_BITMAP map2_obj, map3_obj;
|
||||
MY_BITMAP *map2= &map2_obj, *map3= &map3_obj;
|
||||
my_bitmap_map map2buf[1024];
|
||||
my_bitmap_map map3buf[1024];
|
||||
bitmap_init(&map2_obj, map2buf, bitsize, FALSE);
|
||||
bitmap_init(&map3_obj, map3buf, bitsize, FALSE);
|
||||
bitmap_clear_all(map2);
|
||||
bitmap_clear_all(map3);
|
||||
for (i=0; i < no_loops; i++)
|
||||
{
|
||||
test_bit1=get_rand_bit(bitsize);
|
||||
bitmap_set_prefix(map, test_bit1);
|
||||
test_bit2=get_rand_bit(bitsize);
|
||||
bitmap_set_prefix(map2, test_bit2);
|
||||
bitmap_intersect(map, map2);
|
||||
test_bit3= test_bit2 < test_bit1 ? test_bit2 : test_bit1;
|
||||
bitmap_set_prefix(map3, test_bit3);
|
||||
if (!bitmap_cmp(map, map3))
|
||||
goto error1;
|
||||
bitmap_clear_all(map);
|
||||
bitmap_clear_all(map2);
|
||||
bitmap_clear_all(map3);
|
||||
test_bit1=get_rand_bit(bitsize);
|
||||
test_bit2=get_rand_bit(bitsize);
|
||||
test_bit3=get_rand_bit(bitsize);
|
||||
bitmap_set_prefix(map, test_bit1);
|
||||
bitmap_set_prefix(map2, test_bit2);
|
||||
test_bit3= test_bit2 > test_bit1 ? test_bit2 : test_bit1;
|
||||
bitmap_set_prefix(map3, test_bit3);
|
||||
bitmap_union(map, map2);
|
||||
if (!bitmap_cmp(map, map3))
|
||||
goto error2;
|
||||
bitmap_clear_all(map);
|
||||
bitmap_clear_all(map2);
|
||||
bitmap_clear_all(map3);
|
||||
test_bit1=get_rand_bit(bitsize);
|
||||
test_bit2=get_rand_bit(bitsize);
|
||||
test_bit3=get_rand_bit(bitsize);
|
||||
bitmap_set_prefix(map, test_bit1);
|
||||
bitmap_set_prefix(map2, test_bit2);
|
||||
bitmap_xor(map, map2);
|
||||
test_bit3= test_bit2 > test_bit1 ? test_bit2 : test_bit1;
|
||||
test_bit4= test_bit2 < test_bit1 ? test_bit2 : test_bit1;
|
||||
bitmap_set_prefix(map3, test_bit3);
|
||||
for (j=0; j < test_bit4; j++)
|
||||
bitmap_clear_bit(map3, j);
|
||||
if (!bitmap_cmp(map, map3))
|
||||
goto error3;
|
||||
bitmap_clear_all(map);
|
||||
bitmap_clear_all(map2);
|
||||
bitmap_clear_all(map3);
|
||||
test_bit1=get_rand_bit(bitsize);
|
||||
test_bit2=get_rand_bit(bitsize);
|
||||
test_bit3=get_rand_bit(bitsize);
|
||||
bitmap_set_prefix(map, test_bit1);
|
||||
bitmap_set_prefix(map2, test_bit2);
|
||||
bitmap_subtract(map, map2);
|
||||
if (test_bit2 < test_bit1)
|
||||
{
|
||||
bitmap_set_prefix(map3, test_bit1);
|
||||
for (j=0; j < test_bit2; j++)
|
||||
bitmap_clear_bit(map3, j);
|
||||
}
|
||||
if (!bitmap_cmp(map, map3))
|
||||
goto error4;
|
||||
bitmap_clear_all(map);
|
||||
bitmap_clear_all(map2);
|
||||
bitmap_clear_all(map3);
|
||||
test_bit1=get_rand_bit(bitsize);
|
||||
bitmap_set_prefix(map, test_bit1);
|
||||
bitmap_invert(map);
|
||||
bitmap_set_all(map3);
|
||||
for (j=0; j < test_bit1; j++)
|
||||
bitmap_clear_bit(map3, j);
|
||||
if (!bitmap_cmp(map, map3))
|
||||
goto error5;
|
||||
bitmap_clear_all(map);
|
||||
bitmap_clear_all(map3);
|
||||
}
|
||||
return FALSE;
|
||||
error1:
|
||||
printf("intersect error bitsize=%u,size1=%u,size2=%u", bitsize,
|
||||
test_bit1,test_bit2);
|
||||
return TRUE;
|
||||
error2:
|
||||
printf("union error bitsize=%u,size1=%u,size2=%u", bitsize,
|
||||
test_bit1,test_bit2);
|
||||
return TRUE;
|
||||
error3:
|
||||
printf("xor error bitsize=%u,size1=%u,size2=%u", bitsize,
|
||||
test_bit1,test_bit2);
|
||||
return TRUE;
|
||||
error4:
|
||||
printf("subtract error bitsize=%u,size1=%u,size2=%u", bitsize,
|
||||
test_bit1,test_bit2);
|
||||
return TRUE;
|
||||
error5:
|
||||
printf("invert error bitsize=%u,size=%u", bitsize,
|
||||
test_bit1);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
bool test_count_bits_set(MY_BITMAP *map, uint bitsize)
|
||||
{
|
||||
uint i, bit_count=0, test_bit;
|
||||
uint no_loops= bitsize > 128 ? 128 : bitsize;
|
||||
for (i=0; i < no_loops; i++)
|
||||
{
|
||||
test_bit=get_rand_bit(bitsize);
|
||||
if (!bitmap_is_set(map, test_bit))
|
||||
{
|
||||
bitmap_set_bit(map, test_bit);
|
||||
bit_count++;
|
||||
}
|
||||
}
|
||||
if (bit_count==0 && bitsize > 0)
|
||||
goto error1;
|
||||
if (bitmap_bits_set(map) != bit_count)
|
||||
goto error2;
|
||||
return FALSE;
|
||||
error1:
|
||||
printf("No bits set bitsize = %u", bitsize);
|
||||
return TRUE;
|
||||
error2:
|
||||
printf("Wrong count of bits set, bitsize = %u", bitsize);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
bool test_get_first_bit(MY_BITMAP *map, uint bitsize)
|
||||
{
|
||||
uint i, test_bit;
|
||||
uint no_loops= bitsize > 128 ? 128 : bitsize;
|
||||
for (i=0; i < no_loops; i++)
|
||||
{
|
||||
test_bit=get_rand_bit(bitsize);
|
||||
bitmap_set_bit(map, test_bit);
|
||||
if (bitmap_get_first_set(map) != test_bit)
|
||||
goto error1;
|
||||
bitmap_set_all(map);
|
||||
bitmap_clear_bit(map, test_bit);
|
||||
if (bitmap_get_first(map) != test_bit)
|
||||
goto error2;
|
||||
bitmap_clear_all(map);
|
||||
}
|
||||
return FALSE;
|
||||
error1:
|
||||
printf("get_first_set error bitsize=%u,prefix_size=%u",bitsize,test_bit);
|
||||
return TRUE;
|
||||
error2:
|
||||
printf("get_first error bitsize= %u, prefix_size= %u",bitsize,test_bit);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
bool test_get_next_bit(MY_BITMAP *map, uint bitsize)
|
||||
{
|
||||
uint i, j, test_bit;
|
||||
uint no_loops= bitsize > 128 ? 128 : bitsize;
|
||||
for (i=0; i < no_loops; i++)
|
||||
{
|
||||
test_bit=get_rand_bit(bitsize);
|
||||
for (j=0; j < test_bit; j++)
|
||||
bitmap_set_next(map);
|
||||
if (!bitmap_is_prefix(map, test_bit))
|
||||
goto error1;
|
||||
bitmap_clear_all(map);
|
||||
}
|
||||
return FALSE;
|
||||
error1:
|
||||
printf("get_next error bitsize= %u, prefix_size= %u", bitsize,test_bit);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
bool test_prefix(MY_BITMAP *map, uint bitsize)
|
||||
{
|
||||
uint i, j, test_bit;
|
||||
uint no_loops= bitsize > 128 ? 128 : bitsize;
|
||||
for (i=0; i < no_loops; i++)
|
||||
{
|
||||
test_bit=get_rand_bit(bitsize);
|
||||
bitmap_set_prefix(map, test_bit);
|
||||
if (!bitmap_is_prefix(map, test_bit))
|
||||
goto error1;
|
||||
bitmap_clear_all(map);
|
||||
for (j=0; j < test_bit; j++)
|
||||
bitmap_set_bit(map, j);
|
||||
if (!bitmap_is_prefix(map, test_bit))
|
||||
goto error2;
|
||||
bitmap_set_all(map);
|
||||
for (j=bitsize - 1; ~(j-test_bit); j--)
|
||||
bitmap_clear_bit(map, j);
|
||||
if (!bitmap_is_prefix(map, test_bit))
|
||||
goto error3;
|
||||
bitmap_clear_all(map);
|
||||
}
|
||||
return FALSE;
|
||||
error1:
|
||||
printf("prefix1 error bitsize = %u, prefix_size = %u", bitsize,test_bit);
|
||||
return TRUE;
|
||||
error2:
|
||||
printf("prefix2 error bitsize = %u, prefix_size = %u", bitsize,test_bit);
|
||||
return TRUE;
|
||||
error3:
|
||||
printf("prefix3 error bitsize = %u, prefix_size = %u", bitsize,test_bit);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
bool do_test(uint bitsize)
|
||||
{
|
||||
MY_BITMAP map;
|
||||
my_bitmap_map buf[1024];
|
||||
if (bitmap_init(&map, buf, bitsize, FALSE))
|
||||
{
|
||||
printf("init error for bitsize %d", bitsize);
|
||||
goto error;
|
||||
}
|
||||
if (test_set_get_clear_bit(&map,bitsize))
|
||||
goto error;
|
||||
bitmap_clear_all(&map);
|
||||
if (test_flip_bit(&map,bitsize))
|
||||
goto error;
|
||||
bitmap_clear_all(&map);
|
||||
if (test_operators(&map,bitsize))
|
||||
goto error;
|
||||
bitmap_clear_all(&map);
|
||||
if (test_get_all_bits(&map, bitsize))
|
||||
goto error;
|
||||
bitmap_clear_all(&map);
|
||||
if (test_compare_operators(&map,bitsize))
|
||||
goto error;
|
||||
bitmap_clear_all(&map);
|
||||
if (test_count_bits_set(&map,bitsize))
|
||||
goto error;
|
||||
bitmap_clear_all(&map);
|
||||
if (test_get_first_bit(&map,bitsize))
|
||||
goto error;
|
||||
bitmap_clear_all(&map);
|
||||
if (test_get_next_bit(&map,bitsize))
|
||||
goto error;
|
||||
if (test_prefix(&map,bitsize))
|
||||
goto error;
|
||||
return FALSE;
|
||||
error:
|
||||
printf("\n");
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
int i;
|
||||
for (i= 1; i < 4096; i++)
|
||||
{
|
||||
printf("Start test for bitsize=%u\n",i);
|
||||
if (do_test(i))
|
||||
return -1;
|
||||
}
|
||||
printf("OK\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
In directory mysys:
|
||||
make test_bitmap
|
||||
will build the bitmap tests and ./test_bitmap will execute it
|
||||
*/
|
||||
|
||||
#endif
|
||||
107
deps/mysqllite/mysys/my_chsize.c
vendored
Normal file
107
deps/mysqllite/mysys/my_chsize.c
vendored
Normal file
@@ -0,0 +1,107 @@
|
||||
/* Copyright (C) 2000 MySQL AB
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
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 */
|
||||
|
||||
#include "mysys_priv.h"
|
||||
#include "mysys_err.h"
|
||||
#include "m_string.h"
|
||||
|
||||
/*
|
||||
Change size of file.
|
||||
|
||||
SYNOPSIS
|
||||
my_chsize()
|
||||
fd File descriptor
|
||||
new_length New file size
|
||||
filler If we don't have truncate, fill up all bytes after
|
||||
new_length with this character
|
||||
MyFlags Flags
|
||||
|
||||
DESCRIPTION
|
||||
my_chsize() truncates file if shorter else fill with the filler character.
|
||||
The function also changes the file pointer. Usually it points to the end
|
||||
of the file after execution.
|
||||
|
||||
RETURN VALUE
|
||||
0 Ok
|
||||
1 Error
|
||||
*/
|
||||
int my_chsize(File fd, my_off_t newlength, int filler, myf MyFlags)
|
||||
{
|
||||
my_off_t oldsize;
|
||||
uchar buff[IO_SIZE];
|
||||
DBUG_ENTER("my_chsize");
|
||||
DBUG_PRINT("my",("fd: %d length: %lu MyFlags: %d",fd,(ulong) newlength,
|
||||
MyFlags));
|
||||
|
||||
if ((oldsize= my_seek(fd, 0L, MY_SEEK_END, MYF(MY_WME+MY_FAE))) == newlength)
|
||||
DBUG_RETURN(0);
|
||||
|
||||
DBUG_PRINT("info",("old_size: %ld", (ulong) oldsize));
|
||||
|
||||
if (oldsize > newlength)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
if (my_win_chsize(fd, newlength))
|
||||
{
|
||||
my_errno= errno;
|
||||
goto err;
|
||||
}
|
||||
DBUG_RETURN(0);
|
||||
#elif defined(HAVE_FTRUNCATE)
|
||||
if (ftruncate(fd, (off_t) newlength))
|
||||
{
|
||||
my_errno= errno;
|
||||
goto err;
|
||||
}
|
||||
DBUG_RETURN(0);
|
||||
#elif defined(HAVE_CHSIZE)
|
||||
if (chsize(fd, (off_t) newlength))
|
||||
{
|
||||
my_errno=errno;
|
||||
goto err;
|
||||
}
|
||||
DBUG_RETURN(0);
|
||||
#else
|
||||
/*
|
||||
Fill space between requested length and true length with 'filler'
|
||||
We should never come here on any modern machine
|
||||
*/
|
||||
if (my_seek(fd, newlength, MY_SEEK_SET, MYF(MY_WME+MY_FAE))
|
||||
== MY_FILEPOS_ERROR)
|
||||
{
|
||||
goto err;
|
||||
}
|
||||
swap_variables(my_off_t, newlength, oldsize);
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Full file with 'filler' until it's as big as requested */
|
||||
bfill(buff, IO_SIZE, filler);
|
||||
while (newlength-oldsize > IO_SIZE)
|
||||
{
|
||||
if (my_write(fd, buff, IO_SIZE, MYF(MY_NABP)))
|
||||
goto err;
|
||||
oldsize+= IO_SIZE;
|
||||
}
|
||||
if (my_write(fd,buff,(size_t) (newlength-oldsize), MYF(MY_NABP)))
|
||||
goto err;
|
||||
DBUG_RETURN(0);
|
||||
|
||||
err:
|
||||
DBUG_PRINT("error", ("errno: %d", errno));
|
||||
if (MyFlags & MY_WME)
|
||||
my_error(EE_CANT_CHSIZE, MYF(ME_BELL+ME_WAITTANG), my_errno);
|
||||
DBUG_RETURN(1);
|
||||
} /* my_chsize */
|
||||
264
deps/mysqllite/mysys/my_compress.c
vendored
Normal file
264
deps/mysqllite/mysys/my_compress.c
vendored
Normal file
@@ -0,0 +1,264 @@
|
||||
/* Copyright (C) 2000 MySQL AB
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
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 */
|
||||
|
||||
/* Written by Sinisa Milivojevic <sinisa@mysql.com> */
|
||||
|
||||
#include <my_global.h>
|
||||
#ifdef HAVE_COMPRESS
|
||||
#include <my_sys.h>
|
||||
#ifndef SCO
|
||||
#include <m_string.h>
|
||||
#endif
|
||||
#include <zlib.h>
|
||||
|
||||
/*
|
||||
This replaces the packet with a compressed packet
|
||||
|
||||
SYNOPSIS
|
||||
my_compress()
|
||||
packet Data to compress. This is is replaced with the compressed data.
|
||||
len Length of data to compress at 'packet'
|
||||
complen out: 0 if packet was not compressed
|
||||
|
||||
RETURN
|
||||
1 error. 'len' is not changed'
|
||||
0 ok. In this case 'len' contains the size of the compressed packet
|
||||
*/
|
||||
|
||||
my_bool my_compress(uchar *packet, size_t *len, size_t *complen)
|
||||
{
|
||||
DBUG_ENTER("my_compress");
|
||||
if (*len < MIN_COMPRESS_LENGTH)
|
||||
{
|
||||
*complen=0;
|
||||
DBUG_PRINT("note",("Packet too short: Not compressed"));
|
||||
}
|
||||
else
|
||||
{
|
||||
uchar *compbuf=my_compress_alloc(packet,len,complen);
|
||||
if (!compbuf)
|
||||
DBUG_RETURN(*complen ? 0 : 1);
|
||||
memcpy(packet,compbuf,*len);
|
||||
my_free(compbuf);
|
||||
}
|
||||
DBUG_RETURN(0);
|
||||
}
|
||||
|
||||
|
||||
uchar *my_compress_alloc(const uchar *packet, size_t *len, size_t *complen)
|
||||
{
|
||||
uchar *compbuf;
|
||||
uLongf tmp_complen;
|
||||
int res;
|
||||
*complen= *len * 120 / 100 + 12;
|
||||
|
||||
if (!(compbuf= (uchar *) my_malloc(*complen, MYF(MY_WME))))
|
||||
return 0; /* Not enough memory */
|
||||
|
||||
tmp_complen= (uint) *complen;
|
||||
res= compress((Bytef*) compbuf, &tmp_complen, (Bytef*) packet, (uLong) *len);
|
||||
*complen= tmp_complen;
|
||||
|
||||
if (res != Z_OK)
|
||||
{
|
||||
my_free(compbuf);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (*complen >= *len)
|
||||
{
|
||||
*complen= 0;
|
||||
my_free(compbuf);
|
||||
DBUG_PRINT("note",("Packet got longer on compression; Not compressed"));
|
||||
return 0;
|
||||
}
|
||||
/* Store length of compressed packet in *len */
|
||||
swap_variables(size_t, *len, *complen);
|
||||
return compbuf;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Uncompress packet
|
||||
|
||||
SYNOPSIS
|
||||
my_uncompress()
|
||||
packet Compressed data. This is is replaced with the orignal data.
|
||||
len Length of compressed data
|
||||
complen Length of the packet buffer (must be enough for the original
|
||||
data)
|
||||
|
||||
RETURN
|
||||
1 error
|
||||
0 ok. In this case 'complen' contains the updated size of the
|
||||
real data.
|
||||
*/
|
||||
|
||||
my_bool my_uncompress(uchar *packet, size_t len, size_t *complen)
|
||||
{
|
||||
uLongf tmp_complen;
|
||||
DBUG_ENTER("my_uncompress");
|
||||
|
||||
if (*complen) /* If compressed */
|
||||
{
|
||||
uchar *compbuf= (uchar *) my_malloc(*complen,MYF(MY_WME));
|
||||
int error;
|
||||
if (!compbuf)
|
||||
DBUG_RETURN(1); /* Not enough memory */
|
||||
|
||||
tmp_complen= (uint) *complen;
|
||||
error= uncompress((Bytef*) compbuf, &tmp_complen, (Bytef*) packet,
|
||||
(uLong) len);
|
||||
*complen= tmp_complen;
|
||||
if (error != Z_OK)
|
||||
{ /* Probably wrong packet */
|
||||
DBUG_PRINT("error",("Can't uncompress packet, error: %d",error));
|
||||
my_free(compbuf);
|
||||
DBUG_RETURN(1);
|
||||
}
|
||||
memcpy(packet, compbuf, *complen);
|
||||
my_free(compbuf);
|
||||
}
|
||||
else
|
||||
*complen= len;
|
||||
DBUG_RETURN(0);
|
||||
}
|
||||
|
||||
/*
|
||||
Internal representation of the frm blob is:
|
||||
|
||||
ver 4 bytes
|
||||
orglen 4 bytes
|
||||
complen 4 bytes
|
||||
*/
|
||||
|
||||
#define BLOB_HEADER 12
|
||||
|
||||
|
||||
/*
|
||||
packfrm is a method used to compress the frm file for storage in a
|
||||
handler. This method was developed for the NDB handler and has been moved
|
||||
here to serve also other uses.
|
||||
|
||||
SYNOPSIS
|
||||
packfrm()
|
||||
data Data reference to frm file data.
|
||||
len Length of frm file data
|
||||
out:pack_data Reference to the pointer to the packed frm data
|
||||
out:pack_len Length of packed frm file data
|
||||
|
||||
NOTES
|
||||
data is replaced with compressed content
|
||||
|
||||
RETURN VALUES
|
||||
0 Success
|
||||
>0 Failure
|
||||
*/
|
||||
|
||||
int packfrm(uchar *data, size_t len,
|
||||
uchar **pack_data, size_t *pack_len)
|
||||
{
|
||||
int error;
|
||||
size_t org_len, comp_len, blob_len;
|
||||
uchar *blob;
|
||||
DBUG_ENTER("packfrm");
|
||||
DBUG_PRINT("enter", ("data: 0x%lx len: %lu", (long) data, (ulong) len));
|
||||
|
||||
error= 1;
|
||||
org_len= len;
|
||||
if (my_compress((uchar*)data, &org_len, &comp_len))
|
||||
goto err;
|
||||
|
||||
DBUG_PRINT("info", ("org_len: %lu comp_len: %lu", (ulong) org_len,
|
||||
(ulong) comp_len));
|
||||
DBUG_DUMP("compressed", data, org_len);
|
||||
|
||||
error= 2;
|
||||
blob_len= BLOB_HEADER + org_len;
|
||||
if (!(blob= (uchar*) my_malloc(blob_len,MYF(MY_WME))))
|
||||
goto err;
|
||||
|
||||
/* Store compressed blob in machine independent format */
|
||||
int4store(blob, 1);
|
||||
int4store(blob+4, (uint32) len);
|
||||
int4store(blob+8, (uint32) org_len); /* compressed length */
|
||||
|
||||
/* Copy frm data into blob, already in machine independent format */
|
||||
memcpy(blob+BLOB_HEADER, data, org_len);
|
||||
|
||||
*pack_data= blob;
|
||||
*pack_len= blob_len;
|
||||
error= 0;
|
||||
|
||||
DBUG_PRINT("exit", ("pack_data: 0x%lx pack_len: %lu",
|
||||
(long) *pack_data, (ulong) *pack_len));
|
||||
err:
|
||||
DBUG_RETURN(error);
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
unpackfrm is a method used to decompress the frm file received from a
|
||||
handler. This method was developed for the NDB handler and has been moved
|
||||
here to serve also other uses for other clustered storage engines.
|
||||
|
||||
SYNOPSIS
|
||||
unpackfrm()
|
||||
pack_data Data reference to packed frm file data
|
||||
out:unpack_data Reference to the pointer to the unpacked frm data
|
||||
out:unpack_len Length of unpacked frm file data
|
||||
|
||||
RETURN VALUES¨
|
||||
0 Success
|
||||
>0 Failure
|
||||
*/
|
||||
|
||||
int unpackfrm(uchar **unpack_data, size_t *unpack_len,
|
||||
const uchar *pack_data)
|
||||
{
|
||||
uchar *data;
|
||||
size_t complen, orglen;
|
||||
ulong ver;
|
||||
DBUG_ENTER("unpackfrm");
|
||||
DBUG_PRINT("enter", ("pack_data: 0x%lx", (long) pack_data));
|
||||
|
||||
ver= uint4korr(pack_data);
|
||||
orglen= uint4korr(pack_data+4);
|
||||
complen= uint4korr(pack_data+8);
|
||||
|
||||
DBUG_PRINT("blob",("ver: %lu complen: %lu orglen: %lu",
|
||||
ver, (ulong) complen, (ulong) orglen));
|
||||
DBUG_DUMP("blob->data", pack_data + BLOB_HEADER, complen);
|
||||
|
||||
if (ver != 1)
|
||||
DBUG_RETURN(1);
|
||||
if (!(data= my_malloc(max(orglen, complen), MYF(MY_WME))))
|
||||
DBUG_RETURN(2);
|
||||
memcpy(data, pack_data + BLOB_HEADER, complen);
|
||||
|
||||
if (my_uncompress(data, complen, &orglen))
|
||||
{
|
||||
my_free(data);
|
||||
DBUG_RETURN(3);
|
||||
}
|
||||
|
||||
*unpack_data= data;
|
||||
*unpack_len= orglen;
|
||||
|
||||
DBUG_PRINT("exit", ("frmdata: 0x%lx len: %lu", (long) *unpack_data,
|
||||
(ulong) *unpack_len));
|
||||
DBUG_RETURN(0);
|
||||
}
|
||||
#endif /* HAVE_COMPRESS */
|
||||
222
deps/mysqllite/mysys/my_conio.c
vendored
Normal file
222
deps/mysqllite/mysys/my_conio.c
vendored
Normal file
@@ -0,0 +1,222 @@
|
||||
/* Copyright (C) 2000 MySQL AB
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
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 */
|
||||
|
||||
|
||||
#include "mysys_priv.h"
|
||||
|
||||
#ifdef __WIN__
|
||||
|
||||
static HANDLE my_coninpfh= 0; /* console input */
|
||||
|
||||
/*
|
||||
functions my_pthread_auto_mutex_lock & my_pthread_auto_mutex_free
|
||||
are experimental at this moment, they are intended to bring
|
||||
ability of protecting code sections without necessity to explicitly
|
||||
initialize synchronization object in one of threads
|
||||
|
||||
if found useful they are to be exported in mysys
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
int my_pthread_auto_mutex_lock(HANDLE* ph, const char* name,
|
||||
int id, int time)
|
||||
NOTES
|
||||
creates a mutex with given name and tries to lock it time msec.
|
||||
mutex name is appended with id to allow system wide or process wide
|
||||
locks. Handle to created mutex returned in ph argument.
|
||||
|
||||
RETURN
|
||||
0 thread owns mutex
|
||||
<>0 error
|
||||
*/
|
||||
|
||||
static
|
||||
int my_pthread_auto_mutex_lock(HANDLE* ph, const char* name, int id, int time)
|
||||
{
|
||||
int res;
|
||||
char tname[FN_REFLEN];
|
||||
|
||||
sprintf(tname, "%s-%08X", name, id);
|
||||
|
||||
*ph= CreateMutex(NULL, FALSE, tname);
|
||||
if (*ph == NULL)
|
||||
return GetLastError();
|
||||
|
||||
res= WaitForSingleObject(*ph, time);
|
||||
|
||||
if (res == WAIT_TIMEOUT)
|
||||
return ERROR_SEM_TIMEOUT;
|
||||
|
||||
if (res == WAIT_FAILED)
|
||||
return GetLastError();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
int my_pthread_auto_mutex_free(HANDLE* ph)
|
||||
|
||||
NOTES
|
||||
releases a mutex.
|
||||
|
||||
RETURN
|
||||
0 thread released mutex
|
||||
<>0 error
|
||||
|
||||
*/
|
||||
static
|
||||
int my_pthread_auto_mutex_free(HANDLE* ph)
|
||||
{
|
||||
if (*ph)
|
||||
{
|
||||
ReleaseMutex(*ph);
|
||||
CloseHandle(*ph);
|
||||
*ph= NULL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
#define pthread_auto_mutex_decl(name) \
|
||||
HANDLE __h##name= NULL;
|
||||
|
||||
#define pthread_auto_mutex_lock(name, proc, time) \
|
||||
my_pthread_auto_mutex_lock(&__h##name, #name, (proc), (time))
|
||||
|
||||
#define pthread_auto_mutex_free(name) \
|
||||
my_pthread_auto_mutex_free(&__h##name)
|
||||
|
||||
|
||||
/*
|
||||
char* my_cgets()
|
||||
|
||||
NOTES
|
||||
Replaces _cgets from libc to support input of more than 255 chars.
|
||||
Reads from the console via ReadConsole into buffer which
|
||||
should be at least clen characters.
|
||||
Actual length of string returned in plen.
|
||||
|
||||
WARNING
|
||||
my_cgets() does NOT check the pushback character buffer (i.e., _chbuf).
|
||||
Thus, my_cgets() will not return any character that is pushed back by
|
||||
the _ungetch() call.
|
||||
|
||||
RETURN
|
||||
string pointer ok
|
||||
NULL Error
|
||||
|
||||
*/
|
||||
|
||||
char* my_cgets(char *buffer, size_t clen, size_t* plen)
|
||||
{
|
||||
ULONG state;
|
||||
char *result;
|
||||
DWORD plen_res;
|
||||
CONSOLE_SCREEN_BUFFER_INFO csbi;
|
||||
|
||||
pthread_auto_mutex_decl(my_conio_cs);
|
||||
|
||||
/* lock the console for the current process*/
|
||||
if (pthread_auto_mutex_lock(my_conio_cs, GetCurrentProcessId(), INFINITE))
|
||||
{
|
||||
/* can not lock console */
|
||||
pthread_auto_mutex_free(my_conio_cs);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* init console input */
|
||||
if (my_coninpfh == 0)
|
||||
{
|
||||
/* same handle will be used until process termination */
|
||||
my_coninpfh= CreateFile("CONIN$", GENERIC_READ | GENERIC_WRITE,
|
||||
FILE_SHARE_READ | FILE_SHARE_WRITE,
|
||||
NULL, OPEN_EXISTING, 0, NULL);
|
||||
}
|
||||
|
||||
if (my_coninpfh == INVALID_HANDLE_VALUE)
|
||||
{
|
||||
/* unlock the console */
|
||||
pthread_auto_mutex_free(my_conio_cs);
|
||||
return(NULL);
|
||||
}
|
||||
|
||||
GetConsoleMode((HANDLE)my_coninpfh, &state);
|
||||
SetConsoleMode((HANDLE)my_coninpfh, ENABLE_LINE_INPUT |
|
||||
ENABLE_PROCESSED_INPUT | ENABLE_ECHO_INPUT);
|
||||
|
||||
GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &csbi);
|
||||
|
||||
/*
|
||||
there is no known way to determine allowed buffer size for input
|
||||
though it is known it should not be more than 64K
|
||||
so we cut 64K and try first size of screen buffer
|
||||
if it is still to large we cut half of it and try again
|
||||
later we may want to cycle from min(clen, 65535) to allowed size
|
||||
with small decrement to determine exact allowed buffer
|
||||
*/
|
||||
clen= min(clen, 65535);
|
||||
do
|
||||
{
|
||||
clen= min(clen, (size_t) csbi.dwSize.X*csbi.dwSize.Y);
|
||||
if (!ReadConsole((HANDLE)my_coninpfh, (LPVOID)buffer, (DWORD) clen - 1, &plen_res,
|
||||
NULL))
|
||||
{
|
||||
result= NULL;
|
||||
clen>>= 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
result= buffer;
|
||||
break;
|
||||
}
|
||||
}
|
||||
while (GetLastError() == ERROR_NOT_ENOUGH_MEMORY);
|
||||
*plen= plen_res;
|
||||
|
||||
/* We go here on error reading the string (Ctrl-C for example) */
|
||||
if (!*plen)
|
||||
result= NULL; /* purecov: inspected */
|
||||
|
||||
if (result != NULL)
|
||||
{
|
||||
if (*plen > 1 && buffer[*plen - 2] == '\r')
|
||||
{
|
||||
*plen= *plen - 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (*plen > 0 && buffer[*plen - 1] == '\r')
|
||||
{
|
||||
char tmp[3];
|
||||
int tmplen= sizeof(tmp);
|
||||
|
||||
*plen= *plen - 1;
|
||||
/* read /n left in the buffer */
|
||||
ReadConsole((HANDLE)my_coninpfh, (LPVOID)tmp, tmplen, &tmplen, NULL);
|
||||
}
|
||||
}
|
||||
buffer[*plen]= '\0';
|
||||
}
|
||||
|
||||
SetConsoleMode((HANDLE)my_coninpfh, state);
|
||||
/* unlock the console */
|
||||
pthread_auto_mutex_free(my_conio_cs);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
#endif /* __WIN__ */
|
||||
144
deps/mysqllite/mysys/my_copy.c
vendored
Normal file
144
deps/mysqllite/mysys/my_copy.c
vendored
Normal file
@@ -0,0 +1,144 @@
|
||||
/* Copyright (C) 2000 MySQL AB
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
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 */
|
||||
|
||||
#include "mysys_priv.h"
|
||||
#include <my_dir.h> /* for stat */
|
||||
#include <m_string.h>
|
||||
#include "mysys_err.h"
|
||||
#if defined(HAVE_UTIME_H)
|
||||
#include <utime.h>
|
||||
#elif defined(HAVE_SYS_UTIME_H)
|
||||
#include <sys/utime.h>
|
||||
#elif !defined(HPUX10)
|
||||
#include <time.h>
|
||||
struct utimbuf {
|
||||
time_t actime;
|
||||
time_t modtime;
|
||||
};
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
int my_copy(const char *from, const char *to, myf MyFlags)
|
||||
|
||||
NOTES
|
||||
Ordinary ownership and accesstimes are copied from 'from-file'
|
||||
If MyFlags & MY_HOLD_ORIGINAL_MODES is set and to-file exists then
|
||||
the modes of to-file isn't changed
|
||||
If MyFlags & MY_DONT_OVERWRITE_FILE is set, we will give an error
|
||||
if the file existed.
|
||||
|
||||
WARNING
|
||||
Don't set MY_FNABP or MY_NABP bits on when calling this function !
|
||||
|
||||
RETURN
|
||||
0 ok
|
||||
# Error
|
||||
|
||||
*/
|
||||
|
||||
int my_copy(const char *from, const char *to, myf MyFlags)
|
||||
{
|
||||
size_t Count;
|
||||
my_bool new_file_stat= 0; /* 1 if we could stat "to" */
|
||||
int create_flag;
|
||||
File from_file,to_file;
|
||||
uchar buff[IO_SIZE];
|
||||
MY_STAT stat_buff,new_stat_buff;
|
||||
DBUG_ENTER("my_copy");
|
||||
DBUG_PRINT("my",("from %s to %s MyFlags %d", from, to, MyFlags));
|
||||
|
||||
from_file=to_file= -1;
|
||||
DBUG_ASSERT(!(MyFlags & (MY_FNABP | MY_NABP))); /* for my_read/my_write */
|
||||
if (MyFlags & MY_HOLD_ORIGINAL_MODES) /* Copy stat if possible */
|
||||
new_file_stat= test(my_stat((char*) to, &new_stat_buff, MYF(0)));
|
||||
|
||||
if ((from_file=my_open(from,O_RDONLY | O_SHARE,MyFlags)) >= 0)
|
||||
{
|
||||
if (!my_stat(from, &stat_buff, MyFlags))
|
||||
{
|
||||
my_errno=errno;
|
||||
goto err;
|
||||
}
|
||||
if (MyFlags & MY_HOLD_ORIGINAL_MODES && new_file_stat)
|
||||
stat_buff=new_stat_buff;
|
||||
create_flag= (MyFlags & MY_DONT_OVERWRITE_FILE) ? O_EXCL : O_TRUNC;
|
||||
|
||||
if ((to_file= my_create(to,(int) stat_buff.st_mode,
|
||||
O_WRONLY | create_flag | O_BINARY | O_SHARE,
|
||||
MyFlags)) < 0)
|
||||
goto err;
|
||||
|
||||
while ((Count=my_read(from_file, buff, sizeof(buff), MyFlags)) != 0)
|
||||
{
|
||||
if (Count == (uint) -1 ||
|
||||
my_write(to_file,buff,Count,MYF(MyFlags | MY_NABP)))
|
||||
goto err;
|
||||
}
|
||||
|
||||
/* sync the destination file */
|
||||
if (MyFlags & MY_SYNC)
|
||||
{
|
||||
if (my_sync(to_file, MyFlags))
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (my_close(from_file,MyFlags) | my_close(to_file,MyFlags))
|
||||
DBUG_RETURN(-1); /* Error on close */
|
||||
|
||||
/* Copy modes if possible */
|
||||
|
||||
if (MyFlags & MY_HOLD_ORIGINAL_MODES && !new_file_stat)
|
||||
DBUG_RETURN(0); /* File copyed but not stat */
|
||||
/* Copy modes */
|
||||
if (chmod(to, stat_buff.st_mode & 07777))
|
||||
{
|
||||
my_errno= errno;
|
||||
if (MyFlags & (MY_FAE+MY_WME))
|
||||
my_error(EE_CHANGE_PERMISSIONS, MYF(ME_BELL+ME_WAITTANG), from, errno);
|
||||
goto err;
|
||||
}
|
||||
#if !defined(__WIN__)
|
||||
/* Copy ownership */
|
||||
if (chown(to, stat_buff.st_uid, stat_buff.st_gid))
|
||||
{
|
||||
my_errno= errno;
|
||||
if (MyFlags & (MY_FAE+MY_WME))
|
||||
my_error(EE_CHANGE_OWNERSHIP, MYF(ME_BELL+ME_WAITTANG), from, errno);
|
||||
goto err;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (MyFlags & MY_COPYTIME)
|
||||
{
|
||||
struct utimbuf timep;
|
||||
timep.actime = stat_buff.st_atime;
|
||||
timep.modtime = stat_buff.st_mtime;
|
||||
(void) utime((char*) to, &timep); /* last accessed and modified times */
|
||||
}
|
||||
|
||||
DBUG_RETURN(0);
|
||||
}
|
||||
|
||||
err:
|
||||
if (from_file >= 0) (void) my_close(from_file,MyFlags);
|
||||
if (to_file >= 0)
|
||||
{
|
||||
(void) my_close(to_file, MyFlags);
|
||||
/* attempt to delete the to-file we've partially written */
|
||||
(void) my_delete(to, MyFlags);
|
||||
}
|
||||
DBUG_RETURN(-1);
|
||||
} /* my_copy */
|
||||
73
deps/mysqllite/mysys/my_create.c
vendored
Normal file
73
deps/mysqllite/mysys/my_create.c
vendored
Normal file
@@ -0,0 +1,73 @@
|
||||
/* Copyright (C) 2000 MySQL AB
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
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 */
|
||||
|
||||
#include "mysys_priv.h"
|
||||
#include <my_dir.h>
|
||||
#include "mysys_err.h"
|
||||
#include <errno.h>
|
||||
#include <my_sys.h>
|
||||
#if defined(_WIN32)
|
||||
#include <share.h>
|
||||
#endif
|
||||
|
||||
/*
|
||||
** Create a new file
|
||||
** Arguments:
|
||||
** Path-name of file
|
||||
** Read | write on file (umask value)
|
||||
** Read & Write on open file
|
||||
** Special flags
|
||||
*/
|
||||
|
||||
|
||||
File my_create(const char *FileName, int CreateFlags, int access_flags,
|
||||
myf MyFlags)
|
||||
{
|
||||
int fd, rc;
|
||||
DBUG_ENTER("my_create");
|
||||
DBUG_PRINT("my",("Name: '%s' CreateFlags: %d AccessFlags: %d MyFlags: %d",
|
||||
FileName, CreateFlags, access_flags, MyFlags));
|
||||
#if defined(_WIN32)
|
||||
fd= my_win_open(FileName, access_flags | O_CREAT);
|
||||
#else
|
||||
fd= open((char *) FileName, access_flags | O_CREAT,
|
||||
CreateFlags ? CreateFlags : my_umask);
|
||||
#endif
|
||||
|
||||
if ((MyFlags & MY_SYNC_DIR) && (fd >=0) &&
|
||||
my_sync_dir_by_file(FileName, MyFlags))
|
||||
{
|
||||
my_close(fd, MyFlags);
|
||||
fd= -1;
|
||||
}
|
||||
|
||||
rc= my_register_filename(fd, FileName, FILE_BY_CREATE,
|
||||
EE_CANTCREATEFILE, MyFlags);
|
||||
/*
|
||||
my_register_filename() may fail on some platforms even if the call to
|
||||
*open() above succeeds. In this case, don't leave the stale file because
|
||||
callers assume the file to not exist if my_create() fails, so they don't
|
||||
do any cleanups.
|
||||
*/
|
||||
if (unlikely(fd >= 0 && rc < 0))
|
||||
{
|
||||
int tmp= my_errno;
|
||||
my_close(fd, MyFlags);
|
||||
my_delete(FileName, MyFlags);
|
||||
my_errno= tmp;
|
||||
}
|
||||
|
||||
DBUG_RETURN(rc);
|
||||
} /* my_create */
|
||||
125
deps/mysqllite/mysys/my_delete.c
vendored
Normal file
125
deps/mysqllite/mysys/my_delete.c
vendored
Normal file
@@ -0,0 +1,125 @@
|
||||
/* Copyright (C) 2000 MySQL AB
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
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 */
|
||||
|
||||
#include "mysys_priv.h"
|
||||
#include "mysys_err.h"
|
||||
#include <my_sys.h>
|
||||
|
||||
int my_delete(const char *name, myf MyFlags)
|
||||
{
|
||||
int err;
|
||||
DBUG_ENTER("my_delete");
|
||||
DBUG_PRINT("my",("name %s MyFlags %d", name, MyFlags));
|
||||
|
||||
if ((err = unlink(name)) == -1)
|
||||
{
|
||||
my_errno=errno;
|
||||
if (MyFlags & (MY_FAE+MY_WME))
|
||||
my_error(EE_DELETE,MYF(ME_BELL+ME_WAITTANG+(MyFlags & ME_NOINPUT)),
|
||||
name,errno);
|
||||
}
|
||||
else if ((MyFlags & MY_SYNC_DIR) &&
|
||||
my_sync_dir_by_file(name, MyFlags))
|
||||
err= -1;
|
||||
DBUG_RETURN(err);
|
||||
} /* my_delete */
|
||||
|
||||
#if defined(__WIN__)
|
||||
/**
|
||||
Delete file which is possibly not closed.
|
||||
|
||||
This function is intended to be used exclusively as a temporal solution
|
||||
for Win NT in case when it is needed to delete a not closed file (note
|
||||
that the file must be opened everywhere with FILE_SHARE_DELETE mode).
|
||||
Deleting not-closed files can not be supported on Win 98|ME (and because
|
||||
of that is considered harmful).
|
||||
|
||||
The function deletes the file with its preliminary renaming. This is
|
||||
because when not-closed share-delete file is deleted it still lives on
|
||||
a disk until it will not be closed everwhere. This may conflict with an
|
||||
attempt to create a new file with the same name. The deleted file is
|
||||
renamed to <name>.<num>.deleted where <name> - the initial name of the
|
||||
file, <num> - a hexadecimal number chosen to make the temporal name to
|
||||
be unique.
|
||||
|
||||
@param the name of the being deleted file
|
||||
@param the flags instructing how to react on an error internally in
|
||||
the function
|
||||
|
||||
@note The per-thread @c my_errno holds additional info for a caller to
|
||||
decide how critical the error can be.
|
||||
|
||||
@retval
|
||||
0 ok
|
||||
@retval
|
||||
1 error
|
||||
|
||||
|
||||
*/
|
||||
int nt_share_delete(const char *name, myf MyFlags)
|
||||
{
|
||||
char buf[MAX_PATH + 20];
|
||||
ulong cnt;
|
||||
DBUG_ENTER("nt_share_delete");
|
||||
DBUG_PRINT("my",("name %s MyFlags %d", name, MyFlags));
|
||||
|
||||
for (cnt= GetTickCount(); cnt; cnt--)
|
||||
{
|
||||
errno= 0;
|
||||
sprintf(buf, "%s.%08X.deleted", name, cnt);
|
||||
if (MoveFile(name, buf))
|
||||
break;
|
||||
|
||||
if ((errno= GetLastError()) == ERROR_ALREADY_EXISTS)
|
||||
continue;
|
||||
|
||||
/* This happened during tests with MERGE tables. */
|
||||
if (errno == ERROR_ACCESS_DENIED)
|
||||
continue;
|
||||
|
||||
DBUG_PRINT("warning", ("Failed to rename %s to %s, errno: %d",
|
||||
name, buf, errno));
|
||||
break;
|
||||
}
|
||||
|
||||
if (errno == ERROR_FILE_NOT_FOUND)
|
||||
{
|
||||
my_errno= ENOENT; // marking, that `name' doesn't exist
|
||||
}
|
||||
else if (errno == 0)
|
||||
{
|
||||
if (DeleteFile(buf))
|
||||
DBUG_RETURN(0);
|
||||
/*
|
||||
The below is more complicated than necessary. For some reason, the
|
||||
assignment to my_errno clears the error number, which is retrieved
|
||||
by GetLastError() (VC2005EE). Assigning to errno first, allows to
|
||||
retrieve the correct value.
|
||||
*/
|
||||
errno= GetLastError();
|
||||
if (errno == 0)
|
||||
my_errno= ENOENT; // marking, that `buf' doesn't exist
|
||||
else
|
||||
my_errno= errno;
|
||||
}
|
||||
else
|
||||
my_errno= errno;
|
||||
|
||||
if (MyFlags & (MY_FAE+MY_WME))
|
||||
my_error(EE_DELETE, MYF(ME_BELL + ME_WAITTANG + (MyFlags & ME_NOINPUT)),
|
||||
name, my_errno);
|
||||
DBUG_RETURN(-1);
|
||||
}
|
||||
#endif
|
||||
37
deps/mysqllite/mysys/my_div.c
vendored
Normal file
37
deps/mysqllite/mysys/my_div.c
vendored
Normal file
@@ -0,0 +1,37 @@
|
||||
/* Copyright (C) 2000 MySQL AB
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
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 */
|
||||
|
||||
#include "mysys_priv.h"
|
||||
|
||||
/*
|
||||
Get filename of file
|
||||
|
||||
SYNOPSIS
|
||||
my_filename()
|
||||
fd File descriptor
|
||||
*/
|
||||
|
||||
char * my_filename(File fd)
|
||||
{
|
||||
DBUG_ENTER("my_filename");
|
||||
if ((uint) fd >= (uint) my_file_limit)
|
||||
DBUG_RETURN((char*) "UNKNOWN");
|
||||
if (fd >= 0 && my_file_info[fd].type != UNOPEN)
|
||||
{
|
||||
DBUG_RETURN(my_file_info[fd].name);
|
||||
}
|
||||
else
|
||||
DBUG_RETURN((char*) "UNOPENED"); /* Debug message */
|
||||
}
|
||||
290
deps/mysqllite/mysys/my_error.c
vendored
Normal file
290
deps/mysqllite/mysys/my_error.c
vendored
Normal file
@@ -0,0 +1,290 @@
|
||||
/* Copyright (C) 2000 MySQL AB
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
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 */
|
||||
|
||||
#include "mysys_priv.h"
|
||||
#include "mysys_err.h"
|
||||
#include <m_string.h>
|
||||
#include <stdarg.h>
|
||||
#include <m_ctype.h>
|
||||
|
||||
/* Max length of a error message. Should be kept in sync with MYSQL_ERRMSG_SIZE. */
|
||||
#define ERRMSGSIZE (512)
|
||||
|
||||
/* Define some external variables for error handling */
|
||||
|
||||
/*
|
||||
WARNING!
|
||||
my_error family functions have to be used according following rules:
|
||||
- if message have not parameters use my_message(ER_CODE, ER(ER_CODE), MYF(N))
|
||||
- if message registered use my_error(ER_CODE, MYF(N), ...).
|
||||
- With some special text of errror message use:
|
||||
my_printf_error(ER_CODE, format, MYF(N), ...)
|
||||
*/
|
||||
|
||||
/*
|
||||
Message texts are registered into a linked list of 'my_err_head' structs.
|
||||
Each struct contains (1.) an array of pointers to C character strings with
|
||||
'\0' termination, (2.) the error number for the first message in the array
|
||||
(array index 0) and (3.) the error number for the last message in the array
|
||||
(array index (last - first)).
|
||||
The array may contain gaps with NULL pointers and pointers to empty strings.
|
||||
Both kinds of gaps will be translated to "Unknown error %d.", if my_error()
|
||||
is called with a respective error number.
|
||||
The list of header structs is sorted in increasing order of error numbers.
|
||||
Negative error numbers are allowed. Overlap of error numbers is not allowed.
|
||||
Not registered error numbers will be translated to "Unknown error %d.".
|
||||
*/
|
||||
static struct my_err_head
|
||||
{
|
||||
struct my_err_head *meh_next; /* chain link */
|
||||
const char** (*get_errmsgs) (); /* returns error message format */
|
||||
int meh_first; /* error number matching array slot 0 */
|
||||
int meh_last; /* error number matching last slot */
|
||||
} my_errmsgs_globerrs = {NULL, get_global_errmsgs, EE_ERROR_FIRST, EE_ERROR_LAST};
|
||||
|
||||
static struct my_err_head *my_errmsgs_list= &my_errmsgs_globerrs;
|
||||
|
||||
|
||||
/*
|
||||
Error message to user
|
||||
|
||||
SYNOPSIS
|
||||
my_error()
|
||||
nr Errno
|
||||
MyFlags Flags
|
||||
... variable list
|
||||
|
||||
*/
|
||||
|
||||
void my_error(int nr, myf MyFlags, ...)
|
||||
{
|
||||
const char *format;
|
||||
struct my_err_head *meh_p;
|
||||
va_list args;
|
||||
char ebuff[ERRMSGSIZE];
|
||||
DBUG_ENTER("my_error");
|
||||
DBUG_PRINT("my", ("nr: %d MyFlags: %d errno: %d", nr, MyFlags, errno));
|
||||
|
||||
/* Search for the error messages array, which could contain the message. */
|
||||
for (meh_p= my_errmsgs_list; meh_p; meh_p= meh_p->meh_next)
|
||||
if (nr <= meh_p->meh_last)
|
||||
break;
|
||||
|
||||
/* get the error message string. Default, if NULL or empty string (""). */
|
||||
if (! (format= (meh_p && (nr >= meh_p->meh_first)) ?
|
||||
meh_p->get_errmsgs()[nr - meh_p->meh_first] : NULL) || ! *format)
|
||||
(void) my_snprintf (ebuff, sizeof(ebuff), "Unknown error %d", nr);
|
||||
else
|
||||
{
|
||||
va_start(args,MyFlags);
|
||||
(void) my_vsnprintf_ex(&my_charset_utf8_general_ci, ebuff,
|
||||
sizeof(ebuff), format, args);
|
||||
va_end(args);
|
||||
}
|
||||
(*error_handler_hook)(nr, ebuff, MyFlags);
|
||||
DBUG_VOID_RETURN;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Error as printf
|
||||
|
||||
SYNOPSIS
|
||||
my_printf_error()
|
||||
error Errno
|
||||
format Format string
|
||||
MyFlags Flags
|
||||
... variable list
|
||||
*/
|
||||
|
||||
void my_printf_error(uint error, const char *format, myf MyFlags, ...)
|
||||
{
|
||||
va_list args;
|
||||
char ebuff[ERRMSGSIZE];
|
||||
DBUG_ENTER("my_printf_error");
|
||||
DBUG_PRINT("my", ("nr: %d MyFlags: %d errno: %d Format: %s",
|
||||
error, MyFlags, errno, format));
|
||||
|
||||
va_start(args,MyFlags);
|
||||
(void) my_vsnprintf_ex(&my_charset_utf8_general_ci, ebuff,
|
||||
sizeof(ebuff), format, args);
|
||||
va_end(args);
|
||||
(*error_handler_hook)(error, ebuff, MyFlags);
|
||||
DBUG_VOID_RETURN;
|
||||
}
|
||||
|
||||
/*
|
||||
Error with va_list
|
||||
|
||||
SYNOPSIS
|
||||
my_printv_error()
|
||||
error Errno
|
||||
format Format string
|
||||
MyFlags Flags
|
||||
... variable list
|
||||
*/
|
||||
|
||||
void my_printv_error(uint error, const char *format, myf MyFlags, va_list ap)
|
||||
{
|
||||
char ebuff[ERRMSGSIZE];
|
||||
DBUG_ENTER("my_printv_error");
|
||||
DBUG_PRINT("my", ("nr: %d MyFlags: %d errno: %d format: %s",
|
||||
error, MyFlags, errno, format));
|
||||
|
||||
(void) my_vsnprintf(ebuff, sizeof(ebuff), format, ap);
|
||||
(*error_handler_hook)(error, ebuff, MyFlags);
|
||||
DBUG_VOID_RETURN;
|
||||
}
|
||||
|
||||
/*
|
||||
Give message using error_handler_hook
|
||||
|
||||
SYNOPSIS
|
||||
my_message()
|
||||
error Errno
|
||||
str Error message
|
||||
MyFlags Flags
|
||||
*/
|
||||
|
||||
void my_message(uint error, const char *str, register myf MyFlags)
|
||||
{
|
||||
(*error_handler_hook)(error, str, MyFlags);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Register error messages for use with my_error().
|
||||
|
||||
SYNOPSIS
|
||||
my_error_register()
|
||||
errmsgs array of pointers to error messages
|
||||
first error number of first message in the array
|
||||
last error number of last message in the array
|
||||
|
||||
DESCRIPTION
|
||||
The pointer array is expected to contain addresses to NUL-terminated
|
||||
C character strings. The array contains (last - first + 1) pointers.
|
||||
NULL pointers and empty strings ("") are allowed. These will be mapped to
|
||||
"Unknown error" when my_error() is called with a matching error number.
|
||||
This function registers the error numbers 'first' to 'last'.
|
||||
No overlapping with previously registered error numbers is allowed.
|
||||
|
||||
RETURN
|
||||
0 OK
|
||||
!= 0 Error
|
||||
*/
|
||||
|
||||
int my_error_register(const char** (*get_errmsgs) (), int first, int last)
|
||||
{
|
||||
struct my_err_head *meh_p;
|
||||
struct my_err_head **search_meh_pp;
|
||||
|
||||
/* Allocate a new header structure. */
|
||||
if (! (meh_p= (struct my_err_head*) my_malloc(sizeof(struct my_err_head),
|
||||
MYF(MY_WME))))
|
||||
return 1;
|
||||
meh_p->get_errmsgs= get_errmsgs;
|
||||
meh_p->meh_first= first;
|
||||
meh_p->meh_last= last;
|
||||
|
||||
/* Search for the right position in the list. */
|
||||
for (search_meh_pp= &my_errmsgs_list;
|
||||
*search_meh_pp;
|
||||
search_meh_pp= &(*search_meh_pp)->meh_next)
|
||||
{
|
||||
if ((*search_meh_pp)->meh_last > first)
|
||||
break;
|
||||
}
|
||||
|
||||
/* Error numbers must be unique. No overlapping is allowed. */
|
||||
if (*search_meh_pp && ((*search_meh_pp)->meh_first <= last))
|
||||
{
|
||||
my_free(meh_p);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Insert header into the chain. */
|
||||
meh_p->meh_next= *search_meh_pp;
|
||||
*search_meh_pp= meh_p;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Unregister formerly registered error messages.
|
||||
|
||||
SYNOPSIS
|
||||
my_error_unregister()
|
||||
first error number of first message
|
||||
last error number of last message
|
||||
|
||||
DESCRIPTION
|
||||
This function unregisters the error numbers 'first' to 'last'.
|
||||
These must have been previously registered by my_error_register().
|
||||
'first' and 'last' must exactly match the registration.
|
||||
If a matching registration is present, the header is removed from the
|
||||
list and the pointer to the error messages pointers array is returned.
|
||||
Otherwise, NULL is returned.
|
||||
|
||||
RETURN
|
||||
non-NULL OK, returns address of error messages pointers array.
|
||||
NULL Error, no such number range registered.
|
||||
*/
|
||||
|
||||
const char **my_error_unregister(int first, int last)
|
||||
{
|
||||
struct my_err_head *meh_p;
|
||||
struct my_err_head **search_meh_pp;
|
||||
const char **errmsgs;
|
||||
|
||||
/* Search for the registration in the list. */
|
||||
for (search_meh_pp= &my_errmsgs_list;
|
||||
*search_meh_pp;
|
||||
search_meh_pp= &(*search_meh_pp)->meh_next)
|
||||
{
|
||||
if (((*search_meh_pp)->meh_first == first) &&
|
||||
((*search_meh_pp)->meh_last == last))
|
||||
break;
|
||||
}
|
||||
if (! *search_meh_pp)
|
||||
return NULL;
|
||||
|
||||
/* Remove header from the chain. */
|
||||
meh_p= *search_meh_pp;
|
||||
*search_meh_pp= meh_p->meh_next;
|
||||
|
||||
/* Save the return value and free the header. */
|
||||
errmsgs= meh_p->get_errmsgs();
|
||||
my_free(meh_p);
|
||||
|
||||
return errmsgs;
|
||||
}
|
||||
|
||||
|
||||
void my_error_unregister_all(void)
|
||||
{
|
||||
struct my_err_head *cursor, *saved_next;
|
||||
|
||||
for (cursor= my_errmsgs_globerrs.meh_next; cursor != NULL; cursor= saved_next)
|
||||
{
|
||||
/* We need this ptr, but we're about to free its container, so save it. */
|
||||
saved_next= cursor->meh_next;
|
||||
|
||||
my_free(cursor);
|
||||
}
|
||||
my_errmsgs_globerrs.meh_next= NULL; /* Freed in first iteration above. */
|
||||
|
||||
my_errmsgs_list= &my_errmsgs_globerrs;
|
||||
}
|
||||
135
deps/mysqllite/mysys/my_file.c
vendored
Normal file
135
deps/mysqllite/mysys/my_file.c
vendored
Normal file
@@ -0,0 +1,135 @@
|
||||
/* Copyright (C) 2000 MySQL AB
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
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 */
|
||||
|
||||
#include "mysys_priv.h"
|
||||
#include "my_static.h"
|
||||
#include <m_string.h>
|
||||
|
||||
/*
|
||||
set how many open files we want to be able to handle
|
||||
|
||||
SYNOPSIS
|
||||
set_maximum_open_files()
|
||||
max_file_limit Files to open
|
||||
|
||||
NOTES
|
||||
The request may not fulfilled becasue of system limitations
|
||||
|
||||
RETURN
|
||||
Files available to open.
|
||||
May be more or less than max_file_limit!
|
||||
*/
|
||||
|
||||
#if defined(HAVE_GETRLIMIT) && defined(RLIMIT_NOFILE)
|
||||
|
||||
#ifndef RLIM_INFINITY
|
||||
#define RLIM_INFINITY ((uint) 0xffffffff)
|
||||
#endif
|
||||
|
||||
static uint set_max_open_files(uint max_file_limit)
|
||||
{
|
||||
struct rlimit rlimit;
|
||||
uint old_cur;
|
||||
DBUG_ENTER("set_max_open_files");
|
||||
DBUG_PRINT("enter",("files: %u", max_file_limit));
|
||||
|
||||
if (!getrlimit(RLIMIT_NOFILE,&rlimit))
|
||||
{
|
||||
old_cur= (uint) rlimit.rlim_cur;
|
||||
DBUG_PRINT("info", ("rlim_cur: %u rlim_max: %u",
|
||||
(uint) rlimit.rlim_cur,
|
||||
(uint) rlimit.rlim_max));
|
||||
if (rlimit.rlim_cur == RLIM_INFINITY)
|
||||
rlimit.rlim_cur = max_file_limit;
|
||||
if (rlimit.rlim_cur >= max_file_limit)
|
||||
DBUG_RETURN(rlimit.rlim_cur); /* purecov: inspected */
|
||||
rlimit.rlim_cur= rlimit.rlim_max= max_file_limit;
|
||||
if (setrlimit(RLIMIT_NOFILE, &rlimit))
|
||||
max_file_limit= old_cur; /* Use original value */
|
||||
else
|
||||
{
|
||||
rlimit.rlim_cur= 0; /* Safety if next call fails */
|
||||
(void) getrlimit(RLIMIT_NOFILE,&rlimit);
|
||||
DBUG_PRINT("info", ("rlim_cur: %u", (uint) rlimit.rlim_cur));
|
||||
if (rlimit.rlim_cur) /* If call didn't fail */
|
||||
max_file_limit= (uint) rlimit.rlim_cur;
|
||||
}
|
||||
}
|
||||
DBUG_PRINT("exit",("max_file_limit: %u", max_file_limit));
|
||||
DBUG_RETURN(max_file_limit);
|
||||
}
|
||||
|
||||
#else
|
||||
static uint set_max_open_files(uint max_file_limit)
|
||||
{
|
||||
/* We don't know the limit. Return best guess */
|
||||
return min(max_file_limit, OS_FILE_LIMIT);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
Change number of open files
|
||||
|
||||
SYNOPSIS:
|
||||
my_set_max_open_files()
|
||||
files Number of requested files
|
||||
|
||||
RETURN
|
||||
number of files available for open
|
||||
*/
|
||||
|
||||
uint my_set_max_open_files(uint files)
|
||||
{
|
||||
struct st_my_file_info *tmp;
|
||||
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);
|
||||
|
||||
if (!(tmp= (struct st_my_file_info*) my_malloc(sizeof(*tmp) * files,
|
||||
MYF(MY_WME))))
|
||||
DBUG_RETURN(MY_NFILE);
|
||||
|
||||
/* Copy any initialized files */
|
||||
memcpy((char*) tmp, (char*) my_file_info,
|
||||
sizeof(*tmp) * min(my_file_limit, files));
|
||||
bzero((char*) (tmp + my_file_limit),
|
||||
max((int) (files- my_file_limit), 0)*sizeof(*tmp));
|
||||
my_free_open_file_info(); /* Free if already allocated */
|
||||
my_file_info= tmp;
|
||||
my_file_limit= files;
|
||||
DBUG_PRINT("exit",("files: %u", files));
|
||||
DBUG_RETURN(files);
|
||||
}
|
||||
|
||||
|
||||
void my_free_open_file_info()
|
||||
{
|
||||
DBUG_ENTER("my_free_file_info");
|
||||
if (my_file_info != my_file_info_default)
|
||||
{
|
||||
/* Copy data back for my_print_open_files */
|
||||
memcpy((char*) my_file_info_default, my_file_info,
|
||||
sizeof(*my_file_info_default)* MY_NFILE);
|
||||
my_free(my_file_info);
|
||||
my_file_info= my_file_info_default;
|
||||
my_file_limit= MY_NFILE;
|
||||
}
|
||||
DBUG_VOID_RETURN;
|
||||
}
|
||||
358
deps/mysqllite/mysys/my_fopen.c
vendored
Normal file
358
deps/mysqllite/mysys/my_fopen.c
vendored
Normal file
@@ -0,0 +1,358 @@
|
||||
/* Copyright (C) 2000 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 */
|
||||
|
||||
#include "mysys_priv.h"
|
||||
#include "my_static.h"
|
||||
#include <errno.h>
|
||||
#include "mysys_err.h"
|
||||
|
||||
#if defined(__FreeBSD__)
|
||||
extern int getosreldate(void);
|
||||
#endif
|
||||
|
||||
static void make_ftype(char * to,int flag);
|
||||
|
||||
/*
|
||||
Open a file as stream
|
||||
|
||||
SYNOPSIS
|
||||
my_fopen()
|
||||
FileName Path-name of file
|
||||
Flags Read | write | append | trunc (like for open())
|
||||
MyFlags Flags for handling errors
|
||||
|
||||
RETURN
|
||||
0 Error
|
||||
# File handler
|
||||
*/
|
||||
|
||||
FILE *my_fopen(const char *filename, int flags, myf MyFlags)
|
||||
{
|
||||
FILE *fd;
|
||||
char type[5];
|
||||
DBUG_ENTER("my_fopen");
|
||||
DBUG_PRINT("my",("Name: '%s' flags: %d MyFlags: %d",
|
||||
filename, flags, MyFlags));
|
||||
|
||||
make_ftype(type,flags);
|
||||
|
||||
#ifdef _WIN32
|
||||
fd= my_win_fopen(filename, type);
|
||||
#else
|
||||
fd= fopen(filename, type);
|
||||
#endif
|
||||
if (fd != 0)
|
||||
{
|
||||
/*
|
||||
The test works if MY_NFILE < 128. The problem is that fileno() is char
|
||||
on some OS (SUNOS). Actually the filename save isn't that important
|
||||
so we can ignore if this doesn't work.
|
||||
*/
|
||||
|
||||
int filedesc= my_fileno(fd);
|
||||
if ((uint)filedesc >= my_file_limit)
|
||||
{
|
||||
thread_safe_increment(my_stream_opened,&THR_LOCK_open);
|
||||
DBUG_RETURN(fd); /* safeguard */
|
||||
}
|
||||
mysql_mutex_lock(&THR_LOCK_open);
|
||||
if ((my_file_info[filedesc].name= (char*)
|
||||
my_strdup(filename,MyFlags)))
|
||||
{
|
||||
my_stream_opened++;
|
||||
my_file_total_opened++;
|
||||
my_file_info[filedesc].type= STREAM_BY_FOPEN;
|
||||
mysql_mutex_unlock(&THR_LOCK_open);
|
||||
DBUG_PRINT("exit",("stream: 0x%lx", (long) fd));
|
||||
DBUG_RETURN(fd);
|
||||
}
|
||||
mysql_mutex_unlock(&THR_LOCK_open);
|
||||
(void) my_fclose(fd,MyFlags);
|
||||
my_errno=ENOMEM;
|
||||
}
|
||||
else
|
||||
my_errno=errno;
|
||||
DBUG_PRINT("error",("Got error %d on open",my_errno));
|
||||
if (MyFlags & (MY_FFNF | MY_FAE | MY_WME))
|
||||
my_error((flags & O_RDONLY) || (flags == O_RDONLY ) ? EE_FILENOTFOUND :
|
||||
EE_CANTCREATEFILE,
|
||||
MYF(ME_BELL+ME_WAITTANG), filename, my_errno);
|
||||
DBUG_RETURN((FILE*) 0);
|
||||
} /* my_fopen */
|
||||
|
||||
|
||||
#if defined(_WIN32)
|
||||
|
||||
static FILE *my_win_freopen(const char *path, const char *mode, FILE *stream)
|
||||
{
|
||||
int handle_fd, fd= _fileno(stream);
|
||||
HANDLE osfh;
|
||||
|
||||
DBUG_ASSERT(path && stream);
|
||||
|
||||
/* Services don't have stdout/stderr on Windows, so _fileno returns -1. */
|
||||
if (fd < 0)
|
||||
{
|
||||
if (!freopen(path, mode, stream))
|
||||
return NULL;
|
||||
|
||||
fd= _fileno(stream);
|
||||
}
|
||||
|
||||
if ((osfh= CreateFile(path, GENERIC_READ | GENERIC_WRITE,
|
||||
FILE_SHARE_READ | FILE_SHARE_WRITE |
|
||||
FILE_SHARE_DELETE, NULL,
|
||||
OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL,
|
||||
NULL)) == INVALID_HANDLE_VALUE)
|
||||
return NULL;
|
||||
|
||||
if ((handle_fd= _open_osfhandle((intptr_t)osfh,
|
||||
_O_APPEND | _O_TEXT)) == -1)
|
||||
{
|
||||
CloseHandle(osfh);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (_dup2(handle_fd, fd) < 0)
|
||||
{
|
||||
CloseHandle(osfh);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
_close(handle_fd);
|
||||
|
||||
return stream;
|
||||
}
|
||||
|
||||
#elif defined(__FreeBSD__)
|
||||
|
||||
/* No close operation hook. */
|
||||
|
||||
static int no_close(void *cookie __attribute__((unused)))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
A hack around a race condition in the implementation of freopen.
|
||||
|
||||
The race condition steams from the fact that the current fd of
|
||||
the stream is closed before its number is used to duplicate the
|
||||
new file descriptor. This defeats the desired atomicity of the
|
||||
close and duplicate of dup2().
|
||||
|
||||
See PR number 79887 for reference:
|
||||
http://www.freebsd.org/cgi/query-pr.cgi?pr=79887
|
||||
*/
|
||||
|
||||
static FILE *my_freebsd_freopen(const char *path, const char *mode, FILE *stream)
|
||||
{
|
||||
int old_fd;
|
||||
FILE *result;
|
||||
|
||||
flockfile(stream);
|
||||
|
||||
old_fd= fileno(stream);
|
||||
|
||||
/* Use a no operation close hook to avoid having the fd closed. */
|
||||
stream->_close= no_close;
|
||||
|
||||
/* Relies on the implicit dup2 to close old_fd. */
|
||||
result= freopen(path, mode, stream);
|
||||
|
||||
/* If successful, the _close hook was replaced. */
|
||||
|
||||
if (result == NULL)
|
||||
close(old_fd);
|
||||
else
|
||||
funlockfile(result);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
/**
|
||||
Change the file associated with a file stream.
|
||||
|
||||
@param path Path to file.
|
||||
@param mode Mode of the stream.
|
||||
@param stream File stream.
|
||||
|
||||
@note
|
||||
This function is used to redirect stdout and stderr to a file and
|
||||
subsequently to close and reopen that file for log rotation.
|
||||
|
||||
@retval A FILE pointer on success. Otherwise, NULL.
|
||||
*/
|
||||
|
||||
FILE *my_freopen(const char *path, const char *mode, FILE *stream)
|
||||
{
|
||||
FILE *result;
|
||||
|
||||
#if defined(_WIN32)
|
||||
result= my_win_freopen(path, mode, stream);
|
||||
#elif defined(__FreeBSD__)
|
||||
/*
|
||||
XXX: Once the fix is ported to the stable releases, this should
|
||||
be dependent upon the specific FreeBSD versions. Check at:
|
||||
http://www.freebsd.org/cgi/query-pr.cgi?pr=79887
|
||||
*/
|
||||
if (getosreldate() > 900027)
|
||||
result= freopen(path, mode, stream);
|
||||
else
|
||||
result= my_freebsd_freopen(path, mode, stream);
|
||||
#else
|
||||
result= freopen(path, mode, stream);
|
||||
#endif
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
/* Close a stream */
|
||||
int my_fclose(FILE *fd, myf MyFlags)
|
||||
{
|
||||
int err,file;
|
||||
DBUG_ENTER("my_fclose");
|
||||
DBUG_PRINT("my",("stream: 0x%lx MyFlags: %d", (long) fd, MyFlags));
|
||||
|
||||
mysql_mutex_lock(&THR_LOCK_open);
|
||||
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))
|
||||
my_error(EE_BADCLOSE, MYF(ME_BELL+ME_WAITTANG),
|
||||
my_filename(file),errno);
|
||||
}
|
||||
else
|
||||
my_stream_opened--;
|
||||
if ((uint) file < my_file_limit && my_file_info[file].type != UNOPEN)
|
||||
{
|
||||
my_file_info[file].type = UNOPEN;
|
||||
my_free(my_file_info[file].name);
|
||||
}
|
||||
mysql_mutex_unlock(&THR_LOCK_open);
|
||||
DBUG_RETURN(err);
|
||||
} /* my_fclose */
|
||||
|
||||
|
||||
/* Make a stream out of a file handle */
|
||||
/* Name may be 0 */
|
||||
|
||||
FILE *my_fdopen(File Filedes, const char *name, int Flags, myf MyFlags)
|
||||
{
|
||||
FILE *fd;
|
||||
char type[5];
|
||||
DBUG_ENTER("my_fdopen");
|
||||
DBUG_PRINT("my",("Fd: %d Flags: %d MyFlags: %d",
|
||||
Filedes, Flags, MyFlags));
|
||||
|
||||
make_ftype(type,Flags);
|
||||
#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))
|
||||
my_error(EE_CANT_OPEN_STREAM, MYF(ME_BELL+ME_WAITTANG),errno);
|
||||
}
|
||||
else
|
||||
{
|
||||
mysql_mutex_lock(&THR_LOCK_open);
|
||||
my_stream_opened++;
|
||||
if ((uint) Filedes < (uint) my_file_limit)
|
||||
{
|
||||
if (my_file_info[Filedes].type != UNOPEN)
|
||||
{
|
||||
my_file_opened--; /* File is opened with my_open ! */
|
||||
}
|
||||
else
|
||||
{
|
||||
my_file_info[Filedes].name= my_strdup(name,MyFlags);
|
||||
}
|
||||
my_file_info[Filedes].type = STREAM_BY_FDOPEN;
|
||||
}
|
||||
mysql_mutex_unlock(&THR_LOCK_open);
|
||||
}
|
||||
|
||||
DBUG_PRINT("exit",("stream: 0x%lx", (long) fd));
|
||||
DBUG_RETURN(fd);
|
||||
} /* my_fdopen */
|
||||
|
||||
|
||||
/*
|
||||
Make a fopen() typestring from a open() type bitmap
|
||||
|
||||
SYNOPSIS
|
||||
make_ftype()
|
||||
to String for fopen() is stored here
|
||||
flag Flag used by open()
|
||||
|
||||
IMPLEMENTATION
|
||||
This routine attempts to find the best possible match
|
||||
between a numeric option and a string option that could be
|
||||
fed to fopen. There is not a 1 to 1 mapping between the two.
|
||||
|
||||
NOTE
|
||||
On Unix, O_RDONLY is usually 0
|
||||
|
||||
MAPPING
|
||||
r == O_RDONLY
|
||||
w == O_WRONLY|O_TRUNC|O_CREAT
|
||||
a == O_WRONLY|O_APPEND|O_CREAT
|
||||
r+ == O_RDWR
|
||||
w+ == O_RDWR|O_TRUNC|O_CREAT
|
||||
a+ == O_RDWR|O_APPEND|O_CREAT
|
||||
*/
|
||||
|
||||
static void make_ftype(register char * to, register int flag)
|
||||
{
|
||||
/* check some possible invalid combinations */
|
||||
DBUG_ASSERT((flag & (O_TRUNC | O_APPEND)) != (O_TRUNC | O_APPEND));
|
||||
DBUG_ASSERT((flag & (O_WRONLY | O_RDWR)) != (O_WRONLY | O_RDWR));
|
||||
|
||||
if ((flag & (O_RDONLY|O_WRONLY)) == O_WRONLY)
|
||||
*to++= (flag & O_APPEND) ? 'a' : 'w';
|
||||
else if (flag & O_RDWR)
|
||||
{
|
||||
/* Add '+' after theese */
|
||||
if (flag & (O_TRUNC | O_CREAT))
|
||||
*to++= 'w';
|
||||
else if (flag & O_APPEND)
|
||||
*to++= 'a';
|
||||
else
|
||||
*to++= 'r';
|
||||
*to++= '+';
|
||||
}
|
||||
else
|
||||
*to++= 'r';
|
||||
|
||||
#if FILE_BINARY /* If we have binary-files */
|
||||
if (flag & FILE_BINARY)
|
||||
*to++='b';
|
||||
#endif
|
||||
*to='\0';
|
||||
} /* make_ftype */
|
||||
194
deps/mysqllite/mysys/my_fstream.c
vendored
Normal file
194
deps/mysqllite/mysys/my_fstream.c
vendored
Normal file
@@ -0,0 +1,194 @@
|
||||
/* Copyright (C) 2000 MySQL AB
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
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 */
|
||||
|
||||
/* USE_MY_STREAM isn't set because we can't thrust my_fclose! */
|
||||
|
||||
#include "mysys_priv.h"
|
||||
#include "mysys_err.h"
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#ifdef HAVE_FSEEKO
|
||||
#undef ftell
|
||||
#undef fseek
|
||||
#define ftell(A) ftello(A)
|
||||
#define fseek(A,B,C) fseeko((A),(B),(C))
|
||||
#endif
|
||||
|
||||
/*
|
||||
Read a chunk of bytes from a FILE
|
||||
|
||||
SYNOPSIS
|
||||
my_fread()
|
||||
stream File descriptor
|
||||
Buffer Buffer to read to
|
||||
Count Number of bytes to read
|
||||
MyFlags Flags on what to do on error
|
||||
|
||||
RETURN
|
||||
(size_t) -1 Error
|
||||
# Number of bytes read
|
||||
*/
|
||||
|
||||
size_t my_fread(FILE *stream, uchar *Buffer, size_t Count, myf MyFlags)
|
||||
{
|
||||
size_t readbytes;
|
||||
DBUG_ENTER("my_fread");
|
||||
DBUG_PRINT("my",("stream: 0x%lx Buffer: 0x%lx Count: %u MyFlags: %d",
|
||||
(long) stream, (long) Buffer, (uint) Count, MyFlags));
|
||||
|
||||
if ((readbytes= fread(Buffer, sizeof(char), Count, stream)) != Count)
|
||||
{
|
||||
DBUG_PRINT("error",("Read only %d bytes", (int) readbytes));
|
||||
if (MyFlags & (MY_WME | MY_FAE | MY_FNABP))
|
||||
{
|
||||
if (ferror(stream))
|
||||
my_error(EE_READ, MYF(ME_BELL+ME_WAITTANG),
|
||||
my_filename(my_fileno(stream)),errno);
|
||||
else
|
||||
if (MyFlags & (MY_NABP | MY_FNABP))
|
||||
my_error(EE_EOFERR, MYF(ME_BELL+ME_WAITTANG),
|
||||
my_filename(my_fileno(stream)),errno);
|
||||
}
|
||||
my_errno=errno ? errno : -1;
|
||||
if (ferror(stream) || MyFlags & (MY_NABP | MY_FNABP))
|
||||
DBUG_RETURN((size_t) -1); /* Return with error */
|
||||
}
|
||||
if (MyFlags & (MY_NABP | MY_FNABP))
|
||||
DBUG_RETURN(0); /* Read ok */
|
||||
DBUG_RETURN(readbytes);
|
||||
} /* my_fread */
|
||||
|
||||
|
||||
/*
|
||||
Write a chunk of bytes to a stream
|
||||
|
||||
my_fwrite()
|
||||
stream File descriptor
|
||||
Buffer Buffer to write from
|
||||
Count Number of bytes to write
|
||||
MyFlags Flags on what to do on error
|
||||
|
||||
RETURN
|
||||
(size_t) -1 Error
|
||||
# Number of bytes written
|
||||
*/
|
||||
|
||||
size_t my_fwrite(FILE *stream, const uchar *Buffer, size_t Count, myf MyFlags)
|
||||
{
|
||||
size_t writtenbytes =0;
|
||||
my_off_t seekptr;
|
||||
#if !defined(NO_BACKGROUND) && defined(USE_MY_STREAM)
|
||||
uint errors;
|
||||
#endif
|
||||
DBUG_ENTER("my_fwrite");
|
||||
DBUG_PRINT("my",("stream: 0x%lx Buffer: 0x%lx Count: %u MyFlags: %d",
|
||||
(long) stream, (long) Buffer, (uint) Count, MyFlags));
|
||||
|
||||
#if !defined(NO_BACKGROUND) && defined(USE_MY_STREAM)
|
||||
errors=0;
|
||||
#endif
|
||||
seekptr= ftell(stream);
|
||||
for (;;)
|
||||
{
|
||||
size_t written;
|
||||
if ((written = (size_t) fwrite((char*) Buffer,sizeof(char),
|
||||
Count, stream)) != Count)
|
||||
{
|
||||
DBUG_PRINT("error",("Write only %d bytes", (int) writtenbytes));
|
||||
my_errno=errno;
|
||||
if (written != (size_t) -1)
|
||||
{
|
||||
seekptr+=written;
|
||||
Buffer+=written;
|
||||
writtenbytes+=written;
|
||||
Count-=written;
|
||||
}
|
||||
#ifdef EINTR
|
||||
if (errno == EINTR)
|
||||
{
|
||||
(void) my_fseek(stream,seekptr,MY_SEEK_SET,MYF(0));
|
||||
continue;
|
||||
}
|
||||
#endif
|
||||
#if !defined(NO_BACKGROUND) && defined(USE_MY_STREAM)
|
||||
if (my_thread_var->abort)
|
||||
MyFlags&= ~ MY_WAIT_IF_FULL; /* End if aborted by user */
|
||||
|
||||
if ((errno == ENOSPC || errno == EDQUOT) &&
|
||||
(MyFlags & MY_WAIT_IF_FULL))
|
||||
{
|
||||
wait_for_free_space("[stream]", errors);
|
||||
errors++;
|
||||
(void) my_fseek(stream,seekptr,MY_SEEK_SET,MYF(0));
|
||||
continue;
|
||||
}
|
||||
#endif
|
||||
if (ferror(stream) || (MyFlags & (MY_NABP | MY_FNABP)))
|
||||
{
|
||||
if (MyFlags & (MY_WME | MY_FAE | MY_FNABP))
|
||||
{
|
||||
my_error(EE_WRITE, MYF(ME_BELL+ME_WAITTANG),
|
||||
my_filename(my_fileno(stream)),errno);
|
||||
}
|
||||
writtenbytes= (size_t) -1; /* Return that we got error */
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (MyFlags & (MY_NABP | MY_FNABP))
|
||||
writtenbytes= 0; /* Everything OK */
|
||||
else
|
||||
writtenbytes+= written;
|
||||
break;
|
||||
}
|
||||
DBUG_RETURN(writtenbytes);
|
||||
} /* my_fwrite */
|
||||
|
||||
|
||||
/* Seek to position in file */
|
||||
|
||||
my_off_t my_fseek(FILE *stream, my_off_t pos, int whence,
|
||||
myf MyFlags __attribute__((unused)))
|
||||
{
|
||||
DBUG_ENTER("my_fseek");
|
||||
DBUG_PRINT("my",("stream: 0x%lx pos: %lu whence: %d MyFlags: %d",
|
||||
(long) stream, (long) pos, whence, MyFlags));
|
||||
DBUG_RETURN(fseek(stream, (off_t) pos, whence) ?
|
||||
MY_FILEPOS_ERROR : (my_off_t) ftell(stream));
|
||||
} /* my_seek */
|
||||
|
||||
|
||||
/* Tell current position of file */
|
||||
|
||||
my_off_t my_ftell(FILE *stream, myf MyFlags __attribute__((unused)))
|
||||
{
|
||||
off_t pos;
|
||||
DBUG_ENTER("my_ftell");
|
||||
DBUG_PRINT("my",("stream: 0x%lx MyFlags: %d", (long) stream, MyFlags));
|
||||
pos=ftell(stream);
|
||||
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
|
||||
}
|
||||
111
deps/mysqllite/mysys/my_gethostbyname.c
vendored
Normal file
111
deps/mysqllite/mysys/my_gethostbyname.c
vendored
Normal file
@@ -0,0 +1,111 @@
|
||||
/* Copyright (C) 2002, 2004 MySQL AB, 2008-2009 Sun Microsystems, Inc
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Library General Public
|
||||
License as published by the Free Software Foundation; version 2
|
||||
of the License.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Library General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Library General Public
|
||||
License along with this library; if not, write to the Free
|
||||
Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
|
||||
MA 02111-1307, USA */
|
||||
|
||||
/* Thread safe version of gethostbyname_r() */
|
||||
|
||||
#include "mysys_priv.h"
|
||||
#if !defined(__WIN__)
|
||||
#include <netdb.h>
|
||||
#endif
|
||||
#include <my_net.h>
|
||||
|
||||
/* This file is not needed if my_gethostbyname_r is a macro */
|
||||
#if !defined(my_gethostbyname_r)
|
||||
|
||||
/*
|
||||
Emulate SOLARIS style calls, not because it's better, but just to make the
|
||||
usage of getbostbyname_r simpler.
|
||||
*/
|
||||
|
||||
#if defined(HAVE_GETHOSTBYNAME_R)
|
||||
|
||||
#if defined(HAVE_GETHOSTBYNAME_R_GLIBC2_STYLE)
|
||||
|
||||
struct hostent *my_gethostbyname_r(const char *name,
|
||||
struct hostent *result, char *buffer,
|
||||
int buflen, int *h_errnop)
|
||||
{
|
||||
struct hostent *hp;
|
||||
DBUG_ASSERT((size_t) buflen >= sizeof(*result));
|
||||
if (gethostbyname_r(name,result, buffer, (size_t) buflen, &hp, h_errnop))
|
||||
return 0;
|
||||
return hp;
|
||||
}
|
||||
|
||||
#elif defined(HAVE_GETHOSTBYNAME_R_RETURN_INT)
|
||||
|
||||
struct hostent *my_gethostbyname_r(const char *name,
|
||||
struct hostent *result, char *buffer,
|
||||
int buflen, int *h_errnop)
|
||||
{
|
||||
if (gethostbyname_r(name,result,(struct hostent_data *) buffer) == -1)
|
||||
{
|
||||
*h_errnop= errno;
|
||||
return 0;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
/* gethostbyname_r with similar interface as gethostbyname() */
|
||||
|
||||
struct hostent *my_gethostbyname_r(const char *name,
|
||||
struct hostent *result, char *buffer,
|
||||
int buflen, int *h_errnop)
|
||||
{
|
||||
struct hostent *hp;
|
||||
DBUG_ASSERT(buflen >= sizeof(struct hostent_data));
|
||||
hp= gethostbyname_r(name,result,(struct hostent_data *) buffer);
|
||||
*h_errnop= errno;
|
||||
return hp;
|
||||
}
|
||||
#endif /* GLIBC2_STYLE_GETHOSTBYNAME_R */
|
||||
|
||||
#else /* !HAVE_GETHOSTBYNAME_R */
|
||||
|
||||
extern mysql_mutex_t LOCK_gethostbyname_r;
|
||||
|
||||
/*
|
||||
No gethostbyname_r() function exists.
|
||||
In this case we have to keep a mutex over the call to ensure that no
|
||||
other thread is going to reuse the internal memory.
|
||||
|
||||
The user is responsible to call my_gethostbyname_r_free() when he
|
||||
is finished with the structure.
|
||||
*/
|
||||
|
||||
struct hostent *my_gethostbyname_r(const char *name,
|
||||
struct hostent *res __attribute__((unused)),
|
||||
char *buffer __attribute__((unused)),
|
||||
int buflen __attribute__((unused)),
|
||||
int *h_errnop)
|
||||
{
|
||||
struct hostent *hp;
|
||||
mysql_mutex_lock(&LOCK_gethostbyname_r);
|
||||
hp= gethostbyname(name);
|
||||
*h_errnop= h_errno;
|
||||
return hp;
|
||||
}
|
||||
|
||||
void my_gethostbyname_r_free()
|
||||
{
|
||||
mysql_mutex_unlock(&LOCK_gethostbyname_r);
|
||||
}
|
||||
|
||||
#endif /* !HAVE_GETHOSTBYNAME_R */
|
||||
#endif /* !my_gethostbyname_r */
|
||||
226
deps/mysqllite/mysys/my_gethwaddr.c
vendored
Normal file
226
deps/mysqllite/mysys/my_gethwaddr.c
vendored
Normal file
@@ -0,0 +1,226 @@
|
||||
/* Copyright (C) 2004 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 */
|
||||
|
||||
/* get hardware address for an interface */
|
||||
/* if there are many available, any non-zero one can be used */
|
||||
|
||||
#include "mysys_priv.h"
|
||||
#include <m_string.h>
|
||||
|
||||
#ifndef MAIN
|
||||
|
||||
#ifdef __FreeBSD__
|
||||
|
||||
#include <net/ethernet.h>
|
||||
#include <sys/sysctl.h>
|
||||
#include <net/route.h>
|
||||
#include <net/if.h>
|
||||
#include <net/if_dl.h>
|
||||
|
||||
my_bool my_gethwaddr(uchar *to)
|
||||
{
|
||||
size_t len;
|
||||
char *buf, *next, *end;
|
||||
struct if_msghdr *ifm;
|
||||
struct sockaddr_dl *sdl;
|
||||
int res=1, mib[6]={CTL_NET, AF_ROUTE, 0, AF_LINK, NET_RT_IFLIST, 0};
|
||||
char zero_array[ETHER_ADDR_LEN] = {0};
|
||||
|
||||
if (sysctl(mib, 6, NULL, &len, NULL, 0) == -1)
|
||||
goto err;
|
||||
if (!(buf = alloca(len)))
|
||||
goto err;
|
||||
if (sysctl(mib, 6, buf, &len, NULL, 0) < 0)
|
||||
goto err;
|
||||
|
||||
end = buf + len;
|
||||
|
||||
for (next = buf ; res && next < end ; next += ifm->ifm_msglen)
|
||||
{
|
||||
ifm = (struct if_msghdr *)next;
|
||||
if (ifm->ifm_type == RTM_IFINFO)
|
||||
{
|
||||
sdl= (struct sockaddr_dl *)(ifm + 1);
|
||||
memcpy(to, LLADDR(sdl), ETHER_ADDR_LEN);
|
||||
res= memcmp(to, zero_array, ETHER_ADDR_LEN) ? 0 : 1;
|
||||
}
|
||||
}
|
||||
|
||||
err:
|
||||
return res;
|
||||
}
|
||||
|
||||
#elif __linux__
|
||||
|
||||
#include <net/if.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <net/ethernet.h>
|
||||
|
||||
my_bool my_gethwaddr(uchar *to)
|
||||
{
|
||||
int fd, res= 1;
|
||||
struct ifreq ifr;
|
||||
char zero_array[ETHER_ADDR_LEN] = {0};
|
||||
|
||||
fd = socket(AF_INET, SOCK_DGRAM, 0);
|
||||
if (fd < 0)
|
||||
goto err;
|
||||
|
||||
bzero(&ifr, sizeof(ifr));
|
||||
strnmov(ifr.ifr_name, "eth0", sizeof(ifr.ifr_name) - 1);
|
||||
|
||||
do
|
||||
{
|
||||
if (ioctl(fd, SIOCGIFHWADDR, &ifr) >= 0)
|
||||
{
|
||||
memcpy(to, &ifr.ifr_hwaddr.sa_data, ETHER_ADDR_LEN);
|
||||
res= memcmp(to, zero_array, ETHER_ADDR_LEN) ? 0 : 1;
|
||||
}
|
||||
} while (res && (errno == 0 || errno == ENODEV) && ifr.ifr_name[3]++ < '6');
|
||||
|
||||
close(fd);
|
||||
err:
|
||||
return res;
|
||||
}
|
||||
|
||||
#elif defined(__WIN__)
|
||||
|
||||
/*
|
||||
Workaround for BUG#32082 (Definition of VOID in my_global.h conflicts with
|
||||
windows headers)
|
||||
*/
|
||||
#ifdef VOID
|
||||
#undef VOID
|
||||
#define VOID void
|
||||
#endif
|
||||
|
||||
#include <iphlpapi.h>
|
||||
|
||||
/*
|
||||
The following typedef is for dynamically loading iphlpapi.dll /
|
||||
GetAdaptersAddresses. Dynamic loading is used because
|
||||
GetAdaptersAddresses is not available on Windows 2000 which MySQL
|
||||
still supports. Static linking would cause an unresolved export.
|
||||
*/
|
||||
typedef DWORD (WINAPI *pfnGetAdaptersAddresses)(IN ULONG Family,
|
||||
IN DWORD Flags,IN PVOID Reserved,
|
||||
OUT PIP_ADAPTER_ADDRESSES pAdapterAddresses,
|
||||
IN OUT PULONG pOutBufLen);
|
||||
|
||||
/*
|
||||
my_gethwaddr - Windows version
|
||||
|
||||
@brief Retrieve MAC address from network hardware
|
||||
|
||||
@param[out] to MAC address exactly six bytes
|
||||
|
||||
@return Operation status
|
||||
@retval 0 OK
|
||||
@retval <>0 FAILED
|
||||
*/
|
||||
my_bool my_gethwaddr(uchar *to)
|
||||
{
|
||||
PIP_ADAPTER_ADDRESSES pAdapterAddresses;
|
||||
PIP_ADAPTER_ADDRESSES pCurrAddresses;
|
||||
IP_ADAPTER_ADDRESSES adapterAddresses;
|
||||
ULONG address_len;
|
||||
my_bool return_val= 1;
|
||||
static pfnGetAdaptersAddresses fnGetAdaptersAddresses=
|
||||
(pfnGetAdaptersAddresses)-1;
|
||||
|
||||
if(fnGetAdaptersAddresses == (pfnGetAdaptersAddresses)-1)
|
||||
{
|
||||
/* Get the function from the DLL */
|
||||
fnGetAdaptersAddresses= (pfnGetAdaptersAddresses)
|
||||
GetProcAddress(LoadLibrary("iphlpapi.dll"),
|
||||
"GetAdaptersAddresses");
|
||||
}
|
||||
if (!fnGetAdaptersAddresses)
|
||||
return 1; /* failed to get function */
|
||||
address_len= sizeof (IP_ADAPTER_ADDRESSES);
|
||||
|
||||
/* Get the required size for the address data. */
|
||||
if (fnGetAdaptersAddresses(AF_UNSPEC, 0, 0, &adapterAddresses, &address_len)
|
||||
== ERROR_BUFFER_OVERFLOW)
|
||||
{
|
||||
pAdapterAddresses= my_malloc(address_len, 0);
|
||||
if (!pAdapterAddresses)
|
||||
return 1; /* error, alloc failed */
|
||||
}
|
||||
else
|
||||
pAdapterAddresses= &adapterAddresses; /* one is enough don't alloc */
|
||||
|
||||
/* Get the hardware info. */
|
||||
if (fnGetAdaptersAddresses(AF_UNSPEC, 0, 0, pAdapterAddresses, &address_len)
|
||||
== NO_ERROR)
|
||||
{
|
||||
pCurrAddresses= pAdapterAddresses;
|
||||
|
||||
while (pCurrAddresses)
|
||||
{
|
||||
/* Look for ethernet cards. */
|
||||
if (pCurrAddresses->IfType == IF_TYPE_ETHERNET_CSMACD)
|
||||
{
|
||||
/* check for a good address */
|
||||
if (pCurrAddresses->PhysicalAddressLength < 6)
|
||||
continue; /* bad address */
|
||||
|
||||
/* save 6 bytes of the address in the 'to' parameter */
|
||||
memcpy(to, pCurrAddresses->PhysicalAddress, 6);
|
||||
|
||||
/* Network card found, we're done. */
|
||||
return_val= 0;
|
||||
break;
|
||||
}
|
||||
pCurrAddresses= pCurrAddresses->Next;
|
||||
}
|
||||
}
|
||||
|
||||
/* Clean up memory allocation. */
|
||||
if (pAdapterAddresses != &adapterAddresses)
|
||||
my_free(pAdapterAddresses);
|
||||
|
||||
return return_val;
|
||||
}
|
||||
|
||||
#else /* __FreeBSD__ || __linux__ || __WIN__ */
|
||||
/* just fail */
|
||||
my_bool my_gethwaddr(uchar *to __attribute__((unused)))
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
#else /* MAIN */
|
||||
int main(int argc __attribute__((unused)),char **argv)
|
||||
{
|
||||
uchar mac[6];
|
||||
uint i;
|
||||
MY_INIT(argv[0]);
|
||||
if (my_gethwaddr(mac))
|
||||
{
|
||||
printf("my_gethwaddr failed with errno %d\n", errno);
|
||||
exit(1);
|
||||
}
|
||||
for (i=0; i < sizeof(mac); i++)
|
||||
{
|
||||
if (i) printf(":");
|
||||
printf("%02x", mac[i]);
|
||||
}
|
||||
printf("\n");
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
49
deps/mysqllite/mysys/my_getncpus.c
vendored
Normal file
49
deps/mysqllite/mysys/my_getncpus.c
vendored
Normal file
@@ -0,0 +1,49 @@
|
||||
/* Copyright (C) 2006 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 */
|
||||
|
||||
/* get the number of (online) CPUs */
|
||||
|
||||
#include "mysys_priv.h"
|
||||
#ifdef HAVE_UNISTD_H
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
static int ncpus=0;
|
||||
|
||||
int my_getncpus()
|
||||
{
|
||||
if (!ncpus)
|
||||
{
|
||||
#ifdef _SC_NPROCESSORS_ONLN
|
||||
ncpus= sysconf(_SC_NPROCESSORS_ONLN);
|
||||
#elif defined(__WIN__)
|
||||
SYSTEM_INFO sysinfo;
|
||||
|
||||
/*
|
||||
* We are not calling GetNativeSystemInfo here because (1) we
|
||||
* don't believe that they return different values for number
|
||||
* of processors and (2) if WOW64 limits processors for Win32
|
||||
* then we don't want to try to override that.
|
||||
*/
|
||||
GetSystemInfo(&sysinfo);
|
||||
|
||||
ncpus= sysinfo.dwNumberOfProcessors;
|
||||
#else
|
||||
/* unknown so play safe: assume SMP and forbid uniprocessor build */
|
||||
ncpus= 2;
|
||||
#endif
|
||||
}
|
||||
return ncpus;
|
||||
}
|
||||
1419
deps/mysqllite/mysys/my_getopt.c
vendored
Normal file
1419
deps/mysqllite/mysys/my_getopt.c
vendored
Normal file
File diff suppressed because it is too large
Load Diff
40
deps/mysqllite/mysys/my_getpagesize.c
vendored
Normal file
40
deps/mysqllite/mysys/my_getpagesize.c
vendored
Normal file
@@ -0,0 +1,40 @@
|
||||
/* Copyright (C) 2000-2003 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 */
|
||||
|
||||
#include "mysys_priv.h"
|
||||
|
||||
#ifndef HAVE_GETPAGESIZE
|
||||
|
||||
#if defined __WIN__
|
||||
|
||||
int my_getpagesize(void)
|
||||
{
|
||||
SYSTEM_INFO si;
|
||||
GetSystemInfo(&si);
|
||||
return si.dwPageSize;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
/* Default implementation */
|
||||
int my_getpagesize(void)
|
||||
{
|
||||
return (int)8192;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
226
deps/mysqllite/mysys/my_getsystime.c
vendored
Normal file
226
deps/mysqllite/mysys/my_getsystime.c
vendored
Normal file
@@ -0,0 +1,226 @@
|
||||
/* Copyright (C) 2004 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 */
|
||||
|
||||
/* 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"
|
||||
|
||||
ulonglong my_getsystime()
|
||||
{
|
||||
#ifdef HAVE_CLOCK_GETTIME
|
||||
struct timespec tp;
|
||||
clock_gettime(CLOCK_REALTIME, &tp);
|
||||
return (ulonglong)tp.tv_sec*10000000+(ulonglong)tp.tv_nsec/100;
|
||||
#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 0;
|
||||
#else
|
||||
/* TODO: check for other possibilities for hi-res timestamping */
|
||||
struct timeval tv;
|
||||
gettimeofday(&tv,NULL);
|
||||
return (ulonglong)tv.tv_sec*10000000+(ulonglong)tv.tv_usec*10;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Return current time
|
||||
|
||||
SYNOPSIS
|
||||
my_time()
|
||||
flags If MY_WME is set, write error if time call fails
|
||||
|
||||
*/
|
||||
|
||||
time_t my_time(myf flags __attribute__((unused)))
|
||||
{
|
||||
time_t t;
|
||||
#ifdef HAVE_GETHRTIME
|
||||
(void) my_micro_time_and_time(&t);
|
||||
return t;
|
||||
#else
|
||||
/* The following loop is here beacuse time() may fail on some systems */
|
||||
while ((t= time(0)) == (time_t) -1)
|
||||
{
|
||||
if (flags & MY_WME)
|
||||
fprintf(stderr, "%s: Warning: time() call failed\n", my_progname);
|
||||
}
|
||||
return t;
|
||||
#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
|
||||
Value in microseconds from some undefined point in time
|
||||
*/
|
||||
|
||||
#define DELTA_FOR_SECONDS 500000000LL /* Half a second */
|
||||
|
||||
/* Difference between GetSystemTimeAsFileTime() and now() */
|
||||
#define OFFSET_TO_EPOCH 116444736000000000ULL
|
||||
|
||||
ulonglong my_micro_time_and_time(time_t *time_arg)
|
||||
{
|
||||
#if defined(__WIN__)
|
||||
ulonglong newtime;
|
||||
GetSystemTimeAsFileTime((FILETIME*)&newtime);
|
||||
*time_arg= (time_t) ((newtime - OFFSET_TO_EPOCH) / 10000000);
|
||||
return (newtime/10);
|
||||
#elif defined(HAVE_GETHRTIME)
|
||||
/*
|
||||
Solaris has a very slow time() call. We optimize this by using the very
|
||||
fast gethrtime() call and only calling time() every 1/2 second
|
||||
*/
|
||||
static hrtime_t prev_gethrtime= 0;
|
||||
static time_t cur_time= 0;
|
||||
hrtime_t cur_gethrtime;
|
||||
|
||||
mysql_mutex_lock(&THR_LOCK_time);
|
||||
cur_gethrtime= gethrtime();
|
||||
/*
|
||||
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;
|
||||
mysql_mutex_unlock(&THR_LOCK_time);
|
||||
return cur_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)
|
||||
{}
|
||||
*time_arg= t.tv_sec;
|
||||
newtime= (ulonglong)t.tv_sec * 1000000 + t.tv_usec;
|
||||
return newtime;
|
||||
#endif /* defined(__WIN__) */
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
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)))
|
||||
{
|
||||
#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__) */
|
||||
}
|
||||
|
||||
167
deps/mysqllite/mysys/my_getwd.c
vendored
Normal file
167
deps/mysqllite/mysys/my_getwd.c
vendored
Normal file
@@ -0,0 +1,167 @@
|
||||
/* Copyright (C) 2000 MySQL AB
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
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 */
|
||||
|
||||
/* my_setwd() and my_getwd() works with intern_filenames !! */
|
||||
|
||||
#include "mysys_priv.h"
|
||||
#include <m_string.h>
|
||||
#include "mysys_err.h"
|
||||
#ifdef HAVE_GETWD
|
||||
#include <sys/param.h>
|
||||
#endif
|
||||
#if defined(__WIN__)
|
||||
#include <m_ctype.h>
|
||||
#include <dos.h>
|
||||
#include <direct.h>
|
||||
#endif
|
||||
|
||||
/* Gets current working directory in buff.
|
||||
|
||||
SYNPOSIS
|
||||
my_getwd()
|
||||
buf Buffer to store result. Can be curr_dir[].
|
||||
size Size of buffer
|
||||
MyFlags Flags
|
||||
|
||||
NOTES
|
||||
Directory is allways ended with FN_LIBCHAR
|
||||
|
||||
RESULT
|
||||
0 ok
|
||||
# error
|
||||
*/
|
||||
|
||||
int my_getwd(char * buf, size_t size, myf MyFlags)
|
||||
{
|
||||
char * pos;
|
||||
DBUG_ENTER("my_getwd");
|
||||
DBUG_PRINT("my",("buf: 0x%lx size: %u MyFlags %d",
|
||||
(long) buf, (uint) size, MyFlags));
|
||||
|
||||
if (size < 1)
|
||||
DBUG_RETURN(-1);
|
||||
|
||||
if (curr_dir[0]) /* Current pos is saved here */
|
||||
(void) strmake(buf,&curr_dir[0],size-1);
|
||||
else
|
||||
{
|
||||
#if defined(HAVE_GETCWD)
|
||||
if (size < 2)
|
||||
DBUG_RETURN(-1);
|
||||
if (!getcwd(buf,(uint) (size-2)) && MyFlags & MY_WME)
|
||||
{
|
||||
my_errno=errno;
|
||||
my_error(EE_GETWD,MYF(ME_BELL+ME_WAITTANG),errno);
|
||||
DBUG_RETURN(-1);
|
||||
}
|
||||
#elif defined(HAVE_GETWD)
|
||||
{
|
||||
char pathname[MAXPATHLEN];
|
||||
getwd(pathname);
|
||||
strmake(buf,pathname,size-1);
|
||||
}
|
||||
#else
|
||||
#error "No way to get current directory"
|
||||
#endif
|
||||
if (*((pos=strend(buf))-1) != FN_LIBCHAR) /* End with FN_LIBCHAR */
|
||||
{
|
||||
pos[0]= FN_LIBCHAR;
|
||||
pos[1]=0;
|
||||
}
|
||||
(void) strmake(&curr_dir[0],buf, (size_t) (FN_REFLEN-1));
|
||||
}
|
||||
DBUG_RETURN(0);
|
||||
} /* my_getwd */
|
||||
|
||||
|
||||
/* Set new working directory */
|
||||
|
||||
int my_setwd(const char *dir, myf MyFlags)
|
||||
{
|
||||
int res;
|
||||
size_t length;
|
||||
char *start, *pos;
|
||||
DBUG_ENTER("my_setwd");
|
||||
DBUG_PRINT("my",("dir: '%s' MyFlags %d", dir, MyFlags));
|
||||
|
||||
start=(char *) dir;
|
||||
if (! dir[0] || (dir[0] == FN_LIBCHAR && dir[1] == 0))
|
||||
dir=FN_ROOTDIR;
|
||||
if ((res=chdir((char*) dir)) != 0)
|
||||
{
|
||||
my_errno=errno;
|
||||
if (MyFlags & MY_WME)
|
||||
my_error(EE_SETWD,MYF(ME_BELL+ME_WAITTANG),start,errno);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (test_if_hard_path(start))
|
||||
{ /* Hard pathname */
|
||||
pos= strmake(&curr_dir[0],start,(size_t) FN_REFLEN-1);
|
||||
if (pos[-1] != FN_LIBCHAR)
|
||||
{
|
||||
length=(uint) (pos-(char*) curr_dir);
|
||||
curr_dir[length]=FN_LIBCHAR; /* must end with '/' */
|
||||
curr_dir[length+1]='\0';
|
||||
}
|
||||
}
|
||||
else
|
||||
curr_dir[0]='\0'; /* Don't save name */
|
||||
}
|
||||
DBUG_RETURN(res);
|
||||
} /* my_setwd */
|
||||
|
||||
|
||||
|
||||
/* Test if hard pathname */
|
||||
/* Returns 1 if dirname is a hard path */
|
||||
|
||||
int test_if_hard_path(register const char *dir_name)
|
||||
{
|
||||
if (dir_name[0] == FN_HOMELIB && dir_name[1] == FN_LIBCHAR)
|
||||
return (home_dir != NullS && test_if_hard_path(home_dir));
|
||||
if (dir_name[0] == FN_LIBCHAR)
|
||||
return (TRUE);
|
||||
#ifdef FN_DEVCHAR
|
||||
return (strchr(dir_name,FN_DEVCHAR) != 0);
|
||||
#else
|
||||
return FALSE;
|
||||
#endif
|
||||
} /* test_if_hard_path */
|
||||
|
||||
|
||||
/*
|
||||
Test if a name contains an (absolute or relative) path.
|
||||
|
||||
SYNOPSIS
|
||||
has_path()
|
||||
name The name to test.
|
||||
|
||||
RETURN
|
||||
TRUE name contains a path.
|
||||
FALSE name does not contain a path.
|
||||
*/
|
||||
|
||||
my_bool has_path(const char *name)
|
||||
{
|
||||
return test(strchr(name, FN_LIBCHAR))
|
||||
#if FN_LIBCHAR != '/'
|
||||
|| test(strchr(name,'/'))
|
||||
#endif
|
||||
#ifdef FN_DEVCHAR
|
||||
|| test(strchr(name, FN_DEVCHAR))
|
||||
#endif
|
||||
;
|
||||
}
|
||||
604
deps/mysqllite/mysys/my_handler.c
vendored
Normal file
604
deps/mysqllite/mysys/my_handler.c
vendored
Normal file
@@ -0,0 +1,604 @@
|
||||
/* Copyright (C) 2002-2006 MySQL AB
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Library General Public
|
||||
License as published by the Free Software Foundation; version 2
|
||||
of the License.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Library General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Library General Public
|
||||
License along with this library; if not, write to the Free
|
||||
Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
|
||||
MA 02111-1307, USA */
|
||||
|
||||
#include <my_global.h>
|
||||
#include <m_ctype.h>
|
||||
#include <my_base.h>
|
||||
#include <my_handler.h>
|
||||
#include <my_sys.h>
|
||||
|
||||
#include "my_handler_errors.h"
|
||||
|
||||
#define CMP_NUM(a,b) (((a) < (b)) ? -1 : ((a) == (b)) ? 0 : 1)
|
||||
|
||||
int ha_compare_text(CHARSET_INFO *charset_info, uchar *a, uint a_length,
|
||||
uchar *b, uint b_length, my_bool part_key,
|
||||
my_bool skip_end_space)
|
||||
{
|
||||
if (!part_key)
|
||||
return charset_info->coll->strnncollsp(charset_info, a, a_length,
|
||||
b, b_length, (my_bool)!skip_end_space);
|
||||
return charset_info->coll->strnncoll(charset_info, a, a_length,
|
||||
b, b_length, part_key);
|
||||
}
|
||||
|
||||
|
||||
static int compare_bin(uchar *a, uint a_length, uchar *b, uint b_length,
|
||||
my_bool part_key, my_bool skip_end_space)
|
||||
{
|
||||
uint length= min(a_length,b_length);
|
||||
uchar *end= a+ length;
|
||||
int flag;
|
||||
|
||||
while (a < end)
|
||||
if ((flag= (int) *a++ - (int) *b++))
|
||||
return flag;
|
||||
if (part_key && b_length < a_length)
|
||||
return 0;
|
||||
if (skip_end_space && a_length != b_length)
|
||||
{
|
||||
int swap= 1;
|
||||
/*
|
||||
We are using space compression. We have to check if longer key
|
||||
has next character < ' ', in which case it's less than the shorter
|
||||
key that has an implicite space afterwards.
|
||||
|
||||
This code is identical to the one in
|
||||
strings/ctype-simple.c:my_strnncollsp_simple
|
||||
*/
|
||||
if (a_length < b_length)
|
||||
{
|
||||
/* put shorter key in a */
|
||||
a_length= b_length;
|
||||
a= b;
|
||||
swap= -1; /* swap sign of result */
|
||||
}
|
||||
for (end= a + a_length-length; a < end ; a++)
|
||||
{
|
||||
if (*a != ' ')
|
||||
return (*a < ' ') ? -swap : swap;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
return (int) (a_length-b_length);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Compare two keys
|
||||
|
||||
SYNOPSIS
|
||||
ha_key_cmp()
|
||||
keyseg Array of key segments of key to compare
|
||||
a First key to compare, in format from _mi_pack_key()
|
||||
This is normally key specified by user
|
||||
b Second key to compare. This is always from a row
|
||||
key_length Length of key to compare. This can be shorter than
|
||||
a to just compare sub keys
|
||||
next_flag How keys should be compared
|
||||
If bit SEARCH_FIND is not set the keys includes the row
|
||||
position and this should also be compared
|
||||
diff_pos OUT Number of first keypart where values differ, counting
|
||||
from one.
|
||||
diff_pos[1] OUT (b + diff_pos[1]) points to first value in tuple b
|
||||
that is different from corresponding value in tuple a.
|
||||
|
||||
EXAMPLES
|
||||
Example1: if the function is called for tuples
|
||||
('aaa','bbb') and ('eee','fff'), then
|
||||
diff_pos[0] = 1 (as 'aaa' != 'eee')
|
||||
diff_pos[1] = 0 (offset from beggining of tuple b to 'eee' keypart).
|
||||
|
||||
Example2: if the index function is called for tuples
|
||||
('aaa','bbb') and ('aaa','fff'),
|
||||
diff_pos[0] = 2 (as 'aaa' != 'eee')
|
||||
diff_pos[1] = 3 (offset from beggining of tuple b to 'fff' keypart,
|
||||
here we assume that first key part is CHAR(3) NOT NULL)
|
||||
|
||||
NOTES
|
||||
Number-keys can't be splited
|
||||
|
||||
RETURN VALUES
|
||||
<0 If a < b
|
||||
0 If a == b
|
||||
>0 If a > b
|
||||
*/
|
||||
|
||||
#define FCMP(A,B) ((int) (A) - (int) (B))
|
||||
|
||||
int ha_key_cmp(register HA_KEYSEG *keyseg, register uchar *a,
|
||||
register uchar *b, uint key_length, uint nextflag,
|
||||
uint *diff_pos)
|
||||
{
|
||||
int flag;
|
||||
int16 s_1,s_2;
|
||||
int32 l_1,l_2;
|
||||
uint32 u_1,u_2;
|
||||
float f_1,f_2;
|
||||
double d_1,d_2;
|
||||
uint next_key_length;
|
||||
uchar *orig_b= b;
|
||||
|
||||
*diff_pos=0;
|
||||
for ( ; (int) key_length >0 ; key_length=next_key_length, keyseg++)
|
||||
{
|
||||
uchar *end;
|
||||
uint piks=! (keyseg->flag & HA_NO_SORT);
|
||||
(*diff_pos)++;
|
||||
diff_pos[1]= (uint)(b - orig_b);
|
||||
|
||||
/* Handle NULL part */
|
||||
if (keyseg->null_bit)
|
||||
{
|
||||
key_length--;
|
||||
if (*a != *b && piks)
|
||||
{
|
||||
flag = (int) *a - (int) *b;
|
||||
return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag);
|
||||
}
|
||||
b++;
|
||||
if (!*a++) /* If key was NULL */
|
||||
{
|
||||
if (nextflag == (SEARCH_FIND | SEARCH_UPDATE))
|
||||
nextflag=SEARCH_SAME; /* Allow duplicate keys */
|
||||
else if (nextflag & SEARCH_NULL_ARE_NOT_EQUAL)
|
||||
{
|
||||
/*
|
||||
This is only used from mi_check() to calculate cardinality.
|
||||
It can't be used when searching for a key as this would cause
|
||||
compare of (a,b) and (b,a) to return the same value.
|
||||
*/
|
||||
return -1;
|
||||
}
|
||||
next_key_length=key_length;
|
||||
continue; /* To next key part */
|
||||
}
|
||||
}
|
||||
end= a+ min(keyseg->length,key_length);
|
||||
next_key_length=key_length-keyseg->length;
|
||||
|
||||
switch ((enum ha_base_keytype) keyseg->type) {
|
||||
case HA_KEYTYPE_TEXT: /* Ascii; Key is converted */
|
||||
if (keyseg->flag & HA_SPACE_PACK)
|
||||
{
|
||||
int a_length,b_length,pack_length;
|
||||
get_key_length(a_length,a);
|
||||
get_key_pack_length(b_length,pack_length,b);
|
||||
next_key_length=key_length-b_length-pack_length;
|
||||
|
||||
if (piks &&
|
||||
(flag=ha_compare_text(keyseg->charset,a,a_length,b,b_length,
|
||||
(my_bool) ((nextflag & SEARCH_PREFIX) &&
|
||||
next_key_length <= 0),
|
||||
(my_bool)!(nextflag & SEARCH_PREFIX))))
|
||||
return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag);
|
||||
a+=a_length;
|
||||
b+=b_length;
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
uint length=(uint) (end-a), a_length=length, b_length=length;
|
||||
if (piks &&
|
||||
(flag= ha_compare_text(keyseg->charset, a, a_length, b, b_length,
|
||||
(my_bool) ((nextflag & SEARCH_PREFIX) &&
|
||||
next_key_length <= 0),
|
||||
(my_bool)!(nextflag & SEARCH_PREFIX))))
|
||||
return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag);
|
||||
a=end;
|
||||
b+=length;
|
||||
}
|
||||
break;
|
||||
case HA_KEYTYPE_BINARY:
|
||||
case HA_KEYTYPE_BIT:
|
||||
if (keyseg->flag & HA_SPACE_PACK)
|
||||
{
|
||||
int a_length,b_length,pack_length;
|
||||
get_key_length(a_length,a);
|
||||
get_key_pack_length(b_length,pack_length,b);
|
||||
next_key_length=key_length-b_length-pack_length;
|
||||
|
||||
if (piks &&
|
||||
(flag=compare_bin(a,a_length,b,b_length,
|
||||
(my_bool) ((nextflag & SEARCH_PREFIX) &&
|
||||
next_key_length <= 0),1)))
|
||||
return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag);
|
||||
a+=a_length;
|
||||
b+=b_length;
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
uint length=keyseg->length;
|
||||
if (piks &&
|
||||
(flag=compare_bin(a,length,b,length,
|
||||
(my_bool) ((nextflag & SEARCH_PREFIX) &&
|
||||
next_key_length <= 0),0)))
|
||||
return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag);
|
||||
a+=length;
|
||||
b+=length;
|
||||
}
|
||||
break;
|
||||
case HA_KEYTYPE_VARTEXT1:
|
||||
case HA_KEYTYPE_VARTEXT2:
|
||||
{
|
||||
int a_length,b_length,pack_length;
|
||||
get_key_length(a_length,a);
|
||||
get_key_pack_length(b_length,pack_length,b);
|
||||
next_key_length=key_length-b_length-pack_length;
|
||||
|
||||
if (piks &&
|
||||
(flag= ha_compare_text(keyseg->charset,a,a_length,b,b_length,
|
||||
(my_bool) ((nextflag & SEARCH_PREFIX) &&
|
||||
next_key_length <= 0),
|
||||
(my_bool) ((nextflag & (SEARCH_FIND |
|
||||
SEARCH_UPDATE)) ==
|
||||
SEARCH_FIND &&
|
||||
! (keyseg->flag &
|
||||
HA_END_SPACE_ARE_EQUAL)))))
|
||||
return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag);
|
||||
a+= a_length;
|
||||
b+= b_length;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case HA_KEYTYPE_VARBINARY1:
|
||||
case HA_KEYTYPE_VARBINARY2:
|
||||
{
|
||||
int a_length,b_length,pack_length;
|
||||
get_key_length(a_length,a);
|
||||
get_key_pack_length(b_length,pack_length,b);
|
||||
next_key_length=key_length-b_length-pack_length;
|
||||
|
||||
if (piks &&
|
||||
(flag=compare_bin(a,a_length,b,b_length,
|
||||
(my_bool) ((nextflag & SEARCH_PREFIX) &&
|
||||
next_key_length <= 0), 0)))
|
||||
return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag);
|
||||
a+=a_length;
|
||||
b+=b_length;
|
||||
}
|
||||
break;
|
||||
case HA_KEYTYPE_INT8:
|
||||
{
|
||||
int i_1= (int) *((signed char*) a);
|
||||
int i_2= (int) *((signed char*) b);
|
||||
if (piks && (flag = CMP_NUM(i_1,i_2)))
|
||||
return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag);
|
||||
a= end;
|
||||
b++;
|
||||
break;
|
||||
}
|
||||
case HA_KEYTYPE_SHORT_INT:
|
||||
s_1= mi_sint2korr(a);
|
||||
s_2= mi_sint2korr(b);
|
||||
if (piks && (flag = CMP_NUM(s_1,s_2)))
|
||||
return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag);
|
||||
a= end;
|
||||
b+= 2; /* sizeof(short int); */
|
||||
break;
|
||||
case HA_KEYTYPE_USHORT_INT:
|
||||
{
|
||||
uint16 us_1,us_2;
|
||||
us_1= mi_sint2korr(a);
|
||||
us_2= mi_sint2korr(b);
|
||||
if (piks && (flag = CMP_NUM(us_1,us_2)))
|
||||
return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag);
|
||||
a= end;
|
||||
b+=2; /* sizeof(short int); */
|
||||
break;
|
||||
}
|
||||
case HA_KEYTYPE_LONG_INT:
|
||||
l_1= mi_sint4korr(a);
|
||||
l_2= mi_sint4korr(b);
|
||||
if (piks && (flag = CMP_NUM(l_1,l_2)))
|
||||
return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag);
|
||||
a= end;
|
||||
b+= 4; /* sizeof(long int); */
|
||||
break;
|
||||
case HA_KEYTYPE_ULONG_INT:
|
||||
u_1= mi_sint4korr(a);
|
||||
u_2= mi_sint4korr(b);
|
||||
if (piks && (flag = CMP_NUM(u_1,u_2)))
|
||||
return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag);
|
||||
a= end;
|
||||
b+= 4; /* sizeof(long int); */
|
||||
break;
|
||||
case HA_KEYTYPE_INT24:
|
||||
l_1=mi_sint3korr(a);
|
||||
l_2=mi_sint3korr(b);
|
||||
if (piks && (flag = CMP_NUM(l_1,l_2)))
|
||||
return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag);
|
||||
a= end;
|
||||
b+= 3;
|
||||
break;
|
||||
case HA_KEYTYPE_UINT24:
|
||||
l_1=mi_uint3korr(a);
|
||||
l_2=mi_uint3korr(b);
|
||||
if (piks && (flag = CMP_NUM(l_1,l_2)))
|
||||
return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag);
|
||||
a= end;
|
||||
b+= 3;
|
||||
break;
|
||||
case HA_KEYTYPE_FLOAT:
|
||||
mi_float4get(f_1,a);
|
||||
mi_float4get(f_2,b);
|
||||
/*
|
||||
The following may give a compiler warning about floating point
|
||||
comparison not being safe, but this is ok in this context as
|
||||
we are bascily doing sorting
|
||||
*/
|
||||
if (piks && (flag = CMP_NUM(f_1,f_2)))
|
||||
return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag);
|
||||
a= end;
|
||||
b+= 4; /* sizeof(float); */
|
||||
break;
|
||||
case HA_KEYTYPE_DOUBLE:
|
||||
mi_float8get(d_1,a);
|
||||
mi_float8get(d_2,b);
|
||||
/*
|
||||
The following may give a compiler warning about floating point
|
||||
comparison not being safe, but this is ok in this context as
|
||||
we are bascily doing sorting
|
||||
*/
|
||||
if (piks && (flag = CMP_NUM(d_1,d_2)))
|
||||
return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag);
|
||||
a= end;
|
||||
b+= 8; /* sizeof(double); */
|
||||
break;
|
||||
case HA_KEYTYPE_NUM: /* Numeric key */
|
||||
{
|
||||
int swap_flag= 0;
|
||||
int alength,blength;
|
||||
|
||||
if (keyseg->flag & HA_REVERSE_SORT)
|
||||
{
|
||||
swap_variables(uchar*, a, b);
|
||||
swap_flag=1; /* Remember swap of a & b */
|
||||
end= a+ (int) (end-b);
|
||||
}
|
||||
if (keyseg->flag & HA_SPACE_PACK)
|
||||
{
|
||||
alength= *a++; blength= *b++;
|
||||
end=a+alength;
|
||||
next_key_length=key_length-blength-1;
|
||||
}
|
||||
else
|
||||
{
|
||||
alength= (int) (end-a);
|
||||
blength=keyseg->length;
|
||||
/* remove pre space from keys */
|
||||
for ( ; alength && *a == ' ' ; a++, alength--) ;
|
||||
for ( ; blength && *b == ' ' ; b++, blength--) ;
|
||||
}
|
||||
if (piks)
|
||||
{
|
||||
if (*a == '-')
|
||||
{
|
||||
if (*b != '-')
|
||||
return -1;
|
||||
a++; b++;
|
||||
swap_variables(uchar*, a, b);
|
||||
swap_variables(int, alength, blength);
|
||||
swap_flag=1-swap_flag;
|
||||
alength--; blength--;
|
||||
end=a+alength;
|
||||
}
|
||||
else if (*b == '-')
|
||||
return 1;
|
||||
while (alength && (*a == '+' || *a == '0'))
|
||||
{
|
||||
a++; alength--;
|
||||
}
|
||||
while (blength && (*b == '+' || *b == '0'))
|
||||
{
|
||||
b++; blength--;
|
||||
}
|
||||
if (alength != blength)
|
||||
return (alength < blength) ? -1 : 1;
|
||||
while (a < end)
|
||||
if (*a++ != *b++)
|
||||
return ((int) a[-1] - (int) b[-1]);
|
||||
}
|
||||
else
|
||||
{
|
||||
b+=(end-a);
|
||||
a=end;
|
||||
}
|
||||
|
||||
if (swap_flag) /* Restore pointers */
|
||||
swap_variables(uchar*, a, b);
|
||||
break;
|
||||
}
|
||||
#ifdef HAVE_LONG_LONG
|
||||
case HA_KEYTYPE_LONGLONG:
|
||||
{
|
||||
longlong ll_a,ll_b;
|
||||
ll_a= mi_sint8korr(a);
|
||||
ll_b= mi_sint8korr(b);
|
||||
if (piks && (flag = CMP_NUM(ll_a,ll_b)))
|
||||
return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag);
|
||||
a= end;
|
||||
b+= 8;
|
||||
break;
|
||||
}
|
||||
case HA_KEYTYPE_ULONGLONG:
|
||||
{
|
||||
ulonglong ll_a,ll_b;
|
||||
ll_a= mi_uint8korr(a);
|
||||
ll_b= mi_uint8korr(b);
|
||||
if (piks && (flag = CMP_NUM(ll_a,ll_b)))
|
||||
return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag);
|
||||
a= end;
|
||||
b+= 8;
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
case HA_KEYTYPE_END: /* Ready */
|
||||
goto end; /* diff_pos is incremented */
|
||||
}
|
||||
}
|
||||
(*diff_pos)++;
|
||||
end:
|
||||
if (!(nextflag & SEARCH_FIND))
|
||||
{
|
||||
uint i;
|
||||
if (nextflag & (SEARCH_NO_FIND | SEARCH_LAST)) /* Find record after key */
|
||||
return (nextflag & (SEARCH_BIGGER | SEARCH_LAST)) ? -1 : 1;
|
||||
flag=0;
|
||||
for (i=keyseg->length ; i-- > 0 ; )
|
||||
{
|
||||
if (*a++ != *b++)
|
||||
{
|
||||
flag= FCMP(a[-1],b[-1]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (nextflag & SEARCH_SAME)
|
||||
return (flag); /* read same */
|
||||
if (nextflag & SEARCH_BIGGER)
|
||||
return (flag <= 0 ? -1 : 1); /* read next */
|
||||
return (flag < 0 ? -1 : 1); /* read previous */
|
||||
}
|
||||
return 0;
|
||||
} /* ha_key_cmp */
|
||||
|
||||
|
||||
/*
|
||||
Find the first NULL value in index-suffix values tuple
|
||||
|
||||
SYNOPSIS
|
||||
ha_find_null()
|
||||
keyseg Array of keyparts for key suffix
|
||||
a Key suffix value tuple
|
||||
|
||||
DESCRIPTION
|
||||
Find the first NULL value in index-suffix values tuple.
|
||||
|
||||
TODO
|
||||
Consider optimizing this function or its use so we don't search for
|
||||
NULL values in completely NOT NULL index suffixes.
|
||||
|
||||
RETURN
|
||||
First key part that has NULL as value in values tuple, or the last key
|
||||
part (with keyseg->type==HA_TYPE_END) if values tuple doesn't contain
|
||||
NULLs.
|
||||
*/
|
||||
|
||||
HA_KEYSEG *ha_find_null(HA_KEYSEG *keyseg, uchar *a)
|
||||
{
|
||||
for (; (enum ha_base_keytype) keyseg->type != HA_KEYTYPE_END; keyseg++)
|
||||
{
|
||||
uchar *end;
|
||||
if (keyseg->null_bit)
|
||||
{
|
||||
if (!*a++)
|
||||
return keyseg;
|
||||
}
|
||||
end= a+ keyseg->length;
|
||||
|
||||
switch ((enum ha_base_keytype) keyseg->type) {
|
||||
case HA_KEYTYPE_TEXT:
|
||||
case HA_KEYTYPE_BINARY:
|
||||
case HA_KEYTYPE_BIT:
|
||||
if (keyseg->flag & HA_SPACE_PACK)
|
||||
{
|
||||
int a_length;
|
||||
get_key_length(a_length, a);
|
||||
a += a_length;
|
||||
break;
|
||||
}
|
||||
else
|
||||
a= end;
|
||||
break;
|
||||
case HA_KEYTYPE_VARTEXT1:
|
||||
case HA_KEYTYPE_VARTEXT2:
|
||||
case HA_KEYTYPE_VARBINARY1:
|
||||
case HA_KEYTYPE_VARBINARY2:
|
||||
{
|
||||
int a_length;
|
||||
get_key_length(a_length, a);
|
||||
a+= a_length;
|
||||
break;
|
||||
}
|
||||
case HA_KEYTYPE_NUM:
|
||||
if (keyseg->flag & HA_SPACE_PACK)
|
||||
{
|
||||
int alength= *a++;
|
||||
end= a+alength;
|
||||
}
|
||||
a= end;
|
||||
break;
|
||||
case HA_KEYTYPE_INT8:
|
||||
case HA_KEYTYPE_SHORT_INT:
|
||||
case HA_KEYTYPE_USHORT_INT:
|
||||
case HA_KEYTYPE_LONG_INT:
|
||||
case HA_KEYTYPE_ULONG_INT:
|
||||
case HA_KEYTYPE_INT24:
|
||||
case HA_KEYTYPE_UINT24:
|
||||
#ifdef HAVE_LONG_LONG
|
||||
case HA_KEYTYPE_LONGLONG:
|
||||
case HA_KEYTYPE_ULONGLONG:
|
||||
#endif
|
||||
case HA_KEYTYPE_FLOAT:
|
||||
case HA_KEYTYPE_DOUBLE:
|
||||
a= end;
|
||||
break;
|
||||
case HA_KEYTYPE_END: /* purecov: inspected */
|
||||
/* keep compiler happy */
|
||||
DBUG_ASSERT(0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return keyseg;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
Register handler error messages for usage with my_error()
|
||||
|
||||
NOTES
|
||||
This is safe to call multiple times as my_error_register()
|
||||
will ignore calls to register already registered error numbers.
|
||||
*/
|
||||
|
||||
static const char **get_handler_error_messages()
|
||||
{
|
||||
return handler_error_messages;
|
||||
}
|
||||
|
||||
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
|
||||
include/my_base.h).
|
||||
*/
|
||||
compile_time_assert(HA_ERR_FIRST + array_elements(handler_error_messages) ==
|
||||
HA_ERR_LAST + 1);
|
||||
my_error_register(get_handler_error_messages, HA_ERR_FIRST,
|
||||
HA_ERR_FIRST+ array_elements(handler_error_messages)-1);
|
||||
}
|
||||
|
||||
|
||||
void my_handler_error_unregister(void)
|
||||
{
|
||||
my_error_unregister(HA_ERR_FIRST,
|
||||
HA_ERR_FIRST+ array_elements(handler_error_messages)-1);
|
||||
}
|
||||
71
deps/mysqllite/mysys/my_handler_errors.h
vendored
Normal file
71
deps/mysqllite/mysys/my_handler_errors.h
vendored
Normal file
@@ -0,0 +1,71 @@
|
||||
#ifndef MYSYS_MY_HANDLER_ERRORS_INCLUDED
|
||||
#define MYSYS_MY_HANDLER_ERRORS_INCLUDED
|
||||
|
||||
/*
|
||||
Errors a handler can give you
|
||||
*/
|
||||
|
||||
static const char *handler_error_messages[]=
|
||||
{
|
||||
"Didn't find key on read or update",
|
||||
"Duplicate key on write or update",
|
||||
"Internal (unspecified) error in handler",
|
||||
"Someone has changed the row since it was read (while the table was locked to prevent it)",
|
||||
"Wrong index given to function",
|
||||
"Undefined handler error 125",
|
||||
"Index file is crashed",
|
||||
"Record file is crashed",
|
||||
"Out of memory in engine",
|
||||
"Undefined handler error 129",
|
||||
"Incorrect file format",
|
||||
"Command not supported by database",
|
||||
"Old database file",
|
||||
"No record read before update",
|
||||
"Record was already deleted (or record file crashed)",
|
||||
"No more room in record file",
|
||||
"No more room in index file",
|
||||
"No more records (read after end of file)",
|
||||
"Unsupported extension used for table",
|
||||
"Too big row",
|
||||
"Wrong create options",
|
||||
"Duplicate unique key or constraint on write or update",
|
||||
"Unknown character set used in table",
|
||||
"Conflicting table definitions in sub-tables of MERGE table",
|
||||
"Table is crashed and last repair failed",
|
||||
"Table was marked as crashed and should be repaired",
|
||||
"Lock timed out; Retry transaction",
|
||||
"Lock table is full; Restart program with a larger locktable",
|
||||
"Updates are not allowed under a read only transactions",
|
||||
"Lock deadlock; Retry transaction",
|
||||
"Foreign key constraint is incorrectly formed",
|
||||
"Cannot add a child row",
|
||||
"Cannot delete a parent row",
|
||||
"No savepoint with that name",
|
||||
"Non unique key block size",
|
||||
"The table does not exist in engine",
|
||||
"The table already existed in storage engine",
|
||||
"Could not connect to storage engine",
|
||||
"Unexpected null pointer found when using spatial index",
|
||||
"The table changed in storage engine",
|
||||
"There's no partition in table for the given value",
|
||||
"Row-based binlogging of row failed",
|
||||
"Index needed in foreign key constraint",
|
||||
"Upholding foreign key constraints would lead to a duplicate key error in "
|
||||
"some other table",
|
||||
"Table needs to be upgraded before it can be used",
|
||||
"Table is read only",
|
||||
"Failed to get next auto increment value",
|
||||
"Failed to set row auto increment value",
|
||||
"Unknown (generic) error from engine",
|
||||
"Record is the same",
|
||||
"It is not possible to log this statement",
|
||||
"The event was corrupt, leading to illegal data being read",
|
||||
"The table is of a new format not supported by this version",
|
||||
"The event could not be processed no other hanlder error happened",
|
||||
"Got a fatal error during initialzaction of handler",
|
||||
"File to short; Expected more data in file",
|
||||
"Read page with wrong checksum",
|
||||
"Too many active concurrent transactions"
|
||||
};
|
||||
|
||||
#endif /* MYSYS_MY_HANDLER_ERRORS_INCLUDED */
|
||||
607
deps/mysqllite/mysys/my_init.c
vendored
Normal file
607
deps/mysqllite/mysys/my_init.c
vendored
Normal file
@@ -0,0 +1,607 @@
|
||||
/* Copyright (C) 2000-2003 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 */
|
||||
|
||||
#include "mysys_priv.h"
|
||||
#include "my_static.h"
|
||||
#include "mysys_err.h"
|
||||
#include <m_string.h>
|
||||
#include <m_ctype.h>
|
||||
#include <signal.h>
|
||||
#ifdef __WIN__
|
||||
#ifdef _MSC_VER
|
||||
#include <locale.h>
|
||||
#include <crtdbg.h>
|
||||
/* WSAStartup needs winsock library*/
|
||||
#pragma comment(lib, "ws2_32")
|
||||
#endif
|
||||
my_bool have_tcpip=0;
|
||||
static void my_win_init(void);
|
||||
static my_bool win32_init_tcp_ip();
|
||||
#else
|
||||
#define my_win_init()
|
||||
#endif
|
||||
|
||||
#define SCALE_SEC 100
|
||||
#define SCALE_USEC 10000
|
||||
|
||||
my_bool my_init_done= 0;
|
||||
/** True if @c my_basic_init() has been called. */
|
||||
my_bool my_basic_init_done= 0;
|
||||
uint mysys_usage_id= 0; /* Incremented for each my_init() */
|
||||
ulong my_thread_stack_size= 65536;
|
||||
|
||||
static ulong atoi_octal(const char *str)
|
||||
{
|
||||
long int tmp;
|
||||
while (*str && my_isspace(&my_charset_latin1, *str))
|
||||
str++;
|
||||
str2int(str,
|
||||
(*str == '0' ? 8 : 10), /* Octalt or decimalt */
|
||||
0, INT_MAX, &tmp);
|
||||
return (ulong) tmp;
|
||||
}
|
||||
|
||||
MYSQL_FILE *mysql_stdin= NULL;
|
||||
static MYSQL_FILE instrumented_stdin;
|
||||
|
||||
/**
|
||||
Perform a limited initialisation of mysys.
|
||||
This initialisation is sufficient to:
|
||||
- allocate memory,
|
||||
- read configuration files,
|
||||
- parse command lines arguments.
|
||||
To complete the mysys initialisation,
|
||||
call my_init().
|
||||
@return 0 on success
|
||||
*/
|
||||
my_bool my_basic_init(void)
|
||||
{
|
||||
char * str;
|
||||
|
||||
if (my_basic_init_done)
|
||||
return 0;
|
||||
my_basic_init_done= 1;
|
||||
|
||||
mysys_usage_id++;
|
||||
my_umask= 0660; /* Default umask for new files */
|
||||
my_umask_dir= 0700; /* Default umask for new directories */
|
||||
|
||||
/* Default creation of new files */
|
||||
if ((str= getenv("UMASK")) != 0)
|
||||
my_umask= (int) (atoi_octal(str) | 0600);
|
||||
/* Default creation of new dir's */
|
||||
if ((str= getenv("UMASK_DIR")) != 0)
|
||||
my_umask_dir= (int) (atoi_octal(str) | 0700);
|
||||
|
||||
init_glob_errs();
|
||||
|
||||
instrumented_stdin.m_file= stdin;
|
||||
instrumented_stdin.m_psi= NULL; /* not yet instrumented */
|
||||
mysql_stdin= & instrumented_stdin;
|
||||
|
||||
if (my_thread_global_init())
|
||||
return 1;
|
||||
|
||||
#if defined(SAFE_MUTEX)
|
||||
safe_mutex_global_init(); /* Must be called early */
|
||||
#endif
|
||||
|
||||
#if defined(MY_PTHREAD_FASTMUTEX) && !defined(SAFE_MUTEX)
|
||||
fastmutex_global_init(); /* Must be called early */
|
||||
#endif
|
||||
|
||||
#if defined(HAVE_PTHREAD_INIT)
|
||||
pthread_init(); /* Must be called before DBUG_ENTER */
|
||||
#endif
|
||||
if (my_thread_basic_global_init())
|
||||
return 1;
|
||||
|
||||
/* $HOME is needed early to parse configuration files located in ~/ */
|
||||
if ((home_dir= getenv("HOME")) != 0)
|
||||
home_dir= intern_filename(home_dir_buff, home_dir);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Init my_sys functions and my_sys variabels
|
||||
|
||||
SYNOPSIS
|
||||
my_init()
|
||||
|
||||
RETURN
|
||||
0 ok
|
||||
1 Couldn't initialize environment
|
||||
*/
|
||||
|
||||
my_bool my_init(void)
|
||||
{
|
||||
if (my_init_done)
|
||||
return 0;
|
||||
|
||||
my_init_done= 1;
|
||||
|
||||
if (my_basic_init())
|
||||
return 1;
|
||||
|
||||
if (my_thread_global_init())
|
||||
return 1;
|
||||
|
||||
{
|
||||
DBUG_ENTER("my_init");
|
||||
DBUG_PROCESS((char*) (my_progname ? my_progname : "unknown"));
|
||||
my_win_init();
|
||||
DBUG_PRINT("exit", ("home: '%s'", home_dir));
|
||||
#ifdef __WIN__
|
||||
win32_init_tcp_ip();
|
||||
#endif
|
||||
DBUG_RETURN(0);
|
||||
}
|
||||
} /* my_init */
|
||||
|
||||
|
||||
/* End my_sys */
|
||||
|
||||
void my_end(int infoflag)
|
||||
{
|
||||
/*
|
||||
this code is suboptimal to workaround a bug in
|
||||
Sun CC: Sun C++ 5.6 2004/06/02 for x86, and should not be
|
||||
optimized until this compiler is not in use anymore
|
||||
*/
|
||||
FILE *info_file= DBUG_FILE;
|
||||
my_bool print_info= (info_file != stderr);
|
||||
|
||||
if (!my_init_done)
|
||||
return;
|
||||
|
||||
/*
|
||||
We do not use DBUG_ENTER here, as after cleanup DBUG is no longer
|
||||
operational, so we cannot use DBUG_RETURN.
|
||||
*/
|
||||
DBUG_PRINT("info",("Shutting down: infoflag: %d print_info: %d",
|
||||
infoflag, print_info));
|
||||
if (!info_file)
|
||||
{
|
||||
info_file= stderr;
|
||||
print_info= 0;
|
||||
}
|
||||
|
||||
if ((infoflag & MY_CHECK_ERROR) || print_info)
|
||||
|
||||
{ /* Test if some file is left open */
|
||||
if (my_file_opened | my_stream_opened)
|
||||
{
|
||||
char ebuff[512];
|
||||
my_snprintf(ebuff, sizeof(ebuff), EE(EE_OPEN_WARNING),
|
||||
my_file_opened, my_stream_opened);
|
||||
my_message_stderr(EE_OPEN_WARNING, ebuff, ME_BELL);
|
||||
DBUG_PRINT("error", ("%s", ebuff));
|
||||
my_print_open_files();
|
||||
}
|
||||
}
|
||||
free_charsets();
|
||||
my_error_unregister_all();
|
||||
my_once_free();
|
||||
|
||||
if ((infoflag & MY_GIVE_INFO) || print_info)
|
||||
{
|
||||
#ifdef HAVE_GETRUSAGE
|
||||
struct rusage rus;
|
||||
#ifdef HAVE_purify
|
||||
/* Purify assumes that rus is uninitialized after getrusage call */
|
||||
bzero((char*) &rus, sizeof(rus));
|
||||
#endif
|
||||
if (!getrusage(RUSAGE_SELF, &rus))
|
||||
fprintf(info_file,"\n\
|
||||
User time %.2f, System time %.2f\n\
|
||||
Maximum resident set size %ld, Integral resident set size %ld\n\
|
||||
Non-physical pagefaults %ld, Physical pagefaults %ld, Swaps %ld\n\
|
||||
Blocks in %ld out %ld, Messages in %ld out %ld, Signals %ld\n\
|
||||
Voluntary context switches %ld, Involuntary context switches %ld\n",
|
||||
(rus.ru_utime.tv_sec * SCALE_SEC +
|
||||
rus.ru_utime.tv_usec / SCALE_USEC) / 100.0,
|
||||
(rus.ru_stime.tv_sec * SCALE_SEC +
|
||||
rus.ru_stime.tv_usec / SCALE_USEC) / 100.0,
|
||||
rus.ru_maxrss, rus.ru_idrss,
|
||||
rus.ru_minflt, rus.ru_majflt,
|
||||
rus.ru_nswap, rus.ru_inblock, rus.ru_oublock,
|
||||
rus.ru_msgsnd, rus.ru_msgrcv, rus.ru_nsignals,
|
||||
rus.ru_nvcsw, rus.ru_nivcsw);
|
||||
#endif
|
||||
#if defined(__WIN__) && defined(_MSC_VER)
|
||||
_CrtSetReportMode( _CRT_WARN, _CRTDBG_MODE_FILE );
|
||||
_CrtSetReportFile( _CRT_WARN, _CRTDBG_FILE_STDERR );
|
||||
_CrtSetReportMode( _CRT_ERROR, _CRTDBG_MODE_FILE );
|
||||
_CrtSetReportFile( _CRT_ERROR, _CRTDBG_FILE_STDERR );
|
||||
_CrtSetReportMode( _CRT_ASSERT, _CRTDBG_MODE_FILE );
|
||||
_CrtSetReportFile( _CRT_ASSERT, _CRTDBG_FILE_STDERR );
|
||||
_CrtCheckMemory();
|
||||
_CrtDumpMemoryLeaks();
|
||||
#endif
|
||||
}
|
||||
|
||||
if (!(infoflag & MY_DONT_FREE_DBUG))
|
||||
{
|
||||
DBUG_END(); /* Must be done before my_thread_end */
|
||||
}
|
||||
|
||||
my_thread_end();
|
||||
my_thread_global_end();
|
||||
#if defined(SAFE_MUTEX)
|
||||
/*
|
||||
Check on destroying of mutexes. A few may be left that will get cleaned
|
||||
up by C++ destructors
|
||||
*/
|
||||
safe_mutex_end((infoflag & (MY_GIVE_INFO | MY_CHECK_ERROR)) ? stderr :
|
||||
(FILE *) 0);
|
||||
#endif /* defined(SAFE_MUTEX) */
|
||||
|
||||
#ifdef __WIN__
|
||||
if (have_tcpip)
|
||||
WSACleanup();
|
||||
#endif /* __WIN__ */
|
||||
|
||||
my_init_done=0;
|
||||
my_basic_init_done= 0;
|
||||
} /* my_end */
|
||||
|
||||
|
||||
#ifdef __WIN__
|
||||
|
||||
|
||||
/*
|
||||
my_parameter_handler
|
||||
|
||||
Invalid parameter handler we will use instead of the one "baked"
|
||||
into the CRT for MSC v8. This one just prints out what invalid
|
||||
parameter was encountered. By providing this routine, routines like
|
||||
lseek will return -1 when we expect them to instead of crash.
|
||||
*/
|
||||
|
||||
void my_parameter_handler(const wchar_t * expression, const wchar_t * function,
|
||||
const wchar_t * file, unsigned int line,
|
||||
uintptr_t pReserved)
|
||||
{
|
||||
DBUG_PRINT("my",("Expression: %s function: %s file: %s, line: %d",
|
||||
expression, function, file, line));
|
||||
}
|
||||
|
||||
|
||||
#ifdef __MSVC_RUNTIME_CHECKS
|
||||
#include <rtcapi.h>
|
||||
|
||||
/* Turn off runtime checks for 'handle_rtc_failure' */
|
||||
#pragma runtime_checks("", off)
|
||||
|
||||
/*
|
||||
handle_rtc_failure
|
||||
Catch the RTC error and dump it to stderr
|
||||
*/
|
||||
|
||||
int handle_rtc_failure(int err_type, const char *file, int line,
|
||||
const char* module, const char *format, ...)
|
||||
{
|
||||
va_list args;
|
||||
va_start(args, format);
|
||||
fprintf(stderr, "Error:");
|
||||
vfprintf(stderr, format, args);
|
||||
fprintf(stderr, " At %s:%d\n", file, line);
|
||||
va_end(args);
|
||||
(void) fflush(stderr);
|
||||
|
||||
return 0; /* Error is handled */
|
||||
}
|
||||
#pragma runtime_checks("", restore)
|
||||
#endif
|
||||
|
||||
#define OFFSET_TO_EPOC ((__int64) 134774 * 24 * 60 * 60 * 1000 * 1000 * 10)
|
||||
#define MS 10000000
|
||||
|
||||
static void win_init_time(void)
|
||||
{
|
||||
/* The following is used by time functions */
|
||||
FILETIME ft;
|
||||
LARGE_INTEGER li, t_cnt;
|
||||
|
||||
DBUG_ASSERT(sizeof(LARGE_INTEGER) == sizeof(query_performance_frequency));
|
||||
|
||||
if (QueryPerformanceFrequency((LARGE_INTEGER *)&query_performance_frequency) == 0)
|
||||
query_performance_frequency= 0;
|
||||
else
|
||||
{
|
||||
GetSystemTimeAsFileTime(&ft);
|
||||
li.LowPart= ft.dwLowDateTime;
|
||||
li.HighPart= ft.dwHighDateTime;
|
||||
query_performance_offset= li.QuadPart-OFFSET_TO_EPOC;
|
||||
QueryPerformanceCounter(&t_cnt);
|
||||
query_performance_offset-= (t_cnt.QuadPart /
|
||||
query_performance_frequency * MS +
|
||||
t_cnt.QuadPart %
|
||||
query_performance_frequency * MS /
|
||||
query_performance_frequency);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Open HKEY_LOCAL_MACHINE\SOFTWARE\MySQL and set any strings found
|
||||
there as environment variables
|
||||
*/
|
||||
static void win_init_registry(void)
|
||||
{
|
||||
HKEY key_handle;
|
||||
|
||||
if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, (LPCTSTR)"SOFTWARE\\MySQL",
|
||||
0, KEY_READ, &key_handle) == ERROR_SUCCESS)
|
||||
{
|
||||
LONG ret;
|
||||
DWORD index= 0;
|
||||
DWORD type;
|
||||
char key_name[256], key_data[1024];
|
||||
DWORD key_name_len= sizeof(key_name) - 1;
|
||||
DWORD key_data_len= sizeof(key_data) - 1;
|
||||
|
||||
while ((ret= RegEnumValue(key_handle, index++,
|
||||
key_name, &key_name_len,
|
||||
NULL, &type, (LPBYTE)&key_data,
|
||||
&key_data_len)) != ERROR_NO_MORE_ITEMS)
|
||||
{
|
||||
char env_string[sizeof(key_name) + sizeof(key_data) + 2];
|
||||
|
||||
if (ret == ERROR_MORE_DATA)
|
||||
{
|
||||
/* Registry value larger than 'key_data', skip it */
|
||||
DBUG_PRINT("error", ("Skipped registry value that was too large"));
|
||||
}
|
||||
else if (ret == ERROR_SUCCESS)
|
||||
{
|
||||
if (type == REG_SZ)
|
||||
{
|
||||
strxmov(env_string, key_name, "=", key_data, NullS);
|
||||
|
||||
/* variable for putenv must be allocated ! */
|
||||
putenv(strdup(env_string)) ;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Unhandled error, break out of loop */
|
||||
break;
|
||||
}
|
||||
|
||||
key_name_len= sizeof(key_name) - 1;
|
||||
key_data_len= sizeof(key_data) - 1;
|
||||
}
|
||||
|
||||
RegCloseKey(key_handle);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void my_win_init(void)
|
||||
{
|
||||
DBUG_ENTER("my_win_init");
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
#if _MSC_VER < 1300
|
||||
/*
|
||||
Clear the OS system variable TZ and avoid the 100% CPU usage
|
||||
Only for old versions of Visual C++
|
||||
*/
|
||||
_putenv("TZ=");
|
||||
#endif
|
||||
#if _MSC_VER >= 1400
|
||||
/* this is required to make crt functions return -1 appropriately */
|
||||
_set_invalid_parameter_handler(my_parameter_handler);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef __MSVC_RUNTIME_CHECKS
|
||||
/*
|
||||
Install handler to send RTC (Runtime Error Check) warnings
|
||||
to log file
|
||||
*/
|
||||
_RTC_SetErrorFunc(handle_rtc_failure);
|
||||
#endif
|
||||
|
||||
_tzset();
|
||||
|
||||
win_init_time();
|
||||
win_init_registry();
|
||||
|
||||
DBUG_VOID_RETURN;
|
||||
}
|
||||
|
||||
|
||||
/*------------------------------------------------------------------
|
||||
Name: CheckForTcpip| Desc: checks if tcpip has been installed on system
|
||||
According to Microsoft Developers documentation the first registry
|
||||
entry should be enough to check if TCP/IP is installed, but as expected
|
||||
this doesn't work on all Win32 machines :(
|
||||
------------------------------------------------------------------*/
|
||||
|
||||
#define TCPIPKEY "SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters"
|
||||
#define WINSOCK2KEY "SYSTEM\\CurrentControlSet\\Services\\Winsock2\\Parameters"
|
||||
#define WINSOCKKEY "SYSTEM\\CurrentControlSet\\Services\\Winsock\\Parameters"
|
||||
|
||||
static my_bool win32_have_tcpip(void)
|
||||
{
|
||||
HKEY hTcpipRegKey;
|
||||
if (RegOpenKeyEx ( HKEY_LOCAL_MACHINE, TCPIPKEY, 0, KEY_READ,
|
||||
&hTcpipRegKey) != ERROR_SUCCESS)
|
||||
{
|
||||
if (RegOpenKeyEx ( HKEY_LOCAL_MACHINE, WINSOCK2KEY, 0, KEY_READ,
|
||||
&hTcpipRegKey) != ERROR_SUCCESS)
|
||||
{
|
||||
if (RegOpenKeyEx ( HKEY_LOCAL_MACHINE, WINSOCKKEY, 0, KEY_READ,
|
||||
&hTcpipRegKey) != ERROR_SUCCESS)
|
||||
if (!getenv("HAVE_TCPIP") || have_tcpip) /* Provide a workaround */
|
||||
return (FALSE);
|
||||
}
|
||||
}
|
||||
RegCloseKey ( hTcpipRegKey);
|
||||
return (TRUE);
|
||||
}
|
||||
|
||||
|
||||
static my_bool win32_init_tcp_ip()
|
||||
{
|
||||
if (win32_have_tcpip())
|
||||
{
|
||||
WORD wVersionRequested = MAKEWORD( 2, 2 );
|
||||
WSADATA wsaData;
|
||||
/* Be a good citizen: maybe another lib has already initialised
|
||||
sockets, so dont clobber them unless necessary */
|
||||
if (WSAStartup( wVersionRequested, &wsaData ))
|
||||
{
|
||||
/* Load failed, maybe because of previously loaded
|
||||
incompatible version; try again */
|
||||
WSACleanup( );
|
||||
if (!WSAStartup( wVersionRequested, &wsaData ))
|
||||
have_tcpip=1;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (wsaData.wVersion != wVersionRequested)
|
||||
{
|
||||
/* Version is no good, try again */
|
||||
WSACleanup( );
|
||||
if (!WSAStartup( wVersionRequested, &wsaData ))
|
||||
have_tcpip=1;
|
||||
}
|
||||
else
|
||||
have_tcpip=1;
|
||||
}
|
||||
}
|
||||
return(0);
|
||||
}
|
||||
#endif /* __WIN__ */
|
||||
|
||||
#ifdef HAVE_PSI_INTERFACE
|
||||
|
||||
#if !defined(HAVE_PREAD) && !defined(_WIN32)
|
||||
PSI_mutex_key key_my_file_info_mutex;
|
||||
#endif /* !defined(HAVE_PREAD) && !defined(_WIN32) */
|
||||
|
||||
#if !defined(HAVE_LOCALTIME_R) || !defined(HAVE_GMTIME_R)
|
||||
PSI_mutex_key key_LOCK_localtime_r;
|
||||
#endif /* !defined(HAVE_LOCALTIME_R) || !defined(HAVE_GMTIME_R) */
|
||||
|
||||
#ifndef HAVE_GETHOSTBYNAME_R
|
||||
PSI_mutex_key key_LOCK_gethostbyname_r;
|
||||
#endif /* HAVE_GETHOSTBYNAME_R */
|
||||
|
||||
PSI_mutex_key key_BITMAP_mutex, key_IO_CACHE_append_buffer_lock,
|
||||
key_IO_CACHE_SHARE_mutex, key_KEY_CACHE_cache_lock, key_LOCK_alarm,
|
||||
key_my_thread_var_mutex, key_THR_LOCK_charset, key_THR_LOCK_heap,
|
||||
key_THR_LOCK_isam, key_THR_LOCK_lock, key_THR_LOCK_malloc,
|
||||
key_THR_LOCK_mutex, key_THR_LOCK_myisam, key_THR_LOCK_net,
|
||||
key_THR_LOCK_open, key_THR_LOCK_threads, key_THR_LOCK_time,
|
||||
key_TMPDIR_mutex, key_THR_LOCK_myisam_mmap;
|
||||
|
||||
static PSI_mutex_info all_mysys_mutexes[]=
|
||||
{
|
||||
#if !defined(HAVE_PREAD) && !defined(_WIN32)
|
||||
{ &key_my_file_info_mutex, "st_my_file_info:mutex", 0},
|
||||
#endif /* !defined(HAVE_PREAD) && !defined(_WIN32) */
|
||||
#if !defined(HAVE_LOCALTIME_R) || !defined(HAVE_GMTIME_R)
|
||||
{ &key_LOCK_localtime_r, "LOCK_localtime_r", PSI_FLAG_GLOBAL},
|
||||
#endif /* !defined(HAVE_LOCALTIME_R) || !defined(HAVE_GMTIME_R) */
|
||||
#ifndef HAVE_GETHOSTBYNAME_R
|
||||
{ &key_LOCK_gethostbyname_r, "LOCK_gethostbyname_r", PSI_FLAG_GLOBAL},
|
||||
#endif /* HAVE_GETHOSTBYNAME_R */
|
||||
{ &key_BITMAP_mutex, "BITMAP::mutex", 0},
|
||||
{ &key_IO_CACHE_append_buffer_lock, "IO_CACHE::append_buffer_lock", 0},
|
||||
{ &key_IO_CACHE_SHARE_mutex, "IO_CACHE::SHARE_mutex", 0},
|
||||
{ &key_KEY_CACHE_cache_lock, "KEY_CACHE::cache_lock", 0},
|
||||
{ &key_LOCK_alarm, "LOCK_alarm", PSI_FLAG_GLOBAL},
|
||||
{ &key_my_thread_var_mutex, "my_thread_var::mutex", 0},
|
||||
{ &key_THR_LOCK_charset, "THR_LOCK_charset", PSI_FLAG_GLOBAL},
|
||||
{ &key_THR_LOCK_heap, "THR_LOCK_heap", PSI_FLAG_GLOBAL},
|
||||
{ &key_THR_LOCK_isam, "THR_LOCK_isam", PSI_FLAG_GLOBAL},
|
||||
{ &key_THR_LOCK_lock, "THR_LOCK_lock", PSI_FLAG_GLOBAL},
|
||||
{ &key_THR_LOCK_malloc, "THR_LOCK_malloc", PSI_FLAG_GLOBAL},
|
||||
{ &key_THR_LOCK_mutex, "THR_LOCK::mutex", 0},
|
||||
{ &key_THR_LOCK_myisam, "THR_LOCK_myisam", PSI_FLAG_GLOBAL},
|
||||
{ &key_THR_LOCK_net, "THR_LOCK_net", PSI_FLAG_GLOBAL},
|
||||
{ &key_THR_LOCK_open, "THR_LOCK_open", PSI_FLAG_GLOBAL},
|
||||
{ &key_THR_LOCK_threads, "THR_LOCK_threads", PSI_FLAG_GLOBAL},
|
||||
{ &key_THR_LOCK_time, "THR_LOCK_time", PSI_FLAG_GLOBAL},
|
||||
{ &key_TMPDIR_mutex, "TMPDIR_mutex", PSI_FLAG_GLOBAL},
|
||||
{ &key_THR_LOCK_myisam_mmap, "THR_LOCK_myisam_mmap", PSI_FLAG_GLOBAL}
|
||||
};
|
||||
|
||||
PSI_cond_key key_COND_alarm, key_IO_CACHE_SHARE_cond,
|
||||
key_IO_CACHE_SHARE_cond_writer, key_my_thread_var_suspend,
|
||||
key_THR_COND_threads;
|
||||
|
||||
static PSI_cond_info all_mysys_conds[]=
|
||||
{
|
||||
{ &key_COND_alarm, "COND_alarm", PSI_FLAG_GLOBAL},
|
||||
{ &key_IO_CACHE_SHARE_cond, "IO_CACHE_SHARE::cond", 0},
|
||||
{ &key_IO_CACHE_SHARE_cond_writer, "IO_CACHE_SHARE::cond_writer", 0},
|
||||
{ &key_my_thread_var_suspend, "my_thread_var::suspend", 0},
|
||||
{ &key_THR_COND_threads, "THR_COND_threads", 0}
|
||||
};
|
||||
|
||||
#ifdef USE_ALARM_THREAD
|
||||
PSI_thread_key key_thread_alarm;
|
||||
|
||||
static PSI_thread_info all_mysys_threads[]=
|
||||
{
|
||||
{ &key_thread_alarm, "alarm", PSI_FLAG_GLOBAL}
|
||||
};
|
||||
#endif /* USE_ALARM_THREAD */
|
||||
|
||||
#ifdef HUGETLB_USE_PROC_MEMINFO
|
||||
PSI_file_key key_file_proc_meminfo;
|
||||
#endif /* HUGETLB_USE_PROC_MEMINFO */
|
||||
PSI_file_key key_file_charset, key_file_cnf;
|
||||
|
||||
static PSI_file_info all_mysys_files[]=
|
||||
{
|
||||
#ifdef HUGETLB_USE_PROC_MEMINFO
|
||||
{ &key_file_proc_meminfo, "proc_meminfo", 0},
|
||||
#endif /* HUGETLB_USE_PROC_MEMINFO */
|
||||
{ &key_file_charset, "charset", 0},
|
||||
{ &key_file_cnf, "cnf", 0}
|
||||
};
|
||||
|
||||
void my_init_mysys_psi_keys()
|
||||
{
|
||||
const char* category= "mysys";
|
||||
int count;
|
||||
|
||||
if (PSI_server == NULL)
|
||||
return;
|
||||
|
||||
count= sizeof(all_mysys_mutexes)/sizeof(all_mysys_mutexes[0]);
|
||||
PSI_server->register_mutex(category, all_mysys_mutexes, count);
|
||||
|
||||
count= sizeof(all_mysys_conds)/sizeof(all_mysys_conds[0]);
|
||||
PSI_server->register_cond(category, all_mysys_conds, count);
|
||||
|
||||
#ifdef USE_ALARM_THREAD
|
||||
count= sizeof(all_mysys_threads)/sizeof(all_mysys_threads[0]);
|
||||
PSI_server->register_thread(category, all_mysys_threads, count);
|
||||
#endif /* USE_ALARM_THREAD */
|
||||
|
||||
count= sizeof(all_mysys_files)/sizeof(all_mysys_files[0]);
|
||||
PSI_server->register_file(category, all_mysys_files, count);
|
||||
}
|
||||
#endif /* HAVE_PSI_INTERFACE */
|
||||
|
||||
166
deps/mysqllite/mysys/my_largepage.c
vendored
Normal file
166
deps/mysqllite/mysys/my_largepage.c
vendored
Normal file
@@ -0,0 +1,166 @@
|
||||
/* Copyright (C) 2004 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 */
|
||||
|
||||
#include "mysys_priv.h"
|
||||
|
||||
#ifdef HAVE_LARGE_PAGES
|
||||
|
||||
#ifdef HAVE_SYS_IPC_H
|
||||
#include <sys/ipc.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_SYS_SHM_H
|
||||
#include <sys/shm.h>
|
||||
#endif
|
||||
|
||||
static uint my_get_large_page_size_int(void);
|
||||
static uchar* my_large_malloc_int(size_t size, myf my_flags);
|
||||
static my_bool my_large_free_int(uchar* ptr);
|
||||
|
||||
/* Gets the size of large pages from the OS */
|
||||
|
||||
uint my_get_large_page_size(void)
|
||||
{
|
||||
uint size;
|
||||
DBUG_ENTER("my_get_large_page_size");
|
||||
|
||||
if (!(size = my_get_large_page_size_int()))
|
||||
fprintf(stderr, "Warning: Failed to determine large page size\n");
|
||||
|
||||
DBUG_RETURN(size);
|
||||
}
|
||||
|
||||
/*
|
||||
General large pages allocator.
|
||||
Tries to allocate memory from large pages pool and falls back to
|
||||
my_malloc_lock() in case of failure
|
||||
*/
|
||||
|
||||
uchar* my_large_malloc(size_t size, myf my_flags)
|
||||
{
|
||||
uchar* ptr;
|
||||
DBUG_ENTER("my_large_malloc");
|
||||
|
||||
if (my_use_large_pages && my_large_page_size)
|
||||
{
|
||||
if ((ptr = my_large_malloc_int(size, my_flags)) != NULL)
|
||||
DBUG_RETURN(ptr);
|
||||
if (my_flags & MY_WME)
|
||||
fprintf(stderr, "Warning: Using conventional memory pool\n");
|
||||
}
|
||||
|
||||
DBUG_RETURN(my_malloc_lock(size, my_flags));
|
||||
}
|
||||
|
||||
/*
|
||||
General large pages deallocator.
|
||||
Tries to deallocate memory as if it was from large pages pool and falls back
|
||||
to my_free_lock() in case of failure
|
||||
*/
|
||||
|
||||
void my_large_free(uchar* ptr)
|
||||
{
|
||||
DBUG_ENTER("my_large_free");
|
||||
|
||||
/*
|
||||
my_large_free_int() can only fail if ptr was not allocated with
|
||||
my_large_malloc_int(), i.e. my_malloc_lock() was used so we should free it
|
||||
with my_free_lock()
|
||||
*/
|
||||
if (!my_use_large_pages || !my_large_page_size || !my_large_free_int(ptr))
|
||||
my_free_lock(ptr);
|
||||
|
||||
DBUG_VOID_RETURN;
|
||||
}
|
||||
|
||||
#ifdef HUGETLB_USE_PROC_MEMINFO
|
||||
/* Linux-specific function to determine the size of large pages */
|
||||
|
||||
uint my_get_large_page_size_int(void)
|
||||
{
|
||||
MYSQL_FILE *f;
|
||||
uint size = 0;
|
||||
char buf[256];
|
||||
DBUG_ENTER("my_get_large_page_size_int");
|
||||
|
||||
if (!(f= mysql_file_fopen(key_file_proc_meminfo, "/proc/meminfo",
|
||||
O_RDONLY, MYF(MY_WME))))
|
||||
goto finish;
|
||||
|
||||
while (mysql_file_fgets(buf, sizeof(buf), f))
|
||||
if (sscanf(buf, "Hugepagesize: %u kB", &size))
|
||||
break;
|
||||
|
||||
mysql_file_fclose(f, MYF(MY_WME));
|
||||
|
||||
finish:
|
||||
DBUG_RETURN(size * 1024);
|
||||
}
|
||||
#endif /* HUGETLB_USE_PROC_MEMINFO */
|
||||
|
||||
#if HAVE_DECL_SHM_HUGETLB
|
||||
/* Linux-specific large pages allocator */
|
||||
|
||||
uchar* my_large_malloc_int(size_t size, myf my_flags)
|
||||
{
|
||||
int shmid;
|
||||
uchar* ptr;
|
||||
struct shmid_ds buf;
|
||||
DBUG_ENTER("my_large_malloc_int");
|
||||
|
||||
/* Align block size to my_large_page_size */
|
||||
size= MY_ALIGN(size, (size_t) my_large_page_size);
|
||||
|
||||
shmid = shmget(IPC_PRIVATE, size, SHM_HUGETLB | SHM_R | SHM_W);
|
||||
if (shmid < 0)
|
||||
{
|
||||
if (my_flags & MY_WME)
|
||||
fprintf(stderr,
|
||||
"Warning: Failed to allocate %lu bytes from HugeTLB memory."
|
||||
" errno %d\n", (ulong) size, errno);
|
||||
|
||||
DBUG_RETURN(NULL);
|
||||
}
|
||||
|
||||
ptr = (uchar*) shmat(shmid, NULL, 0);
|
||||
if (ptr == (uchar *) -1)
|
||||
{
|
||||
if (my_flags& MY_WME)
|
||||
fprintf(stderr, "Warning: Failed to attach shared memory segment,"
|
||||
" errno %d\n", errno);
|
||||
shmctl(shmid, IPC_RMID, &buf);
|
||||
|
||||
DBUG_RETURN(NULL);
|
||||
}
|
||||
|
||||
/*
|
||||
Remove the shared memory segment so that it will be automatically freed
|
||||
after memory is detached or process exits
|
||||
*/
|
||||
shmctl(shmid, IPC_RMID, &buf);
|
||||
|
||||
DBUG_RETURN(ptr);
|
||||
}
|
||||
|
||||
/* Linux-specific large pages deallocator */
|
||||
|
||||
my_bool my_large_free_int(uchar *ptr)
|
||||
{
|
||||
DBUG_ENTER("my_large_free_int");
|
||||
DBUG_RETURN(shmdt(ptr) == 0);
|
||||
}
|
||||
#endif /* HAVE_DECL_SHM_HUGETLB */
|
||||
|
||||
#endif /* HAVE_LARGE_PAGES */
|
||||
424
deps/mysqllite/mysys/my_lib.c
vendored
Normal file
424
deps/mysqllite/mysys/my_lib.c
vendored
Normal file
@@ -0,0 +1,424 @@
|
||||
/* Copyright (C) 2000 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 */
|
||||
|
||||
/* TODO: check for overun of memory for names. */
|
||||
|
||||
#include "mysys_priv.h"
|
||||
#include <m_string.h>
|
||||
#include <my_dir.h> /* Structs used by my_dir,includes sys/types */
|
||||
#include "mysys_err.h"
|
||||
#if defined(HAVE_DIRENT_H)
|
||||
# include <dirent.h>
|
||||
# define NAMLEN(dirent) strlen((dirent)->d_name)
|
||||
#else
|
||||
# define dirent direct
|
||||
# define NAMLEN(dirent) (dirent)->d_namlen
|
||||
# if defined(HAVE_SYS_NDIR_H)
|
||||
# include <sys/ndir.h>
|
||||
# endif
|
||||
# if defined(HAVE_SYS_DIR_H)
|
||||
# include <sys/dir.h>
|
||||
# endif
|
||||
# if defined(HAVE_NDIR_H)
|
||||
# include <ndir.h>
|
||||
# endif
|
||||
# if defined(_WIN32)
|
||||
# ifdef __BORLANDC__
|
||||
# include <dir.h>
|
||||
# endif
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#if defined(HAVE_READDIR_R)
|
||||
#define READDIR(A,B,C) ((errno=readdir_r(A,B,&C)) != 0 || !C)
|
||||
#else
|
||||
#define READDIR(A,B,C) (!(C=readdir(A)))
|
||||
#endif
|
||||
|
||||
/*
|
||||
We are assuming that directory we are reading is either has less than
|
||||
100 files and so can be read in one initial chunk or has more than 1000
|
||||
files and so big increment are suitable.
|
||||
*/
|
||||
#define ENTRIES_START_SIZE (8192/sizeof(FILEINFO))
|
||||
#define ENTRIES_INCREMENT (65536/sizeof(FILEINFO))
|
||||
#define NAMES_START_SIZE 32768
|
||||
|
||||
|
||||
static int comp_names(struct fileinfo *a,struct fileinfo *b);
|
||||
|
||||
|
||||
/* We need this because program don't know with malloc we used */
|
||||
|
||||
void my_dirend(MY_DIR *buffer)
|
||||
{
|
||||
DBUG_ENTER("my_dirend");
|
||||
if (buffer)
|
||||
{
|
||||
delete_dynamic((DYNAMIC_ARRAY*)((char*)buffer +
|
||||
ALIGN_SIZE(sizeof(MY_DIR))));
|
||||
free_root((MEM_ROOT*)((char*)buffer + ALIGN_SIZE(sizeof(MY_DIR)) +
|
||||
ALIGN_SIZE(sizeof(DYNAMIC_ARRAY))), MYF(0));
|
||||
my_free(buffer);
|
||||
}
|
||||
DBUG_VOID_RETURN;
|
||||
} /* my_dirend */
|
||||
|
||||
|
||||
/* Compare in sort of filenames */
|
||||
|
||||
static int comp_names(struct fileinfo *a, struct fileinfo *b)
|
||||
{
|
||||
return (strcmp(a->name,b->name));
|
||||
} /* comp_names */
|
||||
|
||||
|
||||
#if !defined(_WIN32)
|
||||
|
||||
MY_DIR *my_dir(const char *path, myf MyFlags)
|
||||
{
|
||||
char *buffer;
|
||||
MY_DIR *result= 0;
|
||||
FILEINFO finfo;
|
||||
DYNAMIC_ARRAY *dir_entries_storage;
|
||||
MEM_ROOT *names_storage;
|
||||
DIR *dirp;
|
||||
struct dirent *dp;
|
||||
char tmp_path[FN_REFLEN+1],*tmp_file;
|
||||
char dirent_tmp[sizeof(struct dirent)+_POSIX_PATH_MAX+1];
|
||||
|
||||
DBUG_ENTER("my_dir");
|
||||
DBUG_PRINT("my",("path: '%s' MyFlags: %d",path,MyFlags));
|
||||
|
||||
#if !defined(HAVE_READDIR_R)
|
||||
mysql_mutex_lock(&THR_LOCK_open);
|
||||
#endif
|
||||
|
||||
dirp = opendir(directory_file_name(tmp_path,(char *) path));
|
||||
#if defined(__amiga__)
|
||||
if ((dirp->dd_fd) < 0) /* Directory doesn't exists */
|
||||
goto error;
|
||||
#endif
|
||||
if (dirp == NULL ||
|
||||
! (buffer= my_malloc(ALIGN_SIZE(sizeof(MY_DIR)) +
|
||||
ALIGN_SIZE(sizeof(DYNAMIC_ARRAY)) +
|
||||
sizeof(MEM_ROOT), MyFlags)))
|
||||
goto error;
|
||||
|
||||
dir_entries_storage= (DYNAMIC_ARRAY*)(buffer + ALIGN_SIZE(sizeof(MY_DIR)));
|
||||
names_storage= (MEM_ROOT*)(buffer + ALIGN_SIZE(sizeof(MY_DIR)) +
|
||||
ALIGN_SIZE(sizeof(DYNAMIC_ARRAY)));
|
||||
|
||||
if (my_init_dynamic_array(dir_entries_storage, sizeof(FILEINFO),
|
||||
ENTRIES_START_SIZE, ENTRIES_INCREMENT))
|
||||
{
|
||||
my_free(buffer);
|
||||
goto error;
|
||||
}
|
||||
init_alloc_root(names_storage, NAMES_START_SIZE, NAMES_START_SIZE);
|
||||
|
||||
/* MY_DIR structure is allocated and completly initialized at this point */
|
||||
result= (MY_DIR*)buffer;
|
||||
|
||||
tmp_file=strend(tmp_path);
|
||||
|
||||
dp= (struct dirent*) dirent_tmp;
|
||||
|
||||
while (!(READDIR(dirp,(struct dirent*) dirent_tmp,dp)))
|
||||
{
|
||||
if (!(finfo.name= strdup_root(names_storage, dp->d_name)))
|
||||
goto error;
|
||||
|
||||
if (MyFlags & MY_WANT_STAT)
|
||||
{
|
||||
if (!(finfo.mystat= (MY_STAT*)alloc_root(names_storage,
|
||||
sizeof(MY_STAT))))
|
||||
goto error;
|
||||
|
||||
bzero(finfo.mystat, sizeof(MY_STAT));
|
||||
(void) strmov(tmp_file,dp->d_name);
|
||||
(void) my_stat(tmp_path, finfo.mystat, MyFlags);
|
||||
if (!(finfo.mystat->st_mode & MY_S_IREAD))
|
||||
continue;
|
||||
}
|
||||
else
|
||||
finfo.mystat= NULL;
|
||||
|
||||
if (push_dynamic(dir_entries_storage, (uchar*)&finfo))
|
||||
goto error;
|
||||
}
|
||||
|
||||
(void) closedir(dirp);
|
||||
#if !defined(HAVE_READDIR_R)
|
||||
mysql_mutex_unlock(&THR_LOCK_open);
|
||||
#endif
|
||||
result->dir_entry= (FILEINFO *)dir_entries_storage->buffer;
|
||||
result->number_off_files= dir_entries_storage->elements;
|
||||
|
||||
if (!(MyFlags & MY_DONT_SORT))
|
||||
my_qsort((void *) result->dir_entry, result->number_off_files,
|
||||
sizeof(FILEINFO), (qsort_cmp) comp_names);
|
||||
DBUG_RETURN(result);
|
||||
|
||||
error:
|
||||
#if !defined(HAVE_READDIR_R)
|
||||
mysql_mutex_unlock(&THR_LOCK_open);
|
||||
#endif
|
||||
my_errno=errno;
|
||||
if (dirp)
|
||||
(void) closedir(dirp);
|
||||
my_dirend(result);
|
||||
if (MyFlags & (MY_FAE | MY_WME))
|
||||
my_error(EE_DIR,MYF(ME_BELL+ME_WAITTANG),path,my_errno);
|
||||
DBUG_RETURN((MY_DIR *) NULL);
|
||||
} /* my_dir */
|
||||
|
||||
|
||||
/*
|
||||
* Convert from directory name to filename.
|
||||
* On UNIX, it's simple: just make sure there is a terminating /
|
||||
|
||||
* Returns pointer to dst;
|
||||
*/
|
||||
|
||||
char * directory_file_name (char * dst, const char *src)
|
||||
{
|
||||
/* Process as Unix format: just remove test the final slash. */
|
||||
char *end;
|
||||
|
||||
if (src[0] == 0)
|
||||
src= (char*) "."; /* Use empty as current */
|
||||
end=strmov(dst, src);
|
||||
if (end[-1] != FN_LIBCHAR)
|
||||
{
|
||||
end[0]=FN_LIBCHAR; /* Add last '/' */
|
||||
end[1]='\0';
|
||||
}
|
||||
return dst;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
/*
|
||||
*****************************************************************************
|
||||
** Read long filename using windows rutines
|
||||
*****************************************************************************
|
||||
*/
|
||||
|
||||
MY_DIR *my_dir(const char *path, myf MyFlags)
|
||||
{
|
||||
char *buffer;
|
||||
MY_DIR *result= 0;
|
||||
FILEINFO finfo;
|
||||
DYNAMIC_ARRAY *dir_entries_storage;
|
||||
MEM_ROOT *names_storage;
|
||||
#ifdef __BORLANDC__
|
||||
struct ffblk find;
|
||||
#else
|
||||
struct _finddata_t find;
|
||||
#endif
|
||||
ushort mode;
|
||||
char tmp_path[FN_REFLEN],*tmp_file,attrib;
|
||||
#ifdef _WIN64
|
||||
__int64 handle;
|
||||
#else
|
||||
long handle;
|
||||
#endif
|
||||
DBUG_ENTER("my_dir");
|
||||
DBUG_PRINT("my",("path: '%s' stat: %d MyFlags: %d",path,MyFlags));
|
||||
|
||||
/* Put LIB-CHAR as last path-character if not there */
|
||||
tmp_file=tmp_path;
|
||||
if (!*path)
|
||||
*tmp_file++ ='.'; /* From current dir */
|
||||
tmp_file= strnmov(tmp_file, path, FN_REFLEN-5);
|
||||
if (tmp_file[-1] == FN_DEVCHAR)
|
||||
*tmp_file++= '.'; /* From current dev-dir */
|
||||
if (tmp_file[-1] != FN_LIBCHAR)
|
||||
*tmp_file++ =FN_LIBCHAR;
|
||||
tmp_file[0]='*'; /* Windows needs this !??? */
|
||||
tmp_file[1]='.';
|
||||
tmp_file[2]='*';
|
||||
tmp_file[3]='\0';
|
||||
|
||||
if (!(buffer= my_malloc(ALIGN_SIZE(sizeof(MY_DIR)) +
|
||||
ALIGN_SIZE(sizeof(DYNAMIC_ARRAY)) +
|
||||
sizeof(MEM_ROOT), MyFlags)))
|
||||
goto error;
|
||||
|
||||
dir_entries_storage= (DYNAMIC_ARRAY*)(buffer + ALIGN_SIZE(sizeof(MY_DIR)));
|
||||
names_storage= (MEM_ROOT*)(buffer + ALIGN_SIZE(sizeof(MY_DIR)) +
|
||||
ALIGN_SIZE(sizeof(DYNAMIC_ARRAY)));
|
||||
|
||||
if (my_init_dynamic_array(dir_entries_storage, sizeof(FILEINFO),
|
||||
ENTRIES_START_SIZE, ENTRIES_INCREMENT))
|
||||
{
|
||||
my_free(buffer);
|
||||
goto error;
|
||||
}
|
||||
init_alloc_root(names_storage, NAMES_START_SIZE, NAMES_START_SIZE);
|
||||
|
||||
/* MY_DIR structure is allocated and completly initialized at this point */
|
||||
result= (MY_DIR*)buffer;
|
||||
|
||||
#ifdef __BORLANDC__
|
||||
if ((handle= findfirst(tmp_path,&find,0)) == -1L)
|
||||
#else
|
||||
if ((handle=_findfirst(tmp_path,&find)) == -1L)
|
||||
#endif
|
||||
{
|
||||
DBUG_PRINT("info", ("findfirst returned error, errno: %d", errno));
|
||||
if (errno != EINVAL)
|
||||
goto error;
|
||||
/*
|
||||
Could not read the directory, no read access.
|
||||
Probably because by "chmod -r".
|
||||
continue and return zero files in dir
|
||||
*/
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
do
|
||||
{
|
||||
#ifdef __BORLANDC__
|
||||
attrib= find.ff_attrib;
|
||||
#else
|
||||
attrib= find.attrib;
|
||||
/*
|
||||
Do not show hidden and system files which Windows sometimes create.
|
||||
Note. Because Borland's findfirst() is called with the third
|
||||
argument = 0 hidden/system files are excluded from the search.
|
||||
*/
|
||||
if (attrib & (_A_HIDDEN | _A_SYSTEM))
|
||||
continue;
|
||||
#endif
|
||||
#ifdef __BORLANDC__
|
||||
if (!(finfo.name= strdup_root(names_storage, find.ff_name)))
|
||||
goto error;
|
||||
#else
|
||||
if (!(finfo.name= strdup_root(names_storage, find.name)))
|
||||
goto error;
|
||||
#endif
|
||||
if (MyFlags & MY_WANT_STAT)
|
||||
{
|
||||
if (!(finfo.mystat= (MY_STAT*)alloc_root(names_storage,
|
||||
sizeof(MY_STAT))))
|
||||
goto error;
|
||||
|
||||
bzero(finfo.mystat, sizeof(MY_STAT));
|
||||
#ifdef __BORLANDC__
|
||||
finfo.mystat->st_size=find.ff_fsize;
|
||||
#else
|
||||
finfo.mystat->st_size=find.size;
|
||||
#endif
|
||||
mode= MY_S_IREAD;
|
||||
if (!(attrib & _A_RDONLY))
|
||||
mode|= MY_S_IWRITE;
|
||||
if (attrib & _A_SUBDIR)
|
||||
mode|= MY_S_IFDIR;
|
||||
finfo.mystat->st_mode= mode;
|
||||
#ifdef __BORLANDC__
|
||||
finfo.mystat->st_mtime= ((uint32) find.ff_ftime);
|
||||
#else
|
||||
finfo.mystat->st_mtime= ((uint32) find.time_write);
|
||||
#endif
|
||||
}
|
||||
else
|
||||
finfo.mystat= NULL;
|
||||
|
||||
if (push_dynamic(dir_entries_storage, (uchar*)&finfo))
|
||||
goto error;
|
||||
}
|
||||
#ifdef __BORLANDC__
|
||||
while (findnext(&find) == 0);
|
||||
#else
|
||||
while (_findnext(handle,&find) == 0);
|
||||
|
||||
_findclose(handle);
|
||||
#endif
|
||||
}
|
||||
|
||||
result->dir_entry= (FILEINFO *)dir_entries_storage->buffer;
|
||||
result->number_off_files= dir_entries_storage->elements;
|
||||
|
||||
if (!(MyFlags & MY_DONT_SORT))
|
||||
my_qsort((void *) result->dir_entry, result->number_off_files,
|
||||
sizeof(FILEINFO), (qsort_cmp) comp_names);
|
||||
DBUG_PRINT("exit", ("found %d files", result->number_off_files));
|
||||
DBUG_RETURN(result);
|
||||
error:
|
||||
my_errno=errno;
|
||||
#ifndef __BORLANDC__
|
||||
if (handle != -1)
|
||||
_findclose(handle);
|
||||
#endif
|
||||
my_dirend(result);
|
||||
if (MyFlags & MY_FAE+MY_WME)
|
||||
my_error(EE_DIR,MYF(ME_BELL+ME_WAITTANG),path,errno);
|
||||
DBUG_RETURN((MY_DIR *) NULL);
|
||||
} /* my_dir */
|
||||
|
||||
#endif /* _WIN32 */
|
||||
|
||||
/****************************************************************************
|
||||
** File status
|
||||
** Note that MY_STAT is assumed to be same as struct stat
|
||||
****************************************************************************/
|
||||
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
|
||||
MY_STAT *my_stat(const char *path, MY_STAT *stat_area, myf my_flags)
|
||||
{
|
||||
int m_used;
|
||||
DBUG_ENTER("my_stat");
|
||||
DBUG_PRINT("my", ("path: '%s' stat_area: 0x%lx MyFlags: %d", path,
|
||||
(long) stat_area, my_flags));
|
||||
|
||||
if ((m_used= (stat_area == NULL)))
|
||||
if (!(stat_area= (MY_STAT *) my_malloc(sizeof(MY_STAT), my_flags)))
|
||||
goto error;
|
||||
#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 */
|
||||
my_free(stat_area);
|
||||
|
||||
error:
|
||||
if (my_flags & (MY_FAE+MY_WME))
|
||||
{
|
||||
my_error(EE_STAT, MYF(ME_BELL+ME_WAITTANG),path,my_errno);
|
||||
DBUG_RETURN((MY_STAT *) NULL);
|
||||
}
|
||||
DBUG_RETURN((MY_STAT *) NULL);
|
||||
} /* my_stat */
|
||||
41
deps/mysqllite/mysys/my_libwrap.c
vendored
Normal file
41
deps/mysqllite/mysys/my_libwrap.c
vendored
Normal file
@@ -0,0 +1,41 @@
|
||||
/* Copyright (C) 2003 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 */
|
||||
|
||||
/*
|
||||
This is needed to be able to compile with original libwrap header
|
||||
files that don't have the prototypes
|
||||
*/
|
||||
|
||||
#include <my_global.h>
|
||||
#include <my_libwrap.h>
|
||||
|
||||
#ifdef HAVE_LIBWRAP
|
||||
|
||||
void my_fromhost(struct request_info *req)
|
||||
{
|
||||
fromhost(req);
|
||||
}
|
||||
|
||||
int my_hosts_access(struct request_info *req)
|
||||
{
|
||||
return hosts_access(req);
|
||||
}
|
||||
|
||||
char *my_eval_client(struct request_info *req)
|
||||
{
|
||||
return eval_client(req);
|
||||
}
|
||||
|
||||
#endif /* HAVE_LIBWRAP */
|
||||
223
deps/mysqllite/mysys/my_lock.c
vendored
Normal file
223
deps/mysqllite/mysys/my_lock.c
vendored
Normal file
@@ -0,0 +1,223 @@
|
||||
/* Copyright (C) 2000-2003 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 */
|
||||
|
||||
#include "mysys_priv.h"
|
||||
#include "mysys_err.h"
|
||||
#include <errno.h>
|
||||
#undef MY_HOW_OFTEN_TO_ALARM
|
||||
#define MY_HOW_OFTEN_TO_ALARM ((int) my_time_to_wait_for_lock)
|
||||
#ifdef NO_ALARM_LOOP
|
||||
#undef NO_ALARM_LOOP
|
||||
#endif
|
||||
#include <my_alarm.h>
|
||||
|
||||
#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
|
||||
|
||||
RETURN VALUE
|
||||
0 Success
|
||||
-1 An error has occured and 'my_errno' is set
|
||||
to indicate the actual error code.
|
||||
*/
|
||||
|
||||
int my_lock(File fd, int locktype, my_off_t start, my_off_t length,
|
||||
myf MyFlags)
|
||||
{
|
||||
#ifdef HAVE_FCNTL
|
||||
int value;
|
||||
ALARM_VARIABLES;
|
||||
#endif
|
||||
|
||||
DBUG_ENTER("my_lock");
|
||||
DBUG_PRINT("my",("fd: %d Op: %d start: %ld Length: %ld MyFlags: %d",
|
||||
fd,locktype,(long) start,(long) length,MyFlags));
|
||||
if (my_disable_locking)
|
||||
DBUG_RETURN(0);
|
||||
|
||||
#if defined(_WIN32)
|
||||
{
|
||||
int timeout_sec;
|
||||
if (MyFlags & MY_DONT_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)
|
||||
{
|
||||
struct flock lock;
|
||||
|
||||
lock.l_type= (short) locktype;
|
||||
lock.l_whence= SEEK_SET;
|
||||
lock.l_start= (off_t) start;
|
||||
lock.l_len= (off_t) length;
|
||||
|
||||
if (MyFlags & MY_DONT_WAIT)
|
||||
{
|
||||
if (fcntl(fd,F_SETLK,&lock) != -1) /* Check if we can lock */
|
||||
DBUG_RETURN(0); /* Ok, file locked */
|
||||
DBUG_PRINT("info",("Was locked, trying with alarm"));
|
||||
ALARM_INIT;
|
||||
while ((value=fcntl(fd,F_SETLKW,&lock)) && ! ALARM_TEST &&
|
||||
errno == EINTR)
|
||||
{ /* Setup again so we don`t miss it */
|
||||
ALARM_REINIT;
|
||||
}
|
||||
ALARM_END;
|
||||
if (value != -1)
|
||||
DBUG_RETURN(0);
|
||||
if (errno == EINTR)
|
||||
errno=EAGAIN;
|
||||
}
|
||||
else if (fcntl(fd,F_SETLKW,&lock) != -1) /* Wait until a lock */
|
||||
DBUG_RETURN(0);
|
||||
}
|
||||
#else
|
||||
if (MyFlags & MY_SEEK_NOT_DONE)
|
||||
{
|
||||
if (my_seek(fd,start,MY_SEEK_SET,MYF(MyFlags & ~MY_SEEK_NOT_DONE))
|
||||
== MY_FILEPOS_ERROR)
|
||||
{
|
||||
/*
|
||||
If an error has occured in my_seek then we will already
|
||||
have an error code in my_errno; Just return error code.
|
||||
*/
|
||||
DBUG_RETURN(-1);
|
||||
}
|
||||
}
|
||||
if (lockf(fd,locktype,length) != -1)
|
||||
DBUG_RETURN(0);
|
||||
#endif /* HAVE_FCNTL */
|
||||
#endif /* HAVE_LOCKING */
|
||||
|
||||
/* We got an error. We don't want EACCES errors */
|
||||
my_errno=(errno == EACCES) ? EAGAIN : errno ? errno : -1;
|
||||
|
||||
if (MyFlags & MY_WME)
|
||||
{
|
||||
if (locktype == F_UNLCK)
|
||||
my_error(EE_CANTUNLOCK,MYF(ME_BELL+ME_WAITTANG),my_errno);
|
||||
else
|
||||
my_error(EE_CANTLOCK,MYF(ME_BELL+ME_WAITTANG),my_errno);
|
||||
}
|
||||
DBUG_PRINT("error",("my_errno: %d (%d)",my_errno,errno));
|
||||
DBUG_RETURN(-1);
|
||||
} /* my_lock */
|
||||
98
deps/mysqllite/mysys/my_lockmem.c
vendored
Normal file
98
deps/mysqllite/mysys/my_lockmem.c
vendored
Normal file
@@ -0,0 +1,98 @@
|
||||
/* Copyright (C) 2000 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 */
|
||||
|
||||
/* Alloc a block of locked memory */
|
||||
|
||||
#include "mysys_priv.h"
|
||||
#include "mysys_err.h"
|
||||
#include <my_list.h>
|
||||
|
||||
#ifdef HAVE_MLOCK
|
||||
#include <sys/mman.h>
|
||||
|
||||
struct st_mem_list
|
||||
{
|
||||
LIST list;
|
||||
uchar *page;
|
||||
uint size;
|
||||
};
|
||||
|
||||
LIST *mem_list;
|
||||
|
||||
uchar *my_malloc_lock(uint size,myf MyFlags)
|
||||
{
|
||||
int success;
|
||||
uint pagesize=sysconf(_SC_PAGESIZE);
|
||||
uchar *ptr;
|
||||
struct st_mem_list *element;
|
||||
DBUG_ENTER("my_malloc_lock");
|
||||
|
||||
size=((size-1) & ~(pagesize-1))+pagesize;
|
||||
if (!(ptr=memalign(pagesize,size)))
|
||||
{
|
||||
if (MyFlags & (MY_FAE+MY_WME))
|
||||
my_error(EE_OUTOFMEMORY, MYF(ME_BELL+ME_WAITTANG),size);
|
||||
DBUG_RETURN(0);
|
||||
}
|
||||
success = mlock((uchar*) ptr,size);
|
||||
if (success != 0 && geteuid() == 0)
|
||||
{
|
||||
DBUG_PRINT("warning",("Failed to lock memory. errno %d\n",
|
||||
errno));
|
||||
fprintf(stderr, "Warning: Failed to lock memory. errno %d\n",
|
||||
errno);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Add block in a list for munlock */
|
||||
if (!(element=(struct st_mem_list*) my_malloc(sizeof(*element),MyFlags)))
|
||||
{
|
||||
(void) munlock((uchar*) ptr,size);
|
||||
free(ptr);
|
||||
DBUG_RETURN(0);
|
||||
}
|
||||
element->list.data=(uchar*) element;
|
||||
element->page=ptr;
|
||||
element->size=size;
|
||||
mysql_mutex_lock(&THR_LOCK_malloc);
|
||||
mem_list=list_add(mem_list,&element->list);
|
||||
mysql_mutex_unlock(&THR_LOCK_malloc);
|
||||
}
|
||||
DBUG_RETURN(ptr);
|
||||
}
|
||||
|
||||
|
||||
void my_free_lock(uchar *ptr)
|
||||
{
|
||||
LIST *list;
|
||||
struct st_mem_list *element=0;
|
||||
|
||||
mysql_mutex_lock(&THR_LOCK_malloc);
|
||||
for (list=mem_list ; list ; list=list->next)
|
||||
{
|
||||
element=(struct st_mem_list*) list->data;
|
||||
if (ptr == element->page)
|
||||
{ /* Found locked mem */
|
||||
(void) munlock((uchar*) ptr,element->size);
|
||||
mem_list=list_delete(mem_list,list);
|
||||
break;
|
||||
}
|
||||
}
|
||||
mysql_mutex_unlock(&THR_LOCK_malloc);
|
||||
my_free(element);
|
||||
free(ptr); /* Free even if not locked */
|
||||
}
|
||||
|
||||
#endif /* HAVE_MLOCK */
|
||||
162
deps/mysqllite/mysys/my_malloc.c
vendored
Normal file
162
deps/mysqllite/mysys/my_malloc.c
vendored
Normal file
@@ -0,0 +1,162 @@
|
||||
/* Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved.
|
||||
|
||||
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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */
|
||||
|
||||
#include "mysys_priv.h"
|
||||
#include "mysys_err.h"
|
||||
#include <m_string.h>
|
||||
|
||||
/**
|
||||
Allocate a sized block of memory.
|
||||
|
||||
@param size The size of the memory block in bytes.
|
||||
@param flags Failure action modifiers (bitmasks).
|
||||
|
||||
@return A pointer to the allocated memory block, or NULL on failure.
|
||||
*/
|
||||
void *my_malloc(size_t size, myf my_flags)
|
||||
{
|
||||
void* point;
|
||||
DBUG_ENTER("my_malloc");
|
||||
DBUG_PRINT("my",("size: %lu my_flags: %d", (ulong) size, my_flags));
|
||||
|
||||
/* Safety */
|
||||
if (!size)
|
||||
size=1;
|
||||
|
||||
point= malloc(size);
|
||||
DBUG_EXECUTE_IF("simulate_out_of_memory",
|
||||
{
|
||||
free(point);
|
||||
point= NULL;
|
||||
});
|
||||
|
||||
if (point == NULL)
|
||||
{
|
||||
my_errno=errno;
|
||||
if (my_flags & MY_FAE)
|
||||
error_handler_hook=fatal_error_handler_hook;
|
||||
if (my_flags & (MY_FAE+MY_WME))
|
||||
my_error(EE_OUTOFMEMORY, MYF(ME_BELL+ME_WAITTANG+ME_NOREFRESH),size);
|
||||
DBUG_EXECUTE_IF("simulate_out_of_memory",
|
||||
DBUG_SET("-d,simulate_out_of_memory"););
|
||||
if (my_flags & MY_FAE)
|
||||
exit(1);
|
||||
}
|
||||
else if (my_flags & MY_ZEROFILL)
|
||||
bzero(point, size);
|
||||
DBUG_PRINT("exit",("ptr: %p", point));
|
||||
DBUG_RETURN(point);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
@brief wrapper around realloc()
|
||||
|
||||
@param oldpoint pointer to currently allocated area
|
||||
@param size new size requested, must be >0
|
||||
@param my_flags flags
|
||||
|
||||
@note if size==0 realloc() may return NULL; my_realloc() treats this as an
|
||||
error which is not the intention of realloc()
|
||||
*/
|
||||
void *my_realloc(void *oldpoint, size_t size, myf my_flags)
|
||||
{
|
||||
void *point;
|
||||
DBUG_ENTER("my_realloc");
|
||||
DBUG_PRINT("my",("ptr: %p size: %lu my_flags: %d", oldpoint,
|
||||
(ulong) size, my_flags));
|
||||
|
||||
DBUG_ASSERT(size > 0);
|
||||
if (!oldpoint && (my_flags & MY_ALLOW_ZERO_PTR))
|
||||
DBUG_RETURN(my_malloc(size, my_flags));
|
||||
#ifdef USE_HALLOC
|
||||
if (!(point = malloc(size)))
|
||||
{
|
||||
if (my_flags & MY_FREE_ON_ERROR)
|
||||
my_free(oldpoint);
|
||||
if (my_flags & MY_HOLD_ON_ERROR)
|
||||
DBUG_RETURN(oldpoint);
|
||||
my_errno=errno;
|
||||
if (my_flags & MY_FAE+MY_WME)
|
||||
my_error(EE_OUTOFMEMORY, MYF(ME_BELL+ME_WAITTANG),size);
|
||||
}
|
||||
else
|
||||
{
|
||||
memcpy(point,oldpoint,size);
|
||||
free(oldpoint);
|
||||
}
|
||||
#else
|
||||
if ((point= realloc(oldpoint, size)) == NULL)
|
||||
{
|
||||
if (my_flags & MY_FREE_ON_ERROR)
|
||||
my_free(oldpoint);
|
||||
if (my_flags & MY_HOLD_ON_ERROR)
|
||||
DBUG_RETURN(oldpoint);
|
||||
my_errno=errno;
|
||||
if (my_flags & (MY_FAE+MY_WME))
|
||||
my_error(EE_OUTOFMEMORY, MYF(ME_BELL+ME_WAITTANG), size);
|
||||
}
|
||||
#endif
|
||||
DBUG_PRINT("exit",("ptr: %p", point));
|
||||
DBUG_RETURN(point);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Free memory allocated with my_malloc.
|
||||
|
||||
@remark Relies on free being able to handle a NULL argument.
|
||||
|
||||
@param ptr Pointer to the memory allocated by my_malloc.
|
||||
*/
|
||||
void my_free(void *ptr)
|
||||
{
|
||||
DBUG_ENTER("my_free");
|
||||
DBUG_PRINT("my",("ptr: %p", ptr));
|
||||
free(ptr);
|
||||
DBUG_VOID_RETURN;
|
||||
}
|
||||
|
||||
|
||||
void *my_memdup(const void *from, size_t length, myf my_flags)
|
||||
{
|
||||
void *ptr;
|
||||
if ((ptr= my_malloc(length,my_flags)) != 0)
|
||||
memcpy(ptr, from, length);
|
||||
return ptr;
|
||||
}
|
||||
|
||||
|
||||
char *my_strdup(const char *from, myf my_flags)
|
||||
{
|
||||
char *ptr;
|
||||
size_t length= strlen(from)+1;
|
||||
if ((ptr= (char*) my_malloc(length, my_flags)))
|
||||
memcpy(ptr, from, length);
|
||||
return ptr;
|
||||
}
|
||||
|
||||
|
||||
char *my_strndup(const char *from, size_t length, myf my_flags)
|
||||
{
|
||||
char *ptr;
|
||||
if ((ptr= (char*) my_malloc(length+1, my_flags)))
|
||||
{
|
||||
memcpy(ptr, from, length);
|
||||
ptr[length]= 0;
|
||||
}
|
||||
return ptr;
|
||||
}
|
||||
|
||||
83
deps/mysqllite/mysys/my_memmem.c
vendored
Normal file
83
deps/mysqllite/mysys/my_memmem.c
vendored
Normal file
@@ -0,0 +1,83 @@
|
||||
/* Copyright (C) 2000 MySQL AB
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
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 */
|
||||
|
||||
#include <my_global.h>
|
||||
#include <m_string.h>
|
||||
|
||||
/*
|
||||
my_memmem, port of a GNU extension.
|
||||
|
||||
Returns a pointer to the beginning of the substring, needle, or NULL if the
|
||||
substring is not found in haystack.
|
||||
*/
|
||||
|
||||
void *my_memmem(const void *haystack, size_t haystacklen,
|
||||
const void *needle, size_t needlelen)
|
||||
{
|
||||
const unsigned char *cursor;
|
||||
const unsigned char *last_possible_needle_location =
|
||||
(unsigned char *)haystack + haystacklen - needlelen;
|
||||
|
||||
/* Easy answers */
|
||||
if (needlelen > haystacklen) return(NULL);
|
||||
if (needle == NULL) return(NULL);
|
||||
if (haystack == NULL) return(NULL);
|
||||
if (needlelen == 0) return(NULL);
|
||||
if (haystacklen == 0) return(NULL);
|
||||
|
||||
for (cursor = haystack; cursor <= last_possible_needle_location; cursor++) {
|
||||
if (memcmp(needle, cursor, needlelen) == 0) {
|
||||
return((void *) cursor);
|
||||
}
|
||||
}
|
||||
return(NULL);
|
||||
}
|
||||
|
||||
|
||||
|
||||
#ifdef MAIN
|
||||
#include <assert.h>
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
char haystack[10], needle[3];
|
||||
|
||||
memmove(haystack, "0123456789", 10);
|
||||
|
||||
memmove(needle, "no", 2);
|
||||
assert(my_memmem(haystack, 10, needle, 2) == NULL);
|
||||
|
||||
memmove(needle, "345", 3);
|
||||
assert(my_memmem(haystack, 10, needle, 3) != NULL);
|
||||
|
||||
memmove(needle, "789", 3);
|
||||
assert(my_memmem(haystack, 10, needle, 3) != NULL);
|
||||
assert(my_memmem(haystack, 9, needle, 3) == NULL);
|
||||
|
||||
memmove(needle, "012", 3);
|
||||
assert(my_memmem(haystack, 10, needle, 3) != NULL);
|
||||
assert(my_memmem(NULL, 10, needle, 3) == NULL);
|
||||
|
||||
assert(my_memmem(NULL, 10, needle, 3) == NULL);
|
||||
assert(my_memmem(haystack, 0, needle, 3) == NULL);
|
||||
assert(my_memmem(haystack, 10, NULL, 3) == NULL);
|
||||
assert(my_memmem(haystack, 10, needle, 0) == NULL);
|
||||
|
||||
assert(my_memmem(haystack, 1, needle, 3) == NULL);
|
||||
|
||||
printf("success\n");
|
||||
return(0);
|
||||
}
|
||||
|
||||
#endif
|
||||
34
deps/mysqllite/mysys/my_mess.c
vendored
Normal file
34
deps/mysqllite/mysys/my_mess.c
vendored
Normal file
@@ -0,0 +1,34 @@
|
||||
/* Copyright (C) 2000 MySQL AB
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
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 */
|
||||
|
||||
#include "mysys_priv.h"
|
||||
|
||||
void my_message_stderr(uint error __attribute__((unused)),
|
||||
const char *str, myf MyFlags)
|
||||
{
|
||||
DBUG_ENTER("my_message_stderr");
|
||||
DBUG_PRINT("enter",("message: %s",str));
|
||||
(void) fflush(stdout);
|
||||
if (MyFlags & ME_BELL)
|
||||
(void) fputc('\007', stderr);
|
||||
if (my_progname)
|
||||
{
|
||||
(void)fputs(my_progname,stderr); (void)fputs(": ",stderr);
|
||||
}
|
||||
(void)fputs(str,stderr);
|
||||
(void)fputc('\n',stderr);
|
||||
(void)fflush(stderr);
|
||||
DBUG_VOID_RETURN;
|
||||
}
|
||||
42
deps/mysqllite/mysys/my_mkdir.c
vendored
Normal file
42
deps/mysqllite/mysys/my_mkdir.c
vendored
Normal file
@@ -0,0 +1,42 @@
|
||||
/* Copyright (C) 2000 MySQL AB
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
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 */
|
||||
|
||||
#include "mysys_priv.h"
|
||||
#include "mysys_err.h"
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#ifdef __WIN__
|
||||
#include <direct.h>
|
||||
#endif
|
||||
|
||||
int my_mkdir(const char *dir, int Flags, myf MyFlags)
|
||||
{
|
||||
DBUG_ENTER("my_dir");
|
||||
DBUG_PRINT("enter",("dir: %s",dir));
|
||||
|
||||
#if defined(__WIN__)
|
||||
if (mkdir((char*) dir))
|
||||
#else
|
||||
if (mkdir((char*) dir, Flags & my_umask_dir))
|
||||
#endif
|
||||
{
|
||||
my_errno=errno;
|
||||
DBUG_PRINT("error",("error %d when creating direcory %s",my_errno,dir));
|
||||
if (MyFlags & (MY_FFNF | MY_FAE | MY_WME))
|
||||
my_error(EE_CANT_MKDIR, MYF(ME_BELL+ME_WAITTANG), dir, my_errno);
|
||||
DBUG_RETURN(-1);
|
||||
}
|
||||
DBUG_RETURN(0);
|
||||
}
|
||||
88
deps/mysqllite/mysys/my_mmap.c
vendored
Normal file
88
deps/mysqllite/mysys/my_mmap.c
vendored
Normal file
@@ -0,0 +1,88 @@
|
||||
/* Copyright (C) 2000-2003 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 */
|
||||
|
||||
#include "mysys_priv.h"
|
||||
|
||||
#ifdef HAVE_SYS_MMAN_H
|
||||
|
||||
/*
|
||||
system msync() only syncs mmap'ed area to fs cache.
|
||||
fsync() is required to really sync to disc
|
||||
*/
|
||||
int my_msync(int fd, void *addr, size_t len, int flags)
|
||||
{
|
||||
msync(addr, len, flags);
|
||||
return my_sync(fd, MYF(0));
|
||||
}
|
||||
|
||||
#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, File fd, my_off_t offset)
|
||||
{
|
||||
HANDLE hFileMap;
|
||||
LPVOID ptr;
|
||||
HANDLE hFile= (HANDLE)my_get_osfhandle(fd);
|
||||
DBUG_ENTER("my_mmap");
|
||||
DBUG_PRINT("mysys", ("map fd: %d", fd));
|
||||
|
||||
if (hFile == INVALID_HANDLE_VALUE)
|
||||
DBUG_RETURN(MAP_FAILED);
|
||||
|
||||
hFileMap=CreateFileMapping(hFile, &mmap_security_attributes,
|
||||
PAGE_READWRITE, 0, (DWORD) len, NULL);
|
||||
if (hFileMap == 0)
|
||||
DBUG_RETURN(MAP_FAILED);
|
||||
|
||||
ptr=MapViewOfFile(hFileMap,
|
||||
prot & PROT_WRITE ? FILE_MAP_WRITE : FILE_MAP_READ,
|
||||
(DWORD)(offset >> 32), (DWORD)offset, len);
|
||||
|
||||
/*
|
||||
MSDN explicitly states that it's possible to close File Mapping Object
|
||||
even when a view is not unmapped - then the object will be held open
|
||||
implicitly until unmap, as every view stores internally a handler of
|
||||
a corresponding File Mapping Object
|
||||
*/
|
||||
CloseHandle(hFileMap);
|
||||
|
||||
if (ptr)
|
||||
{
|
||||
DBUG_PRINT("mysys", ("mapped addr: %p", ptr));
|
||||
DBUG_RETURN(ptr);
|
||||
}
|
||||
|
||||
DBUG_RETURN(MAP_FAILED);
|
||||
}
|
||||
|
||||
int my_munmap(void *addr, size_t len)
|
||||
{
|
||||
DBUG_ENTER("my_munmap");
|
||||
DBUG_PRINT("mysys", ("unmap addr: %p", addr));
|
||||
DBUG_RETURN(UnmapViewOfFile(addr) ? 0 : -1);
|
||||
}
|
||||
|
||||
int my_msync(int fd, void *addr, size_t len, int flags)
|
||||
{
|
||||
return FlushViewOfFile(addr, len) ? 0 : -1;
|
||||
}
|
||||
|
||||
#else
|
||||
#warning "no mmap!"
|
||||
#endif
|
||||
|
||||
58
deps/mysqllite/mysys/my_new.cc
vendored
Normal file
58
deps/mysqllite/mysys/my_new.cc
vendored
Normal file
@@ -0,0 +1,58 @@
|
||||
/* Copyright (C) 2000 MySQL AB
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
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 */
|
||||
|
||||
/*
|
||||
This is a replacement of new/delete operators to be used when compiling
|
||||
with gcc 3.0.x to avoid including libstdc++
|
||||
*/
|
||||
|
||||
#include "mysys_priv.h"
|
||||
|
||||
#ifdef USE_MYSYS_NEW
|
||||
|
||||
void *operator new (size_t sz)
|
||||
{
|
||||
return (void *) malloc (sz ? sz : 1);
|
||||
}
|
||||
|
||||
void *operator new[] (size_t sz)
|
||||
{
|
||||
return (void *) malloc (sz ? sz : 1);
|
||||
}
|
||||
|
||||
void operator delete (void *ptr)
|
||||
{
|
||||
if (ptr)
|
||||
free(ptr);
|
||||
}
|
||||
|
||||
void operator delete[] (void *ptr) throw ()
|
||||
{
|
||||
if (ptr)
|
||||
free(ptr);
|
||||
}
|
||||
|
||||
C_MODE_START
|
||||
|
||||
int __cxa_pure_virtual()
|
||||
{
|
||||
assert(! "Aborted: pure virtual method called.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
C_MODE_END
|
||||
|
||||
#endif /* USE_MYSYS_NEW */
|
||||
|
||||
119
deps/mysqllite/mysys/my_once.c
vendored
Normal file
119
deps/mysqllite/mysys/my_once.c
vendored
Normal file
@@ -0,0 +1,119 @@
|
||||
/* Copyright (C) 2000 MySQL AB
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
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 */
|
||||
|
||||
/* Not MT-SAFE */
|
||||
|
||||
#include "mysys_priv.h"
|
||||
#include "my_static.h"
|
||||
#include "mysys_err.h"
|
||||
#include <m_string.h>
|
||||
|
||||
/*
|
||||
Alloc for things we don't nend to free run-time (that only
|
||||
should be free'd on exit)
|
||||
|
||||
SYNOPSIS
|
||||
my_once_alloc()
|
||||
Size
|
||||
MyFlags
|
||||
|
||||
NOTES
|
||||
No DBUG_ENTER... here to get smaller dbug-startup
|
||||
*/
|
||||
|
||||
void* my_once_alloc(size_t Size, myf MyFlags)
|
||||
{
|
||||
size_t get_size, max_left;
|
||||
uchar* point;
|
||||
reg1 USED_MEM *next;
|
||||
reg2 USED_MEM **prev;
|
||||
|
||||
Size= ALIGN_SIZE(Size);
|
||||
prev= &my_once_root_block;
|
||||
max_left=0;
|
||||
for (next=my_once_root_block ; next && next->left < Size ; next= next->next)
|
||||
{
|
||||
if (next->left > max_left)
|
||||
max_left=next->left;
|
||||
prev= &next->next;
|
||||
}
|
||||
if (! next)
|
||||
{ /* Time to alloc new block */
|
||||
get_size= Size+ALIGN_SIZE(sizeof(USED_MEM));
|
||||
if (max_left*4 < my_once_extra && get_size < my_once_extra)
|
||||
get_size=my_once_extra; /* Normal alloc */
|
||||
|
||||
if ((next = (USED_MEM*) malloc(get_size)) == 0)
|
||||
{
|
||||
my_errno=errno;
|
||||
if (MyFlags & (MY_FAE+MY_WME))
|
||||
my_error(EE_OUTOFMEMORY, MYF(ME_BELL+ME_WAITTANG),get_size);
|
||||
return((uchar*) 0);
|
||||
}
|
||||
DBUG_PRINT("test",("my_once_malloc %lu byte malloced", (ulong) get_size));
|
||||
next->next= 0;
|
||||
next->size= get_size;
|
||||
next->left= get_size-ALIGN_SIZE(sizeof(USED_MEM));
|
||||
*prev=next;
|
||||
}
|
||||
point= (uchar*) ((char*) next+ (next->size-next->left));
|
||||
next->left-= Size;
|
||||
|
||||
if (MyFlags & MY_ZEROFILL)
|
||||
bzero(point, Size);
|
||||
return((void*) point);
|
||||
} /* my_once_alloc */
|
||||
|
||||
|
||||
char *my_once_strdup(const char *src,myf myflags)
|
||||
{
|
||||
size_t len= strlen(src)+1;
|
||||
uchar *dst= my_once_alloc(len, myflags);
|
||||
if (dst)
|
||||
memcpy(dst, src, len);
|
||||
return (char*) dst;
|
||||
}
|
||||
|
||||
|
||||
void *my_once_memdup(const void *src, size_t len, myf myflags)
|
||||
{
|
||||
uchar *dst= my_once_alloc(len, myflags);
|
||||
if (dst)
|
||||
memcpy(dst, src, len);
|
||||
return dst;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Deallocate everything that was allocated with my_once_alloc
|
||||
|
||||
SYNOPSIS
|
||||
my_once_free()
|
||||
*/
|
||||
|
||||
void my_once_free(void)
|
||||
{
|
||||
reg1 USED_MEM *next,*old;
|
||||
DBUG_ENTER("my_once_free");
|
||||
|
||||
for (next=my_once_root_block ; next ; )
|
||||
{
|
||||
old=next; next= next->next ;
|
||||
free((uchar*) old);
|
||||
}
|
||||
my_once_root_block=0;
|
||||
|
||||
DBUG_VOID_RETURN;
|
||||
} /* my_once_free */
|
||||
192
deps/mysqllite/mysys/my_open.c
vendored
Normal file
192
deps/mysqllite/mysys/my_open.c
vendored
Normal file
@@ -0,0 +1,192 @@
|
||||
/* Copyright (C) 2000 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 */
|
||||
|
||||
#include "mysys_priv.h"
|
||||
#include "mysys_err.h"
|
||||
#include <my_dir.h>
|
||||
#include <errno.h>
|
||||
|
||||
|
||||
/*
|
||||
Open a file
|
||||
|
||||
SYNOPSIS
|
||||
my_open()
|
||||
FileName Fully qualified file name
|
||||
Flags Read | write
|
||||
MyFlags Special flags
|
||||
|
||||
RETURN VALUE
|
||||
File descriptor
|
||||
*/
|
||||
|
||||
File my_open(const char *FileName, int Flags, myf MyFlags)
|
||||
/* Path-name of file */
|
||||
/* Read | write .. */
|
||||
/* Special flags */
|
||||
{
|
||||
File fd;
|
||||
DBUG_ENTER("my_open");
|
||||
DBUG_PRINT("my",("Name: '%s' Flags: %d MyFlags: %d",
|
||||
FileName, Flags, MyFlags));
|
||||
#if defined(_WIN32)
|
||||
fd= my_win_open(FileName, Flags);
|
||||
#elif !defined(NO_OPEN_3)
|
||||
fd = open(FileName, Flags, my_umask); /* Normal unix */
|
||||
#else
|
||||
fd = open((char *) FileName, Flags);
|
||||
#endif
|
||||
|
||||
DBUG_RETURN(my_register_filename(fd, FileName, FILE_BY_OPEN,
|
||||
EE_FILENOTFOUND, MyFlags));
|
||||
} /* my_open */
|
||||
|
||||
|
||||
/*
|
||||
Close a file
|
||||
|
||||
SYNOPSIS
|
||||
my_close()
|
||||
fd File sescriptor
|
||||
myf Special Flags
|
||||
|
||||
*/
|
||||
|
||||
int my_close(File fd, myf MyFlags)
|
||||
{
|
||||
int err;
|
||||
DBUG_ENTER("my_close");
|
||||
DBUG_PRINT("my",("fd: %d MyFlags: %d",fd, MyFlags));
|
||||
|
||||
mysql_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));
|
||||
my_errno=errno;
|
||||
if (MyFlags & (MY_FAE | MY_WME))
|
||||
my_error(EE_BADCLOSE, MYF(ME_BELL+ME_WAITTANG),my_filename(fd),errno);
|
||||
}
|
||||
if ((uint) fd < my_file_limit && my_file_info[fd].type != UNOPEN)
|
||||
{
|
||||
my_free(my_file_info[fd].name);
|
||||
#if !defined(HAVE_PREAD) && !defined(_WIN32)
|
||||
mysql_mutex_destroy(&my_file_info[fd].mutex);
|
||||
#endif
|
||||
my_file_info[fd].type = UNOPEN;
|
||||
}
|
||||
my_file_opened--;
|
||||
mysql_mutex_unlock(&THR_LOCK_open);
|
||||
DBUG_RETURN(err);
|
||||
} /* my_close */
|
||||
|
||||
|
||||
/*
|
||||
Register file in my_file_info[]
|
||||
|
||||
SYNOPSIS
|
||||
my_register_filename()
|
||||
fd File number opened, -1 if error on open
|
||||
FileName File name
|
||||
type_file_type How file was created
|
||||
error_message_number Error message number if caller got error (fd == -1)
|
||||
MyFlags Flags for my_close()
|
||||
|
||||
RETURN
|
||||
-1 error
|
||||
# Filenumber
|
||||
|
||||
*/
|
||||
|
||||
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 >= MY_FILE_MIN)
|
||||
{
|
||||
if ((uint) fd >= my_file_limit)
|
||||
{
|
||||
#if !defined(HAVE_PREAD)
|
||||
my_errno= EMFILE;
|
||||
#else
|
||||
thread_safe_increment(my_file_opened,&THR_LOCK_open);
|
||||
DBUG_RETURN(fd); /* safeguard */
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
mysql_mutex_lock(&THR_LOCK_open);
|
||||
if ((my_file_info[fd].name = (char*) my_strdup(FileName,MyFlags)))
|
||||
{
|
||||
my_file_opened++;
|
||||
my_file_total_opened++;
|
||||
my_file_info[fd].type = type_of_file;
|
||||
#if !defined(HAVE_PREAD) && !defined(_WIN32)
|
||||
mysql_mutex_init(key_my_file_info_mutex, &my_file_info[fd].mutex,
|
||||
MY_MUTEX_INIT_FAST);
|
||||
#endif
|
||||
mysql_mutex_unlock(&THR_LOCK_open);
|
||||
DBUG_PRINT("exit",("fd: %d",fd));
|
||||
DBUG_RETURN(fd);
|
||||
}
|
||||
mysql_mutex_unlock(&THR_LOCK_open);
|
||||
my_errno= ENOMEM;
|
||||
}
|
||||
(void) my_close(fd, MyFlags);
|
||||
}
|
||||
else
|
||||
my_errno= errno;
|
||||
|
||||
DBUG_PRINT("error",("Got error %d on open", my_errno));
|
||||
if (MyFlags & (MY_FFNF | MY_FAE | MY_WME))
|
||||
{
|
||||
if (my_errno == EMFILE)
|
||||
error_message_number= EE_OUT_OF_FILERESOURCES;
|
||||
DBUG_PRINT("error",("print err: %d",error_message_number));
|
||||
my_error(error_message_number, MYF(ME_BELL+ME_WAITTANG),
|
||||
FileName, my_errno);
|
||||
}
|
||||
DBUG_RETURN(-1);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
#ifdef EXTRA_DEBUG
|
||||
|
||||
void my_print_open_files(void)
|
||||
{
|
||||
if (my_file_opened | my_stream_opened)
|
||||
{
|
||||
uint i;
|
||||
for (i= 0 ; i < my_file_limit ; i++)
|
||||
{
|
||||
if (my_file_info[i].type != UNOPEN)
|
||||
{
|
||||
fprintf(stderr, EE(EE_FILE_NOT_CLOSED), my_file_info[i].name, i);
|
||||
fputc('\n', stderr);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
40
deps/mysqllite/mysys/my_port.c
vendored
Normal file
40
deps/mysqllite/mysys/my_port.c
vendored
Normal file
@@ -0,0 +1,40 @@
|
||||
/* Copyright (C) 2002 MySQL AB
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Library General Public
|
||||
License as published by the Free Software Foundation; version 2
|
||||
of the License.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Library General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Library General Public
|
||||
License along with this library; if not, write to the Free
|
||||
Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
|
||||
MA 02111-1307, USA */
|
||||
|
||||
/*
|
||||
Small functions to make code portable
|
||||
*/
|
||||
|
||||
#include "mysys_priv.h"
|
||||
|
||||
#ifdef _AIX
|
||||
|
||||
/*
|
||||
On AIX, at least with gcc 3.1, the expression
|
||||
'(double) (ulonglong) var' doesn't always work for big unsigned
|
||||
integers like '18446744073709551615'. The end result is that the
|
||||
high bit is simply dropped. (probably bug in gcc optimizations)
|
||||
Handling the conversion in a sub function seems to work.
|
||||
*/
|
||||
|
||||
|
||||
|
||||
double my_ulonglong2double(unsigned long long nr)
|
||||
{
|
||||
return (double) nr;
|
||||
}
|
||||
#endif /* _AIX */
|
||||
206
deps/mysqllite/mysys/my_pread.c
vendored
Normal file
206
deps/mysqllite/mysys/my_pread.c
vendored
Normal file
@@ -0,0 +1,206 @@
|
||||
/* Copyright (C) 2000 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 */
|
||||
|
||||
#include "mysys_priv.h"
|
||||
#include "mysys_err.h"
|
||||
#include "my_base.h"
|
||||
#include <m_string.h>
|
||||
#include <errno.h>
|
||||
#if defined (HAVE_PREAD) && !defined(_WIN32)
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
/*
|
||||
Read a chunk of bytes from a file from a given position
|
||||
|
||||
SYNOPSIOS
|
||||
my_pread()
|
||||
Filedes File decsriptor
|
||||
Buffer Buffer to read data into
|
||||
Count Number of bytes to read
|
||||
offset Position to read from
|
||||
MyFlags Flags
|
||||
|
||||
NOTES
|
||||
This differs from the normal pread() call in that we don't care
|
||||
to set the position in the file back to the original position
|
||||
if the system doesn't support pread().
|
||||
|
||||
RETURN
|
||||
(size_t) -1 Error
|
||||
# Number of bytes read
|
||||
*/
|
||||
|
||||
size_t my_pread(File Filedes, uchar *Buffer, size_t Count, my_off_t offset,
|
||||
myf MyFlags)
|
||||
{
|
||||
size_t readbytes;
|
||||
int error= 0;
|
||||
#if !defined (HAVE_PREAD) && !defined (_WIN32)
|
||||
int save_errno;
|
||||
#endif
|
||||
DBUG_ENTER("my_pread");
|
||||
DBUG_PRINT("my",("fd: %d Seek: %llu Buffer: %p Count: %lu MyFlags: %d",
|
||||
Filedes, (ulonglong)offset, Buffer, (ulong)Count, MyFlags));
|
||||
for (;;)
|
||||
{
|
||||
errno= 0; /* Linux, Windows don't reset this on EOF/success */
|
||||
#if !defined (HAVE_PREAD) && !defined (_WIN32)
|
||||
mysql_mutex_lock(&my_file_info[Filedes].mutex);
|
||||
readbytes= (uint) -1;
|
||||
error= (lseek(Filedes, offset, MY_SEEK_SET) == (my_off_t) -1 ||
|
||||
(readbytes= read(Filedes, Buffer, Count)) != Count);
|
||||
save_errno= errno;
|
||||
mysql_mutex_unlock(&my_file_info[Filedes].mutex);
|
||||
if (error)
|
||||
errno= save_errno;
|
||||
#else
|
||||
#if defined(_WIN32)
|
||||
readbytes= my_win_pread(Filedes, Buffer, Count, offset);
|
||||
#else
|
||||
readbytes= pread(Filedes, Buffer, Count, offset);
|
||||
#endif
|
||||
error= (readbytes != Count);
|
||||
#endif
|
||||
if(error)
|
||||
{
|
||||
my_errno= errno ? errno : -1;
|
||||
if (errno == 0 || (readbytes != (size_t) -1 &&
|
||||
(MyFlags & (MY_NABP | MY_FNABP))))
|
||||
my_errno= HA_ERR_FILE_TOO_SHORT;
|
||||
|
||||
DBUG_PRINT("warning",("Read only %d bytes off %u from %d, errno: %d",
|
||||
(int) readbytes, (uint) Count,Filedes,my_errno));
|
||||
|
||||
if ((readbytes == 0 || readbytes == (size_t) -1) && errno == EINTR)
|
||||
{
|
||||
DBUG_PRINT("debug", ("my_pread() was interrupted and returned %d",
|
||||
(int) readbytes));
|
||||
continue; /* Interrupted */
|
||||
}
|
||||
|
||||
if (MyFlags & (MY_WME | MY_FAE | MY_FNABP))
|
||||
{
|
||||
if (readbytes == (size_t) -1)
|
||||
my_error(EE_READ, MYF(ME_BELL+ME_WAITTANG),
|
||||
my_filename(Filedes),my_errno);
|
||||
else if (MyFlags & (MY_NABP | MY_FNABP))
|
||||
my_error(EE_EOFERR, MYF(ME_BELL+ME_WAITTANG),
|
||||
my_filename(Filedes),my_errno);
|
||||
}
|
||||
if (readbytes == (size_t) -1 || (MyFlags & (MY_FNABP | MY_NABP)))
|
||||
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 */
|
||||
}
|
||||
} /* my_pread */
|
||||
|
||||
|
||||
/*
|
||||
Write a chunk of bytes to a file at a given position
|
||||
|
||||
SYNOPSIOS
|
||||
my_pwrite()
|
||||
Filedes File decsriptor
|
||||
Buffer Buffer to write data from
|
||||
Count Number of bytes to write
|
||||
offset Position to write to
|
||||
MyFlags Flags
|
||||
|
||||
NOTES
|
||||
This differs from the normal pwrite() call in that we don't care
|
||||
to set the position in the file back to the original position
|
||||
if the system doesn't support pwrite()
|
||||
|
||||
RETURN
|
||||
(size_t) -1 Error
|
||||
# Number of bytes read
|
||||
*/
|
||||
|
||||
size_t my_pwrite(File Filedes, const uchar *Buffer, size_t Count,
|
||||
my_off_t offset, myf MyFlags)
|
||||
{
|
||||
size_t writtenbytes, written;
|
||||
uint errors;
|
||||
|
||||
DBUG_ENTER("my_pwrite");
|
||||
DBUG_PRINT("my",("fd: %d Seek: %llu Buffer: %p Count: %lu MyFlags: %d",
|
||||
Filedes, offset, Buffer, (ulong)Count, MyFlags));
|
||||
errors= 0;
|
||||
written= 0;
|
||||
|
||||
for (;;)
|
||||
{
|
||||
#if !defined (HAVE_PREAD) && !defined (_WIN32)
|
||||
int error;
|
||||
writtenbytes= (size_t) -1;
|
||||
mysql_mutex_lock(&my_file_info[Filedes].mutex);
|
||||
error= (lseek(Filedes, offset, MY_SEEK_SET) != (my_off_t) -1 &&
|
||||
(writtenbytes= write(Filedes, Buffer, Count)) == Count);
|
||||
mysql_mutex_unlock(&my_file_info[Filedes].mutex);
|
||||
if (error)
|
||||
break;
|
||||
#elif defined (_WIN32)
|
||||
writtenbytes= my_win_pwrite(Filedes, Buffer, Count, offset);
|
||||
#else
|
||||
writtenbytes= pwrite(Filedes, Buffer, Count, offset);
|
||||
#endif
|
||||
if(writtenbytes == Count)
|
||||
break;
|
||||
my_errno= errno;
|
||||
if (writtenbytes != (size_t) -1)
|
||||
{
|
||||
written+= writtenbytes;
|
||||
Buffer+= writtenbytes;
|
||||
Count-= writtenbytes;
|
||||
offset+= writtenbytes;
|
||||
}
|
||||
DBUG_PRINT("error",("Write only %u bytes", (uint) writtenbytes));
|
||||
#ifndef NO_BACKGROUND
|
||||
|
||||
if (my_thread_var->abort)
|
||||
MyFlags&= ~ MY_WAIT_IF_FULL; /* End if aborted by user */
|
||||
|
||||
if ((my_errno == ENOSPC || my_errno == EDQUOT) &&
|
||||
(MyFlags & MY_WAIT_IF_FULL))
|
||||
{
|
||||
wait_for_free_space(my_filename(Filedes), errors);
|
||||
errors++;
|
||||
continue;
|
||||
}
|
||||
if ((writtenbytes && writtenbytes != (size_t) -1) || my_errno == EINTR)
|
||||
continue; /* Retry */
|
||||
#endif
|
||||
if (MyFlags & (MY_NABP | MY_FNABP))
|
||||
{
|
||||
if (MyFlags & (MY_WME | MY_FAE | MY_FNABP))
|
||||
{
|
||||
my_error(EE_WRITE, MYF(ME_BELL | ME_WAITTANG),
|
||||
my_filename(Filedes),my_errno);
|
||||
}
|
||||
DBUG_RETURN(MY_FILE_ERROR); /* Error on read */
|
||||
}
|
||||
else
|
||||
break; /* Return bytes written */
|
||||
}
|
||||
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(writtenbytes+written); /* purecov: inspected */
|
||||
} /* my_pwrite */
|
||||
469
deps/mysqllite/mysys/my_pthread.c
vendored
Normal file
469
deps/mysqllite/mysys/my_pthread.c
vendored
Normal file
@@ -0,0 +1,469 @@
|
||||
/* Copyright (C) 2000-2003 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 */
|
||||
|
||||
/* Functions to get threads more portable */
|
||||
|
||||
#define DONT_REMAP_PTHREAD_FUNCTIONS
|
||||
|
||||
#include "mysys_priv.h"
|
||||
#include <signal.h>
|
||||
#include <m_string.h>
|
||||
#include <thr_alarm.h>
|
||||
|
||||
#if (defined(__BSD__) || defined(_BSDI_VERSION))
|
||||
#define SCHED_POLICY SCHED_RR
|
||||
#else
|
||||
#define SCHED_POLICY SCHED_OTHER
|
||||
#endif
|
||||
|
||||
uint thd_lib_detected= 0;
|
||||
|
||||
/* To allow use of pthread_getspecific with two arguments */
|
||||
|
||||
#ifdef HAVE_NONPOSIX_PTHREAD_GETSPECIFIC
|
||||
#undef pthread_getspecific
|
||||
|
||||
void *my_pthread_getspecific_imp(pthread_key_t key)
|
||||
{
|
||||
void *value;
|
||||
if (pthread_getspecific(key,(void *) &value))
|
||||
return 0;
|
||||
return value;
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
Some functions for RTS threads, AIX, Siemens Unix and UnixWare 7
|
||||
(and DEC OSF/1 3.2 too)
|
||||
*/
|
||||
|
||||
int my_pthread_create_detached=1;
|
||||
|
||||
#if defined(HAVE_NONPOSIX_SIGWAIT) || defined(HAVE_DEC_3_2_THREADS)
|
||||
|
||||
int my_sigwait(const sigset_t *set,int *sig)
|
||||
{
|
||||
int signal=sigwait((sigset_t*) set);
|
||||
if (signal < 0)
|
||||
return errno;
|
||||
*sig=signal;
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* localtime_r for SCO 3.2V4.2 */
|
||||
|
||||
#if !defined(HAVE_LOCALTIME_R) || !defined(HAVE_GMTIME_R)
|
||||
|
||||
extern mysql_mutex_t LOCK_localtime_r;
|
||||
|
||||
#endif
|
||||
|
||||
#if !defined(HAVE_LOCALTIME_R)
|
||||
struct tm *localtime_r(const time_t *clock, struct tm *res)
|
||||
{
|
||||
struct tm *tmp;
|
||||
mysql_mutex_lock(&LOCK_localtime_r);
|
||||
tmp=localtime(clock);
|
||||
*res= *tmp;
|
||||
mysql_mutex_unlock(&LOCK_localtime_r);
|
||||
return res;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if !defined(HAVE_GMTIME_R)
|
||||
/*
|
||||
Reentrant version of standard gmtime() function.
|
||||
Needed on some systems which don't implement it.
|
||||
*/
|
||||
|
||||
struct tm *gmtime_r(const time_t *clock, struct tm *res)
|
||||
{
|
||||
struct tm *tmp;
|
||||
mysql_mutex_lock(&LOCK_localtime_r);
|
||||
tmp= gmtime(clock);
|
||||
*res= *tmp;
|
||||
mysql_mutex_unlock(&LOCK_localtime_r);
|
||||
return res;
|
||||
}
|
||||
#endif
|
||||
|
||||
/****************************************************************************
|
||||
** Replacement of sigwait if the system doesn't have one (like BSDI 3.0)
|
||||
**
|
||||
** Note:
|
||||
** This version of sigwait() is assumed to called in a loop so the signalmask
|
||||
** is permanently modified to reflect the signal set. This is done to get
|
||||
** a much faster implementation.
|
||||
**
|
||||
** This implementation isn't thread safe: It assumes that only one
|
||||
** thread is using sigwait.
|
||||
**
|
||||
** If one later supplies a different signal mask, all old signals that
|
||||
** was used before are unblocked and set to SIGDFL.
|
||||
**
|
||||
** Author: Gary Wisniewski <garyw@spidereye.com.au>, much modified by Monty
|
||||
****************************************************************************/
|
||||
|
||||
#if !defined(HAVE_SIGWAIT) && !defined(sigwait) && !defined(__WIN__) && !defined(HAVE_rts_threads) && !defined(HAVE_NONPOSIX_SIGWAIT) && !defined(HAVE_DEC_3_2_THREADS)
|
||||
|
||||
#if !defined(DONT_USE_SIGSUSPEND)
|
||||
|
||||
static sigset_t sigwait_set,rev_sigwait_set,px_recd;
|
||||
|
||||
void px_handle_sig(int sig)
|
||||
{
|
||||
sigaddset(&px_recd, sig);
|
||||
}
|
||||
|
||||
|
||||
void sigwait_setup(sigset_t *set)
|
||||
{
|
||||
int i;
|
||||
struct sigaction sact,sact1;
|
||||
sigset_t unblock_mask;
|
||||
|
||||
sact.sa_flags = 0;
|
||||
sact.sa_handler = px_handle_sig;
|
||||
memcpy(&sact.sa_mask, set, sizeof(*set)); /* handler isn't thread_safe */
|
||||
sigemptyset(&unblock_mask);
|
||||
pthread_sigmask(SIG_UNBLOCK,(sigset_t*) 0,&rev_sigwait_set);
|
||||
|
||||
for (i = 1; i <= sizeof(sigwait_set)*8; i++)
|
||||
{
|
||||
if (sigismember(set,i))
|
||||
{
|
||||
sigdelset(&rev_sigwait_set,i);
|
||||
if (!sigismember(&sigwait_set,i))
|
||||
sigaction(i, &sact, (struct sigaction*) 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
sigdelset(&px_recd,i); /* Don't handle this */
|
||||
if (sigismember(&sigwait_set,i))
|
||||
{ /* Remove the old handler */
|
||||
sigaddset(&unblock_mask,i);
|
||||
sigdelset(&rev_sigwait_set,i);
|
||||
sact1.sa_flags = 0;
|
||||
sact1.sa_handler = SIG_DFL;
|
||||
sigemptyset(&sact1.sa_mask);
|
||||
sigaction(i, &sact1, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
memcpy(&sigwait_set, set, sizeof(*set));
|
||||
pthread_sigmask(SIG_BLOCK,(sigset_t*) set,(sigset_t*) 0);
|
||||
pthread_sigmask(SIG_UNBLOCK,&unblock_mask,(sigset_t*) 0);
|
||||
}
|
||||
|
||||
|
||||
int sigwait(sigset_t *setp, int *sigp)
|
||||
{
|
||||
if (memcmp(setp,&sigwait_set,sizeof(sigwait_set)))
|
||||
sigwait_setup(setp); /* Init or change of set */
|
||||
|
||||
for (;;)
|
||||
{
|
||||
/*
|
||||
This is a fast, not 100% portable implementation to find the signal.
|
||||
Because the handler is blocked there should be at most 1 bit set, but
|
||||
the specification on this is somewhat shady so we use a set instead a
|
||||
single variable.
|
||||
*/
|
||||
|
||||
ulong *ptr= (ulong*) &px_recd;
|
||||
ulong *end=ptr+sizeof(px_recd)/sizeof(ulong);
|
||||
|
||||
for ( ; ptr != end ; ptr++)
|
||||
{
|
||||
if (*ptr)
|
||||
{
|
||||
ulong set= *ptr;
|
||||
int found= (int) ((char*) ptr - (char*) &px_recd)*8+1;
|
||||
while (!(set & 1))
|
||||
{
|
||||
found++;
|
||||
set>>=1;
|
||||
}
|
||||
*sigp=found;
|
||||
sigdelset(&px_recd,found);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
sigsuspend(&rev_sigwait_set);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
#else /* !DONT_USE_SIGSUSPEND */
|
||||
|
||||
/****************************************************************************
|
||||
** Replacement of sigwait if the system doesn't have one (like BSDI 3.0)
|
||||
**
|
||||
** Note:
|
||||
** This version of sigwait() is assumed to called in a loop so the signalmask
|
||||
** is permanently modified to reflect the signal set. This is done to get
|
||||
** a much faster implementation.
|
||||
**
|
||||
** This implementation uses a extra thread to handle the signals and one
|
||||
** must always call sigwait() with the same signal mask!
|
||||
**
|
||||
** BSDI 3.0 NOTE:
|
||||
**
|
||||
** pthread_kill() doesn't work on a thread in a select() or sleep() loop?
|
||||
** After adding the sleep to sigwait_thread, all signals are checked and
|
||||
** delivered every second. This isn't that terrible performance vice, but
|
||||
** someone should report this to BSDI and ask for a fix!
|
||||
** Another problem is that when the sleep() ends, every select() in other
|
||||
** threads are interrupted!
|
||||
****************************************************************************/
|
||||
|
||||
static sigset_t pending_set;
|
||||
static bool inited=0;
|
||||
static pthread_cond_t COND_sigwait;
|
||||
static pthread_mutex_t LOCK_sigwait;
|
||||
|
||||
|
||||
void sigwait_handle_sig(int sig)
|
||||
{
|
||||
pthread_mutex_lock(&LOCK_sigwait);
|
||||
sigaddset(&pending_set, sig);
|
||||
pthread_cond_signal(&COND_sigwait); /* inform sigwait() about signal */
|
||||
pthread_mutex_unlock(&LOCK_sigwait);
|
||||
}
|
||||
|
||||
void *sigwait_thread(void *set_arg)
|
||||
{
|
||||
sigset_t *set=(sigset_t*) set_arg;
|
||||
|
||||
int i;
|
||||
struct sigaction sact;
|
||||
sact.sa_flags = 0;
|
||||
sact.sa_handler = sigwait_handle_sig;
|
||||
memcpy(&sact.sa_mask, set, sizeof(*set)); /* handler isn't thread_safe */
|
||||
sigemptyset(&pending_set);
|
||||
|
||||
for (i = 1; i <= sizeof(pending_set)*8; i++)
|
||||
{
|
||||
if (sigismember(set,i))
|
||||
{
|
||||
sigaction(i, &sact, (struct sigaction*) 0);
|
||||
}
|
||||
}
|
||||
/* Ensure that init_thr_alarm() is called */
|
||||
DBUG_ASSERT(thr_client_alarm);
|
||||
sigaddset(set, thr_client_alarm);
|
||||
pthread_sigmask(SIG_UNBLOCK,(sigset_t*) set,(sigset_t*) 0);
|
||||
alarm_thread=pthread_self(); /* For thr_alarm */
|
||||
|
||||
for (;;)
|
||||
{ /* Wait for signals */
|
||||
#ifdef HAVE_NOT_BROKEN_SELECT
|
||||
fd_set fd;
|
||||
FD_ZERO(&fd);
|
||||
select(0,&fd,0,0,0);
|
||||
#else
|
||||
sleep(1); /* Because of broken BSDI */
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int sigwait(sigset_t *setp, int *sigp)
|
||||
{
|
||||
if (!inited)
|
||||
{
|
||||
pthread_attr_t thr_attr;
|
||||
pthread_t sigwait_thread_id;
|
||||
inited=1;
|
||||
sigemptyset(&pending_set);
|
||||
pthread_mutex_init(&LOCK_sigwait, MY_MUTEX_INIT_FAST);
|
||||
pthread_cond_init(&COND_sigwait, NULL);
|
||||
|
||||
pthread_attr_init(&thr_attr);
|
||||
pthread_attr_setscope(&thr_attr,PTHREAD_SCOPE_PROCESS);
|
||||
pthread_attr_setdetachstate(&thr_attr,PTHREAD_CREATE_DETACHED);
|
||||
pthread_attr_setstacksize(&thr_attr,8196);
|
||||
pthread_create(&sigwait_thread_id, &thr_attr, sigwait_thread, setp);
|
||||
pthread_attr_destroy(&thr_attr);
|
||||
}
|
||||
|
||||
pthread_mutex_lock(&LOCK_sigwait);
|
||||
for (;;)
|
||||
{
|
||||
ulong *ptr= (ulong*) &pending_set;
|
||||
ulong *end=ptr+sizeof(pending_set)/sizeof(ulong);
|
||||
|
||||
for ( ; ptr != end ; ptr++)
|
||||
{
|
||||
if (*ptr)
|
||||
{
|
||||
ulong set= *ptr;
|
||||
int found= (int) ((char*) ptr - (char*) &pending_set)*8+1;
|
||||
while (!(set & 1))
|
||||
{
|
||||
found++;
|
||||
set>>=1;
|
||||
}
|
||||
*sigp=found;
|
||||
sigdelset(&pending_set,found);
|
||||
pthread_mutex_unlock(&LOCK_sigwait);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
pthread_cond_wait(&COND_sigwait, &LOCK_sigwait);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif /* DONT_USE_SIGSUSPEND */
|
||||
#endif /* HAVE_SIGWAIT */
|
||||
|
||||
|
||||
/****************************************************************************
|
||||
The following functions fixes that all pthread functions should work
|
||||
according to latest posix standard
|
||||
****************************************************************************/
|
||||
|
||||
/* Undefined wrappers set my_pthread.h so that we call os functions */
|
||||
#undef pthread_mutex_init
|
||||
#undef pthread_mutex_lock
|
||||
#undef pthread_mutex_unlock
|
||||
#undef pthread_mutex_destroy
|
||||
#undef pthread_mutex_wait
|
||||
#undef pthread_mutex_timedwait
|
||||
#undef pthread_mutex_trylock
|
||||
#undef pthread_mutex_t
|
||||
#undef pthread_cond_init
|
||||
#undef pthread_cond_wait
|
||||
#undef pthread_cond_timedwait
|
||||
#undef pthread_cond_t
|
||||
#undef pthread_attr_getstacksize
|
||||
|
||||
/*****************************************************************************
|
||||
** Patches for AIX and DEC OSF/1 3.2
|
||||
*****************************************************************************/
|
||||
|
||||
#if defined(HAVE_NONPOSIX_PTHREAD_MUTEX_INIT)
|
||||
|
||||
#include <netdb.h>
|
||||
|
||||
int my_pthread_mutex_init(pthread_mutex_t *mp, const pthread_mutexattr_t *attr)
|
||||
{
|
||||
int error;
|
||||
if (!attr)
|
||||
error=pthread_mutex_init(mp,pthread_mutexattr_default);
|
||||
else
|
||||
error=pthread_mutex_init(mp,*attr);
|
||||
return error;
|
||||
}
|
||||
|
||||
int my_pthread_cond_init(pthread_cond_t *mp, const pthread_condattr_t *attr)
|
||||
{
|
||||
int error;
|
||||
if (!attr)
|
||||
error=pthread_cond_init(mp,pthread_condattr_default);
|
||||
else
|
||||
error=pthread_cond_init(mp,*attr);
|
||||
return error;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
/*****************************************************************************
|
||||
Patches for HPUX
|
||||
We need these because the pthread_mutex.. code returns -1 on error,
|
||||
instead of the error code.
|
||||
|
||||
Note that currently we only remap pthread_ functions used by MySQL.
|
||||
If we are depending on the value for some other pthread_xxx functions,
|
||||
this has to be added here.
|
||||
****************************************************************************/
|
||||
|
||||
#if defined(HPUX10) || defined(HAVE_BROKEN_PTHREAD_COND_TIMEDWAIT)
|
||||
|
||||
int my_pthread_cond_timedwait(pthread_cond_t *cond, pthread_mutex_t *mutex,
|
||||
struct timespec *abstime)
|
||||
{
|
||||
int error=pthread_cond_timedwait(cond, mutex, abstime);
|
||||
if (error == -1) /* Safety if the lib is fixed */
|
||||
{
|
||||
if (!(error=errno))
|
||||
error= ETIMEDOUT; /* Can happen on HPUX */
|
||||
}
|
||||
if (error == EAGAIN) /* Correct errno to Posix */
|
||||
error= ETIMEDOUT;
|
||||
return error;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(HPUX10)
|
||||
|
||||
void my_pthread_attr_getstacksize(pthread_attr_t *connection_attrib,
|
||||
size_t *stack_size)
|
||||
{
|
||||
*stack_size= pthread_attr_getstacksize(*connection_attrib);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef HAVE_POSIX1003_4a_MUTEX
|
||||
/*
|
||||
In HP-UX-10.20 and other old Posix 1003.4a Draft 4 implementations
|
||||
pthread_mutex_trylock returns 1 on success, not 0 like
|
||||
pthread_mutex_lock
|
||||
|
||||
From the HP-UX-10.20 man page:
|
||||
RETURN VALUES
|
||||
If the function fails, errno may be set to one of the following
|
||||
values:
|
||||
Return | Error | Description
|
||||
_______|__________|_________________________________________
|
||||
1 | | Successful completion.
|
||||
0 | | The mutex is locked; therefore, it was
|
||||
| | not acquired.
|
||||
-1 | [EINVAL] | The value specified by mutex is invalid.
|
||||
|
||||
*/
|
||||
|
||||
/*
|
||||
Convert pthread_mutex_trylock to return values according to latest POSIX
|
||||
|
||||
RETURN VALUES
|
||||
0 If we are able successfully lock the mutex.
|
||||
EBUSY Mutex was locked by another thread
|
||||
# Other error number returned by pthread_mutex_trylock()
|
||||
(Not likely)
|
||||
*/
|
||||
|
||||
int my_pthread_mutex_trylock(pthread_mutex_t *mutex)
|
||||
{
|
||||
int error= pthread_mutex_trylock(mutex);
|
||||
if (error == 1)
|
||||
return 0; /* Got lock on mutex */
|
||||
if (error == 0) /* Someon else is locking mutex */
|
||||
return EBUSY;
|
||||
if (error == -1) /* Safety if the lib is fixed */
|
||||
error= errno; /* Probably invalid parameter */
|
||||
return error;
|
||||
}
|
||||
#endif /* HAVE_POSIX1003_4a_MUTEX */
|
||||
|
||||
/* Some help functions */
|
||||
|
||||
int pthread_dummy(int ret)
|
||||
{
|
||||
return ret;
|
||||
}
|
||||
81
deps/mysqllite/mysys/my_quick.c
vendored
Normal file
81
deps/mysqllite/mysys/my_quick.c
vendored
Normal file
@@ -0,0 +1,81 @@
|
||||
/* Copyright (C) 2000 MySQL AB
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
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 */
|
||||
|
||||
/* Quicker interface to read & write. Used with my_nosys.h */
|
||||
|
||||
#include "mysys_priv.h"
|
||||
#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;
|
||||
#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)
|
||||
{
|
||||
DBUG_PRINT("error", ("my_quick_read() was interrupted and returned %d"
|
||||
". This function does not retry the read!",
|
||||
(int) readbytes));
|
||||
}
|
||||
#endif
|
||||
my_errno=errno;
|
||||
return readbytes;
|
||||
}
|
||||
return (MyFlags & (MY_NABP | MY_FNABP)) ? 0 : readbytes;
|
||||
}
|
||||
|
||||
|
||||
|
||||
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
|
||||
|
||||
if ((
|
||||
#ifndef DBUG_OFF
|
||||
writtenbytes =
|
||||
#endif
|
||||
(size_t) write(Filedes,Buffer,Count)) != Count)
|
||||
{
|
||||
#ifndef DBUG_OFF
|
||||
if ((writtenbytes == 0 || writtenbytes == (size_t) -1) && errno == EINTR)
|
||||
{
|
||||
DBUG_PRINT("error", ("my_quick_write() was interrupted and returned %d"
|
||||
". This function does not retry the write!",
|
||||
(int) writtenbytes));
|
||||
}
|
||||
#endif
|
||||
my_errno=errno;
|
||||
return (size_t) -1;
|
||||
}
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
962
deps/mysqllite/mysys/my_rdtsc.c
vendored
Normal file
962
deps/mysqllite/mysys/my_rdtsc.c
vendored
Normal file
@@ -0,0 +1,962 @@
|
||||
/* Copyright (C) 2008-2010 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 */
|
||||
|
||||
/*
|
||||
rdtsc3 -- multi-platform timer code
|
||||
pgulutzan@mysql.com, 2005-08-29
|
||||
modified 2008-11-02
|
||||
|
||||
Functions:
|
||||
|
||||
my_timer_cycles ulonglong cycles
|
||||
my_timer_nanoseconds ulonglong nanoseconds
|
||||
my_timer_microseconds ulonglong "microseconds"
|
||||
my_timer_milliseconds ulonglong milliseconds
|
||||
my_timer_ticks ulonglong ticks
|
||||
my_timer_init initialization / test
|
||||
|
||||
We'll call the first 5 functions (the ones that return
|
||||
a ulonglong) "my_timer_xxx" functions.
|
||||
Each my_timer_xxx function returns a 64-bit timing value
|
||||
since an arbitrary 'epoch' start. Since the only purpose
|
||||
is to determine elapsed times, wall-clock time-of-day
|
||||
is not known and not relevant.
|
||||
|
||||
The my_timer_init function is necessary for initializing.
|
||||
It returns information (underlying routine name,
|
||||
frequency, resolution, overhead) about all my_timer_xxx
|
||||
functions. A program should call my_timer_init once,
|
||||
use the information to decide what my_timer_xxx function
|
||||
to use, and subsequently call that function by function
|
||||
pointer.
|
||||
|
||||
A typical use would be:
|
||||
my_timer_init() ... once, at program start
|
||||
...
|
||||
time1= my_timer_xxx() ... time before start
|
||||
[code that's timed]
|
||||
time2= my_timer_xxx() ... time after end
|
||||
elapsed_time= (time2 - time1) - overhead
|
||||
*/
|
||||
|
||||
#include "my_global.h"
|
||||
#include "my_rdtsc.h"
|
||||
|
||||
#if defined(_WIN32)
|
||||
#include <stdio.h>
|
||||
#include "windows.h"
|
||||
#else
|
||||
#include <stdio.h>
|
||||
#endif
|
||||
|
||||
#if !defined(_WIN32)
|
||||
#if TIME_WITH_SYS_TIME
|
||||
#include <sys/time.h>
|
||||
#include <time.h> /* for clock_gettime */
|
||||
#else
|
||||
#if HAVE_SYS_TIME_H
|
||||
#include <sys/time.h>
|
||||
#elif defined(HAVE_TIME_H)
|
||||
#include <time.h>
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if defined(HAVE_ASM_MSR_H) && defined(HAVE_RDTSCLL)
|
||||
#include <asm/msr.h> /* for rdtscll */
|
||||
#endif
|
||||
|
||||
#if defined(HAVE_SYS_TIMEB_H) && defined(HAVE_FTIME)
|
||||
#include <sys/timeb.h> /* for ftime */
|
||||
#endif
|
||||
|
||||
#if defined(HAVE_SYS_TIMES_H) && defined(HAVE_TIMES)
|
||||
#include <sys/times.h> /* for times */
|
||||
#endif
|
||||
|
||||
#if defined(__INTEL_COMPILER) && defined(__ia64__) && defined(HAVE_IA64INTRIN_H)
|
||||
#include <ia64intrin.h> /* for __GetReg */
|
||||
#endif
|
||||
|
||||
#if defined(__APPLE__) && defined(__MACH__)
|
||||
#include <mach/mach_time.h>
|
||||
#endif
|
||||
|
||||
#if defined(__SUNPRO_CC) && defined(__sparcv9) && defined(_LP64) && !defined(__SunOS_5_7)
|
||||
extern "C" ulonglong my_timer_cycles_il_sparc64();
|
||||
#elif defined(__SUNPRO_CC) && defined(_ILP32) && !defined(__SunOS_5_7)
|
||||
extern "C" ulonglong my_timer_cycles_il_sparc32();
|
||||
#elif defined(__SUNPRO_CC) && defined(__i386) && defined(_ILP32)
|
||||
extern "C" ulonglong my_timer_cycles_il_i386();
|
||||
#elif defined(__SUNPRO_CC) && defined(__x86_64) && defined(_LP64)
|
||||
extern "C" ulonglong my_timer_cycles_il_x86_64();
|
||||
#elif defined(__SUNPRO_C) && defined(__sparcv9) && defined(_LP64) && !defined(__SunOS_5_7)
|
||||
ulonglong my_timer_cycles_il_sparc64();
|
||||
#elif defined(__SUNPRO_C) && defined(_ILP32) && !defined(__SunOS_5_7)
|
||||
ulonglong my_timer_cycles_il_sparc32();
|
||||
#elif defined(__SUNPRO_C) && defined(__i386) && defined(_ILP32)
|
||||
ulonglong my_timer_cycles_il_i386();
|
||||
#elif defined(__SUNPRO_C) && defined(__x86_64) && defined(_LP64)
|
||||
ulonglong my_timer_cycles_il_x86_64();
|
||||
#endif
|
||||
|
||||
#if defined(__INTEL_COMPILER)
|
||||
/*
|
||||
icc warning #1011 is:
|
||||
missing return statement at end of non-void function
|
||||
*/
|
||||
#pragma warning (disable:1011)
|
||||
#endif
|
||||
|
||||
/*
|
||||
For cycles, we depend on RDTSC for x86 platforms,
|
||||
or on time buffer (which is not really a cycle count
|
||||
but a separate counter with less than nanosecond
|
||||
resolution) for most PowerPC platforms, or on
|
||||
gethrtime which is okay for hpux and solaris, or on
|
||||
clock_gettime(CLOCK_SGI_CYCLE) for Irix platforms,
|
||||
or on read_real_time for aix platforms. There is
|
||||
nothing for Alpha platforms, they would be tricky.
|
||||
*/
|
||||
|
||||
ulonglong my_timer_cycles(void)
|
||||
{
|
||||
#if defined(__GNUC__) && defined(__i386__)
|
||||
/* This works much better if compiled with "gcc -O3". */
|
||||
ulonglong result;
|
||||
__asm__ __volatile__ ("rdtsc" : "=A" (result));
|
||||
return result;
|
||||
#elif defined(__SUNPRO_C) && defined(__i386)
|
||||
__asm("rdtsc");
|
||||
#elif defined(__GNUC__) && defined(__x86_64__)
|
||||
ulonglong result;
|
||||
__asm__ __volatile__ ("rdtsc\n\t" \
|
||||
"shlq $32,%%rdx\n\t" \
|
||||
"orq %%rdx,%%rax"
|
||||
: "=a" (result) :: "%edx");
|
||||
return result;
|
||||
#elif defined(HAVE_ASM_MSR_H) && defined(HAVE_RDTSCLL)
|
||||
{
|
||||
ulonglong result;
|
||||
rdtscll(result);
|
||||
return result;
|
||||
}
|
||||
#elif defined(_WIN32) && defined(_M_IX86)
|
||||
__asm {rdtsc};
|
||||
#elif defined(_WIN64) && defined(_M_X64)
|
||||
/* For 64-bit Windows: unsigned __int64 __rdtsc(); */
|
||||
return __rdtsc();
|
||||
#elif defined(__INTEL_COMPILER) && defined(__ia64__) && defined(HAVE_IA64INTRIN_H)
|
||||
return (ulonglong) __getReg(_IA64_REG_AR_ITC); /* (3116) */
|
||||
#elif defined(__GNUC__) && defined(__ia64__)
|
||||
{
|
||||
ulonglong result;
|
||||
__asm __volatile__ ("mov %0=ar.itc" : "=r" (result));
|
||||
return result;
|
||||
}
|
||||
#elif defined(__GNUC__) && (defined(__powerpc__) || defined(__POWERPC__) || (defined(_POWER) && defined(_AIX52))) && (defined(__64BIT__) || defined(_ARCH_PPC64))
|
||||
{
|
||||
ulonglong result;
|
||||
__asm __volatile__ ("mftb %0" : "=r" (result));
|
||||
return result;
|
||||
}
|
||||
#elif defined(__GNUC__) && (defined(__powerpc__) || defined(__POWERPC__) || (defined(_POWER) && defined(_AIX52))) && (!defined(__64BIT__) && !defined(_ARCH_PPC64))
|
||||
{
|
||||
/*
|
||||
mftbu means "move from time-buffer-upper to result".
|
||||
The loop is saying: x1=upper, x2=lower, x3=upper,
|
||||
if x1!=x3 there was an overflow so repeat.
|
||||
*/
|
||||
unsigned int x1, x2, x3;
|
||||
ulonglong result;
|
||||
for (;;)
|
||||
{
|
||||
__asm __volatile__ ( "mftbu %0" : "=r"(x1) );
|
||||
__asm __volatile__ ( "mftb %0" : "=r"(x2) );
|
||||
__asm __volatile__ ( "mftbu %0" : "=r"(x3) );
|
||||
if (x1 == x3) break;
|
||||
}
|
||||
result = x1;
|
||||
return ( result << 32 ) | x2;
|
||||
}
|
||||
#elif (defined(__SUNPRO_CC) || defined(__SUNPRO_C)) && defined(__sparcv9) && defined(_LP64) && !defined(__SunOS_5_7)
|
||||
return (my_timer_cycles_il_sparc64());
|
||||
#elif (defined(__SUNPRO_CC) || defined(__SUNPRO_C)) && defined(_ILP32) && !defined(__SunOS_5_7)
|
||||
return (my_timer_cycles_il_sparc32());
|
||||
#elif (defined(__SUNPRO_CC) || defined(__SUNPRO_C)) && defined(__i386) && defined(_ILP32)
|
||||
/* This is probably redundant for __SUNPRO_C. */
|
||||
return (my_timer_cycles_il_i386());
|
||||
#elif (defined(__SUNPRO_CC) || defined(__SUNPRO_C)) && defined(__x86_64) && defined(_LP64)
|
||||
return (my_timer_cycles_il_x86_64());
|
||||
#elif defined(__GNUC__) && defined(__sparcv9) && defined(_LP64) && (__GNUC__>2)
|
||||
{
|
||||
ulonglong result;
|
||||
__asm __volatile__ ("rd %%tick,%0" : "=r" (result));
|
||||
return result;
|
||||
}
|
||||
#elif defined(__GNUC__) && defined(__sparc__) && !defined(_LP64) && (__GNUC__>2)
|
||||
{
|
||||
union {
|
||||
ulonglong wholeresult;
|
||||
struct {
|
||||
ulong high;
|
||||
ulong low;
|
||||
} splitresult;
|
||||
} result;
|
||||
__asm __volatile__ ("rd %%tick,%1; srlx %1,32,%0" : "=r" (result.splitresult.high), "=r" (result.splitresult.low));
|
||||
return result.wholeresult;
|
||||
}
|
||||
#elif defined(__sgi) && defined(HAVE_CLOCK_GETTIME) && defined(CLOCK_SGI_CYCLE)
|
||||
{
|
||||
struct timespec tp;
|
||||
clock_gettime(CLOCK_SGI_CYCLE, &tp);
|
||||
return (ulonglong) tp.tv_sec * 1000000000 + (ulonglong) tp.tv_nsec;
|
||||
}
|
||||
#elif defined(HAVE_SYS_TIMES_H) && defined(HAVE_GETHRTIME)
|
||||
/* gethrtime may appear as either cycle or nanosecond counter */
|
||||
return (ulonglong) gethrtime();
|
||||
#else
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
#if defined(__INTEL_COMPILER)
|
||||
/* re-enable warning#1011 which was only for my_timer_cycles() */
|
||||
/* There may be an icc bug which means we must leave disabled. */
|
||||
#pragma warning (default:1011)
|
||||
#endif
|
||||
|
||||
/*
|
||||
For nanoseconds, most platforms have nothing available that
|
||||
(a) doesn't require bringing in a 40-kb librt.so library
|
||||
(b) really has nanosecond resolution.
|
||||
*/
|
||||
|
||||
ulonglong my_timer_nanoseconds(void)
|
||||
{
|
||||
#if defined(HAVE_READ_REAL_TIME)
|
||||
{
|
||||
timebasestruct_t tr;
|
||||
read_real_time(&tr, TIMEBASE_SZ);
|
||||
return (ulonglong) tr.tb_high * 1000000000 + (ulonglong) tr.tb_low;
|
||||
}
|
||||
#elif defined(HAVE_SYS_TIMES_H) && defined(HAVE_GETHRTIME)
|
||||
/* SunOS 5.10+, Solaris, HP-UX: hrtime_t gethrtime(void) */
|
||||
return (ulonglong) gethrtime();
|
||||
#elif defined(HAVE_CLOCK_GETTIME) && defined(CLOCK_REALTIME)
|
||||
{
|
||||
struct timespec tp;
|
||||
clock_gettime(CLOCK_REALTIME, &tp);
|
||||
return (ulonglong) tp.tv_sec * 1000000000 + (ulonglong) tp.tv_nsec;
|
||||
}
|
||||
#elif defined(__APPLE__) && defined(__MACH__)
|
||||
{
|
||||
ulonglong tm;
|
||||
static mach_timebase_info_data_t timebase_info= {0,0};
|
||||
if (timebase_info.denom == 0)
|
||||
(void) mach_timebase_info(&timebase_info);
|
||||
tm= mach_absolute_time();
|
||||
return (tm * timebase_info.numer) / timebase_info.denom;
|
||||
}
|
||||
#else
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
For microseconds, gettimeofday() is available on
|
||||
almost all platforms. On Windows we use
|
||||
QueryPerformanceCounter which will usually tick over
|
||||
3.5 million times per second, and we don't throw
|
||||
away the extra precision. (On Windows Server 2003
|
||||
the frequency is same as the cycle frequency.)
|
||||
*/
|
||||
|
||||
ulonglong my_timer_microseconds(void)
|
||||
{
|
||||
#if defined(HAVE_GETTIMEOFDAY)
|
||||
{
|
||||
static ulonglong last_value= 0;
|
||||
struct timeval tv;
|
||||
if (gettimeofday(&tv, NULL) == 0)
|
||||
last_value= (ulonglong) tv.tv_sec * 1000000 + (ulonglong) tv.tv_usec;
|
||||
else
|
||||
{
|
||||
/*
|
||||
There are reports that gettimeofday(2) can have intermittent failures
|
||||
on some platform, see for example Bug#36819.
|
||||
We are not trying again or looping, just returning the best value possible
|
||||
under the circumstances ...
|
||||
*/
|
||||
last_value++;
|
||||
}
|
||||
return last_value;
|
||||
}
|
||||
#elif defined(_WIN32)
|
||||
{
|
||||
/* QueryPerformanceCounter usually works with about 1/3 microsecond. */
|
||||
LARGE_INTEGER t_cnt;
|
||||
|
||||
QueryPerformanceCounter(&t_cnt);
|
||||
return (ulonglong) t_cnt.QuadPart;
|
||||
}
|
||||
#else
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
For milliseconds, we use ftime() if it's supported
|
||||
or time()*1000 if it's not. With modern versions of
|
||||
Windows and with HP Itanium, resolution is 10-15
|
||||
milliseconds.
|
||||
*/
|
||||
|
||||
ulonglong my_timer_milliseconds(void)
|
||||
{
|
||||
#if defined(HAVE_SYS_TIMEB_H) && defined(HAVE_FTIME)
|
||||
/* ftime() is obsolete but maybe the platform is old */
|
||||
struct timeb ft;
|
||||
ftime(&ft);
|
||||
return (ulonglong)ft.time * 1000 + (ulonglong)ft.millitm;
|
||||
#elif defined(HAVE_TIME)
|
||||
return (ulonglong) time(NULL) * 1000;
|
||||
#elif defined(_WIN32)
|
||||
FILETIME ft;
|
||||
GetSystemTimeAsFileTime( &ft );
|
||||
return ((ulonglong)ft.dwLowDateTime +
|
||||
(((ulonglong)ft.dwHighDateTime) << 32))/10000;
|
||||
#else
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
For ticks, which we handle with times(), the frequency
|
||||
is usually 100/second and the overhead is surprisingly
|
||||
bad, sometimes even worse than gettimeofday's overhead.
|
||||
*/
|
||||
|
||||
ulonglong my_timer_ticks(void)
|
||||
{
|
||||
#if defined(HAVE_SYS_TIMES_H) && defined(HAVE_TIMES)
|
||||
{
|
||||
struct tms times_buf;
|
||||
return (ulonglong) times(×_buf);
|
||||
}
|
||||
#elif defined(_WIN32)
|
||||
return (ulonglong) GetTickCount();
|
||||
#else
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
The my_timer_init() function and its sub-functions
|
||||
have several loops which call timers. If there's
|
||||
something wrong with a timer -- which has never
|
||||
happened in tests -- we want the loop to end after
|
||||
an arbitrary number of iterations, and my_timer_info
|
||||
will show a discouraging result. The arbitrary
|
||||
number is 1,000,000.
|
||||
*/
|
||||
#define MY_TIMER_ITERATIONS 1000000
|
||||
|
||||
/*
|
||||
Calculate overhead. Called from my_timer_init().
|
||||
Usually best_timer_overhead = cycles.overhead or
|
||||
nanoseconds.overhead, so returned amount is in
|
||||
cycles or nanoseconds. We repeat the calculation
|
||||
ten times, so that we can disregard effects of
|
||||
caching or interrupts. Result is quite consistent
|
||||
for cycles, at least. But remember it's a minimum.
|
||||
*/
|
||||
|
||||
static void my_timer_init_overhead(ulonglong *overhead,
|
||||
ulonglong (*cycle_timer)(void),
|
||||
ulonglong (*this_timer)(void),
|
||||
ulonglong best_timer_overhead)
|
||||
{
|
||||
ulonglong time1, time2;
|
||||
int i;
|
||||
|
||||
/* *overhead, least of 20 calculations - cycles.overhead */
|
||||
for (i= 0, *overhead= 1000000000; i < 20; ++i)
|
||||
{
|
||||
time1= cycle_timer();
|
||||
this_timer(); /* rather than 'time_tmp= timer();' */
|
||||
time2= cycle_timer() - time1;
|
||||
if (*overhead > time2)
|
||||
*overhead= time2;
|
||||
}
|
||||
*overhead-= best_timer_overhead;
|
||||
}
|
||||
|
||||
/*
|
||||
Calculate Resolution. Called from my_timer_init().
|
||||
If a timer goes up by jumps, e.g. 1050, 1075, 1100, ...
|
||||
then the best resolution is the minimum jump, e.g. 25.
|
||||
If it's always divisible by 1000 then it's just a
|
||||
result of multiplication of a lower-precision timer
|
||||
result, e.g. nanoseconds are often microseconds * 1000.
|
||||
If the minimum jump is less than an arbitrary passed
|
||||
figure (a guess based on maximum overhead * 2), ignore.
|
||||
Usually we end up with nanoseconds = 1 because it's too
|
||||
hard to detect anything <= 100 nanoseconds.
|
||||
Often GetTickCount() has resolution = 15.
|
||||
We don't check with ticks because they take too long.
|
||||
*/
|
||||
static ulonglong my_timer_init_resolution(ulonglong (*this_timer)(void),
|
||||
ulonglong overhead_times_2)
|
||||
{
|
||||
ulonglong time1, time2;
|
||||
ulonglong best_jump;
|
||||
int i, jumps, divisible_by_1000, divisible_by_1000000;
|
||||
|
||||
divisible_by_1000= divisible_by_1000000= 0;
|
||||
best_jump= 1000000;
|
||||
for (i= jumps= 0; jumps < 3 && i < MY_TIMER_ITERATIONS * 10; ++i)
|
||||
{
|
||||
time1= this_timer();
|
||||
time2= this_timer();
|
||||
time2-= time1;
|
||||
if (time2)
|
||||
{
|
||||
++jumps;
|
||||
if (!(time2 % 1000))
|
||||
{
|
||||
++divisible_by_1000;
|
||||
if (!(time2 % 1000000))
|
||||
++divisible_by_1000000;
|
||||
}
|
||||
if (best_jump > time2)
|
||||
best_jump= time2;
|
||||
/* For milliseconds, one jump is enough. */
|
||||
if (overhead_times_2 == 0)
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (jumps == 3)
|
||||
{
|
||||
if (jumps == divisible_by_1000000)
|
||||
return 1000000;
|
||||
if (jumps == divisible_by_1000)
|
||||
return 1000;
|
||||
}
|
||||
if (best_jump > overhead_times_2)
|
||||
return best_jump;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
Calculate cycle frequency by seeing how many cycles pass
|
||||
in a 200-microsecond period. I tried with 10-microsecond
|
||||
periods originally, and the result was often very wrong.
|
||||
*/
|
||||
|
||||
static ulonglong my_timer_init_frequency(MY_TIMER_INFO *mti)
|
||||
{
|
||||
int i;
|
||||
ulonglong time1, time2, time3, time4;
|
||||
time1= my_timer_cycles();
|
||||
time2= my_timer_microseconds();
|
||||
time3= time2; /* Avoids a Microsoft/IBM compiler warning */
|
||||
for (i= 0; i < MY_TIMER_ITERATIONS; ++i)
|
||||
{
|
||||
time3= my_timer_microseconds();
|
||||
if (time3 - time2 > 200) break;
|
||||
}
|
||||
time4= my_timer_cycles() - mti->cycles.overhead;
|
||||
time4-= mti->microseconds.overhead;
|
||||
return (mti->microseconds.frequency * (time4 - time1)) / (time3 - time2);
|
||||
}
|
||||
|
||||
/*
|
||||
Call my_timer_init before the first call to my_timer_xxx().
|
||||
If something must be initialized, it happens here.
|
||||
Set: what routine is being used e.g. "asm_x86"
|
||||
Set: function, overhead, actual frequency, resolution.
|
||||
*/
|
||||
|
||||
void my_timer_init(MY_TIMER_INFO *mti)
|
||||
{
|
||||
ulonglong (*best_timer)(void);
|
||||
ulonglong best_timer_overhead;
|
||||
ulonglong time1, time2;
|
||||
int i;
|
||||
|
||||
/* cycles */
|
||||
mti->cycles.frequency= 1000000000;
|
||||
#if defined(__GNUC__) && defined(__i386__)
|
||||
mti->cycles.routine= MY_TIMER_ROUTINE_ASM_X86;
|
||||
#elif defined(__SUNPRO_C) && defined(__i386)
|
||||
mti->cycles.routine= MY_TIMER_ROUTINE_ASM_X86;
|
||||
#elif defined(__GNUC__) && defined(__x86_64__)
|
||||
mti->cycles.routine= MY_TIMER_ROUTINE_ASM_X86_64;
|
||||
#elif defined(HAVE_ASM_MSR_H) && defined(HAVE_RDTSCLL)
|
||||
mti->cycles.routine= MY_TIMER_ROUTINE_RDTSCLL;
|
||||
#elif defined(_WIN32) && defined(_M_IX86)
|
||||
mti->cycles.routine= MY_TIMER_ROUTINE_ASM_X86_WIN;
|
||||
#elif defined(_WIN64) && defined(_M_X64)
|
||||
mti->cycles.routine= MY_TIMER_ROUTINE_RDTSC;
|
||||
#elif defined(__INTEL_COMPILER) && defined(__ia64__) && defined(HAVE_IA64INTRIN_H)
|
||||
mti->cycles.routine= MY_TIMER_ROUTINE_ASM_IA64;
|
||||
#elif defined(__GNUC__) && defined(__ia64__)
|
||||
mti->cycles.routine= MY_TIMER_ROUTINE_ASM_IA64;
|
||||
#elif defined(__GNUC__) && (defined(__powerpc__) || defined(__POWERPC__) || (defined(_POWER) && defined(_AIX52))) && (defined(__64BIT__) || defined(_ARCH_PPC64))
|
||||
mti->cycles.routine= MY_TIMER_ROUTINE_ASM_PPC64;
|
||||
#elif defined(__GNUC__) && (defined(__powerpc__) || defined(__POWERPC__) || (defined(_POWER) && defined(_AIX52))) && (!defined(__64BIT__) && !defined(_ARCH_PPC64))
|
||||
mti->cycles.routine= MY_TIMER_ROUTINE_ASM_PPC;
|
||||
#elif (defined(__SUNPRO_CC) || defined(__SUNPRO_C)) && defined(__sparcv9) && defined(_LP64) && !defined(__SunOS_5_7)
|
||||
mti->cycles.routine= MY_TIMER_ROUTINE_ASM_SUNPRO_SPARC64;
|
||||
#elif (defined(__SUNPRO_CC) || defined(__SUNPRO_C)) && defined(_ILP32) && !defined(__SunOS_5_7)
|
||||
mti->cycles.routine= MY_TIMER_ROUTINE_ASM_SUNPRO_SPARC32;
|
||||
#elif (defined(__SUNPRO_CC) || defined(__SUNPRO_C)) && defined(__i386) && defined(_ILP32)
|
||||
mti->cycles.routine= MY_TIMER_ROUTINE_ASM_SUNPRO_I386;
|
||||
#elif (defined(__SUNPRO_CC) || defined(__SUNPRO_C)) && defined(__x86_64) && defined(_LP64)
|
||||
mti->cycles.routine= MY_TIMER_ROUTINE_ASM_SUNPRO_X86_64;
|
||||
#elif defined(__GNUC__) && defined(__sparcv9) && defined(_LP64) && (__GNUC__>2)
|
||||
mti->cycles.routine= MY_TIMER_ROUTINE_ASM_GCC_SPARC64;
|
||||
#elif defined(__GNUC__) && defined(__sparc__) && !defined(_LP64) && (__GNUC__>2)
|
||||
mti->cycles.routine= MY_TIMER_ROUTINE_ASM_GCC_SPARC32;
|
||||
#elif defined(__sgi) && defined(HAVE_CLOCK_GETTIME) && defined(CLOCK_SGI_CYCLE)
|
||||
mti->cycles.routine= MY_TIMER_ROUTINE_SGI_CYCLE;
|
||||
#elif defined(HAVE_SYS_TIMES_H) && defined(HAVE_GETHRTIME)
|
||||
mti->cycles.routine= MY_TIMER_ROUTINE_GETHRTIME;
|
||||
#else
|
||||
mti->cycles.routine= 0;
|
||||
#endif
|
||||
|
||||
if (!mti->cycles.routine || !my_timer_cycles())
|
||||
{
|
||||
mti->cycles.routine= 0;
|
||||
mti->cycles.resolution= 0;
|
||||
mti->cycles.frequency= 0;
|
||||
mti->cycles.overhead= 0;
|
||||
}
|
||||
|
||||
/* nanoseconds */
|
||||
mti->nanoseconds.frequency= 1000000000; /* initial assumption */
|
||||
#if defined(HAVE_READ_REAL_TIME)
|
||||
mti->nanoseconds.routine= MY_TIMER_ROUTINE_READ_REAL_TIME;
|
||||
#elif defined(HAVE_SYS_TIMES_H) && defined(HAVE_GETHRTIME)
|
||||
mti->nanoseconds.routine= MY_TIMER_ROUTINE_GETHRTIME;
|
||||
#elif defined(HAVE_CLOCK_GETTIME)
|
||||
mti->nanoseconds.routine= MY_TIMER_ROUTINE_CLOCK_GETTIME;
|
||||
#elif defined(__APPLE__) && defined(__MACH__)
|
||||
mti->nanoseconds.routine= MY_TIMER_ROUTINE_MACH_ABSOLUTE_TIME;
|
||||
#else
|
||||
mti->nanoseconds.routine= 0;
|
||||
#endif
|
||||
if (!mti->nanoseconds.routine || !my_timer_nanoseconds())
|
||||
{
|
||||
mti->nanoseconds.routine= 0;
|
||||
mti->nanoseconds.resolution= 0;
|
||||
mti->nanoseconds.frequency= 0;
|
||||
mti->nanoseconds.overhead= 0;
|
||||
}
|
||||
|
||||
/* microseconds */
|
||||
mti->microseconds.frequency= 1000000; /* initial assumption */
|
||||
#if defined(HAVE_GETTIMEOFDAY)
|
||||
mti->microseconds.routine= MY_TIMER_ROUTINE_GETTIMEOFDAY;
|
||||
#elif defined(_WIN32)
|
||||
{
|
||||
LARGE_INTEGER li;
|
||||
/* Windows: typical frequency = 3579545, actually 1/3 microsecond. */
|
||||
if (!QueryPerformanceFrequency(&li))
|
||||
mti->microseconds.routine= 0;
|
||||
else
|
||||
{
|
||||
mti->microseconds.frequency= li.QuadPart;
|
||||
mti->microseconds.routine= MY_TIMER_ROUTINE_QUERYPERFORMANCECOUNTER;
|
||||
}
|
||||
}
|
||||
#else
|
||||
mti->microseconds.routine= 0;
|
||||
#endif
|
||||
if (!mti->microseconds.routine || !my_timer_microseconds())
|
||||
{
|
||||
mti->microseconds.routine= 0;
|
||||
mti->microseconds.resolution= 0;
|
||||
mti->microseconds.frequency= 0;
|
||||
mti->microseconds.overhead= 0;
|
||||
}
|
||||
|
||||
/* milliseconds */
|
||||
mti->milliseconds.frequency= 1000; /* initial assumption */
|
||||
#if defined(HAVE_SYS_TIMEB_H) && defined(HAVE_FTIME)
|
||||
mti->milliseconds.routine= MY_TIMER_ROUTINE_FTIME;
|
||||
#elif defined(_WIN32)
|
||||
mti->milliseconds.routine= MY_TIMER_ROUTINE_GETSYSTEMTIMEASFILETIME;
|
||||
#elif defined(HAVE_TIME)
|
||||
mti->milliseconds.routine= MY_TIMER_ROUTINE_TIME;
|
||||
#else
|
||||
mti->milliseconds.routine= 0;
|
||||
#endif
|
||||
if (!mti->milliseconds.routine || !my_timer_milliseconds())
|
||||
{
|
||||
mti->milliseconds.routine= 0;
|
||||
mti->milliseconds.resolution= 0;
|
||||
mti->milliseconds.frequency= 0;
|
||||
mti->milliseconds.overhead= 0;
|
||||
}
|
||||
|
||||
/* ticks */
|
||||
mti->ticks.frequency= 100; /* permanent assumption */
|
||||
#if defined(HAVE_SYS_TIMES_H) && defined(HAVE_TIMES)
|
||||
mti->ticks.routine= MY_TIMER_ROUTINE_TIMES;
|
||||
#elif defined(_WIN32)
|
||||
mti->ticks.routine= MY_TIMER_ROUTINE_GETTICKCOUNT;
|
||||
#else
|
||||
mti->ticks.routine= 0;
|
||||
#endif
|
||||
if (!mti->ticks.routine || !my_timer_ticks())
|
||||
{
|
||||
mti->ticks.routine= 0;
|
||||
mti->ticks.resolution= 0;
|
||||
mti->ticks.frequency= 0;
|
||||
mti->ticks.overhead= 0;
|
||||
}
|
||||
|
||||
/*
|
||||
Calculate overhead in terms of the timer that
|
||||
gives the best resolution: cycles or nanoseconds.
|
||||
I doubt it ever will be as bad as microseconds.
|
||||
*/
|
||||
if (mti->cycles.routine)
|
||||
best_timer= &my_timer_cycles;
|
||||
else
|
||||
{
|
||||
if (mti->nanoseconds.routine)
|
||||
{
|
||||
best_timer= &my_timer_nanoseconds;
|
||||
}
|
||||
else
|
||||
best_timer= &my_timer_microseconds;
|
||||
}
|
||||
|
||||
/* best_timer_overhead = least of 20 calculations */
|
||||
for (i= 0, best_timer_overhead= 1000000000; i < 20; ++i)
|
||||
{
|
||||
time1= best_timer();
|
||||
time2= best_timer() - time1;
|
||||
if (best_timer_overhead > time2)
|
||||
best_timer_overhead= time2;
|
||||
}
|
||||
if (mti->cycles.routine)
|
||||
my_timer_init_overhead(&mti->cycles.overhead,
|
||||
best_timer,
|
||||
&my_timer_cycles,
|
||||
best_timer_overhead);
|
||||
if (mti->nanoseconds.routine)
|
||||
my_timer_init_overhead(&mti->nanoseconds.overhead,
|
||||
best_timer,
|
||||
&my_timer_nanoseconds,
|
||||
best_timer_overhead);
|
||||
if (mti->microseconds.routine)
|
||||
my_timer_init_overhead(&mti->microseconds.overhead,
|
||||
best_timer,
|
||||
&my_timer_microseconds,
|
||||
best_timer_overhead);
|
||||
if (mti->milliseconds.routine)
|
||||
my_timer_init_overhead(&mti->milliseconds.overhead,
|
||||
best_timer,
|
||||
&my_timer_milliseconds,
|
||||
best_timer_overhead);
|
||||
if (mti->ticks.routine)
|
||||
my_timer_init_overhead(&mti->ticks.overhead,
|
||||
best_timer,
|
||||
&my_timer_ticks,
|
||||
best_timer_overhead);
|
||||
|
||||
/*
|
||||
Calculate resolution for nanoseconds or microseconds
|
||||
or milliseconds, by seeing if it's always divisible
|
||||
by 1000, and by noticing how much jumping occurs.
|
||||
For ticks, just assume the resolution is 1.
|
||||
*/
|
||||
if (mti->cycles.routine)
|
||||
mti->cycles.resolution= 1;
|
||||
if (mti->nanoseconds.routine)
|
||||
mti->nanoseconds.resolution=
|
||||
my_timer_init_resolution(&my_timer_nanoseconds, 20000);
|
||||
if (mti->microseconds.routine)
|
||||
mti->microseconds.resolution=
|
||||
my_timer_init_resolution(&my_timer_microseconds, 20);
|
||||
if (mti->milliseconds.routine)
|
||||
{
|
||||
if (mti->milliseconds.routine == MY_TIMER_ROUTINE_TIME)
|
||||
mti->milliseconds.resolution= 1000;
|
||||
else
|
||||
mti->milliseconds.resolution=
|
||||
my_timer_init_resolution(&my_timer_milliseconds, 0);
|
||||
}
|
||||
if (mti->ticks.routine)
|
||||
mti->ticks.resolution= 1;
|
||||
|
||||
/*
|
||||
Calculate cycles frequency,
|
||||
if we have both a cycles routine and a microseconds routine.
|
||||
In tests, this usually results in a figure within 2% of
|
||||
what "cat /proc/cpuinfo" says.
|
||||
If the microseconds routine is QueryPerformanceCounter
|
||||
(i.e. it's Windows), and the microseconds frequency is >
|
||||
500,000,000 (i.e. it's Windows Server so it uses RDTSC)
|
||||
and the microseconds resolution is > 100 (i.e. dreadful),
|
||||
then calculate cycles frequency = microseconds frequency.
|
||||
*/
|
||||
if (mti->cycles.routine
|
||||
&& mti->microseconds.routine)
|
||||
{
|
||||
if (mti->microseconds.routine ==
|
||||
MY_TIMER_ROUTINE_QUERYPERFORMANCECOUNTER
|
||||
&& mti->microseconds.frequency > 500000000
|
||||
&& mti->microseconds.resolution > 100)
|
||||
mti->cycles.frequency= mti->microseconds.frequency;
|
||||
else
|
||||
{
|
||||
ulonglong time1, time2;
|
||||
time1= my_timer_init_frequency(mti);
|
||||
/* Repeat once in case there was an interruption. */
|
||||
time2= my_timer_init_frequency(mti);
|
||||
if (time1 < time2) mti->cycles.frequency= time1;
|
||||
else mti->cycles.frequency= time2;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
Calculate milliseconds frequency =
|
||||
(cycles-frequency/#-of-cycles) * #-of-milliseconds,
|
||||
if we have both a milliseconds routine and a cycles
|
||||
routine.
|
||||
This will be inaccurate if milliseconds resolution > 1.
|
||||
This is probably only useful when testing new platforms.
|
||||
*/
|
||||
if (mti->milliseconds.routine
|
||||
&& mti->milliseconds.resolution < 1000
|
||||
&& mti->microseconds.routine
|
||||
&& mti->cycles.routine)
|
||||
{
|
||||
int i;
|
||||
ulonglong time1, time2, time3, time4;
|
||||
time1= my_timer_cycles();
|
||||
time2= my_timer_milliseconds();
|
||||
time3= time2; /* Avoids a Microsoft/IBM compiler warning */
|
||||
for (i= 0; i < MY_TIMER_ITERATIONS * 1000; ++i)
|
||||
{
|
||||
time3= my_timer_milliseconds();
|
||||
if (time3 - time2 > 10) break;
|
||||
}
|
||||
time4= my_timer_cycles();
|
||||
mti->milliseconds.frequency=
|
||||
(mti->cycles.frequency * (time3 - time2)) / (time4 - time1);
|
||||
}
|
||||
|
||||
/*
|
||||
Calculate ticks.frequency =
|
||||
(cycles-frequency/#-of-cycles * #-of-ticks,
|
||||
if we have both a ticks routine and a cycles
|
||||
routine,
|
||||
This is probably only useful when testing new platforms.
|
||||
*/
|
||||
if (mti->ticks.routine
|
||||
&& mti->microseconds.routine
|
||||
&& mti->cycles.routine)
|
||||
{
|
||||
int i;
|
||||
ulonglong time1, time2, time3, time4;
|
||||
time1= my_timer_cycles();
|
||||
time2= my_timer_ticks();
|
||||
time3= time2; /* Avoids a Microsoft/IBM compiler warning */
|
||||
for (i= 0; i < MY_TIMER_ITERATIONS * 1000; ++i)
|
||||
{
|
||||
time3= my_timer_ticks();
|
||||
if (time3 - time2 > 10) break;
|
||||
}
|
||||
time4= my_timer_cycles();
|
||||
mti->ticks.frequency=
|
||||
(mti->cycles.frequency * (time3 - time2)) / (time4 - time1);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
Additional Comments
|
||||
-------------------
|
||||
|
||||
This is for timing, i.e. finding out how long a piece of code
|
||||
takes. If you want time of day matching a wall clock, the
|
||||
my_timer_xxx functions won't help you.
|
||||
|
||||
The best timer is the one with highest frequency, lowest
|
||||
overhead, and resolution=1. The my_timer_info() routine will tell
|
||||
you at runtime which timer that is. Usually it will be
|
||||
my_timer_cycles() but be aware that, although it's best,
|
||||
it has possible flaws and dangers. Depending on platform:
|
||||
- The frequency might change. We don't test for this. It
|
||||
happens on laptops for power saving, and on blade servers
|
||||
for avoiding overheating.
|
||||
- The overhead that my_timer_init() returns is the minimum.
|
||||
In fact it could be slightly greater because of caching or
|
||||
because you call the routine by address, as recommended.
|
||||
It could be hugely greater if there's an interrupt.
|
||||
- The x86 cycle counter, RDTSC doesn't "serialize". That is,
|
||||
if there is out-of-order execution, rdtsc might be processed
|
||||
after an instruction that logically follows it.
|
||||
(We could force serialization, but that would be slower.)
|
||||
- It is possible to set a flag which renders RDTSC
|
||||
inoperative. Somebody responsible for the kernel
|
||||
of the operating system would have to make this
|
||||
decision. For the platforms we've tested with, there's
|
||||
no such problem.
|
||||
- With a multi-processor arrangement, it's possible
|
||||
to get the cycle count from one processor in
|
||||
thread X, and the cycle count from another processor
|
||||
in thread Y. They may not always be in synch.
|
||||
- You can't depend on a cycle counter being available for
|
||||
all platforms. On Alphas, the
|
||||
cycle counter is only 32-bit, so it would overflow quickly,
|
||||
so we don't bother with it. On platforms that we haven't
|
||||
tested, there might be some if/endif combination that we
|
||||
didn't expect, or some assembler routine that we didn't
|
||||
supply.
|
||||
|
||||
The recommended way to use the timer routines is:
|
||||
1. Somewhere near the beginning of the program, call
|
||||
my_timer_init(). This should only be necessary once,
|
||||
although you can call it again if you think that the
|
||||
frequency has changed.
|
||||
2. Determine the best timer based on frequency, resolution,
|
||||
overhead -- all things that my_timer_init() returns.
|
||||
Preserve the address of the timer and the my_timer_into
|
||||
results in an easily-accessible place.
|
||||
3. Instrument the code section that you're monitoring, thus:
|
||||
time1= my_timer_xxx();
|
||||
Instrumented code;
|
||||
time2= my_timer_xxx();
|
||||
elapsed_time= (time2 - time1) - overhead;
|
||||
If the timer is always on, then overhead is always there,
|
||||
so don't subtract it.
|
||||
4. Save the elapsed time, or add it to a totaller.
|
||||
5. When all timing processes are complete, transfer the
|
||||
saved / totalled elapsed time to permanent storage.
|
||||
Optionally you can convert cycles to microseconds at
|
||||
this point. (Don't do so every time you calculate
|
||||
elapsed_time! That would waste time and lose precision!)
|
||||
For converting cycles to microseconds, use the frequency
|
||||
that my_timer_init() returns. You'll also need to convert
|
||||
if the my_timer_microseconds() function is the Windows
|
||||
function QueryPerformanceCounter(), since that's sometimes
|
||||
a counter with precision slightly better than microseconds.
|
||||
|
||||
Since we recommend calls by function pointer, we supply
|
||||
no inline functions.
|
||||
|
||||
Some comments on the many candidate routines for timing ...
|
||||
|
||||
clock() -- We don't use because it would overflow frequently.
|
||||
|
||||
clock_gettime() -- In tests, clock_gettime often had
|
||||
resolution = 1000.
|
||||
|
||||
ftime() -- A "man ftime" says: "This function is obsolete.
|
||||
Don't use it." On every platform that we tested, if ftime()
|
||||
was available, then so was gettimeofday(), and gettimeofday()
|
||||
overhead was always at least as good as ftime() overhead.
|
||||
|
||||
gettimeofday() -- available on most platforms, though not
|
||||
on Windows. There is a hardware timer (sometimes a Programmable
|
||||
Interrupt Timer or "PIT") (sometimes a "HPET") used for
|
||||
interrupt generation. When it interrupts (a "tick" or "jiffy",
|
||||
typically 1 centisecond) it sets xtime. For gettimeofday, a
|
||||
Linux kernel routine usually gets xtime and then gets rdtsc
|
||||
to get elapsed nanoseconds since the last tick. On Red Hat
|
||||
Enterprise Linux 3, there was once a bug which caused the
|
||||
resolution to be 1000, i.e. one centisecond. We never check
|
||||
for time-zone change.
|
||||
|
||||
getnstimeofday() -- something to watch for in future Linux
|
||||
|
||||
do_gettimeofday() -- exists on Linux but not for "userland"
|
||||
|
||||
get_cycles() -- a multi-platform function, worth watching
|
||||
in future Linux versions. But we found platform-specific
|
||||
functions which were better documented in operating-system
|
||||
manuals. And get_cycles() can fail or return a useless
|
||||
32-bit number. It might be available on some platforms,
|
||||
such as arm, which we didn't test. Using
|
||||
"include <linux/timex.h>" or "include <asm/timex.h>"
|
||||
can lead to autoconf or compile errors, depending on system.
|
||||
|
||||
rdtsc, __rdtsc, rdtscll: available for x86 with Linux BSD,
|
||||
Solaris, Windows. See "possible flaws and dangers" comments.
|
||||
|
||||
times(): what we use for ticks. Should just read the last
|
||||
(xtime) tick count, therefore should be fast, but usually
|
||||
isn't.
|
||||
|
||||
GetTickCount(): we use this for my_timer_ticks() on
|
||||
Windows. Actually it really is a tick counter, so resolution
|
||||
>= 10 milliseconds unless you have a very old Windows version.
|
||||
With Windows 95 or 98 or ME, timeGetTime() has better resolution than
|
||||
GetTickCount (1ms rather than 55ms). But with Windows NT or XP or 2000,
|
||||
they're both getting from a variable in the Process Environment Block
|
||||
(PEB), and the variable is set by the programmable interrupt timer, so
|
||||
the resolution is the same (usually 10-15 milliseconds). Also timeGetTime
|
||||
is slower on old machines:
|
||||
http://www.doumo.jp/aon-java/jsp/postgretips/tips.jsp?tips=74.
|
||||
Also timeGetTime requires linking winmm.lib,
|
||||
Therefore we use GetTickCount.
|
||||
It will overflow every 49 days because the return is 32-bit.
|
||||
There is also a GetTickCount64 but it requires Vista or Windows Server 2008.
|
||||
(As for GetSystemTimeAsFileTime, its precision is spurious, it
|
||||
just reads the tick variable like the other functions do.
|
||||
However, we don't expect it to overflow every 49 days, so we
|
||||
will prefer it for my_timer_milliseconds().)
|
||||
|
||||
QueryPerformanceCounter() we use this for my_timer_microseconds()
|
||||
on Windows. 1-PIT-tick (often 1/3-microsecond). Usually reads
|
||||
the PIT so it's slow. On some Windows variants, uses RDTSC.
|
||||
|
||||
GetLocalTime() this is available on Windows but we don't use it.
|
||||
|
||||
getclock(): documented for Alpha, but not found during tests.
|
||||
|
||||
mach_absolute_time() and UpTime() are recommended for Apple.
|
||||
Inititally they weren't tried, because asm_ppc seems to do the job.
|
||||
But now we use mach_absolute_time for nanoseconds.
|
||||
|
||||
Any clock-based timer can be affected by NPT (ntpd program),
|
||||
which means:
|
||||
- full-second correction can occur for leap second
|
||||
- tiny corrections can occcur approimately every 11 minutes
|
||||
(but I think they only affect the RTC which isn't the PIT).
|
||||
|
||||
We define "precision" as "frequency" and "high precision" is
|
||||
"frequency better than 1 microsecond". We define "resolution"
|
||||
as a synonym for "granularity". We define "accuracy" as
|
||||
"closeness to the truth" as established by some authoritative
|
||||
clock, but we can't measure accuracy.
|
||||
|
||||
Do not expect any of our timers to be monotonic; we
|
||||
won't guarantee that they return constantly-increasing
|
||||
unique numbers.
|
||||
|
||||
We tested with AIX, Solaris (x86 + Sparc), Linux (x86 +
|
||||
Itanium), Windows, 64-bit Windows, QNX, FreeBSD, HPUX,
|
||||
Irix, Mac. We didn't test with SCO.
|
||||
|
||||
*/
|
||||
|
||||
97
deps/mysqllite/mysys/my_read.c
vendored
Normal file
97
deps/mysqllite/mysys/my_read.c
vendored
Normal file
@@ -0,0 +1,97 @@
|
||||
/* Copyright (C) 2000 MySQL AB
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
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 */
|
||||
|
||||
#include "mysys_priv.h"
|
||||
#include "mysys_err.h"
|
||||
#include <my_base.h>
|
||||
#include <errno.h>
|
||||
|
||||
/*
|
||||
Read a chunk of bytes from a file with retry's if needed
|
||||
|
||||
The parameters are:
|
||||
File descriptor
|
||||
Buffer to hold at least Count bytes
|
||||
Bytes to read
|
||||
Flags on what to do on error
|
||||
|
||||
Return:
|
||||
-1 on error
|
||||
0 if flag has bits MY_NABP or MY_FNABP set
|
||||
N number of bytes read.
|
||||
*/
|
||||
|
||||
size_t my_read(File Filedes, uchar *Buffer, size_t Count, myf MyFlags)
|
||||
{
|
||||
size_t readbytes, save_count;
|
||||
DBUG_ENTER("my_read");
|
||||
DBUG_PRINT("my",("fd: %d Buffer: %p Count: %lu MyFlags: %d",
|
||||
Filedes, Buffer, (ulong) Count, MyFlags));
|
||||
save_count= Count;
|
||||
|
||||
for (;;)
|
||||
{
|
||||
errno= 0; /* Linux, Windows don't reset this on EOF/success */
|
||||
#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 &&
|
||||
(MyFlags & (MY_NABP | MY_FNABP))))
|
||||
my_errno= HA_ERR_FILE_TOO_SHORT;
|
||||
DBUG_PRINT("warning",("Read only %d bytes off %lu from %d, errno: %d",
|
||||
(int) readbytes, (ulong) Count, Filedes,
|
||||
my_errno));
|
||||
|
||||
if ((readbytes == 0 || (int) readbytes == -1) && errno == EINTR)
|
||||
{
|
||||
DBUG_PRINT("debug", ("my_read() was interrupted and returned %ld",
|
||||
(long) readbytes));
|
||||
continue; /* Interrupted */
|
||||
}
|
||||
|
||||
if (MyFlags & (MY_WME | MY_FAE | MY_FNABP))
|
||||
{
|
||||
if (readbytes == (size_t) -1)
|
||||
my_error(EE_READ, MYF(ME_BELL+ME_WAITTANG),
|
||||
my_filename(Filedes),my_errno);
|
||||
else if (MyFlags & (MY_NABP | MY_FNABP))
|
||||
my_error(EE_EOFERR, MYF(ME_BELL+ME_WAITTANG),
|
||||
my_filename(Filedes),my_errno);
|
||||
}
|
||||
if (readbytes == (size_t) -1 ||
|
||||
((MyFlags & (MY_FNABP | MY_NABP)) && !(MyFlags & MY_FULL_IO)))
|
||||
DBUG_RETURN(MY_FILE_ERROR); /* Return with error */
|
||||
if (readbytes != (size_t) -1 && (MyFlags & MY_FULL_IO))
|
||||
{
|
||||
Buffer+= readbytes;
|
||||
Count-= readbytes;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (MyFlags & (MY_NABP | MY_FNABP))
|
||||
readbytes= 0; /* Ok on read */
|
||||
else if (MyFlags & MY_FULL_IO)
|
||||
readbytes= save_count;
|
||||
break;
|
||||
}
|
||||
DBUG_RETURN(readbytes);
|
||||
} /* my_read */
|
||||
124
deps/mysqllite/mysys/my_redel.c
vendored
Normal file
124
deps/mysqllite/mysys/my_redel.c
vendored
Normal file
@@ -0,0 +1,124 @@
|
||||
/* Copyright (C) 2000 MySQL AB
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
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 */
|
||||
|
||||
#include "mysys_priv.h"
|
||||
#include <my_dir.h>
|
||||
#include <m_string.h>
|
||||
#include "mysys_err.h"
|
||||
#if defined(HAVE_UTIME_H)
|
||||
#include <utime.h>
|
||||
#elif defined(HAVE_SYS_UTIME_H)
|
||||
#include <sys/utime.h>
|
||||
#elif !defined(HPUX10)
|
||||
struct utimbuf {
|
||||
time_t actime;
|
||||
time_t modtime;
|
||||
};
|
||||
#endif
|
||||
|
||||
/*
|
||||
Rename with copy stat form old file
|
||||
Copy stats from old file to new file, deletes orginal and
|
||||
changes new file name to old file name
|
||||
|
||||
if MY_REDEL_MAKE_COPY is given, then the orginal file
|
||||
is renamed to org_name-'current_time'.BAK
|
||||
*/
|
||||
|
||||
#define REDEL_EXT ".BAK"
|
||||
|
||||
int my_redel(const char *org_name, const char *tmp_name, myf MyFlags)
|
||||
{
|
||||
int error=1;
|
||||
DBUG_ENTER("my_redel");
|
||||
DBUG_PRINT("my",("org_name: '%s' tmp_name: '%s' MyFlags: %d",
|
||||
org_name,tmp_name,MyFlags));
|
||||
|
||||
if (my_copystat(org_name,tmp_name,MyFlags) < 0)
|
||||
goto end;
|
||||
if (MyFlags & MY_REDEL_MAKE_BACKUP)
|
||||
{
|
||||
char name_buff[FN_REFLEN+20];
|
||||
char ext[20];
|
||||
ext[0]='-';
|
||||
get_date(ext+1,2+4,(time_t) 0);
|
||||
strmov(strend(ext),REDEL_EXT);
|
||||
if (my_rename(org_name, fn_format(name_buff, org_name, "", ext, 2),
|
||||
MyFlags))
|
||||
goto end;
|
||||
}
|
||||
else if (my_delete_allow_opened(org_name, MyFlags))
|
||||
goto end;
|
||||
if (my_rename(tmp_name,org_name,MyFlags))
|
||||
goto end;
|
||||
|
||||
error=0;
|
||||
end:
|
||||
DBUG_RETURN(error);
|
||||
} /* my_redel */
|
||||
|
||||
|
||||
/* Copy stat from one file to another */
|
||||
/* Return -1 if can't get stat, 1 if wrong type of file */
|
||||
|
||||
int my_copystat(const char *from, const char *to, int MyFlags)
|
||||
{
|
||||
struct stat statbuf;
|
||||
|
||||
if (stat(from, &statbuf))
|
||||
{
|
||||
my_errno=errno;
|
||||
if (MyFlags & (MY_FAE+MY_WME))
|
||||
my_error(EE_STAT, MYF(ME_BELL+ME_WAITTANG),from,errno);
|
||||
return -1; /* Can't get stat on input file */
|
||||
}
|
||||
if ((statbuf.st_mode & S_IFMT) != S_IFREG)
|
||||
return 1;
|
||||
|
||||
/* Copy modes */
|
||||
if (chmod(to, statbuf.st_mode & 07777))
|
||||
{
|
||||
my_errno= errno;
|
||||
if (MyFlags & (MY_FAE+MY_WME))
|
||||
my_error(EE_CHANGE_PERMISSIONS, MYF(ME_BELL+ME_WAITTANG), from, errno);
|
||||
return -1;
|
||||
}
|
||||
|
||||
#if !defined(__WIN__)
|
||||
if (statbuf.st_nlink > 1 && MyFlags & MY_LINK_WARNING)
|
||||
{
|
||||
if (MyFlags & MY_LINK_WARNING)
|
||||
my_error(EE_LINK_WARNING,MYF(ME_BELL+ME_WAITTANG),from,statbuf.st_nlink);
|
||||
}
|
||||
/* Copy ownership */
|
||||
if (chown(to, statbuf.st_uid, statbuf.st_gid))
|
||||
{
|
||||
my_errno= errno;
|
||||
if (MyFlags & (MY_FAE+MY_WME))
|
||||
my_error(EE_CHANGE_OWNERSHIP, MYF(ME_BELL+ME_WAITTANG), from, errno);
|
||||
return -1;
|
||||
}
|
||||
#endif /* !__WIN__ */
|
||||
|
||||
if (MyFlags & MY_COPYTIME)
|
||||
{
|
||||
struct utimbuf timep;
|
||||
timep.actime = statbuf.st_atime;
|
||||
timep.modtime = statbuf.st_mtime;
|
||||
(void) utime((char*) to, &timep);/* Update last accessed and modified times */
|
||||
}
|
||||
|
||||
return 0;
|
||||
} /* my_copystat */
|
||||
79
deps/mysqllite/mysys/my_rename.c
vendored
Normal file
79
deps/mysqllite/mysys/my_rename.c
vendored
Normal file
@@ -0,0 +1,79 @@
|
||||
/* Copyright (C) 2000 MySQL AB
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
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 */
|
||||
|
||||
#include "mysys_priv.h"
|
||||
#include <my_dir.h>
|
||||
#include "mysys_err.h"
|
||||
#include "m_string.h"
|
||||
#undef my_rename
|
||||
|
||||
/* On unix rename deletes to file if it exists */
|
||||
|
||||
int my_rename(const char *from, const char *to, myf MyFlags)
|
||||
{
|
||||
int error = 0;
|
||||
DBUG_ENTER("my_rename");
|
||||
DBUG_PRINT("my",("from %s to %s MyFlags %d", from, to, MyFlags));
|
||||
|
||||
#if defined(HAVE_FILE_VERSIONS)
|
||||
{ /* Check that there isn't a old file */
|
||||
int save_errno;
|
||||
MY_STAT my_stat_result;
|
||||
save_errno=my_errno;
|
||||
if (my_stat(to,&my_stat_result,MYF(0)))
|
||||
{
|
||||
my_errno=EEXIST;
|
||||
error= -1;
|
||||
if (MyFlags & MY_FAE+MY_WME)
|
||||
my_error(EE_LINK, MYF(ME_BELL+ME_WAITTANG),from,to,my_errno);
|
||||
DBUG_RETURN(error);
|
||||
}
|
||||
my_errno=save_errno;
|
||||
}
|
||||
#endif
|
||||
#if defined(HAVE_RENAME)
|
||||
#if defined(__WIN__)
|
||||
/*
|
||||
On windows we can't rename over an existing file:
|
||||
Remove any conflicting files:
|
||||
*/
|
||||
(void) my_delete(to, MYF(0));
|
||||
#endif
|
||||
if (rename(from,to))
|
||||
#else
|
||||
if (link(from, to) || unlink(from))
|
||||
#endif
|
||||
{
|
||||
my_errno=errno;
|
||||
error = -1;
|
||||
if (MyFlags & (MY_FAE+MY_WME))
|
||||
my_error(EE_LINK, MYF(ME_BELL+ME_WAITTANG),from,to,my_errno);
|
||||
}
|
||||
else if (MyFlags & MY_SYNC_DIR)
|
||||
{
|
||||
#ifdef NEED_EXPLICIT_SYNC_DIR
|
||||
/* do only the needed amount of syncs: */
|
||||
char dir_from[FN_REFLEN], dir_to[FN_REFLEN];
|
||||
size_t dir_from_length, dir_to_length;
|
||||
dirname_part(dir_from, from, &dir_from_length);
|
||||
dirname_part(dir_to, to, &dir_to_length);
|
||||
if (my_sync_dir(dir_from, MyFlags) ||
|
||||
(strcmp(dir_from, dir_to) &&
|
||||
my_sync_dir(dir_to, MyFlags)))
|
||||
error= -1;
|
||||
#endif
|
||||
}
|
||||
DBUG_RETURN(error);
|
||||
} /* my_rename */
|
||||
102
deps/mysqllite/mysys/my_seek.c
vendored
Normal file
102
deps/mysqllite/mysys/my_seek.c
vendored
Normal file
@@ -0,0 +1,102 @@
|
||||
/* Copyright (C) 2000 MySQL AB
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
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 */
|
||||
|
||||
#include "mysys_priv.h"
|
||||
#include "mysys_err.h"
|
||||
|
||||
/*
|
||||
Seek to a position in a file.
|
||||
|
||||
ARGUMENTS
|
||||
File fd The file descriptor
|
||||
my_off_t pos The expected position (absolute or relative)
|
||||
int whence A direction parameter and one of
|
||||
{SEEK_SET, SEEK_CUR, SEEK_END}
|
||||
myf MyFlags MY_THREADSAFE must be set in case my_seek may be mixed
|
||||
with my_pread/my_pwrite calls and fd is shared among
|
||||
threads.
|
||||
|
||||
DESCRIPTION
|
||||
The my_seek function is a wrapper around the system call lseek and
|
||||
repositions the offset of the file descriptor fd to the argument
|
||||
offset according to the directive whence as follows:
|
||||
SEEK_SET The offset is set to offset bytes.
|
||||
SEEK_CUR The offset is set to its current location plus offset bytes
|
||||
SEEK_END The offset is set to the size of the file plus offset bytes
|
||||
|
||||
RETURN VALUE
|
||||
my_off_t newpos The new position in the file.
|
||||
MY_FILEPOS_ERROR An error was encountered while performing
|
||||
the seek. my_errno is set to indicate the
|
||||
actual error.
|
||||
*/
|
||||
|
||||
my_off_t my_seek(File fd, my_off_t pos, int whence, myf MyFlags)
|
||||
{
|
||||
os_off_t newpos= -1;
|
||||
DBUG_ENTER("my_seek");
|
||||
DBUG_PRINT("my",("fd: %d Pos: %llu Whence: %d MyFlags: %d",
|
||||
fd, (ulonglong) pos, whence, MyFlags));
|
||||
DBUG_ASSERT(pos != MY_FILEPOS_ERROR); /* safety check */
|
||||
|
||||
/*
|
||||
Make sure we are using a valid file descriptor!
|
||||
*/
|
||||
DBUG_ASSERT(fd != -1);
|
||||
#if defined (_WIN32)
|
||||
newpos= my_win_lseek(fd, pos, whence);
|
||||
#else
|
||||
newpos= lseek(fd, pos, whence);
|
||||
#endif
|
||||
if (newpos == (os_off_t) -1)
|
||||
{
|
||||
my_errno= errno;
|
||||
if (MyFlags & MY_WME)
|
||||
my_error(EE_CANT_SEEK, MYF(0), my_filename(fd), my_errno);
|
||||
DBUG_PRINT("error", ("lseek: %llu errno: %d", (ulonglong) newpos, errno));
|
||||
DBUG_RETURN(MY_FILEPOS_ERROR);
|
||||
}
|
||||
if ((my_off_t) newpos != pos)
|
||||
{
|
||||
DBUG_PRINT("exit",("pos: %llu", (ulonglong) newpos));
|
||||
}
|
||||
DBUG_RETURN((my_off_t) newpos);
|
||||
} /* my_seek */
|
||||
|
||||
|
||||
/* Tell current position of file */
|
||||
/* ARGSUSED */
|
||||
|
||||
my_off_t my_tell(File fd, myf MyFlags)
|
||||
{
|
||||
os_off_t pos;
|
||||
DBUG_ENTER("my_tell");
|
||||
DBUG_PRINT("my",("fd: %d MyFlags: %d",fd, MyFlags));
|
||||
DBUG_ASSERT(fd >= 0);
|
||||
#if defined (HAVE_TELL) && !defined (_WIN32)
|
||||
pos= tell(fd);
|
||||
#else
|
||||
pos= my_seek(fd, 0L, MY_SEEK_CUR,0);
|
||||
#endif
|
||||
if (pos == (os_off_t) -1)
|
||||
{
|
||||
my_errno= errno;
|
||||
if (MyFlags & MY_WME)
|
||||
my_error(EE_CANT_SEEK, MYF(0), my_filename(fd), my_errno);
|
||||
DBUG_PRINT("error", ("tell: %llu errno: %d", (ulonglong) pos, my_errno));
|
||||
}
|
||||
DBUG_PRINT("exit",("pos: %llu", (ulonglong) pos));
|
||||
DBUG_RETURN((my_off_t) pos);
|
||||
} /* my_tell */
|
||||
35
deps/mysqllite/mysys/my_sleep.c
vendored
Normal file
35
deps/mysqllite/mysys/my_sleep.c
vendored
Normal file
@@ -0,0 +1,35 @@
|
||||
/* Copyright (C) 2000 MySQL AB
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
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 */
|
||||
|
||||
/* Wait a given number of microseconds */
|
||||
|
||||
#include "mysys_priv.h"
|
||||
#include <m_string.h>
|
||||
|
||||
void my_sleep(ulong m_seconds)
|
||||
{
|
||||
#if defined(__WIN__)
|
||||
Sleep(m_seconds/1000+1); /* Sleep() has millisecond arg */
|
||||
#elif defined(HAVE_SELECT)
|
||||
struct timeval t;
|
||||
t.tv_sec= m_seconds / 1000000L;
|
||||
t.tv_usec= m_seconds % 1000000L;
|
||||
select(0,0,0,0,&t); /* sleep */
|
||||
#else
|
||||
uint sec= (uint) (m_seconds / 1000000L);
|
||||
ulong start= (ulong) time((time_t*) 0);
|
||||
while ((ulong) time((time_t*) 0) < start+sec);
|
||||
#endif
|
||||
}
|
||||
135
deps/mysqllite/mysys/my_static.c
vendored
Normal file
135
deps/mysqllite/mysys/my_static.c
vendored
Normal file
@@ -0,0 +1,135 @@
|
||||
/* Copyright (C) 2000-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 */
|
||||
|
||||
/*
|
||||
Static variables for mysys library. All definied here for easy making of
|
||||
a shared library
|
||||
*/
|
||||
|
||||
#include "mysys_priv.h"
|
||||
#include "my_static.h"
|
||||
#include "my_alarm.h"
|
||||
|
||||
my_bool timed_mutexes= 0;
|
||||
|
||||
/* from my_init */
|
||||
char * home_dir=0;
|
||||
const char *my_progname=0;
|
||||
char curr_dir[FN_REFLEN]= {0},
|
||||
home_dir_buff[FN_REFLEN]= {0};
|
||||
ulong my_stream_opened=0,my_file_opened=0, my_tmp_file_created=0;
|
||||
ulong my_file_total_opened= 0;
|
||||
int my_umask=0664, my_umask_dir=0777;
|
||||
|
||||
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;
|
||||
|
||||
/* From mf_brkhant */
|
||||
int my_dont_interrupt=0;
|
||||
volatile int _my_signals=0;
|
||||
struct st_remember _my_sig_remember[MAX_SIGNALS]={{0,0}};
|
||||
|
||||
/* from mf_reccache.c */
|
||||
ulong my_default_record_cache_size=RECORD_CACHE_SIZE;
|
||||
|
||||
/* from soundex.c */
|
||||
/* ABCDEFGHIJKLMNOPQRSTUVWXYZ */
|
||||
/* :::::::::::::::::::::::::: */
|
||||
const char *soundex_map= "01230120022455012623010202";
|
||||
|
||||
/* from my_malloc */
|
||||
USED_MEM* my_once_root_block=0; /* pointer to first block */
|
||||
uint my_once_extra=ONCE_ALLOC_INIT; /* Memory to alloc / block */
|
||||
|
||||
/* from my_largepage.c */
|
||||
#ifdef HAVE_LARGE_PAGES
|
||||
my_bool my_use_large_pages= 0;
|
||||
uint my_large_page_size= 0;
|
||||
#endif
|
||||
|
||||
/* from my_alarm */
|
||||
int volatile my_have_got_alarm=0; /* declare variable to reset */
|
||||
ulong my_time_to_wait_for_lock=2; /* In seconds */
|
||||
|
||||
/* from errors.c */
|
||||
#ifdef SHARED_LIBRARY
|
||||
const char *globerrs[GLOBERRS]; /* my_error_messages is here */
|
||||
#endif
|
||||
void (*my_abort_hook)(int) = (void(*)(int)) exit;
|
||||
void (*error_handler_hook)(uint error, const char *str, myf MyFlags)=
|
||||
my_message_stderr;
|
||||
void (*fatal_error_handler_hook)(uint error, const char *str, myf MyFlags)=
|
||||
my_message_stderr;
|
||||
|
||||
static const char *proc_info_dummy(void *a __attribute__((unused)),
|
||||
const char *b __attribute__((unused)),
|
||||
const char *c __attribute__((unused)),
|
||||
const char *d __attribute__((unused)),
|
||||
const unsigned int e __attribute__((unused)))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* this is to be able to call set_thd_proc_info from the C code */
|
||||
const char *(*proc_info_hook)(void *, const char *, const char *, const char *,
|
||||
const unsigned int)= proc_info_dummy;
|
||||
|
||||
#if defined(ENABLED_DEBUG_SYNC)
|
||||
/**
|
||||
Global pointer to be set if callback function is defined
|
||||
(e.g. in mysqld). See sql/debug_sync.cc.
|
||||
*/
|
||||
void (*debug_sync_C_callback_ptr)(const char *, size_t);
|
||||
#endif /* defined(ENABLED_DEBUG_SYNC) */
|
||||
|
||||
#ifdef __WIN__
|
||||
/* from my_getsystime.c */
|
||||
ulonglong query_performance_frequency, query_performance_offset;
|
||||
#endif
|
||||
|
||||
/* How to disable options */
|
||||
my_bool my_disable_locking=0;
|
||||
my_bool my_disable_async_io=0;
|
||||
my_bool my_disable_flush_key_blocks=0;
|
||||
my_bool my_disable_symlinks=0;
|
||||
|
||||
/*
|
||||
Note that PSI_hook and PSI_server are unconditionally
|
||||
(no ifdef HAVE_PSI_INTERFACE) defined.
|
||||
This is to ensure binary compatibility between the server and plugins,
|
||||
in the case when:
|
||||
- the server is not compiled with HAVE_PSI_INTERFACE
|
||||
- a plugin is compiled with HAVE_PSI_INTERFACE
|
||||
See the doxygen documentation for the performance schema.
|
||||
*/
|
||||
|
||||
/**
|
||||
Hook for the instrumentation interface.
|
||||
Code implementing the instrumentation interface should register here.
|
||||
*/
|
||||
struct PSI_bootstrap *PSI_hook= NULL;
|
||||
|
||||
/**
|
||||
Instance of the instrumentation interface for the MySQL server.
|
||||
@todo This is currently a global variable, which is handy when
|
||||
compiling instrumented code that is bundled with the server.
|
||||
When dynamic plugin are truly supported, this variable will need
|
||||
to be replaced by a macro, so that each XYZ plugin can have it's own
|
||||
xyz_psi_server variable, obtained from PSI_bootstrap::get_interface()
|
||||
with the version used at compile time for plugin XYZ.
|
||||
*/
|
||||
PSI *PSI_server= NULL;
|
||||
|
||||
50
deps/mysqllite/mysys/my_static.h
vendored
Normal file
50
deps/mysqllite/mysys/my_static.h
vendored
Normal file
@@ -0,0 +1,50 @@
|
||||
#ifndef MYSYS_MY_STATIC_INCLUDED
|
||||
#define MYSYS_MY_STATIC_INCLUDED
|
||||
|
||||
/* Copyright (C) 2000 MySQL AB
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
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 */
|
||||
|
||||
/*
|
||||
Static variables for mysys library. All definied here for easy making of
|
||||
a shared library
|
||||
*/
|
||||
|
||||
C_MODE_START
|
||||
#include <signal.h>
|
||||
|
||||
#define MAX_SIGNALS 10 /* Max signals under a dont-allow */
|
||||
|
||||
struct st_remember {
|
||||
int number;
|
||||
sig_handler (*func)(int number);
|
||||
};
|
||||
|
||||
extern char curr_dir[FN_REFLEN], home_dir_buff[FN_REFLEN];
|
||||
|
||||
extern volatile int _my_signals;
|
||||
extern struct st_remember _my_sig_remember[MAX_SIGNALS];
|
||||
|
||||
extern const char *soundex_map;
|
||||
|
||||
extern USED_MEM* my_once_root_block;
|
||||
extern uint my_once_extra;
|
||||
|
||||
extern struct st_my_file_info my_file_info_default[MY_NFILE];
|
||||
|
||||
extern ulonglong query_performance_frequency, query_performance_offset;
|
||||
|
||||
C_MODE_END
|
||||
|
||||
#endif /* MYSYS_MY_STATIC_INCLUDED */
|
||||
167
deps/mysqllite/mysys/my_symlink.c
vendored
Normal file
167
deps/mysqllite/mysys/my_symlink.c
vendored
Normal file
@@ -0,0 +1,167 @@
|
||||
/* Copyright (C) 2000 MySQL AB
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
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 */
|
||||
|
||||
#include "mysys_priv.h"
|
||||
#include "mysys_err.h"
|
||||
#include <m_string.h>
|
||||
#include <errno.h>
|
||||
#ifdef HAVE_REALPATH
|
||||
#include <sys/param.h>
|
||||
#include <sys/stat.h>
|
||||
#endif
|
||||
|
||||
/*
|
||||
Reads the content of a symbolic link
|
||||
If the file is not a symbolic link, return the original file name in to.
|
||||
|
||||
RETURN
|
||||
0 If filename was a symlink, (to will be set to value of symlink)
|
||||
1 If filename was a normal file (to will be set to filename)
|
||||
-1 on error.
|
||||
*/
|
||||
|
||||
int my_readlink(char *to, const char *filename, myf MyFlags)
|
||||
{
|
||||
#ifndef HAVE_READLINK
|
||||
strmov(to,filename);
|
||||
return 1;
|
||||
#else
|
||||
int result=0;
|
||||
int length;
|
||||
DBUG_ENTER("my_readlink");
|
||||
|
||||
if ((length=readlink(filename, to, FN_REFLEN-1)) < 0)
|
||||
{
|
||||
/* Don't give an error if this wasn't a symlink */
|
||||
if ((my_errno=errno) == EINVAL)
|
||||
{
|
||||
result= 1;
|
||||
strmov(to,filename);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (MyFlags & MY_WME)
|
||||
my_error(EE_CANT_READLINK, MYF(0), filename, errno);
|
||||
result= -1;
|
||||
}
|
||||
}
|
||||
else
|
||||
to[length]=0;
|
||||
DBUG_PRINT("exit" ,("result: %d", result));
|
||||
DBUG_RETURN(result);
|
||||
#endif /* HAVE_READLINK */
|
||||
}
|
||||
|
||||
|
||||
/* Create a symbolic link */
|
||||
|
||||
int my_symlink(const char *content, const char *linkname, myf MyFlags)
|
||||
{
|
||||
#ifndef HAVE_READLINK
|
||||
return 0;
|
||||
#else
|
||||
int result;
|
||||
DBUG_ENTER("my_symlink");
|
||||
DBUG_PRINT("enter",("content: %s linkname: %s", content, linkname));
|
||||
|
||||
result= 0;
|
||||
if (symlink(content, linkname))
|
||||
{
|
||||
result= -1;
|
||||
my_errno=errno;
|
||||
if (MyFlags & MY_WME)
|
||||
my_error(EE_CANT_SYMLINK, MYF(0), linkname, content, errno);
|
||||
}
|
||||
else if ((MyFlags & MY_SYNC_DIR) && my_sync_dir_by_file(linkname, MyFlags))
|
||||
result= -1;
|
||||
DBUG_RETURN(result);
|
||||
#endif /* HAVE_READLINK */
|
||||
}
|
||||
|
||||
#if defined(SCO)
|
||||
#define BUFF_LEN 4097
|
||||
#elif defined(MAXPATHLEN)
|
||||
#define BUFF_LEN MAXPATHLEN
|
||||
#else
|
||||
#define BUFF_LEN FN_LEN
|
||||
#endif
|
||||
|
||||
|
||||
int my_is_symlink(const char *filename __attribute__((unused)))
|
||||
{
|
||||
#if defined (HAVE_LSTAT) && defined (S_ISLNK)
|
||||
struct stat stat_buff;
|
||||
return !lstat(filename, &stat_buff) && S_ISLNK(stat_buff.st_mode);
|
||||
#elif defined (_WIN32)
|
||||
DWORD dwAttr = GetFileAttributes(filename);
|
||||
return (dwAttr != INVALID_FILE_ATTRIBUTES) &&
|
||||
(dwAttr & FILE_ATTRIBUTE_REPARSE_POINT);
|
||||
#else /* No symlinks */
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
Resolve all symbolic links in path
|
||||
'to' may be equal to 'filename'
|
||||
*/
|
||||
|
||||
int my_realpath(char *to, const char *filename, myf MyFlags)
|
||||
{
|
||||
#if defined(HAVE_REALPATH) && !defined(HAVE_BROKEN_REALPATH)
|
||||
int result=0;
|
||||
char buff[BUFF_LEN];
|
||||
char *ptr;
|
||||
DBUG_ENTER("my_realpath");
|
||||
|
||||
DBUG_PRINT("info",("executing realpath"));
|
||||
if ((ptr=realpath(filename,buff)))
|
||||
strmake(to,ptr,FN_REFLEN-1);
|
||||
else
|
||||
{
|
||||
/*
|
||||
Realpath didn't work; Use my_load_path() which is a poor substitute
|
||||
original name but will at least be able to resolve paths that starts
|
||||
with '.'.
|
||||
*/
|
||||
DBUG_PRINT("error",("realpath failed with errno: %d", errno));
|
||||
my_errno=errno;
|
||||
if (MyFlags & MY_WME)
|
||||
my_error(EE_REALPATH, MYF(0), filename, my_errno);
|
||||
my_load_path(to, filename, NullS);
|
||||
result= -1;
|
||||
}
|
||||
DBUG_RETURN(result);
|
||||
#else
|
||||
#ifdef _WIN32
|
||||
int ret= GetFullPathName(filename,FN_REFLEN,
|
||||
to,
|
||||
NULL);
|
||||
if (ret == 0 || ret > FN_REFLEN)
|
||||
{
|
||||
if (ret > FN_REFLEN)
|
||||
my_errno= ENAMETOOLONG;
|
||||
else
|
||||
my_errno= EACCES;
|
||||
if (MyFlags & MY_WME)
|
||||
my_error(EE_REALPATH, MYF(0), filename, my_errno);
|
||||
return -1;
|
||||
}
|
||||
#else
|
||||
my_load_path(to, filename, NullS);
|
||||
#endif
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
183
deps/mysqllite/mysys/my_symlink2.c
vendored
Normal file
183
deps/mysqllite/mysys/my_symlink2.c
vendored
Normal file
@@ -0,0 +1,183 @@
|
||||
/* Copyright (C) 2000 MySQL AB
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
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 */
|
||||
|
||||
/*
|
||||
Advanced symlink handling.
|
||||
This is used in MyISAM to let users symlinks tables to different disk.
|
||||
The main idea with these functions is to automaticly create, delete and
|
||||
rename files and symlinks like they would be one unit.
|
||||
*/
|
||||
|
||||
#include "mysys_priv.h"
|
||||
#include "mysys_err.h"
|
||||
#include <m_string.h>
|
||||
|
||||
File my_create_with_symlink(const char *linkname, const char *filename,
|
||||
int createflags, int access_flags, myf MyFlags)
|
||||
{
|
||||
File file;
|
||||
int tmp_errno;
|
||||
/* Test if we should create a link */
|
||||
int create_link;
|
||||
char abs_linkname[FN_REFLEN];
|
||||
DBUG_ENTER("my_create_with_symlink");
|
||||
DBUG_PRINT("enter", ("linkname: %s filename: %s",
|
||||
linkname ? linkname : "(null)",
|
||||
filename ? filename : "(null)"));
|
||||
|
||||
if (my_disable_symlinks)
|
||||
{
|
||||
DBUG_PRINT("info", ("Symlinks disabled"));
|
||||
/* Create only the file, not the link and file */
|
||||
create_link= 0;
|
||||
if (linkname)
|
||||
filename= linkname;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (linkname)
|
||||
my_realpath(abs_linkname, linkname, MYF(0));
|
||||
create_link= (linkname && strcmp(abs_linkname,filename));
|
||||
}
|
||||
|
||||
if (!(MyFlags & MY_DELETE_OLD))
|
||||
{
|
||||
if (!access(filename,F_OK))
|
||||
{
|
||||
my_errno= errno= EEXIST;
|
||||
my_error(EE_CANTCREATEFILE, MYF(0), filename, EEXIST);
|
||||
DBUG_RETURN(-1);
|
||||
}
|
||||
if (create_link && !access(linkname,F_OK))
|
||||
{
|
||||
my_errno= errno= EEXIST;
|
||||
my_error(EE_CANTCREATEFILE, MYF(0), linkname, EEXIST);
|
||||
DBUG_RETURN(-1);
|
||||
}
|
||||
}
|
||||
|
||||
if ((file=my_create(filename, createflags, access_flags, MyFlags)) >= 0)
|
||||
{
|
||||
if (create_link)
|
||||
{
|
||||
/* Delete old link/file */
|
||||
if (MyFlags & MY_DELETE_OLD)
|
||||
my_delete(linkname, MYF(0));
|
||||
/* Create link */
|
||||
if (my_symlink(filename, linkname, MyFlags))
|
||||
{
|
||||
/* Fail, remove everything we have done */
|
||||
tmp_errno=my_errno;
|
||||
my_close(file,MYF(0));
|
||||
my_delete(filename, MYF(0));
|
||||
file= -1;
|
||||
my_errno=tmp_errno;
|
||||
}
|
||||
}
|
||||
}
|
||||
DBUG_RETURN(file);
|
||||
}
|
||||
|
||||
/*
|
||||
If the file was a symlink, delete both symlink and the file which the
|
||||
symlink pointed to.
|
||||
*/
|
||||
|
||||
int my_delete_with_symlink(const char *name, myf MyFlags)
|
||||
{
|
||||
char link_name[FN_REFLEN];
|
||||
int was_symlink= (!my_disable_symlinks &&
|
||||
!my_readlink(link_name, name, MYF(0)));
|
||||
int result;
|
||||
DBUG_ENTER("my_delete_with_symlink");
|
||||
|
||||
if (!(result=my_delete(name, MyFlags)))
|
||||
{
|
||||
if (was_symlink)
|
||||
result=my_delete(link_name, MyFlags);
|
||||
}
|
||||
DBUG_RETURN(result);
|
||||
}
|
||||
|
||||
/*
|
||||
If the file is a normal file, just rename it.
|
||||
If the file is a symlink:
|
||||
- Create a new file with the name 'to' that points at
|
||||
symlink_dir/basename(to)
|
||||
- Rename the symlinked file to symlink_dir/basename(to)
|
||||
- Delete 'from'
|
||||
If something goes wrong, restore everything.
|
||||
*/
|
||||
|
||||
int my_rename_with_symlink(const char *from, const char *to, myf MyFlags)
|
||||
{
|
||||
#ifndef HAVE_READLINK
|
||||
return my_rename(from, to, MyFlags);
|
||||
#else
|
||||
char link_name[FN_REFLEN], tmp_name[FN_REFLEN];
|
||||
int was_symlink= (!my_disable_symlinks &&
|
||||
!my_readlink(link_name, from, MYF(0)));
|
||||
int result=0;
|
||||
int name_is_different;
|
||||
DBUG_ENTER("my_rename_with_symlink");
|
||||
|
||||
if (!was_symlink)
|
||||
DBUG_RETURN(my_rename(from, to, MyFlags));
|
||||
|
||||
/* Change filename that symlink pointed to */
|
||||
strmov(tmp_name, to);
|
||||
fn_same(tmp_name,link_name,1); /* Copy dir */
|
||||
name_is_different= strcmp(link_name, tmp_name);
|
||||
if (name_is_different && !access(tmp_name, F_OK))
|
||||
{
|
||||
my_errno= EEXIST;
|
||||
if (MyFlags & MY_WME)
|
||||
my_error(EE_CANTCREATEFILE, MYF(0), tmp_name, EEXIST);
|
||||
DBUG_RETURN(1);
|
||||
}
|
||||
|
||||
/* Create new symlink */
|
||||
if (my_symlink(tmp_name, to, MyFlags))
|
||||
DBUG_RETURN(1);
|
||||
|
||||
/*
|
||||
Rename symlinked file if the base name didn't change.
|
||||
This can happen if you use this function where 'from' and 'to' has
|
||||
the same basename and different directories.
|
||||
*/
|
||||
|
||||
if (name_is_different && my_rename(link_name, tmp_name, MyFlags))
|
||||
{
|
||||
int save_errno=my_errno;
|
||||
my_delete(to, MyFlags); /* Remove created symlink */
|
||||
my_errno=save_errno;
|
||||
DBUG_RETURN(1);
|
||||
}
|
||||
|
||||
/* Remove original symlink */
|
||||
if (my_delete(from, MyFlags))
|
||||
{
|
||||
int save_errno=my_errno;
|
||||
/* Remove created link */
|
||||
my_delete(to, MyFlags);
|
||||
/* Rename file back */
|
||||
if (strcmp(link_name, tmp_name))
|
||||
(void) my_rename(tmp_name, link_name, MyFlags);
|
||||
my_errno=save_errno;
|
||||
result= 1;
|
||||
}
|
||||
DBUG_RETURN(result);
|
||||
#endif /* HAVE_READLINK */
|
||||
}
|
||||
175
deps/mysqllite/mysys/my_sync.c
vendored
Normal file
175
deps/mysqllite/mysys/my_sync.c
vendored
Normal file
@@ -0,0 +1,175 @@
|
||||
/* Copyright (C) 2003 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 */
|
||||
|
||||
#include "mysys_priv.h"
|
||||
#include "mysys_err.h"
|
||||
#include <errno.h>
|
||||
|
||||
/*
|
||||
Sync data in file to disk
|
||||
|
||||
SYNOPSIS
|
||||
my_sync()
|
||||
fd File descritor to sync
|
||||
my_flags Flags (now only MY_WME is supported)
|
||||
|
||||
NOTE
|
||||
If file system supports its, only file data is synced, not inode data.
|
||||
|
||||
MY_IGNORE_BADFD is useful when fd is "volatile" - not protected by a
|
||||
mutex. In this case by the time of fsync(), fd may be already closed by
|
||||
another thread, or even reassigned to a different file. With this flag -
|
||||
MY_IGNORE_BADFD - such a situation will not be considered an error.
|
||||
(which is correct behaviour, if we know that the other thread synced the
|
||||
file before closing)
|
||||
|
||||
RETURN
|
||||
0 ok
|
||||
-1 error
|
||||
*/
|
||||
|
||||
int my_sync(File fd, myf my_flags)
|
||||
{
|
||||
int res;
|
||||
DBUG_ENTER("my_sync");
|
||||
DBUG_PRINT("my",("Fd: %d my_flags: %d", fd, my_flags));
|
||||
|
||||
do
|
||||
{
|
||||
#if defined(F_FULLFSYNC)
|
||||
/*
|
||||
In Mac OS X >= 10.3 this call is safer than fsync() (it forces the
|
||||
disk's cache and guarantees ordered writes).
|
||||
*/
|
||||
if (!(res= fcntl(fd, F_FULLFSYNC, 0)))
|
||||
break; /* ok */
|
||||
/* Some file systems don't support F_FULLFSYNC and fail above: */
|
||||
DBUG_PRINT("info",("fcntl(F_FULLFSYNC) failed, falling back"));
|
||||
#endif
|
||||
#if defined(HAVE_FDATASYNC) && HAVE_DECL_FDATASYNC
|
||||
res= fdatasync(fd);
|
||||
#elif defined(HAVE_FSYNC)
|
||||
res= fsync(fd);
|
||||
#elif defined(_WIN32)
|
||||
res= my_win_fsync(fd);
|
||||
#else
|
||||
#error Cannot find a way to sync a file, durability in danger
|
||||
res= 0; /* No sync (strange OS) */
|
||||
#endif
|
||||
} while (res == -1 && errno == EINTR);
|
||||
|
||||
if (res)
|
||||
{
|
||||
int er= errno;
|
||||
if (!(my_errno= er))
|
||||
my_errno= -1; /* Unknown error */
|
||||
if ((my_flags & MY_IGNORE_BADFD) &&
|
||||
(er == EBADF || er == EINVAL || er == EROFS))
|
||||
{
|
||||
DBUG_PRINT("info", ("ignoring errno %d", er));
|
||||
res= 0;
|
||||
}
|
||||
else if (my_flags & MY_WME)
|
||||
my_error(EE_SYNC, MYF(ME_BELL+ME_WAITTANG), my_filename(fd), my_errno);
|
||||
}
|
||||
DBUG_RETURN(res);
|
||||
} /* my_sync */
|
||||
|
||||
|
||||
static const char cur_dir_name[]= {FN_CURLIB, 0};
|
||||
|
||||
|
||||
/*
|
||||
Force directory information to disk.
|
||||
|
||||
SYNOPSIS
|
||||
my_sync_dir()
|
||||
dir_name the name of the directory
|
||||
my_flags flags (MY_WME etc)
|
||||
|
||||
RETURN
|
||||
0 if ok, !=0 if error
|
||||
*/
|
||||
|
||||
#ifdef NEED_EXPLICIT_SYNC_DIR
|
||||
|
||||
int my_sync_dir(const char *dir_name, myf my_flags)
|
||||
{
|
||||
File dir_fd;
|
||||
int res= 0;
|
||||
const char *correct_dir_name;
|
||||
DBUG_ENTER("my_sync_dir");
|
||||
DBUG_PRINT("my",("Dir: '%s' my_flags: %d", dir_name, my_flags));
|
||||
/* Sometimes the path does not contain an explicit directory */
|
||||
correct_dir_name= (dir_name[0] == 0) ? cur_dir_name : dir_name;
|
||||
/*
|
||||
Syncing a dir may give EINVAL on tmpfs on Linux, which is ok.
|
||||
EIO on the other hand is very important. Hence MY_IGNORE_BADFD.
|
||||
*/
|
||||
if ((dir_fd= my_open(correct_dir_name, O_RDONLY, MYF(my_flags))) >= 0)
|
||||
{
|
||||
if (my_sync(dir_fd, MYF(my_flags | MY_IGNORE_BADFD)))
|
||||
res= 2;
|
||||
if (my_close(dir_fd, MYF(my_flags)))
|
||||
res= 3;
|
||||
}
|
||||
else
|
||||
res= 1;
|
||||
DBUG_RETURN(res);
|
||||
}
|
||||
|
||||
#else /* NEED_EXPLICIT_SYNC_DIR */
|
||||
|
||||
int my_sync_dir(const char *dir_name __attribute__((unused)),
|
||||
myf my_flags __attribute__((unused)))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif /* NEED_EXPLICIT_SYNC_DIR */
|
||||
|
||||
|
||||
/*
|
||||
Force directory information to disk.
|
||||
|
||||
SYNOPSIS
|
||||
my_sync_dir_by_file()
|
||||
file_name the name of a file in the directory
|
||||
my_flags flags (MY_WME etc)
|
||||
|
||||
RETURN
|
||||
0 if ok, !=0 if error
|
||||
*/
|
||||
|
||||
#ifdef NEED_EXPLICIT_SYNC_DIR
|
||||
|
||||
int my_sync_dir_by_file(const char *file_name, myf my_flags)
|
||||
{
|
||||
char dir_name[FN_REFLEN];
|
||||
size_t dir_name_length;
|
||||
dirname_part(dir_name, file_name, &dir_name_length);
|
||||
return my_sync_dir(dir_name, my_flags);
|
||||
}
|
||||
|
||||
#else /* NEED_EXPLICIT_SYNC_DIR */
|
||||
|
||||
int my_sync_dir_by_file(const char *file_name __attribute__((unused)),
|
||||
myf my_flags __attribute__((unused)))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif /* NEED_EXPLICIT_SYNC_DIR */
|
||||
|
||||
533
deps/mysqllite/mysys/my_thr_init.c
vendored
Normal file
533
deps/mysqllite/mysys/my_thr_init.c
vendored
Normal file
@@ -0,0 +1,533 @@
|
||||
/* Copyright (C) 2000 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 */
|
||||
|
||||
/*
|
||||
Functions to handle initializating and allocationg of all mysys & debug
|
||||
thread variables.
|
||||
*/
|
||||
|
||||
#include "mysys_priv.h"
|
||||
#include <m_string.h>
|
||||
#include <signal.h>
|
||||
|
||||
pthread_key(struct st_my_thread_var*, THR_KEY_mysys);
|
||||
mysql_mutex_t THR_LOCK_malloc, THR_LOCK_open,
|
||||
THR_LOCK_lock, THR_LOCK_isam, THR_LOCK_myisam, THR_LOCK_heap,
|
||||
THR_LOCK_net, THR_LOCK_charset, THR_LOCK_threads, THR_LOCK_time,
|
||||
THR_LOCK_myisam_mmap;
|
||||
|
||||
mysql_cond_t THR_COND_threads;
|
||||
uint THR_thread_count= 0;
|
||||
uint my_thread_end_wait_time= 5;
|
||||
#if !defined(HAVE_LOCALTIME_R) || !defined(HAVE_GMTIME_R)
|
||||
mysql_mutex_t LOCK_localtime_r;
|
||||
#endif
|
||||
#ifndef HAVE_GETHOSTBYNAME_R
|
||||
mysql_mutex_t LOCK_gethostbyname_r;
|
||||
#endif
|
||||
#ifdef PTHREAD_ADAPTIVE_MUTEX_INITIALIZER_NP
|
||||
pthread_mutexattr_t my_fast_mutexattr;
|
||||
#endif
|
||||
#ifdef PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP
|
||||
pthread_mutexattr_t my_errorcheck_mutexattr;
|
||||
#endif
|
||||
#ifdef _MSC_VER
|
||||
static void install_sigabrt_handler();
|
||||
#endif
|
||||
#ifdef TARGET_OS_LINUX
|
||||
|
||||
/*
|
||||
Dummy thread spawned in my_thread_global_init() below to avoid
|
||||
race conditions in NPTL pthread_exit code.
|
||||
*/
|
||||
|
||||
static pthread_handler_t
|
||||
nptl_pthread_exit_hack_handler(void *arg __attribute((unused)))
|
||||
{
|
||||
/* Do nothing! */
|
||||
pthread_exit(0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif /* TARGET_OS_LINUX */
|
||||
|
||||
|
||||
static uint get_thread_lib(void);
|
||||
|
||||
/** True if @c my_thread_basic_global_init() has been called. */
|
||||
static my_bool my_thread_basic_global_init_done= 0;
|
||||
|
||||
/**
|
||||
Perform a minimal initialisation of mysys, when compiled with threads.
|
||||
The initialisation performed is sufficient to:
|
||||
- allocate memory
|
||||
- perform file operations
|
||||
- use charsets
|
||||
- use my_errno
|
||||
@sa my_basic_init
|
||||
@sa my_thread_basic_global_reinit
|
||||
*/
|
||||
my_bool my_thread_basic_global_init(void)
|
||||
{
|
||||
int pth_ret;
|
||||
|
||||
if (my_thread_basic_global_init_done)
|
||||
return 0;
|
||||
my_thread_basic_global_init_done= 1;
|
||||
|
||||
#ifdef PTHREAD_ADAPTIVE_MUTEX_INITIALIZER_NP
|
||||
/*
|
||||
Set mutex type to "fast" a.k.a "adaptive"
|
||||
|
||||
In this case the thread may steal the mutex from some other thread
|
||||
that is waiting for the same mutex. This will save us some
|
||||
context switches but may cause a thread to 'starve forever' while
|
||||
waiting for the mutex (not likely if the code within the mutex is
|
||||
short).
|
||||
*/
|
||||
pthread_mutexattr_init(&my_fast_mutexattr);
|
||||
pthread_mutexattr_settype(&my_fast_mutexattr,
|
||||
PTHREAD_MUTEX_ADAPTIVE_NP);
|
||||
#endif
|
||||
|
||||
#ifdef PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP
|
||||
/*
|
||||
Set mutex type to "errorcheck"
|
||||
*/
|
||||
pthread_mutexattr_init(&my_errorcheck_mutexattr);
|
||||
pthread_mutexattr_settype(&my_errorcheck_mutexattr,
|
||||
PTHREAD_MUTEX_ERRORCHECK);
|
||||
#endif
|
||||
|
||||
mysql_mutex_init(key_THR_LOCK_malloc, &THR_LOCK_malloc, MY_MUTEX_INIT_FAST);
|
||||
mysql_mutex_init(key_THR_LOCK_open, &THR_LOCK_open, MY_MUTEX_INIT_FAST);
|
||||
mysql_mutex_init(key_THR_LOCK_charset, &THR_LOCK_charset, MY_MUTEX_INIT_FAST);
|
||||
mysql_mutex_init(key_THR_LOCK_threads, &THR_LOCK_threads, MY_MUTEX_INIT_FAST);
|
||||
|
||||
if ((pth_ret= pthread_key_create(&THR_KEY_mysys, NULL)) != 0)
|
||||
{
|
||||
fprintf(stderr, "Can't initialize threads: error %d\n", pth_ret);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (my_thread_init())
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
Re-initialize components initialized early with @c my_thread_basic_global_init.
|
||||
Some mutexes were initialized before the instrumentation.
|
||||
Destroy + create them again, now that the instrumentation
|
||||
is in place.
|
||||
This is safe, since this function() is called before creating new threads,
|
||||
so the mutexes are not in use.
|
||||
*/
|
||||
void my_thread_basic_global_reinit(void)
|
||||
{
|
||||
struct st_my_thread_var *tmp;
|
||||
|
||||
DBUG_ASSERT(my_thread_basic_global_init_done);
|
||||
|
||||
#ifdef HAVE_PSI_INTERFACE
|
||||
my_init_mysys_psi_keys();
|
||||
#endif
|
||||
|
||||
mysql_mutex_destroy(&THR_LOCK_malloc);
|
||||
mysql_mutex_init(key_THR_LOCK_malloc, &THR_LOCK_malloc, MY_MUTEX_INIT_FAST);
|
||||
|
||||
mysql_mutex_destroy(&THR_LOCK_open);
|
||||
mysql_mutex_init(key_THR_LOCK_open, &THR_LOCK_open, MY_MUTEX_INIT_FAST);
|
||||
|
||||
mysql_mutex_destroy(&THR_LOCK_charset);
|
||||
mysql_mutex_init(key_THR_LOCK_charset, &THR_LOCK_charset, MY_MUTEX_INIT_FAST);
|
||||
|
||||
mysql_mutex_destroy(&THR_LOCK_threads);
|
||||
mysql_mutex_init(key_THR_LOCK_threads, &THR_LOCK_threads, MY_MUTEX_INIT_FAST);
|
||||
|
||||
tmp= my_pthread_getspecific(struct st_my_thread_var*, THR_KEY_mysys);
|
||||
DBUG_ASSERT(tmp);
|
||||
|
||||
mysql_mutex_destroy(&tmp->mutex);
|
||||
mysql_mutex_init(key_my_thread_var_mutex, &tmp->mutex, MY_MUTEX_INIT_FAST);
|
||||
|
||||
mysql_cond_destroy(&tmp->suspend);
|
||||
mysql_cond_init(key_my_thread_var_suspend, &tmp->suspend, NULL);
|
||||
}
|
||||
|
||||
/*
|
||||
initialize thread environment
|
||||
|
||||
SYNOPSIS
|
||||
my_thread_global_init()
|
||||
|
||||
RETURN
|
||||
0 ok
|
||||
1 error (Couldn't create THR_KEY_mysys)
|
||||
*/
|
||||
|
||||
my_bool my_thread_global_init(void)
|
||||
{
|
||||
if (my_thread_basic_global_init())
|
||||
return 1;
|
||||
|
||||
thd_lib_detected= get_thread_lib();
|
||||
|
||||
#ifdef TARGET_OS_LINUX
|
||||
/*
|
||||
BUG#24507: Race conditions inside current NPTL pthread_exit()
|
||||
implementation.
|
||||
|
||||
To avoid a possible segmentation fault during concurrent
|
||||
executions of pthread_exit(), a dummy thread is spawned which
|
||||
initializes internal variables of pthread lib. See bug description
|
||||
for a full explanation.
|
||||
|
||||
TODO: Remove this code when fixed versions of glibc6 are in common
|
||||
use.
|
||||
*/
|
||||
if (thd_lib_detected == THD_LIB_NPTL)
|
||||
{
|
||||
pthread_t dummy_thread;
|
||||
pthread_attr_t dummy_thread_attr;
|
||||
|
||||
pthread_attr_init(&dummy_thread_attr);
|
||||
pthread_attr_setdetachstate(&dummy_thread_attr, PTHREAD_CREATE_JOINABLE);
|
||||
|
||||
if (pthread_create(&dummy_thread,&dummy_thread_attr,
|
||||
nptl_pthread_exit_hack_handler, NULL) == 0)
|
||||
(void)pthread_join(dummy_thread, NULL);
|
||||
}
|
||||
#endif /* TARGET_OS_LINUX */
|
||||
|
||||
mysql_mutex_init(key_THR_LOCK_lock, &THR_LOCK_lock, MY_MUTEX_INIT_FAST);
|
||||
mysql_mutex_init(key_THR_LOCK_isam, &THR_LOCK_isam, MY_MUTEX_INIT_SLOW);
|
||||
mysql_mutex_init(key_THR_LOCK_myisam, &THR_LOCK_myisam, MY_MUTEX_INIT_SLOW);
|
||||
mysql_mutex_init(key_THR_LOCK_myisam_mmap, &THR_LOCK_myisam_mmap, MY_MUTEX_INIT_FAST);
|
||||
mysql_mutex_init(key_THR_LOCK_heap, &THR_LOCK_heap, MY_MUTEX_INIT_FAST);
|
||||
mysql_mutex_init(key_THR_LOCK_net, &THR_LOCK_net, MY_MUTEX_INIT_FAST);
|
||||
mysql_mutex_init(key_THR_LOCK_time, &THR_LOCK_time, MY_MUTEX_INIT_FAST);
|
||||
mysql_cond_init(key_THR_COND_threads, &THR_COND_threads, NULL);
|
||||
|
||||
#if !defined(HAVE_LOCALTIME_R) || !defined(HAVE_GMTIME_R)
|
||||
mysql_mutex_init(key_LOCK_localtime_r, &LOCK_localtime_r, MY_MUTEX_INIT_SLOW);
|
||||
#endif
|
||||
#ifndef HAVE_GETHOSTBYNAME_R
|
||||
mysql_mutex_init(key_LOCK_gethostbyname_r,
|
||||
&LOCK_gethostbyname_r, MY_MUTEX_INIT_SLOW);
|
||||
#endif
|
||||
|
||||
#ifdef _MSC_VER
|
||||
install_sigabrt_handler();
|
||||
#endif
|
||||
|
||||
if (my_thread_init())
|
||||
{
|
||||
my_thread_global_end(); /* Clean up */
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void my_thread_global_end(void)
|
||||
{
|
||||
struct timespec abstime;
|
||||
my_bool all_threads_killed= 1;
|
||||
|
||||
set_timespec(abstime, my_thread_end_wait_time);
|
||||
mysql_mutex_lock(&THR_LOCK_threads);
|
||||
while (THR_thread_count > 0)
|
||||
{
|
||||
int error= mysql_cond_timedwait(&THR_COND_threads, &THR_LOCK_threads,
|
||||
&abstime);
|
||||
if (error == ETIMEDOUT || error == ETIME)
|
||||
{
|
||||
#ifdef HAVE_PTHREAD_KILL
|
||||
/*
|
||||
We shouldn't give an error here, because if we don't have
|
||||
pthread_kill(), programs like mysqld can't ensure that all threads
|
||||
are killed when we enter here.
|
||||
*/
|
||||
if (THR_thread_count)
|
||||
fprintf(stderr,
|
||||
"Error in my_thread_global_end(): %d threads didn't exit\n",
|
||||
THR_thread_count);
|
||||
#endif
|
||||
all_threads_killed= 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
mysql_mutex_unlock(&THR_LOCK_threads);
|
||||
|
||||
pthread_key_delete(THR_KEY_mysys);
|
||||
#ifdef PTHREAD_ADAPTIVE_MUTEX_INITIALIZER_NP
|
||||
pthread_mutexattr_destroy(&my_fast_mutexattr);
|
||||
#endif
|
||||
#ifdef PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP
|
||||
pthread_mutexattr_destroy(&my_errorcheck_mutexattr);
|
||||
#endif
|
||||
mysql_mutex_destroy(&THR_LOCK_malloc);
|
||||
mysql_mutex_destroy(&THR_LOCK_open);
|
||||
mysql_mutex_destroy(&THR_LOCK_lock);
|
||||
mysql_mutex_destroy(&THR_LOCK_isam);
|
||||
mysql_mutex_destroy(&THR_LOCK_myisam);
|
||||
mysql_mutex_destroy(&THR_LOCK_myisam_mmap);
|
||||
mysql_mutex_destroy(&THR_LOCK_heap);
|
||||
mysql_mutex_destroy(&THR_LOCK_net);
|
||||
mysql_mutex_destroy(&THR_LOCK_time);
|
||||
mysql_mutex_destroy(&THR_LOCK_charset);
|
||||
if (all_threads_killed)
|
||||
{
|
||||
mysql_mutex_destroy(&THR_LOCK_threads);
|
||||
mysql_cond_destroy(&THR_COND_threads);
|
||||
}
|
||||
#if !defined(HAVE_LOCALTIME_R) || !defined(HAVE_GMTIME_R)
|
||||
mysql_mutex_destroy(&LOCK_localtime_r);
|
||||
#endif
|
||||
#ifndef HAVE_GETHOSTBYNAME_R
|
||||
mysql_mutex_destroy(&LOCK_gethostbyname_r);
|
||||
#endif
|
||||
|
||||
my_thread_basic_global_init_done= 0;
|
||||
}
|
||||
|
||||
static my_thread_id thread_id= 0;
|
||||
|
||||
/*
|
||||
Allocate thread specific memory for the thread, used by mysys and dbug
|
||||
|
||||
SYNOPSIS
|
||||
my_thread_init()
|
||||
|
||||
NOTES
|
||||
We can't use mutex_locks here if we are using windows as
|
||||
we may have compiled the program with SAFE_MUTEX, in which
|
||||
case the checking of mutex_locks will not work until
|
||||
the pthread_self thread specific variable is initialized.
|
||||
|
||||
This function may called multiple times for a thread, for example
|
||||
if one uses my_init() followed by mysql_server_init().
|
||||
|
||||
RETURN
|
||||
0 ok
|
||||
1 Fatal error; mysys/dbug functions can't be used
|
||||
*/
|
||||
|
||||
my_bool my_thread_init(void)
|
||||
{
|
||||
struct st_my_thread_var *tmp;
|
||||
my_bool error=0;
|
||||
|
||||
#ifdef EXTRA_DEBUG_THREADS
|
||||
fprintf(stderr,"my_thread_init(): thread_id: 0x%lx\n",
|
||||
(ulong) pthread_self());
|
||||
#endif
|
||||
|
||||
if (my_pthread_getspecific(struct st_my_thread_var *,THR_KEY_mysys))
|
||||
{
|
||||
#ifdef EXTRA_DEBUG_THREADS
|
||||
fprintf(stderr,"my_thread_init() called more than once in thread 0x%lx\n",
|
||||
(long) pthread_self());
|
||||
#endif
|
||||
goto end;
|
||||
}
|
||||
|
||||
#ifdef _MSC_VER
|
||||
install_sigabrt_handler();
|
||||
#endif
|
||||
|
||||
if (!(tmp= (struct st_my_thread_var *) calloc(1, sizeof(*tmp))))
|
||||
{
|
||||
error= 1;
|
||||
goto end;
|
||||
}
|
||||
pthread_setspecific(THR_KEY_mysys,tmp);
|
||||
tmp->pthread_self= pthread_self();
|
||||
mysql_mutex_init(key_my_thread_var_mutex, &tmp->mutex, MY_MUTEX_INIT_FAST);
|
||||
mysql_cond_init(key_my_thread_var_suspend, &tmp->suspend, NULL);
|
||||
|
||||
tmp->stack_ends_here= (char*)&tmp +
|
||||
STACK_DIRECTION * (long)my_thread_stack_size;
|
||||
|
||||
mysql_mutex_lock(&THR_LOCK_threads);
|
||||
tmp->id= ++thread_id;
|
||||
++THR_thread_count;
|
||||
mysql_mutex_unlock(&THR_LOCK_threads);
|
||||
tmp->init= 1;
|
||||
#ifndef DBUG_OFF
|
||||
/* Generate unique name for thread */
|
||||
(void) my_thread_name();
|
||||
#endif
|
||||
|
||||
end:
|
||||
return error;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Deallocate memory used by the thread for book-keeping
|
||||
|
||||
SYNOPSIS
|
||||
my_thread_end()
|
||||
|
||||
NOTE
|
||||
This may be called multiple times for a thread.
|
||||
This happens for example when one calls 'mysql_server_init()'
|
||||
mysql_server_end() and then ends with a mysql_end().
|
||||
*/
|
||||
|
||||
void my_thread_end(void)
|
||||
{
|
||||
struct st_my_thread_var *tmp;
|
||||
tmp= my_pthread_getspecific(struct st_my_thread_var*,THR_KEY_mysys);
|
||||
|
||||
#ifdef EXTRA_DEBUG_THREADS
|
||||
fprintf(stderr,"my_thread_end(): tmp: 0x%lx pthread_self: 0x%lx thread_id: %ld\n",
|
||||
(long) tmp, (long) pthread_self(), tmp ? (long) tmp->id : 0L);
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_PSI_INTERFACE
|
||||
/*
|
||||
Remove the instrumentation for this thread.
|
||||
This must be done before trashing st_my_thread_var,
|
||||
because the LF_HASH depends on it.
|
||||
*/
|
||||
if (PSI_server)
|
||||
PSI_server->delete_current_thread();
|
||||
#endif
|
||||
|
||||
if (tmp && tmp->init)
|
||||
{
|
||||
#if !defined(DBUG_OFF)
|
||||
/* tmp->dbug is allocated inside DBUG library */
|
||||
if (tmp->dbug)
|
||||
{
|
||||
DBUG_POP();
|
||||
free(tmp->dbug);
|
||||
tmp->dbug=0;
|
||||
}
|
||||
#endif
|
||||
#if !defined(__bsdi__) && !defined(__OpenBSD__)
|
||||
/* bsdi and openbsd 3.5 dumps core here */
|
||||
mysql_cond_destroy(&tmp->suspend);
|
||||
#endif
|
||||
mysql_mutex_destroy(&tmp->mutex);
|
||||
free(tmp);
|
||||
|
||||
/*
|
||||
Decrement counter for number of running threads. We are using this
|
||||
in my_thread_global_end() to wait until all threads have called
|
||||
my_thread_end and thus freed all memory they have allocated in
|
||||
my_thread_init() and DBUG_xxxx
|
||||
*/
|
||||
mysql_mutex_lock(&THR_LOCK_threads);
|
||||
DBUG_ASSERT(THR_thread_count != 0);
|
||||
if (--THR_thread_count == 0)
|
||||
mysql_cond_signal(&THR_COND_threads);
|
||||
mysql_mutex_unlock(&THR_LOCK_threads);
|
||||
}
|
||||
pthread_setspecific(THR_KEY_mysys,0);
|
||||
}
|
||||
|
||||
struct st_my_thread_var *_my_thread_var(void)
|
||||
{
|
||||
return my_pthread_getspecific(struct st_my_thread_var*,THR_KEY_mysys);
|
||||
}
|
||||
|
||||
|
||||
/****************************************************************************
|
||||
Get name of current thread.
|
||||
****************************************************************************/
|
||||
|
||||
my_thread_id my_thread_dbug_id()
|
||||
{
|
||||
return my_thread_var->id;
|
||||
}
|
||||
|
||||
#ifdef DBUG_OFF
|
||||
const char *my_thread_name(void)
|
||||
{
|
||||
return "no_name";
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
const char *my_thread_name(void)
|
||||
{
|
||||
char name_buff[100];
|
||||
struct st_my_thread_var *tmp=my_thread_var;
|
||||
if (!tmp->name[0])
|
||||
{
|
||||
my_thread_id id= my_thread_dbug_id();
|
||||
sprintf(name_buff,"T@%lu", (ulong) id);
|
||||
strmake(tmp->name,name_buff,THREAD_NAME_SIZE);
|
||||
}
|
||||
return tmp->name;
|
||||
}
|
||||
|
||||
/* Return pointer to DBUG for holding current state */
|
||||
|
||||
extern void **my_thread_var_dbug()
|
||||
{
|
||||
struct st_my_thread_var *tmp=
|
||||
my_pthread_getspecific(struct st_my_thread_var*,THR_KEY_mysys);
|
||||
return tmp && tmp->init ? &tmp->dbug : 0;
|
||||
}
|
||||
#endif /* DBUG_OFF */
|
||||
|
||||
|
||||
static uint get_thread_lib(void)
|
||||
{
|
||||
#ifdef _CS_GNU_LIBPTHREAD_VERSION
|
||||
char buff[64];
|
||||
|
||||
confstr(_CS_GNU_LIBPTHREAD_VERSION, buff, sizeof(buff));
|
||||
|
||||
if (!strncasecmp(buff, "NPTL", 4))
|
||||
return THD_LIB_NPTL;
|
||||
if (!strncasecmp(buff, "linuxthreads", 12))
|
||||
return THD_LIB_LT;
|
||||
#endif
|
||||
return THD_LIB_OTHER;
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
/*
|
||||
In Visual Studio 2005 and later, default SIGABRT handler will overwrite
|
||||
any unhandled exception filter set by the application and will try to
|
||||
call JIT debugger. This is not what we want, this we calling __debugbreak
|
||||
to stop in debugger, if process is being debugged or to generate
|
||||
EXCEPTION_BREAKPOINT and then handle_segfault will do its magic.
|
||||
*/
|
||||
|
||||
#if (_MSC_VER >= 1400)
|
||||
static void my_sigabrt_handler(int sig)
|
||||
{
|
||||
__debugbreak();
|
||||
}
|
||||
#endif /*_MSC_VER >=1400 */
|
||||
|
||||
static void install_sigabrt_handler(void)
|
||||
{
|
||||
#if (_MSC_VER >=1400)
|
||||
/*abort() should not override our exception filter*/
|
||||
_set_abort_behavior(0,_CALL_REPORTFAULT);
|
||||
signal(SIGABRT,my_sigabrt_handler);
|
||||
#endif /* _MSC_VER >=1400 */
|
||||
}
|
||||
#endif
|
||||
|
||||
369
deps/mysqllite/mysys/my_wincond.c
vendored
Normal file
369
deps/mysqllite/mysys/my_wincond.c
vendored
Normal file
@@ -0,0 +1,369 @@
|
||||
/* Copyright (C) 2000 MySQL AB
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
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 following is a simple implementation of posix conditions
|
||||
*****************************************************************************/
|
||||
#if defined(_WIN32)
|
||||
|
||||
#undef SAFE_MUTEX /* Avoid safe_mutex redefinitions */
|
||||
#include "mysys_priv.h"
|
||||
#include <m_string.h>
|
||||
#include <process.h>
|
||||
#include <sys/timeb.h>
|
||||
|
||||
|
||||
/*
|
||||
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)
|
||||
{
|
||||
long long millis;
|
||||
union ft64 now;
|
||||
|
||||
if (abstime == NULL)
|
||||
return INFINITE;
|
||||
|
||||
GetSystemTimeAsFileTime(&now.ft);
|
||||
|
||||
/*
|
||||
Calculate time left to abstime
|
||||
- subtract start time from current time(values are in 100ns units)
|
||||
- convert to millisec by dividing with 10000
|
||||
*/
|
||||
millis= (abstime->tv.i64 - now.i64) / 10000;
|
||||
|
||||
/* Don't allow the timeout to be negative */
|
||||
if (millis < 0)
|
||||
return 0;
|
||||
|
||||
/*
|
||||
Make sure the calculated timeout does not exceed original timeout
|
||||
value which could cause "wait for ever" if system time changes
|
||||
*/
|
||||
if (millis > abstime->max_timeout_msec)
|
||||
millis= abstime->max_timeout_msec;
|
||||
|
||||
if (millis > UINT_MAX)
|
||||
millis= UINT_MAX;
|
||||
|
||||
return (DWORD)millis;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
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);
|
||||
|
||||
cond->events[SIGNAL]= CreateEvent(NULL, /* no security */
|
||||
FALSE, /* auto-reset event */
|
||||
FALSE, /* non-signaled initially */
|
||||
NULL); /* unnamed */
|
||||
|
||||
/* Create a manual-reset event. */
|
||||
cond->events[BROADCAST]= CreateEvent(NULL, /* no security */
|
||||
TRUE, /* manual-reset */
|
||||
FALSE, /* non-signaled initially */
|
||||
NULL); /* unnamed */
|
||||
|
||||
|
||||
cond->broadcast_block_event= CreateEvent(NULL, /* no security */
|
||||
TRUE, /* manual-reset */
|
||||
TRUE, /* signaled initially */
|
||||
NULL); /* unnamed */
|
||||
|
||||
if( cond->events[SIGNAL] == NULL ||
|
||||
cond->events[BROADCAST] == NULL ||
|
||||
cond->broadcast_block_event == NULL )
|
||||
return ENOMEM;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int legacy_cond_destroy(pthread_cond_t *cond)
|
||||
{
|
||||
DeleteCriticalSection(&cond->lock_waiting);
|
||||
|
||||
if (CloseHandle(cond->events[SIGNAL]) == 0 ||
|
||||
CloseHandle(cond->events[BROADCAST]) == 0 ||
|
||||
CloseHandle(cond->broadcast_block_event) == 0)
|
||||
return EINVAL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int legacy_cond_timedwait(pthread_cond_t *cond, pthread_mutex_t *mutex,
|
||||
struct timespec *abstime)
|
||||
{
|
||||
int result;
|
||||
DWORD timeout;
|
||||
|
||||
timeout= get_milliseconds(abstime);
|
||||
/*
|
||||
Block access if previous broadcast hasn't finished.
|
||||
This is just for safety and should normally not
|
||||
affect the total time spent in this function.
|
||||
*/
|
||||
WaitForSingleObject(cond->broadcast_block_event, INFINITE);
|
||||
|
||||
EnterCriticalSection(&cond->lock_waiting);
|
||||
cond->waiting++;
|
||||
LeaveCriticalSection(&cond->lock_waiting);
|
||||
|
||||
LeaveCriticalSection(mutex);
|
||||
result= WaitForMultipleObjects(2, cond->events, FALSE, timeout);
|
||||
|
||||
EnterCriticalSection(&cond->lock_waiting);
|
||||
cond->waiting--;
|
||||
|
||||
if (cond->waiting == 0)
|
||||
{
|
||||
/*
|
||||
We're the last waiter to be notified or to stop waiting, so
|
||||
reset the manual event.
|
||||
*/
|
||||
/* Close broadcast gate */
|
||||
ResetEvent(cond->events[BROADCAST]);
|
||||
/* Open block gate */
|
||||
SetEvent(cond->broadcast_block_event);
|
||||
}
|
||||
LeaveCriticalSection(&cond->lock_waiting);
|
||||
|
||||
EnterCriticalSection(mutex);
|
||||
|
||||
return result == WAIT_TIMEOUT ? ETIMEDOUT : 0;
|
||||
}
|
||||
|
||||
static int legacy_cond_signal(pthread_cond_t *cond)
|
||||
{
|
||||
EnterCriticalSection(&cond->lock_waiting);
|
||||
|
||||
if(cond->waiting > 0)
|
||||
SetEvent(cond->events[SIGNAL]);
|
||||
|
||||
LeaveCriticalSection(&cond->lock_waiting);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int legacy_cond_broadcast(pthread_cond_t *cond)
|
||||
{
|
||||
EnterCriticalSection(&cond->lock_waiting);
|
||||
/*
|
||||
The mutex protect us from broadcasting if
|
||||
there isn't any thread waiting to open the
|
||||
block gate after this call has closed it.
|
||||
*/
|
||||
if(cond->waiting > 0)
|
||||
{
|
||||
/* Close block gate */
|
||||
ResetEvent(cond->broadcast_block_event);
|
||||
/* Open broadcast gate */
|
||||
SetEvent(cond->events[BROADCAST]);
|
||||
}
|
||||
|
||||
LeaveCriticalSection(&cond->lock_waiting);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
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;
|
||||
connect_att->dwCreatingFlag = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int pthread_attr_setstacksize(pthread_attr_t *connect_att,DWORD stack)
|
||||
{
|
||||
connect_att->dwStackSize=stack;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int pthread_attr_destroy(pthread_attr_t *connect_att)
|
||||
{
|
||||
bzero((uchar*) connect_att,sizeof(*connect_att));
|
||||
return 0;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
** Fix localtime_r() to be a bit safer
|
||||
****************************************************************************/
|
||||
|
||||
struct tm *localtime_r(const time_t *timep,struct tm *tmp)
|
||||
{
|
||||
if (*timep == (time_t) -1) /* This will crash win32 */
|
||||
{
|
||||
bzero(tmp,sizeof(*tmp));
|
||||
}
|
||||
else
|
||||
{
|
||||
struct tm *res=localtime(timep);
|
||||
if (!res) /* Wrong date */
|
||||
{
|
||||
bzero(tmp,sizeof(*tmp)); /* Keep things safe */
|
||||
return 0;
|
||||
}
|
||||
*tmp= *res;
|
||||
}
|
||||
return tmp;
|
||||
}
|
||||
#endif /* __WIN__ */
|
||||
223
deps/mysqllite/mysys/my_windac.c
vendored
Normal file
223
deps/mysqllite/mysys/my_windac.c
vendored
Normal file
@@ -0,0 +1,223 @@
|
||||
/* 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 */
|
||||
|
||||
#include "mysys_priv.h"
|
||||
#include "m_string.h"
|
||||
#ifdef __WIN__
|
||||
|
||||
/* Windows NT/2000 discretionary access control utility functions. */
|
||||
|
||||
/*
|
||||
Check if the operating system is built on NT technology.
|
||||
|
||||
RETURN
|
||||
0 Windows 95/98/Me
|
||||
1 otherwise
|
||||
*/
|
||||
|
||||
static my_bool is_nt()
|
||||
{
|
||||
return GetVersion() < 0x80000000;
|
||||
}
|
||||
|
||||
/*
|
||||
Auxilary structure to store pointers to the data which we need to keep
|
||||
around while SECURITY_ATTRIBUTES is in use.
|
||||
*/
|
||||
|
||||
typedef struct st_my_security_attr
|
||||
{
|
||||
PSID everyone_sid;
|
||||
PACL dacl;
|
||||
} My_security_attr;
|
||||
|
||||
|
||||
/*
|
||||
Allocate and initialize SECURITY_ATTRIBUTES setting up access
|
||||
rights for the owner and group `Everybody'.
|
||||
|
||||
SYNOPSIS
|
||||
my_security_attr_create()
|
||||
psa [OUT] pointer to store the pointer to SA in
|
||||
perror [OUT] pointer to store error message if there was an
|
||||
error
|
||||
owner_rights [IN] access rights for the owner
|
||||
everyone_rights [IN] access rights for group Everybody
|
||||
|
||||
DESCRIPTION
|
||||
Set up the security attributes to provide clients with sufficient
|
||||
access rights to a kernel object. We need this function
|
||||
because if we simply grant all access to everybody (by installing
|
||||
a NULL DACL) a mailicious user can attempt a denial of service
|
||||
attack by taking ownership over the kernel object. Upon successful
|
||||
return `psa' contains a pointer to SECUIRITY_ATTRIBUTES that can be used
|
||||
to create kernel objects with proper access rights.
|
||||
|
||||
RETURN
|
||||
0 success, psa is 0 or points to a valid SA structure,
|
||||
perror is left intact
|
||||
!0 error, SA is set to 0, error message is stored in perror
|
||||
*/
|
||||
|
||||
int my_security_attr_create(SECURITY_ATTRIBUTES **psa, const char **perror,
|
||||
DWORD owner_rights, DWORD everyone_rights)
|
||||
{
|
||||
/* Top-level SID authority */
|
||||
SID_IDENTIFIER_AUTHORITY world_auth= SECURITY_WORLD_SID_AUTHORITY;
|
||||
PSID everyone_sid= 0;
|
||||
HANDLE htoken= 0;
|
||||
SECURITY_ATTRIBUTES *sa= 0;
|
||||
PACL dacl= 0;
|
||||
DWORD owner_token_length, dacl_length;
|
||||
SECURITY_DESCRIPTOR *sd;
|
||||
PTOKEN_USER owner_token;
|
||||
PSID owner_sid;
|
||||
My_security_attr *attr;
|
||||
|
||||
if (! is_nt())
|
||||
{
|
||||
*psa= 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
Get SID of Everyone group. Easier to retrieve all SIDs each time
|
||||
this function is called than worry about thread safety.
|
||||
*/
|
||||
if (! AllocateAndInitializeSid(&world_auth, 1, SECURITY_WORLD_RID,
|
||||
0, 0, 0, 0, 0, 0, 0, &everyone_sid))
|
||||
{
|
||||
*perror= "Failed to retrieve the SID of Everyone group";
|
||||
goto error;
|
||||
}
|
||||
|
||||
/*
|
||||
Get SID of the owner. Using GetSecurityInfo this task can be done
|
||||
in just one call instead of five, but GetSecurityInfo declared in
|
||||
aclapi.h, so I hesitate to use it.
|
||||
SIC: OpenThreadToken works only if there is an active impersonation
|
||||
token, hence OpenProcessToken is used.
|
||||
*/
|
||||
if (! OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &htoken))
|
||||
{
|
||||
*perror= "Failed to retrieve thread access token";
|
||||
goto error;
|
||||
}
|
||||
GetTokenInformation(htoken, TokenUser, 0, 0, &owner_token_length);
|
||||
|
||||
if (! my_multi_malloc(MYF(MY_WME),
|
||||
&sa, ALIGN_SIZE(sizeof(SECURITY_ATTRIBUTES)) +
|
||||
sizeof(My_security_attr),
|
||||
&sd, sizeof(SECURITY_DESCRIPTOR),
|
||||
&owner_token, owner_token_length,
|
||||
0))
|
||||
{
|
||||
*perror= "Failed to allocate memory for SECURITY_ATTRIBUTES";
|
||||
goto error;
|
||||
}
|
||||
bzero(owner_token, owner_token_length);
|
||||
if (! GetTokenInformation(htoken, TokenUser, owner_token,
|
||||
owner_token_length, &owner_token_length))
|
||||
{
|
||||
*perror= "GetTokenInformation failed";
|
||||
goto error;
|
||||
}
|
||||
owner_sid= owner_token->User.Sid;
|
||||
|
||||
if (! IsValidSid(owner_sid))
|
||||
{
|
||||
*perror= "IsValidSid failed";
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* Calculate the amount of memory that must be allocated for the DACL */
|
||||
dacl_length= sizeof(ACL) + (sizeof(ACCESS_ALLOWED_ACE)-sizeof(DWORD)) * 2 +
|
||||
GetLengthSid(everyone_sid) + GetLengthSid(owner_sid);
|
||||
|
||||
/* Create an ACL */
|
||||
if (! (dacl= (PACL) my_malloc(dacl_length, MYF(MY_ZEROFILL|MY_WME))))
|
||||
{
|
||||
*perror= "Failed to allocate memory for DACL";
|
||||
goto error;
|
||||
}
|
||||
if (! InitializeAcl(dacl, dacl_length, ACL_REVISION))
|
||||
{
|
||||
*perror= "Failed to initialize DACL";
|
||||
goto error;
|
||||
}
|
||||
if (! AddAccessAllowedAce(dacl, ACL_REVISION, everyone_rights, everyone_sid))
|
||||
{
|
||||
*perror= "Failed to set up DACL";
|
||||
goto error;
|
||||
}
|
||||
if (! AddAccessAllowedAce(dacl, ACL_REVISION, owner_rights, owner_sid))
|
||||
{
|
||||
*perror= "Failed to set up DACL";
|
||||
goto error;
|
||||
}
|
||||
if (! InitializeSecurityDescriptor(sd, SECURITY_DESCRIPTOR_REVISION))
|
||||
{
|
||||
*perror= "Could not initialize security descriptor";
|
||||
goto error;
|
||||
}
|
||||
if (! SetSecurityDescriptorDacl(sd, TRUE, dacl, FALSE))
|
||||
{
|
||||
*perror= "Failed to install DACL";
|
||||
goto error;
|
||||
}
|
||||
|
||||
sa->nLength= sizeof(*sa);
|
||||
sa->bInheritHandle= TRUE;
|
||||
sa->lpSecurityDescriptor= sd;
|
||||
/* Save pointers to everyone_sid and dacl to be able to clean them up */
|
||||
attr= (My_security_attr*) (((char*) sa) + ALIGN_SIZE(sizeof(*sa)));
|
||||
attr->everyone_sid= everyone_sid;
|
||||
attr->dacl= dacl;
|
||||
*psa= sa;
|
||||
|
||||
CloseHandle(htoken);
|
||||
return 0;
|
||||
error:
|
||||
if (everyone_sid)
|
||||
FreeSid(everyone_sid);
|
||||
if (htoken)
|
||||
CloseHandle(htoken);
|
||||
my_free(sa);
|
||||
my_free(dacl);
|
||||
*psa= 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
Cleanup security attributes freeing used memory.
|
||||
|
||||
SYNOPSIS
|
||||
my_security_attr_free()
|
||||
sa security attributes
|
||||
*/
|
||||
|
||||
void my_security_attr_free(SECURITY_ATTRIBUTES *sa)
|
||||
{
|
||||
if (sa)
|
||||
{
|
||||
My_security_attr *attr= (My_security_attr*)
|
||||
(((char*)sa) + ALIGN_SIZE(sizeof(*sa)));
|
||||
FreeSid(attr->everyone_sid);
|
||||
my_free(attr->dacl);
|
||||
my_free(sa);
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* __WIN__ */
|
||||
123
deps/mysqllite/mysys/my_winerr.c
vendored
Normal file
123
deps/mysqllite/mysys/my_winerr.c
vendored
Normal file
@@ -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);
|
||||
}
|
||||
681
deps/mysqllite/mysys/my_winfile.c
vendored
Normal file
681
deps/mysqllite/mysys/my_winfile.c
vendored
Normal file
@@ -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");
|
||||
|
||||
mysql_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;
|
||||
}
|
||||
}
|
||||
mysql_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*/
|
||||
192
deps/mysqllite/mysys/my_winthread.c
vendored
Normal file
192
deps/mysqllite/mysys/my_winthread.c
vendored
Normal file
@@ -0,0 +1,192 @@
|
||||
/* Copyright (C) 2000 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 */
|
||||
|
||||
/*****************************************************************************
|
||||
** Simulation of posix threads calls for Windows
|
||||
*****************************************************************************/
|
||||
#if defined (_WIN32)
|
||||
/* SAFE_MUTEX will not work until the thread structure is up to date */
|
||||
#undef SAFE_MUTEX
|
||||
#include "mysys_priv.h"
|
||||
#include <process.h>
|
||||
#include <signal.h>
|
||||
|
||||
static void install_sigabrt_handler(void);
|
||||
|
||||
struct thread_start_parameter
|
||||
{
|
||||
pthread_handler func;
|
||||
void *arg;
|
||||
};
|
||||
|
||||
/**
|
||||
Adapter to @c pthread_mutex_trylock()
|
||||
|
||||
@retval 0 Mutex was acquired
|
||||
@retval EBUSY Mutex was already locked by a thread
|
||||
*/
|
||||
int
|
||||
win_pthread_mutex_trylock(pthread_mutex_t *mutex)
|
||||
{
|
||||
if (TryEnterCriticalSection(mutex))
|
||||
{
|
||||
/* Don't allow recursive lock */
|
||||
if (mutex->RecursionCount > 1){
|
||||
LeaveCriticalSection(mutex);
|
||||
return EBUSY;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
return EBUSY;
|
||||
}
|
||||
|
||||
static unsigned int __stdcall pthread_start(void *p)
|
||||
{
|
||||
struct thread_start_parameter *par= (struct thread_start_parameter *)p;
|
||||
pthread_handler func= par->func;
|
||||
void *arg= par->arg;
|
||||
free(p);
|
||||
(*func)(arg);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int pthread_create(pthread_t *thread_id, const pthread_attr_t *attr,
|
||||
pthread_handler func, void *param)
|
||||
{
|
||||
uintptr_t handle;
|
||||
struct thread_start_parameter *par;
|
||||
unsigned int stack_size;
|
||||
DBUG_ENTER("pthread_create");
|
||||
|
||||
par= (struct thread_start_parameter *)malloc(sizeof(*par));
|
||||
if (!par)
|
||||
goto error_return;
|
||||
|
||||
par->func= func;
|
||||
par->arg= param;
|
||||
stack_size= attr?attr->dwStackSize:0;
|
||||
|
||||
handle= _beginthreadex(NULL, stack_size , pthread_start, par, 0, thread_id);
|
||||
if (!handle)
|
||||
goto error_return;
|
||||
DBUG_PRINT("info", ("thread id=%u",*thread_id));
|
||||
|
||||
/* Do not need thread handle, close it */
|
||||
CloseHandle((HANDLE)handle);
|
||||
DBUG_RETURN(0);
|
||||
|
||||
error_return:
|
||||
DBUG_PRINT("error",
|
||||
("Can't create thread to handle request (error %d)",errno));
|
||||
DBUG_RETURN(-1);
|
||||
}
|
||||
|
||||
|
||||
void pthread_exit(void *a)
|
||||
{
|
||||
_endthreadex(0);
|
||||
}
|
||||
|
||||
int pthread_join(pthread_t thread, void **value_ptr)
|
||||
{
|
||||
DWORD ret;
|
||||
HANDLE handle;
|
||||
|
||||
handle= OpenThread(SYNCHRONIZE, FALSE, thread);
|
||||
if (!handle)
|
||||
{
|
||||
errno= EINVAL;
|
||||
goto error_return;
|
||||
}
|
||||
|
||||
ret= WaitForSingleObject(handle, INFINITE);
|
||||
|
||||
if(ret != WAIT_OBJECT_0)
|
||||
{
|
||||
errno= EINVAL;
|
||||
goto error_return;
|
||||
}
|
||||
|
||||
CloseHandle(handle);
|
||||
return 0;
|
||||
|
||||
error_return:
|
||||
if(handle)
|
||||
CloseHandle(handle);
|
||||
return -1;
|
||||
}
|
||||
|
||||
int pthread_cancel(pthread_t thread)
|
||||
{
|
||||
|
||||
HANDLE handle= 0;
|
||||
BOOL ok= FALSE;
|
||||
|
||||
handle= OpenThread(THREAD_TERMINATE, FALSE, thread);
|
||||
if (handle)
|
||||
{
|
||||
ok= TerminateThread(handle,0);
|
||||
CloseHandle(handle);
|
||||
}
|
||||
if (ok)
|
||||
return 0;
|
||||
|
||||
errno= EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
One time initialization. For simplicity, we assume initializer thread
|
||||
does not exit within init_routine().
|
||||
*/
|
||||
int my_pthread_once(my_pthread_once_t *once_control,
|
||||
void (*init_routine)(void))
|
||||
{
|
||||
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:
|
||||
/* This is initializer thread */
|
||||
(*init_routine)();
|
||||
*once_control= MY_PTHREAD_ONCE_DONE;
|
||||
break;
|
||||
|
||||
case MY_PTHREAD_ONCE_INPROGRESS:
|
||||
/* init_routine in progress. Wait for its completion */
|
||||
while(*once_control == MY_PTHREAD_ONCE_INPROGRESS)
|
||||
{
|
||||
Sleep(1);
|
||||
}
|
||||
break;
|
||||
case MY_PTHREAD_ONCE_DONE:
|
||||
/* Nothing to do */
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user