2000-07-31 21:29:14 +02:00
/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
2001-12-06 13:10:51 +01:00
2000-07-31 21:29:14 +02:00
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 ; either version 2 of the License , or
( at your option ) any later version .
2001-12-06 13:10:51 +01:00
2000-07-31 21:29:14 +02:00
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 .
2001-12-06 13:10:51 +01:00
2000-07-31 21:29:14 +02:00
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 */
/* Some general useful functions */
# include "mysql_priv.h"
# include <errno.h>
# include <m_ctype.h>
2004-07-16 00:15:55 +02:00
# include "md5.h"
2000-07-31 21:29:14 +02:00
/* Functions defined in this file */
2004-12-22 15:56:57 +01:00
static void frm_error ( int error , TABLE * form , const char * name ,
int errortype , int errarg ) ;
2000-07-31 21:29:14 +02:00
static void fix_type_pointers ( const char * * * array , TYPELIB * point_to_type ,
uint types , char * * names ) ;
static uint find_field ( TABLE * form , uint start , uint length ) ;
2004-03-28 01:11:54 +01:00
static byte * get_field_name ( Field * * buff , uint * length ,
2000-07-31 21:29:14 +02:00
my_bool not_used __attribute__ ( ( unused ) ) )
{
2004-03-28 01:11:54 +01:00
* length = ( uint ) strlen ( ( * buff ) - > field_name ) ;
return ( byte * ) ( * buff ) - > field_name ;
2000-07-31 21:29:14 +02:00
}
2003-02-12 20:55:37 +01:00
/*
Open a . frm file
SYNOPSIS
openfrm ( )
name path to table - file " db/name "
alias alias for table
db_stat open flags ( for example HA_OPEN_KEYFILE | HA_OPEN_RNDFILE . . )
can be 0 ( example in ha_example_table )
prgflag READ_ALL etc . .
ha_open_flags HA_OPEN_ABORT_IF_LOCKED etc . .
outparam result table
RETURN VALUES
0 ok
1 Error ( see frm_error )
2 Error ( see frm_error )
3 Wrong data in . frm file
4 Error ( see frm_error )
2004-12-22 15:56:57 +01:00
5 Error ( see frm_error : charset unavailable )
2005-05-07 22:57:22 +02:00
6 Unknown . frm version
2003-02-12 20:55:37 +01:00
*/
2000-07-31 21:29:14 +02:00
2004-09-17 02:08:23 +02:00
int openfrm ( THD * thd , const char * name , const char * alias , uint db_stat ,
uint prgflag , uint ha_open_flags , TABLE * outparam )
2000-07-31 21:29:14 +02:00
{
reg1 uint i ;
reg2 uchar * strpos ;
2004-12-22 15:56:57 +01:00
int j , error , errarg = 0 ;
2000-07-31 21:29:14 +02:00
uint rec_buff_length , n_length , int_length , records , key_parts , keys ,
2002-04-12 20:35:46 +02:00
interval_count , interval_parts , read_length , db_create_options ;
2002-06-02 20:22:20 +02:00
uint key_info_length , com_length ;
2005-09-13 03:02:17 +02:00
ulong pos , record_offset ;
2002-06-04 07:23:57 +02:00
char index_file [ FN_REFLEN ] , * names , * keynames , * comment_pos ;
2000-07-31 21:29:14 +02:00
uchar head [ 288 ] , * disk_buff , new_field_pack_flag ;
my_string record ;
const char * * int_array ;
2002-06-02 20:22:20 +02:00
bool use_hash , null_field_first ;
2004-12-23 20:11:38 +01:00
bool error_reported = FALSE ;
2000-07-31 21:29:14 +02:00
File file ;
Field * * field_ptr , * reg_field ;
KEY * keyinfo ;
KEY_PART_INFO * key_part ;
uchar * null_pos ;
2004-12-17 15:06:05 +01:00
uint null_bit_pos , new_frm_ver , field_pack_length ;
2000-07-31 21:29:14 +02:00
SQL_CRYPT * crypted = 0 ;
2004-11-08 00:13:54 +01:00
MEM_ROOT * * root_ptr , * old_root ;
2005-01-06 12:00:13 +01:00
TABLE_SHARE * share ;
2000-07-31 21:29:14 +02:00
DBUG_ENTER ( " openfrm " ) ;
2004-09-09 05:59:26 +02:00
DBUG_PRINT ( " enter " , ( " name: '%s' form: 0x%lx " , name , outparam ) ) ;
2000-07-31 21:29:14 +02:00
2005-01-06 12:00:13 +01:00
error = 1 ;
disk_buff = NULL ;
2004-11-09 02:58:44 +01:00
root_ptr = my_pthread_getspecific_ptr ( MEM_ROOT * * , THR_MALLOC ) ;
old_root = * root_ptr ;
2004-07-16 00:15:55 +02:00
2005-01-06 12:00:13 +01:00
bzero ( ( char * ) outparam , sizeof ( * outparam ) ) ;
outparam - > in_use = thd ;
outparam - > s = share = & outparam - > share_not_to_be_used ;
2004-07-16 00:15:55 +02:00
if ( ( file = my_open ( fn_format ( index_file , name , " " , reg_ext ,
MY_UNPACK_FILENAME ) ,
O_RDONLY | O_SHARE ,
MYF ( 0 ) ) )
< 0 )
2005-01-13 02:02:49 +01:00
goto err ;
2004-07-16 00:15:55 +02:00
2005-01-06 12:00:13 +01:00
error = 4 ;
2004-07-16 00:15:55 +02:00
if ( my_read ( file , ( byte * ) head , 64 , MYF ( MY_NABP ) ) )
2005-01-13 02:02:49 +01:00
goto err ;
2004-07-16 00:15:55 +02:00
2005-11-20 19:47:07 +01:00
if ( memcmp ( head , STRING_WITH_LEN ( " TYPE= " ) ) = = 0 )
2004-07-16 00:15:55 +02:00
{
// new .frm
my_close ( file , MYF ( MY_WME ) ) ;
if ( db_stat & NO_ERR_ON_NEW_FRM )
DBUG_RETURN ( 5 ) ;
2005-01-13 02:02:49 +01:00
file = - 1 ;
2004-07-16 00:15:55 +02:00
// caller can't process new .frm
2005-01-13 02:02:49 +01:00
goto err ;
2004-07-16 00:15:55 +02:00
}
2006-08-08 22:05:42 +02:00
if ( prgflag & OPEN_VIEW_NO_PARSE )
goto err ;
2004-07-16 00:15:55 +02:00
2005-01-06 12:00:13 +01:00
share - > blob_ptr_size = sizeof ( char * ) ;
outparam - > db_stat = db_stat ;
2003-10-11 21:00:24 +02:00
init_sql_alloc ( & outparam - > mem_root , TABLE_ALLOC_BLOCK_SIZE , 0 ) ;
2004-11-08 00:13:54 +01:00
* root_ptr = & outparam - > mem_root ;
2000-07-31 21:29:14 +02:00
2005-01-06 12:00:13 +01:00
share - > table_name = strdup_root ( & outparam - > mem_root ,
name + dirname_length ( name ) ) ;
share - > path = strdup_root ( & outparam - > mem_root , name ) ;
outparam - > alias = my_strdup ( alias , MYF ( MY_WME ) ) ;
if ( ! share - > table_name | | ! share - > path | | ! outparam - > alias )
2005-01-13 02:02:49 +01:00
goto err ;
2005-01-06 12:00:13 +01:00
* fn_ext ( share - > table_name ) = ' \0 ' ; // Remove extension
* fn_ext ( share - > path ) = ' \0 ' ; // Remove extension
2000-07-31 21:29:14 +02:00
2005-05-07 22:57:22 +02:00
if ( head [ 0 ] ! = ( uchar ) 254 | | head [ 1 ] ! = 1 )
2005-01-13 02:02:49 +01:00
goto err ; /* purecov: inspected */
2005-05-09 20:28:57 +02:00
if ( head [ 2 ] ! = FRM_VER & & head [ 2 ] ! = FRM_VER + 1 & &
! ( head [ 2 ] > = FRM_VER + 3 & & head [ 2 ] < = FRM_VER + 4 ) )
2005-05-07 22:57:22 +02:00
{
error = 6 ;
2005-05-09 20:28:57 +02:00
goto err ; /* purecov: inspected */
2005-05-07 22:57:22 +02:00
}
2000-07-31 21:29:14 +02:00
new_field_pack_flag = head [ 27 ] ;
2002-06-02 20:22:20 +02:00
new_frm_ver = ( head [ 2 ] - FRM_VER ) ;
2003-02-07 14:47:24 +01:00
field_pack_length = new_frm_ver < 2 ? 11 : 17 ;
2000-07-31 21:29:14 +02:00
error = 3 ;
if ( ! ( pos = get_form_pos ( file , head , ( TYPELIB * ) 0 ) ) )
2005-01-13 02:02:49 +01:00
goto err ; /* purecov: inspected */
2000-07-31 21:29:14 +02:00
* fn_ext ( index_file ) = ' \0 ' ; // Remove .frm extension
2005-01-06 12:00:13 +01:00
share - > frm_version = head [ 2 ] ;
2005-03-22 14:48:06 +01:00
/*
Check if . frm file created by MySQL 5.0 . In this case we want to
display CHAR fields as CHAR and not as VARCHAR .
We do it this way as we want to keep the old frm version to enable
MySQL 4.1 to read these files .
*/
if ( share - > frm_version = = FRM_VER_TRUE_VARCHAR - 1 & & head [ 33 ] = = 5 )
share - > frm_version = FRM_VER_TRUE_VARCHAR ;
2005-06-17 23:14:44 +02:00
share - > db_type = ha_checktype ( thd , ( enum db_type ) ( uint ) * ( head + 3 ) , 0 , 0 ) ;
2005-01-06 12:00:13 +01:00
share - > db_create_options = db_create_options = uint2korr ( head + 30 ) ;
share - > db_options_in_use = share - > db_create_options ;
2005-05-25 17:33:36 +02:00
share - > mysql_version = uint4korr ( head + 51 ) ;
2005-01-06 12:00:13 +01:00
null_field_first = 0 ;
2000-07-31 21:29:14 +02:00
if ( ! head [ 32 ] ) // New frm file in 3.23
{
2005-01-06 12:00:13 +01:00
share - > avg_row_length = uint4korr ( head + 34 ) ;
share - > row_type = ( row_type ) head [ 40 ] ;
share - > raid_type = head [ 41 ] ;
share - > raid_chunks = head [ 42 ] ;
share - > raid_chunksize = uint4korr ( head + 43 ) ;
share - > table_charset = get_charset ( ( uint ) head [ 38 ] , MYF ( 0 ) ) ;
null_field_first = 1 ;
}
if ( ! share - > table_charset )
{
/* unknown charset in head[38] or pre-3.23 frm */
2005-01-17 21:22:23 +01:00
if ( use_mb ( default_charset_info ) )
{
/* Warn that we may be changing the size of character columns */
sql_print_warning ( " '%s' had no or invalid character set, "
" and default character set is multi-byte, "
" so character column sizes may have changed " ,
name ) ;
}
2005-01-06 12:00:13 +01:00
share - > table_charset = default_charset_info ;
2000-07-31 21:29:14 +02:00
}
2005-01-06 12:00:13 +01:00
share - > db_record_offset = 1 ;
2000-07-31 21:29:14 +02:00
if ( db_create_options & HA_OPTION_LONG_BLOB_PTR )
2005-01-06 12:00:13 +01:00
share - > blob_ptr_size = portable_sizeof_char_ptr ;
2004-10-07 00:45:06 +02:00
/* Set temporarily a good value for db_low_byte_first */
2005-01-06 12:00:13 +01:00
share - > db_low_byte_first = test ( share - > db_type ! = DB_TYPE_ISAM ) ;
2000-07-31 21:29:14 +02:00
error = 4 ;
2005-01-06 12:00:13 +01:00
share - > max_rows = uint4korr ( head + 18 ) ;
share - > min_rows = uint4korr ( head + 22 ) ;
2000-07-31 21:29:14 +02:00
/* Read keyinformation */
2002-04-12 20:35:46 +02:00
key_info_length = ( uint ) uint2korr ( head + 28 ) ;
2000-07-31 21:29:14 +02:00
VOID ( my_seek ( file , ( ulong ) uint2korr ( head + 6 ) , MY_SEEK_SET , MYF ( 0 ) ) ) ;
2002-04-12 20:35:46 +02:00
if ( read_string ( file , ( gptr * ) & disk_buff , key_info_length ) )
2005-01-13 02:02:49 +01:00
goto err ; /* purecov: inspected */
2003-10-30 19:17:57 +01:00
if ( disk_buff [ 0 ] & 0x80 )
2003-10-21 00:13:17 +02:00
{
2005-01-06 12:00:13 +01:00
share - > keys = keys = ( disk_buff [ 1 ] < < 7 ) | ( disk_buff [ 0 ] & 0x7f ) ;
share - > key_parts = key_parts = uint2korr ( disk_buff + 2 ) ;
2003-10-21 00:13:17 +02:00
}
else
{
2005-01-06 12:00:13 +01:00
share - > keys = keys = disk_buff [ 0 ] ;
share - > key_parts = key_parts = disk_buff [ 1 ] ;
2003-10-21 00:13:17 +02:00
}
2005-01-06 12:00:13 +01:00
share - > keys_for_keyread . init ( 0 ) ;
share - > keys_in_use . init ( keys ) ;
2003-10-11 13:06:55 +02:00
outparam - > quick_keys . init ( ) ;
outparam - > used_keys . init ( ) ;
outparam - > keys_in_use_for_query . init ( ) ;
2000-07-31 21:29:14 +02:00
n_length = keys * sizeof ( KEY ) + key_parts * sizeof ( KEY_PART_INFO ) ;
if ( ! ( keyinfo = ( KEY * ) alloc_root ( & outparam - > mem_root ,
n_length + uint2korr ( disk_buff + 4 ) ) ) )
2005-01-13 02:02:49 +01:00
goto err ; /* purecov: inspected */
2000-07-31 21:29:14 +02:00
bzero ( ( char * ) keyinfo , n_length ) ;
outparam - > key_info = keyinfo ;
2003-01-05 19:18:49 +01:00
key_part = my_reinterpret_cast ( KEY_PART_INFO * ) ( keyinfo + keys ) ;
2000-07-31 21:29:14 +02:00
strpos = disk_buff + 6 ;
ulong * rec_per_key ;
if ( ! ( rec_per_key = ( ulong * ) alloc_root ( & outparam - > mem_root ,
sizeof ( ulong * ) * key_parts ) ) )
2005-01-13 02:02:49 +01:00
goto err ;
2000-07-31 21:29:14 +02:00
for ( i = 0 ; i < keys ; i + + , keyinfo + + )
{
2004-12-06 01:00:37 +01:00
keyinfo - > table = outparam ;
if ( new_frm_ver > = 3 )
2002-06-02 20:22:20 +02:00
{
keyinfo - > flags = ( uint ) uint2korr ( strpos ) ^ HA_NOSAME ;
keyinfo - > key_length = ( uint ) uint2korr ( strpos + 2 ) ;
keyinfo - > key_parts = ( uint ) strpos [ 4 ] ;
keyinfo - > algorithm = ( enum ha_key_alg ) strpos [ 5 ] ;
strpos + = 8 ;
}
else
{
keyinfo - > flags = ( ( uint ) strpos [ 0 ] ) ^ HA_NOSAME ;
keyinfo - > key_length = ( uint ) uint2korr ( strpos + 1 ) ;
keyinfo - > key_parts = ( uint ) strpos [ 3 ] ;
keyinfo - > algorithm = HA_KEY_ALG_UNDEF ;
strpos + = 4 ;
}
2002-02-22 12:24:42 +01:00
2000-07-31 21:29:14 +02:00
keyinfo - > key_part = key_part ;
keyinfo - > rec_per_key = rec_per_key ;
for ( j = keyinfo - > key_parts ; j - - ; key_part + + )
{
* rec_per_key + + = 0 ;
key_part - > fieldnr = ( uint16 ) ( uint2korr ( strpos ) & FIELD_NR_MASK ) ;
key_part - > offset = ( uint ) uint2korr ( strpos + 2 ) - 1 ;
key_part - > key_type = ( uint ) uint2korr ( strpos + 5 ) ;
// key_part->field= (Field*) 0; // Will be fixed later
2002-06-02 20:22:20 +02:00
if ( new_frm_ver > = 1 )
2000-07-31 21:29:14 +02:00
{
key_part - > key_part_flag = * ( strpos + 4 ) ;
key_part - > length = ( uint ) uint2korr ( strpos + 7 ) ;
strpos + = 9 ;
}
else
{
key_part - > length = * ( strpos + 4 ) ;
key_part - > key_part_flag = 0 ;
if ( key_part - > length > 128 )
{
key_part - > length & = 127 ; /* purecov: inspected */
key_part - > key_part_flag = HA_REVERSE_SORT ; /* purecov: inspected */
}
strpos + = 7 ;
}
key_part - > store_length = key_part - > length ;
}
}
2002-04-12 20:35:46 +02:00
keynames = ( char * ) key_part ;
strpos + = ( strmov ( keynames , ( char * ) strpos ) - keynames ) + 1 ;
2002-06-18 23:22:30 +02:00
2005-01-06 12:00:13 +01:00
share - > reclength = uint2korr ( ( head + 16 ) ) ;
2000-07-31 21:29:14 +02:00
if ( * ( head + 26 ) = = 1 )
2005-01-06 12:00:13 +01:00
share - > system = 1 ; /* one-record-database */
2000-07-31 21:29:14 +02:00
# ifdef HAVE_CRYPTED_FRM
else if ( * ( head + 26 ) = = 2 )
{
2004-11-08 00:13:54 +01:00
* root_ptr = old_root
2000-07-31 21:29:14 +02:00
crypted = get_crypt_for_frm ( ) ;
2004-11-08 00:13:54 +01:00
* root_ptr = & outparam - > mem_root ;
2000-07-31 21:29:14 +02:00
outparam - > crypted = 1 ;
}
# endif
2005-10-10 20:01:45 +02:00
record_offset = ( ulong ) ( uint2korr ( head + 6 ) +
( ( uint2korr ( head + 14 ) = = 0xffff ?
uint4korr ( head + 47 ) : uint2korr ( head + 14 ) ) ) ) ;
if ( ( n_length = uint2korr ( head + 55 ) ) )
{
/* Read extra data segment */
char * buff , * next_chunk , * buff_end ;
if ( ! ( next_chunk = buff = my_malloc ( n_length , MYF ( MY_WME ) ) ) )
goto err ;
2005-10-13 18:40:46 +02:00
buff_end = buff + n_length ;
2005-10-10 20:01:45 +02:00
if ( my_pread ( file , ( byte * ) buff , n_length , record_offset + share - > reclength ,
MYF ( MY_NABP ) ) )
{
my_free ( buff , MYF ( 0 ) ) ;
goto err ;
}
2005-10-10 20:53:53 +02:00
share - > connect_string . length = uint2korr ( buff ) ;
if ( ! ( share - > connect_string . str = strmake_root ( & outparam - > mem_root ,
next_chunk + 2 , share - > connect_string . length ) ) )
2005-10-10 20:01:45 +02:00
{
2005-10-10 20:53:53 +02:00
my_free ( buff , MYF ( 0 ) ) ;
goto err ;
2005-10-10 20:01:45 +02:00
}
2005-10-10 20:53:53 +02:00
next_chunk + = share - > connect_string . length + 2 ;
2005-10-10 20:01:45 +02:00
if ( next_chunk + 2 < buff_end )
{
uint str_db_type_length = uint2korr ( next_chunk ) ;
share - > db_type = ha_resolve_by_name ( next_chunk + 2 , str_db_type_length ) ;
2005-10-13 18:40:46 +02:00
DBUG_PRINT ( " enter " , ( " Setting dbtype to: %d - %d - '%.*s' \n " ,
share - > db_type ,
str_db_type_length , str_db_type_length ,
next_chunk + 2 ) ) ;
2005-10-10 20:01:45 +02:00
next_chunk + = str_db_type_length + 2 ;
}
my_free ( buff , MYF ( 0 ) ) ;
}
2000-10-16 01:29:48 +02:00
/* Allocate handler */
2005-11-03 12:20:13 +01:00
if ( ! ( outparam - > file = get_new_handler ( outparam , & outparam - > mem_root ,
share - > db_type ) ) )
2005-01-13 02:02:49 +01:00
goto err ;
2000-07-31 21:29:14 +02:00
error = 4 ;
outparam - > reginfo . lock_type = TL_UNLOCK ;
outparam - > current_lock = F_UNLCK ;
2005-01-06 12:00:13 +01:00
if ( ( db_stat & HA_OPEN_KEYFILE ) | | ( prgflag & DELAYED_OPEN ) )
records = 2 ;
else
records = 1 ;
2005-01-12 02:38:53 +01:00
if ( prgflag & ( READ_ALL + EXTRA_RECORD ) )
records + + ;
2000-10-16 01:29:48 +02:00
/* QQ: TODO, remove the +1 from below */
2005-01-06 12:00:13 +01:00
rec_buff_length = ALIGN_SIZE ( share - > reclength + 1 +
outparam - > file - > extra_rec_buf_length ( ) ) ;
share - > rec_buff_length = rec_buff_length ;
if ( ! ( record = ( char * ) alloc_root ( & outparam - > mem_root ,
rec_buff_length * records ) ) )
2005-01-13 02:02:49 +01:00
goto err ; /* purecov: inspected */
2005-01-26 15:19:20 +01:00
share - > default_values = ( byte * ) record ;
2005-09-13 03:02:17 +02:00
2005-01-06 12:00:13 +01:00
if ( my_pread ( file , ( byte * ) record , ( uint ) share - > reclength ,
2005-09-13 03:02:17 +02:00
record_offset , MYF ( MY_NABP ) ) )
2005-01-13 02:02:49 +01:00
goto err ; /* purecov: inspected */
2000-07-31 21:29:14 +02:00
2005-01-12 02:38:53 +01:00
if ( records = = 1 )
{
/* We are probably in hard repair, and the buffers should not be used */
outparam - > record [ 0 ] = outparam - > record [ 1 ] = share - > default_values ;
}
2005-01-06 12:00:13 +01:00
else
2005-01-12 02:38:53 +01:00
{
2005-01-26 15:19:20 +01:00
outparam - > record [ 0 ] = ( byte * ) record + rec_buff_length ;
2005-01-12 02:38:53 +01:00
if ( records > 2 )
2005-01-26 15:19:20 +01:00
outparam - > record [ 1 ] = ( byte * ) record + rec_buff_length * 2 ;
2005-01-12 02:38:53 +01:00
else
outparam - > record [ 1 ] = outparam - > record [ 0 ] ; // Safety
}
2005-10-10 20:01:45 +02:00
2005-01-12 02:38:53 +01:00
# ifdef HAVE_purify
/*
We need this because when we read var - length rows , we are not updating
bytes after end of varchar
*/
if ( records > 1 )
{
memcpy ( outparam - > record [ 0 ] , share - > default_values , rec_buff_length ) ;
if ( records > 2 )
memcpy ( outparam - > record [ 1 ] , share - > default_values , rec_buff_length ) ;
}
# endif
2000-07-31 21:29:14 +02:00
VOID ( my_seek ( file , pos , MY_SEEK_SET , MYF ( 0 ) ) ) ;
2005-01-13 02:02:49 +01:00
if ( my_read ( file , ( byte * ) head , 288 , MYF ( MY_NABP ) ) )
goto err ;
2005-01-24 15:48:25 +01:00
# ifdef HAVE_CRYPTED_FRM
2000-07-31 21:29:14 +02:00
if ( crypted )
{
crypted - > decode ( ( char * ) head + 256 , 288 - 256 ) ;
if ( sint2korr ( head + 284 ) ! = 0 ) // Should be 0
2005-01-13 02:02:49 +01:00
goto err ; // Wrong password
2000-07-31 21:29:14 +02:00
}
2005-01-24 15:48:25 +01:00
# endif
2000-07-31 21:29:14 +02:00
2005-01-06 12:00:13 +01:00
share - > fields = uint2korr ( head + 258 ) ;
pos = uint2korr ( head + 260 ) ; /* Length of all screens */
n_length = uint2korr ( head + 268 ) ;
interval_count = uint2korr ( head + 270 ) ;
interval_parts = uint2korr ( head + 272 ) ;
int_length = uint2korr ( head + 274 ) ;
share - > null_fields = uint2korr ( head + 282 ) ;
com_length = uint2korr ( head + 284 ) ;
2006-06-29 15:39:34 +02:00
share - > comment . length = ( int ) ( head [ 46 ] ) ;
share - > comment . str = strmake_root ( & outparam - > mem_root , ( char * ) head + 47 ,
share - > comment . length ) ;
2000-07-31 21:29:14 +02:00
2005-01-06 12:00:13 +01:00
DBUG_PRINT ( " info " , ( " i_count: %d i_parts: %d index: %d n_length: %d int_length: %d com_length: %d " , interval_count , interval_parts , share - > keys , n_length , int_length , com_length ) ) ;
2000-07-31 21:29:14 +02:00
if ( ! ( field_ptr = ( Field * * )
alloc_root ( & outparam - > mem_root ,
2005-01-06 12:00:13 +01:00
( uint ) ( ( share - > fields + 1 ) * sizeof ( Field * ) +
2000-07-31 21:29:14 +02:00
interval_count * sizeof ( TYPELIB ) +
2005-01-06 12:00:13 +01:00
( share - > fields + interval_parts +
2000-07-31 21:29:14 +02:00
keys + 3 ) * sizeof ( my_string ) +
2002-06-02 20:22:20 +02:00
( n_length + int_length + com_length ) ) ) ) )
2005-01-13 02:02:49 +01:00
goto err ; /* purecov: inspected */
2000-07-31 21:29:14 +02:00
outparam - > field = field_ptr ;
2005-01-06 12:00:13 +01:00
read_length = ( uint ) ( share - > fields * field_pack_length +
2002-06-04 07:23:57 +02:00
pos + ( uint ) ( n_length + int_length + com_length ) ) ;
2000-07-31 21:29:14 +02:00
if ( read_string ( file , ( gptr * ) & disk_buff , read_length ) )
2005-01-13 02:02:49 +01:00
goto err ; /* purecov: inspected */
2005-01-24 15:48:25 +01:00
# ifdef HAVE_CRYPTED_FRM
2000-07-31 21:29:14 +02:00
if ( crypted )
{
crypted - > decode ( ( char * ) disk_buff , read_length ) ;
delete crypted ;
crypted = 0 ;
}
2005-01-24 15:48:25 +01:00
# endif
2000-07-31 21:29:14 +02:00
strpos = disk_buff + pos ;
2005-01-06 12:00:13 +01:00
share - > intervals = ( TYPELIB * ) ( field_ptr + share - > fields + 1 ) ;
int_array = ( const char * * ) ( share - > intervals + interval_count ) ;
names = ( char * ) ( int_array + share - > fields + interval_parts + keys + 3 ) ;
2000-07-31 21:29:14 +02:00
if ( ! interval_count )
2005-01-06 12:00:13 +01:00
share - > intervals = 0 ; // For better debugging
memcpy ( ( char * ) names , strpos + ( share - > fields * field_pack_length ) ,
2000-07-31 21:29:14 +02:00
( uint ) ( n_length + int_length ) ) ;
2005-01-06 12:00:13 +01:00
comment_pos = names + ( n_length + int_length ) ;
2002-06-04 07:23:57 +02:00
memcpy ( comment_pos , disk_buff + read_length - com_length , com_length ) ;
2000-07-31 21:29:14 +02:00
2005-01-06 12:00:13 +01:00
fix_type_pointers ( & int_array , & share - > fieldnames , 1 , & names ) ;
fix_type_pointers ( & int_array , share - > intervals , interval_count ,
2000-07-31 21:29:14 +02:00
& names ) ;
2004-10-25 14:51:26 +02:00
{
/* Set ENUM and SET lengths */
TYPELIB * interval ;
2005-01-06 12:00:13 +01:00
for ( interval = share - > intervals ;
interval < share - > intervals + interval_count ;
2004-10-25 14:51:26 +02:00
interval + + )
{
uint count = ( uint ) ( interval - > count + 1 ) * sizeof ( uint ) ;
if ( ! ( interval - > type_lengths = ( uint * ) alloc_root ( & outparam - > mem_root ,
count ) ) )
2005-01-13 02:02:49 +01:00
goto err ;
2004-10-25 14:51:26 +02:00
for ( count = 0 ; count < interval - > count ; count + + )
interval - > type_lengths [ count ] = strlen ( interval - > type_names [ count ] ) ;
interval - > type_lengths [ count ] = 0 ;
}
}
2000-07-31 21:29:14 +02:00
if ( keynames )
2005-01-06 12:00:13 +01:00
fix_type_pointers ( & int_array , & share - > keynames , 1 , & keynames ) ;
2000-07-31 21:29:14 +02:00
VOID ( my_close ( file , MYF ( MY_WME ) ) ) ;
2000-10-16 01:29:48 +02:00
file = - 1 ;
2000-07-31 21:29:14 +02:00
2005-01-06 12:00:13 +01:00
record = ( char * ) outparam - > record [ 0 ] - 1 ; /* Fieldstart = 1 */
2000-07-31 21:29:14 +02:00
if ( null_field_first )
{
outparam - > null_flags = null_pos = ( uchar * ) record + 1 ;
2004-12-17 15:06:05 +01:00
null_bit_pos = ( db_create_options & HA_OPTION_PACK_RECORD ) ? 0 : 1 ;
2005-10-08 02:37:23 +02:00
/*
null_bytes below is only correct under the condition that
there are no bit fields . Correct values is set below after the
table struct is initialized
*/
2005-01-06 12:00:13 +01:00
share - > null_bytes = ( share - > null_fields + null_bit_pos + 7 ) / 8 ;
2000-07-31 21:29:14 +02:00
}
else
{
2005-01-06 12:00:13 +01:00
share - > null_bytes = ( share - > null_fields + 7 ) / 8 ;
outparam - > null_flags = null_pos =
( uchar * ) ( record + 1 + share - > reclength - share - > null_bytes ) ;
2004-12-17 15:06:05 +01:00
null_bit_pos = 0 ;
2000-07-31 21:29:14 +02:00
}
2005-01-06 12:00:13 +01:00
use_hash = share - > fields > = MAX_FIELDS_BEFORE_HASH ;
2000-07-31 21:29:14 +02:00
if ( use_hash )
2005-01-06 12:00:13 +01:00
use_hash = ! hash_init ( & share - > name_hash ,
2002-03-14 18:44:42 +01:00
system_charset_info ,
2005-01-06 12:00:13 +01:00
share - > fields , 0 , 0 ,
2003-04-01 09:45:16 +02:00
( hash_get_key ) get_field_name , 0 , 0 ) ;
2000-07-31 21:29:14 +02:00
2005-01-06 12:00:13 +01:00
for ( i = 0 ; i < share - > fields ; i + + , strpos + = field_pack_length , field_ptr + + )
2000-07-31 21:29:14 +02:00
{
2003-02-07 14:47:24 +01:00
uint pack_flag , interval_nr , unireg_type , recpos , field_length ;
2002-06-02 20:22:20 +02:00
enum_field_types field_type ;
2002-10-25 10:58:32 +02:00
CHARSET_INFO * charset = NULL ;
2003-03-27 10:09:09 +01:00
Field : : geometry_type geom_type = Field : : GEOM_GEOMETRY ;
2002-06-02 20:22:20 +02:00
LEX_STRING comment ;
2000-07-31 21:29:14 +02:00
2004-12-06 01:00:37 +01:00
if ( new_frm_ver > = 3 )
2002-06-02 20:22:20 +02:00
{
/* new frm file in 4.1 */
2003-02-07 14:47:24 +01:00
field_length = uint2korr ( strpos + 3 ) ;
recpos = uint3korr ( strpos + 5 ) ;
pack_flag = uint2korr ( strpos + 8 ) ;
unireg_type = ( uint ) strpos [ 10 ] ;
interval_nr = ( uint ) strpos [ 12 ] ;
uint comment_length = uint2korr ( strpos + 15 ) ;
field_type = ( enum_field_types ) ( uint ) strpos [ 13 ] ;
2003-03-27 10:09:09 +01:00
2004-12-06 01:00:37 +01:00
/* charset and geometry_type share the same byte in frm */
2003-03-27 10:09:09 +01:00
if ( field_type = = FIELD_TYPE_GEOMETRY )
{
2004-01-15 18:06:22 +01:00
# ifdef HAVE_SPATIAL
2003-03-27 10:09:09 +01:00
geom_type = ( Field : : geometry_type ) strpos [ 14 ] ;
charset = & my_charset_bin ;
2004-01-15 18:06:22 +01:00
# else
error = 4 ; // unsupported field type
2005-01-13 02:02:49 +01:00
goto err ;
2004-01-15 18:06:22 +01:00
# endif
2003-03-27 10:09:09 +01:00
}
else
{
2004-12-22 15:56:57 +01:00
if ( ! strpos [ 14 ] )
charset = & my_charset_bin ;
else if ( ! ( charset = get_charset ( ( uint ) strpos [ 14 ] , MYF ( 0 ) ) ) )
{
error = 5 ; // Unknown or unavailable charset
errarg = ( int ) strpos [ 14 ] ;
2005-01-13 02:02:49 +01:00
goto err ;
2004-12-22 15:56:57 +01:00
}
2003-03-27 10:09:09 +01:00
}
2002-06-02 20:22:20 +02:00
if ( ! comment_length )
{
comment . str = ( char * ) " " ;
comment . length = 0 ;
}
else
{
comment . str = ( char * ) comment_pos ;
comment . length = comment_length ;
comment_pos + = comment_length ;
}
}
else
{
2003-02-07 14:47:24 +01:00
field_length = ( uint ) strpos [ 3 ] ;
recpos = uint2korr ( strpos + 4 ) ,
pack_flag = uint2korr ( strpos + 6 ) ;
2004-10-02 21:20:08 +02:00
pack_flag & = ~ FIELDFLAG_NO_DEFAULT ; // Safety for old files
2003-02-07 14:47:24 +01:00
unireg_type = ( uint ) strpos [ 8 ] ;
interval_nr = ( uint ) strpos [ 10 ] ;
2002-06-02 20:22:20 +02:00
/* old frm file */
field_type = ( enum_field_types ) f_packtype ( pack_flag ) ;
2004-11-25 13:18:47 +01:00
if ( f_is_binary ( pack_flag ) )
{
/*
Try to choose the best 4.1 type :
- for 4.0 " CHAR(N) BINARY " or " VARCHAR(N) BINARY "
try to find a binary collation for character set .
- for other types ( e . g . BLOB ) just use my_charset_bin .
*/
if ( ! f_is_blob ( pack_flag ) )
{
// 3.23 or 4.0 string
2005-01-06 12:00:13 +01:00
if ( ! ( charset = get_charset_by_csname ( share - > table_charset - > csname ,
2004-11-25 13:18:47 +01:00
MY_CS_BINSORT , MYF ( 0 ) ) ) )
charset = & my_charset_bin ;
}
else
charset = & my_charset_bin ;
}
else
2005-01-06 12:00:13 +01:00
charset = share - > table_charset ;
2002-06-02 20:22:20 +02:00
bzero ( ( char * ) & comment , sizeof ( comment ) ) ;
}
2004-12-06 17:45:32 +01:00
if ( interval_nr & & charset - > mbminlen > 1 )
{
/* Unescape UCS2 intervals from HEX notation */
2005-01-06 12:00:13 +01:00
TYPELIB * interval = share - > intervals + interval_nr - 1 ;
2004-12-21 14:12:27 +01:00
unhex_type2 ( interval ) ;
2004-12-06 17:45:32 +01:00
}
2005-05-26 13:00:47 +02:00
# ifndef TO_BE_DELETED_ON_PRODUCTION
if ( field_type = = FIELD_TYPE_NEWDECIMAL & & ! share - > mysql_version )
{
/*
Fix pack length of old decimal values from 5.0 .3 - > 5.0 .4
The difference is that in the old version we stored precision
in the . frm table while we now store the display_length
*/
uint decimals = f_decimals ( pack_flag ) ;
field_length = my_decimal_precision_to_length ( field_length ,
decimals ,
f_is_dec ( pack_flag ) = = 0 ) ;
sql_print_error ( " Found incompatible DECIMAL field '%s' in %s; Please do \" ALTER TABLE '%s' FORCE \" to fix it! " , share - > fieldnames . type_names [ i ] , name , share - > table_name ) ;
push_warning_printf ( thd , MYSQL_ERROR : : WARN_LEVEL_ERROR ,
ER_CRASHED_ON_USAGE ,
" Found incompatible DECIMAL field '%s' in %s; Please do \" ALTER TABLE '%s' FORCE \" to fix it! " , share - > fieldnames . type_names [ i ] , name , share - > table_name ) ;
share - > crashed = 1 ; // Marker for CHECK TABLE
}
# endif
2000-07-31 21:29:14 +02:00
* field_ptr = reg_field =
2003-02-07 14:47:24 +01:00
make_field ( record + recpos ,
( uint32 ) field_length ,
2004-12-17 15:06:05 +01:00
null_pos , null_bit_pos ,
2000-07-31 21:29:14 +02:00
pack_flag ,
2002-06-02 20:22:20 +02:00
field_type ,
2002-10-25 10:58:32 +02:00
charset ,
2003-03-27 10:09:09 +01:00
geom_type ,
2003-02-07 14:47:24 +01:00
( Field : : utype ) MTYP_TYPENR ( unireg_type ) ,
2000-07-31 21:29:14 +02:00
( interval_nr ?
2005-01-06 12:00:13 +01:00
share - > intervals + interval_nr - 1 :
2000-07-31 21:29:14 +02:00
( TYPELIB * ) 0 ) ,
2005-01-06 12:00:13 +01:00
share - > fieldnames . type_names [ i ] ,
2000-07-31 21:29:14 +02:00
outparam ) ;
2002-11-21 14:56:48 +01:00
if ( ! reg_field ) // Not supported field type
2002-11-07 03:02:37 +01:00
{
error = 4 ;
2005-01-13 02:02:49 +01:00
goto err ; /* purecov: inspected */
2002-11-07 03:02:37 +01:00
}
2005-05-25 17:33:36 +02:00
2005-07-01 06:05:42 +02:00
reg_field - > field_index = i ;
2002-06-02 20:22:20 +02:00
reg_field - > comment = comment ;
2005-04-12 09:27:43 +02:00
if ( field_type = = FIELD_TYPE_BIT & & ! f_bit_as_char ( pack_flag ) )
2000-07-31 21:29:14 +02:00
{
2004-12-17 15:06:05 +01:00
if ( ( null_bit_pos + = field_length & 7 ) > 7 )
2000-07-31 21:29:14 +02:00
{
2004-12-17 15:06:05 +01:00
null_pos + + ;
null_bit_pos - = 8 ;
2000-07-31 21:29:14 +02:00
}
}
2004-12-17 15:06:05 +01:00
if ( ! ( reg_field - > flags & NOT_NULL_FLAG ) )
{
if ( ! ( null_bit_pos = ( null_bit_pos + 1 ) & 7 ) )
null_pos + + ;
}
2004-10-02 21:20:08 +02:00
if ( f_no_default ( pack_flag ) )
reg_field - > flags | = NO_DEFAULT_VALUE_FLAG ;
2000-07-31 21:29:14 +02:00
if ( reg_field - > unireg_check = = Field : : NEXT_NUMBER )
2002-07-23 17:31:22 +02:00
outparam - > found_next_number_field = reg_field ;
2000-07-31 21:29:14 +02:00
if ( outparam - > timestamp_field = = reg_field )
2005-01-06 12:00:13 +01:00
share - > timestamp_field_offset = i ;
2000-07-31 21:29:14 +02:00
if ( use_hash )
2005-01-06 12:00:13 +01:00
( void ) my_hash_insert ( & share - > name_hash , ( byte * ) field_ptr ) ; // never fail
2000-07-31 21:29:14 +02:00
}
* field_ptr = 0 ; // End marker
/* Fix key->name and key_part->field */
if ( key_parts )
{
2004-01-14 13:01:55 +01:00
uint primary_key = ( uint ) ( find_type ( ( char * ) primary_key_name ,
2005-01-06 12:00:13 +01:00
& share - > keynames , 3 ) - 1 ) ;
2002-04-12 20:35:46 +02:00
uint ha_option = outparam - > file - > table_flags ( ) ;
2000-07-31 21:29:14 +02:00
keyinfo = outparam - > key_info ;
key_part = keyinfo - > key_part ;
2005-01-06 12:00:13 +01:00
for ( uint key = 0 ; key < share - > keys ; key + + , keyinfo + + )
2000-07-31 21:29:14 +02:00
{
uint usable_parts = 0 ;
2005-01-06 12:00:13 +01:00
keyinfo - > name = ( char * ) share - > keynames . type_names [ key ] ;
2002-06-18 23:22:30 +02:00
/* Fix fulltext keys for old .frm files */
if ( outparam - > key_info [ key ] . flags & HA_FULLTEXT )
outparam - > key_info [ key ] . algorithm = HA_KEY_ALG_FULLTEXT ;
2006-06-30 17:29:27 +02:00
if ( primary_key > = MAX_KEY & & ( keyinfo - > flags & HA_NOSAME ) )
{
/*
If the UNIQUE key doesn ' t have NULL columns and is not a part key
declare this as a primary key .
*/
primary_key = key ;
for ( i = 0 ; i < keyinfo - > key_parts ; i + + )
{
uint fieldnr = key_part [ i ] . fieldnr ;
if ( ! fieldnr | |
outparam - > field [ fieldnr - 1 ] - > null_ptr | |
outparam - > field [ fieldnr - 1 ] - > key_length ( ) ! =
key_part [ i ] . length )
{
primary_key = MAX_KEY ; // Can't be used
break ;
}
}
}
2000-07-31 21:29:14 +02:00
for ( i = 0 ; i < keyinfo - > key_parts ; key_part + + , i + + )
{
if ( new_field_pack_flag < = 1 )
key_part - > fieldnr = ( uint16 ) find_field ( outparam ,
( uint ) key_part - > offset ,
( uint ) key_part - > length ) ;
# ifdef EXTRA_DEBUG
2005-01-06 12:00:13 +01:00
if ( key_part - > fieldnr > share - > fields )
2005-01-13 02:02:49 +01:00
goto err ; // sanity check
2000-07-31 21:29:14 +02:00
# endif
if ( key_part - > fieldnr )
{ // Should always be true !
Field * field = key_part - > field = outparam - > field [ key_part - > fieldnr - 1 ] ;
if ( field - > null_ptr )
{
key_part - > null_offset = ( uint ) ( ( byte * ) field - > null_ptr -
outparam - > record [ 0 ] ) ;
key_part - > null_bit = field - > null_bit ;
key_part - > store_length + = HA_KEY_NULL_LENGTH ;
keyinfo - > flags | = HA_NULL_PART_KEY ;
keyinfo - > extra_length + = HA_KEY_NULL_LENGTH ;
2001-03-06 14:24:08 +01:00
keyinfo - > key_length + = HA_KEY_NULL_LENGTH ;
2000-07-31 21:29:14 +02:00
}
if ( field - > type ( ) = = FIELD_TYPE_BLOB | |
2004-12-06 01:00:37 +01:00
field - > real_type ( ) = = MYSQL_TYPE_VARCHAR )
2000-07-31 21:29:14 +02:00
{
if ( field - > type ( ) = = FIELD_TYPE_BLOB )
key_part - > key_part_flag | = HA_BLOB_PART ;
2004-12-06 01:00:37 +01:00
else
key_part - > key_part_flag | = HA_VAR_LENGTH_PART ;
2000-07-31 21:29:14 +02:00
keyinfo - > extra_length + = HA_KEY_BLOB_LENGTH ;
key_part - > store_length + = HA_KEY_BLOB_LENGTH ;
2001-03-06 14:24:08 +01:00
keyinfo - > key_length + = HA_KEY_BLOB_LENGTH ;
2003-12-12 21:26:58 +01:00
/*
Mark that there may be many matching values for one key
combination ( ' a ' , ' a ' , ' a ' . . . )
*/
if ( ! ( field - > flags & BINARY_FLAG ) )
keyinfo - > flags | = HA_END_SPACE_KEY ;
2000-07-31 21:29:14 +02:00
}
2004-12-19 19:25:19 +01:00
if ( field - > type ( ) = = MYSQL_TYPE_BIT )
key_part - > key_part_flag | = HA_BIT_PART ;
2000-07-31 21:29:14 +02:00
if ( i = = 0 & & key ! = primary_key )
2005-06-22 21:46:21 +02:00
field - > flags | = ( ( keyinfo - > flags & HA_NOSAME ) & &
( keyinfo - > key_parts = = 1 ) ) ?
UNIQUE_KEY_FLAG : MULTIPLE_KEY_FLAG ;
2000-07-31 21:29:14 +02:00
if ( i = = 0 )
2003-10-11 13:06:55 +02:00
field - > key_start . set_bit ( key ) ;
2002-06-04 07:23:57 +02:00
if ( field - > key_length ( ) = = key_part - > length & &
2003-03-20 20:35:03 +01:00
! ( field - > flags & BLOB_FLAG ) )
2001-03-06 14:24:08 +01:00
{
2004-07-09 09:55:16 +02:00
if ( outparam - > file - > index_flags ( key , i , 0 ) & HA_KEYREAD_ONLY )
2004-06-30 10:40:15 +02:00
{
2005-01-06 12:00:13 +01:00
share - > keys_for_keyread . set_bit ( key ) ;
2003-10-11 13:06:55 +02:00
field - > part_of_key . set_bit ( key ) ;
2004-06-30 10:40:15 +02:00
}
2004-07-08 14:45:25 +02:00
if ( outparam - > file - > index_flags ( key , i , 1 ) & HA_READ_ORDER )
2003-10-11 13:06:55 +02:00
field - > part_of_sortkey . set_bit ( key ) ;
2001-03-06 14:24:08 +01:00
}
2000-07-31 21:29:14 +02:00
if ( ! ( key_part - > key_part_flag & HA_REVERSE_SORT ) & &
usable_parts = = i )
usable_parts + + ; // For FILESORT
field - > flags | = PART_KEY_FLAG ;
if ( key = = primary_key )
{
field - > flags | = PRI_KEY_FLAG ;
2001-09-21 02:38:35 +02:00
/*
If this field is part of the primary key and all keys contains
the primary key , then we can use any key to find this column
*/
2000-07-31 21:29:14 +02:00
if ( ha_option & HA_PRIMARY_KEY_IN_READ_INDEX )
2005-01-06 12:00:13 +01:00
field - > part_of_key = share - > keys_in_use ;
2000-07-31 21:29:14 +02:00
}
if ( field - > key_length ( ) ! = key_part - > length )
{
2005-05-25 17:33:36 +02:00
# ifndef TO_BE_DELETED_ON_PRODUCTION
if ( field - > type ( ) = = FIELD_TYPE_NEWDECIMAL )
{
/*
Fix a fatal error in decimal key handling that causes crashes
on Innodb . We fix it by reducing the key length so that
InnoDB never gets a too big key when searching .
This allows the end user to do an ALTER TABLE to fix the
error .
*/
keyinfo - > key_length - = ( key_part - > length - field - > key_length ( ) ) ;
2005-06-18 01:55:42 +02:00
key_part - > store_length - = ( uint16 ) ( key_part - > length -
field - > key_length ( ) ) ;
key_part - > length = ( uint16 ) field - > key_length ( ) ;
2005-05-25 17:33:36 +02:00
sql_print_error ( " Found wrong key definition in %s; Please do \" ALTER TABLE '%s' FORCE \" to fix it! " , name , share - > table_name ) ;
push_warning_printf ( thd , MYSQL_ERROR : : WARN_LEVEL_ERROR ,
ER_CRASHED_ON_USAGE ,
" Found wrong key definition in %s; Please do \" ALTER TABLE '%s' FORCE \" to fix it! " , name , share - > table_name ) ;
share - > crashed = 1 ; // Marker for CHECK TABLE
goto to_be_deleted ;
}
# endif
2003-12-12 21:26:58 +01:00
key_part - > key_part_flag | = HA_PART_KEY_SEG ;
2003-03-20 20:35:03 +01:00
if ( ! ( field - > flags & BLOB_FLAG ) )
2000-07-31 21:29:14 +02:00
{ // Create a new field
2001-12-05 12:03:00 +01:00
field = key_part - > field = field - > new_field ( & outparam - > mem_root ,
2006-06-26 20:57:18 +02:00
outparam ,
outparam = = field - > table ) ;
2000-07-31 21:29:14 +02:00
field - > field_length = key_part - > length ;
}
}
2005-05-25 17:33:36 +02:00
to_be_deleted :
2002-10-14 16:04:12 +02:00
/*
If the field can be NULL , don ' t optimize away the test
key_part_column = expression from the WHERE clause
as we need to test for NULL = NULL .
*/
if ( field - > real_maybe_null ( ) )
2003-12-12 21:26:58 +01:00
key_part - > key_part_flag | = HA_PART_KEY_SEG ;
2000-07-31 21:29:14 +02:00
}
else
{ // Error: shorten key
keyinfo - > key_parts = usable_parts ;
keyinfo - > flags = 0 ;
}
}
keyinfo - > usable_key_parts = usable_parts ; // Filesort
2004-12-31 10:56:50 +01:00
2005-01-06 12:00:13 +01:00
set_if_bigger ( share - > max_key_length , keyinfo - > key_length +
2004-12-31 10:56:50 +01:00
keyinfo - > key_parts ) ;
2005-01-06 12:00:13 +01:00
share - > total_key_length + = keyinfo - > key_length ;
2005-05-18 19:40:39 +02:00
/*
MERGE tables do not have unique indexes . But every key could be
an unique index on the underlying MyISAM table . ( Bug # 10400 )
*/
if ( ( keyinfo - > flags & HA_NOSAME ) | |
( ha_option & HA_ANY_INDEX_MAY_BE_UNIQUE ) )
2005-05-18 22:54:36 +02:00
set_if_bigger ( share - > max_unique_length , keyinfo - > key_length ) ;
2000-07-31 21:29:14 +02:00
}
2003-07-28 16:58:52 +02:00
if ( primary_key < MAX_KEY & &
2005-01-06 12:00:13 +01:00
( share - > keys_in_use . is_set ( primary_key ) ) )
2000-07-31 21:29:14 +02:00
{
2005-01-06 12:00:13 +01:00
share - > primary_key = primary_key ;
2000-10-16 01:29:48 +02:00
/*
If we are using an integer as the primary key then allow the user to
refer to it as ' _rowid '
*/
2000-07-31 21:29:14 +02:00
if ( outparam - > key_info [ primary_key ] . key_parts = = 1 )
{
Field * field = outparam - > key_info [ primary_key ] . key_part [ 0 ] . field ;
if ( field & & field - > result_type ( ) = = INT_RESULT )
outparam - > rowid_field = field ;
}
}
else
2005-01-06 12:00:13 +01:00
share - > primary_key = MAX_KEY ; // we do not have a primary key
2000-07-31 21:29:14 +02:00
}
2000-10-22 00:19:05 +02:00
else
2005-01-06 12:00:13 +01:00
share - > primary_key = MAX_KEY ;
2000-07-31 21:29:14 +02:00
x_free ( ( gptr ) disk_buff ) ;
2000-10-16 01:29:48 +02:00
disk_buff = 0 ;
2000-07-31 21:29:14 +02:00
if ( new_field_pack_flag < = 1 )
2005-01-06 12:00:13 +01:00
{
/* Old file format with default as not null */
uint null_length = ( share - > null_fields + 7 ) / 8 ;
bfill ( share - > default_values + ( outparam - > null_flags - ( uchar * ) record ) ,
null_length , 255 ) ;
2000-07-31 21:29:14 +02:00
}
2002-07-23 17:31:22 +02:00
if ( ( reg_field = outparam - > found_next_number_field ) )
{
2005-01-06 12:00:13 +01:00
if ( ( int ) ( share - > next_number_index = ( uint )
2002-07-23 17:31:22 +02:00
find_ref_key ( outparam , reg_field ,
2005-01-06 12:00:13 +01:00
& share - > next_number_key_offset ) ) < 0 )
2002-07-23 17:31:22 +02:00
{
reg_field - > unireg_check = Field : : NONE ; /* purecov: inspected */
outparam - > found_next_number_field = 0 ;
}
else
reg_field - > flags | = AUTO_INCREMENT_FLAG ;
}
2005-01-06 12:00:13 +01:00
if ( share - > blob_fields )
2000-07-31 21:29:14 +02:00
{
Field * * ptr ;
2005-01-06 12:00:13 +01:00
uint i , * save ;
2000-07-31 21:29:14 +02:00
2005-01-06 12:00:13 +01:00
/* Store offsets to blob fields to find them fast */
if ( ! ( share - > blob_field = save =
( uint * ) alloc_root ( & outparam - > mem_root ,
( uint ) ( share - > blob_fields * sizeof ( uint ) ) ) ) )
2005-01-13 02:02:49 +01:00
goto err ;
2005-01-06 12:00:13 +01:00
for ( i = 0 , ptr = outparam - > field ; * ptr ; ptr + + , i + + )
2000-07-31 21:29:14 +02:00
{
if ( ( * ptr ) - > flags & BLOB_FLAG )
2005-01-06 12:00:13 +01:00
( * save + + ) = i ;
2000-07-31 21:29:14 +02:00
}
}
2005-10-08 02:37:23 +02:00
/*
the correct null_bytes can now be set , since bitfields have been taken
into account
*/
share - > null_bytes = ( null_pos - ( uchar * ) outparam - > null_flags +
( null_bit_pos + 7 ) / 8 ) ;
2005-10-04 17:04:20 +02:00
share - > last_null_bit_pos = null_bit_pos ;
2005-09-19 15:52:57 +02:00
2004-10-07 00:45:06 +02:00
/* The table struct is now initialized; Open the table */
2000-10-16 01:29:48 +02:00
error = 2 ;
if ( db_stat )
{
2005-01-13 02:02:49 +01:00
int ha_err ;
2004-03-10 12:46:11 +01:00
unpack_filename ( index_file , index_file ) ;
2005-01-13 02:02:49 +01:00
if ( ( ha_err = ( outparam - > file - >
ha_open ( index_file ,
( db_stat & HA_READ_ONLY ? O_RDONLY : O_RDWR ) ,
( db_stat & HA_OPEN_TEMPORARY ? HA_OPEN_TMP_TABLE :
( ( db_stat & HA_WAIT_IF_LOCKED ) | |
( specialflag & SPECIAL_WAIT_IF_LOCKED ) ) ?
HA_OPEN_WAIT_IF_LOCKED :
( db_stat & ( HA_ABORT_IF_LOCKED | HA_GET_INFO ) ) ?
HA_OPEN_ABORT_IF_LOCKED :
HA_OPEN_IGNORE_IF_LOCKED ) | ha_open_flags ) ) ) )
2000-10-16 01:29:48 +02:00
{
/* Set a flag if the table is crashed and it can be auto. repaired */
2005-01-13 02:02:49 +01:00
share - > crashed = ( ( ha_err = = HA_ERR_CRASHED_ON_USAGE ) & &
2005-01-06 12:00:13 +01:00
outparam - > file - > auto_repair ( ) & &
! ( ha_open_flags & HA_OPEN_FOR_REPAIR ) ) ;
2004-09-13 14:46:38 +02:00
2005-01-13 02:02:49 +01:00
if ( ha_err = = HA_ERR_NO_SUCH_TABLE )
2004-09-13 14:46:38 +02:00
{
/* The table did not exists in storage engine, use same error message
as if the . frm file didn ' t exist */
error = 1 ;
my_errno = ENOENT ;
}
2004-12-23 20:11:38 +01:00
else
{
2005-01-13 02:02:49 +01:00
outparam - > file - > print_error ( ha_err , MYF ( 0 ) ) ;
2004-12-23 20:11:38 +01:00
error_reported = TRUE ;
}
2005-01-13 02:02:49 +01:00
goto err ; /* purecov: inspected */
2000-10-16 01:29:48 +02:00
}
}
2005-01-06 12:00:13 +01:00
share - > db_low_byte_first = outparam - > file - > low_byte_first ( ) ;
2000-10-16 01:29:48 +02:00
2004-11-08 00:13:54 +01:00
* root_ptr = old_root ;
2004-09-17 02:08:23 +02:00
thd - > status_var . opened_tables + + ;
2000-07-31 21:29:14 +02:00
# ifndef DBUG_OFF
if ( use_hash )
2005-01-06 12:00:13 +01:00
( void ) hash_check ( & share - > name_hash ) ;
2000-07-31 21:29:14 +02:00
# endif
DBUG_RETURN ( 0 ) ;
2005-01-13 02:02:49 +01:00
err :
2000-07-31 21:29:14 +02:00
x_free ( ( gptr ) disk_buff ) ;
2000-10-16 01:29:48 +02:00
if ( file > 0 )
VOID ( my_close ( file , MYF ( MY_WME ) ) ) ;
2000-07-31 21:29:14 +02:00
delete crypted ;
2004-11-08 00:13:54 +01:00
* root_ptr = old_root ;
2004-12-23 20:11:38 +01:00
if ( ! error_reported )
2004-12-31 15:26:24 +01:00
frm_error ( error , outparam , name , ME_ERROR + ME_WAITTANG , errarg ) ;
2000-10-10 23:06:37 +02:00
delete outparam - > file ;
2004-10-07 00:45:06 +02:00
outparam - > file = 0 ; // For easier errorchecking
2000-11-21 02:43:34 +01:00
outparam - > db_stat = 0 ;
2005-01-06 12:00:13 +01:00
hash_free ( & share - > name_hash ) ;
2005-01-13 02:02:49 +01:00
free_root ( & outparam - > mem_root , MYF ( 0 ) ) ; // Safe to call on bzero'd root
2005-01-06 12:00:13 +01:00
my_free ( ( char * ) outparam - > alias , MYF ( MY_ALLOW_ZERO_PTR ) ) ;
2000-07-31 21:29:14 +02:00
DBUG_RETURN ( error ) ;
} /* openfrm */
/* close a .frm file and it's tables */
int closefrm ( register TABLE * table )
{
int error = 0 ;
DBUG_ENTER ( " closefrm " ) ;
if ( table - > db_stat )
error = table - > file - > close ( ) ;
2005-01-06 12:00:13 +01:00
my_free ( ( char * ) table - > alias , MYF ( MY_ALLOW_ZERO_PTR ) ) ;
table - > alias = 0 ;
if ( table - > field )
2000-07-31 21:29:14 +02:00
{
for ( Field * * ptr = table - > field ; * ptr ; ptr + + )
delete * ptr ;
2005-01-06 12:00:13 +01:00
table - > field = 0 ;
2000-07-31 21:29:14 +02:00
}
delete table - > file ;
2005-01-06 12:00:13 +01:00
table - > file = 0 ; /* For easier errorchecking */
hash_free ( & table - > s - > name_hash ) ;
free_root ( & table - > mem_root , MYF ( 0 ) ) ;
2000-07-31 21:29:14 +02:00
DBUG_RETURN ( error ) ;
}
/* Deallocate temporary blob storage */
void free_blobs ( register TABLE * table )
{
2005-01-06 12:00:13 +01:00
uint * ptr , * end ;
for ( ptr = table - > s - > blob_field , end = ptr + table - > s - > blob_fields ;
ptr ! = end ;
ptr + + )
( ( Field_blob * ) table - > field [ * ptr ] ) - > free ( ) ;
2000-07-31 21:29:14 +02:00
}
/* Find where a form starts */
/* if formname is NullS then only formnames is read */
ulong get_form_pos ( File file , uchar * head , TYPELIB * save_names )
{
uint a_length , names , length ;
uchar * pos , * buf ;
ulong ret_value = 0 ;
DBUG_ENTER ( " get_form_pos " ) ;
names = uint2korr ( head + 8 ) ;
a_length = ( names + 2 ) * sizeof ( my_string ) ; /* Room for two extra */
if ( ! save_names )
a_length = 0 ;
else
save_names - > type_names = 0 ; /* Clear if error */
if ( names )
{
length = uint2korr ( head + 4 ) ;
VOID ( my_seek ( file , 64L , MY_SEEK_SET , MYF ( 0 ) ) ) ;
if ( ! ( buf = ( uchar * ) my_malloc ( ( uint ) length + a_length + names * 4 ,
MYF ( MY_WME ) ) ) | |
my_read ( file , ( byte * ) buf + a_length , ( uint ) ( length + names * 4 ) ,
MYF ( MY_NABP ) ) )
{ /* purecov: inspected */
x_free ( ( gptr ) buf ) ; /* purecov: inspected */
DBUG_RETURN ( 0L ) ; /* purecov: inspected */
}
pos = buf + a_length + length ;
ret_value = uint4korr ( pos ) ;
}
if ( ! save_names )
2006-01-03 17:54:54 +01:00
{
if ( names )
my_free ( ( gptr ) buf , MYF ( 0 ) ) ;
}
2000-07-31 21:29:14 +02:00
else if ( ! names )
bzero ( ( char * ) save_names , sizeof ( save_names ) ) ;
else
{
char * str ;
str = ( char * ) ( buf + a_length ) ;
fix_type_pointers ( ( const char * * * ) & buf , save_names , 1 , & str ) ;
}
DBUG_RETURN ( ret_value ) ;
}
/* Read string from a file with malloc */
int read_string ( File file , gptr * to , uint length )
{
DBUG_ENTER ( " read_string " ) ;
x_free ( ( gptr ) * to ) ;
if ( ! ( * to = ( gptr ) my_malloc ( length + 1 , MYF ( MY_WME ) ) ) | |
my_read ( file , ( byte * ) * to , length , MYF ( MY_NABP ) ) )
{
x_free ( ( gptr ) * to ) ; /* purecov: inspected */
* to = 0 ; /* purecov: inspected */
DBUG_RETURN ( 1 ) ; /* purecov: inspected */
}
* ( ( char * ) * to + length ) = ' \0 ' ;
DBUG_RETURN ( 0 ) ;
} /* read_string */
/* Add a new form to a form file */
ulong make_new_entry ( File file , uchar * fileinfo , TYPELIB * formnames ,
const char * newname )
{
uint i , bufflength , maxlength , n_length , length , names ;
ulong endpos , newpos ;
char buff [ IO_SIZE ] ;
uchar * pos ;
DBUG_ENTER ( " make_new_entry " ) ;
2000-08-21 23:18:32 +02:00
length = ( uint ) strlen ( newname ) + 1 ;
2000-07-31 21:29:14 +02:00
n_length = uint2korr ( fileinfo + 4 ) ;
maxlength = uint2korr ( fileinfo + 6 ) ;
names = uint2korr ( fileinfo + 8 ) ;
newpos = uint4korr ( fileinfo + 10 ) ;
if ( 64 + length + n_length + ( names + 1 ) * 4 > maxlength )
{ /* Expand file */
newpos + = IO_SIZE ;
int4store ( fileinfo + 10 , newpos ) ;
2000-08-21 23:18:32 +02:00
endpos = ( ulong ) my_seek ( file , 0L , MY_SEEK_END , MYF ( 0 ) ) ; /* Copy from file-end */
2000-07-31 21:29:14 +02:00
bufflength = ( uint ) ( endpos & ( IO_SIZE - 1 ) ) ; /* IO_SIZE is a power of 2 */
while ( endpos > maxlength )
{
VOID ( my_seek ( file , ( ulong ) ( endpos - bufflength ) , MY_SEEK_SET , MYF ( 0 ) ) ) ;
if ( my_read ( file , ( byte * ) buff , bufflength , MYF ( MY_NABP + MY_WME ) ) )
DBUG_RETURN ( 0L ) ;
VOID ( my_seek ( file , ( ulong ) ( endpos - bufflength + IO_SIZE ) , MY_SEEK_SET ,
MYF ( 0 ) ) ) ;
if ( ( my_write ( file , ( byte * ) buff , bufflength , MYF ( MY_NABP + MY_WME ) ) ) )
DBUG_RETURN ( 0 ) ;
endpos - = bufflength ; bufflength = IO_SIZE ;
}
bzero ( buff , IO_SIZE ) ; /* Null new block */
VOID ( my_seek ( file , ( ulong ) maxlength , MY_SEEK_SET , MYF ( 0 ) ) ) ;
if ( my_write ( file , ( byte * ) buff , bufflength , MYF ( MY_NABP + MY_WME ) ) )
DBUG_RETURN ( 0L ) ;
maxlength + = IO_SIZE ; /* Fix old ref */
int2store ( fileinfo + 6 , maxlength ) ;
for ( i = names , pos = ( uchar * ) * formnames - > type_names + n_length - 1 ; i - - ;
pos + = 4 )
{
endpos = uint4korr ( pos ) + IO_SIZE ;
int4store ( pos , endpos ) ;
}
}
if ( n_length = = 1 )
{ /* First name */
length + + ;
VOID ( strxmov ( buff , " / " , newname , " / " , NullS ) ) ;
}
else
VOID ( strxmov ( buff , newname , " / " , NullS ) ) ; /* purecov: inspected */
VOID ( my_seek ( file , 63L + ( ulong ) n_length , MY_SEEK_SET , MYF ( 0 ) ) ) ;
if ( my_write ( file , ( byte * ) buff , ( uint ) length + 1 , MYF ( MY_NABP + MY_WME ) ) | |
( names & & my_write ( file , ( byte * ) ( * formnames - > type_names + n_length - 1 ) ,
names * 4 , MYF ( MY_NABP + MY_WME ) ) ) | |
my_write ( file , ( byte * ) fileinfo + 10 , ( uint ) 4 , MYF ( MY_NABP + MY_WME ) ) )
DBUG_RETURN ( 0L ) ; /* purecov: inspected */
int2store ( fileinfo + 8 , names + 1 ) ;
int2store ( fileinfo + 4 , n_length + length ) ;
2002-08-08 02:12:02 +02:00
VOID ( my_chsize ( file , newpos , 0 , MYF ( MY_WME ) ) ) ; /* Append file with '\0' */
2000-07-31 21:29:14 +02:00
DBUG_RETURN ( newpos ) ;
} /* make_new_entry */
/* error message when opening a form file */
2004-12-22 15:56:57 +01:00
static void frm_error ( int error , TABLE * form , const char * name ,
myf errortype , int errarg )
2000-07-31 21:29:14 +02:00
{
int err_no ;
char buff [ FN_REFLEN ] ;
const char * form_dev = " " , * datext ;
2005-01-06 12:00:13 +01:00
const char * real_name = ( char * ) name + dirname_length ( name ) ;
2000-07-31 21:29:14 +02:00
DBUG_ENTER ( " frm_error " ) ;
switch ( error ) {
case 1 :
if ( my_errno = = ENOENT )
{
char * db ;
uint length = dirname_part ( buff , name ) ;
buff [ length - 1 ] = 0 ;
db = buff + dirname_length ( buff ) ;
2005-01-06 12:00:13 +01:00
my_error ( ER_NO_SUCH_TABLE , MYF ( 0 ) , db , real_name ) ;
2000-07-31 21:29:14 +02:00
}
else
2006-01-19 11:35:27 +01:00
my_error ( ( my_errno = = EMFILE ) ? ER_CANT_OPEN_FILE : ER_FILE_NOT_FOUND ,
errortype ,
2004-11-13 18:35:51 +01:00
fn_format ( buff , name , form_dev , reg_ext , 0 ) , my_errno ) ;
2000-07-31 21:29:14 +02:00
break ;
case 2 :
{
2004-04-15 09:14:14 +02:00
datext = form - > file ? * form - > file - > bas_ext ( ) : " " ;
datext = datext = = NullS ? " " : datext ;
2000-07-31 21:29:14 +02:00
err_no = ( my_errno = = ENOENT ) ? ER_FILE_NOT_FOUND : ( my_errno = = EAGAIN ) ?
ER_FILE_USED : ER_CANT_OPEN_FILE ;
my_error ( err_no , errortype ,
2005-01-06 12:00:13 +01:00
fn_format ( buff , real_name , form_dev , datext , 2 ) , my_errno ) ;
2000-07-31 21:29:14 +02:00
break ;
}
2004-12-22 15:56:57 +01:00
case 5 :
{
const char * csname = get_charset_name ( ( uint ) errarg ) ;
char tmp [ 10 ] ;
if ( ! csname | | csname [ 0 ] = = ' ? ' )
{
my_snprintf ( tmp , sizeof ( tmp ) , " #%d " , errarg ) ;
csname = tmp ;
}
my_printf_error ( ER_UNKNOWN_COLLATION ,
" Unknown collation '%s' in table '%-.64s' definition " ,
2005-01-06 12:00:13 +01:00
MYF ( 0 ) , csname , real_name ) ;
2000-07-31 21:29:14 +02:00
break ;
}
2005-05-07 22:57:22 +02:00
case 6 :
my_printf_error ( ER_NOT_FORM_FILE ,
" Table '%-.64s' was created with a different version "
" of MySQL and cannot be read " ,
MYF ( 0 ) , name ) ;
break ;
2000-07-31 21:29:14 +02:00
default : /* Better wrong error than none */
case 4 :
2004-11-13 18:35:51 +01:00
my_error ( ER_NOT_FORM_FILE , errortype ,
fn_format ( buff , name , form_dev , reg_ext , 0 ) ) ;
2000-07-31 21:29:14 +02:00
break ;
}
DBUG_VOID_RETURN ;
} /* frm_error */
/*
* * fix a str_type to a array type
2004-10-07 00:45:06 +02:00
* * typeparts separated with some char . differents types are separated
2000-07-31 21:29:14 +02:00
* * with a ' \0 '
*/
static void
fix_type_pointers ( const char * * * array , TYPELIB * point_to_type , uint types ,
char * * names )
{
char * type_name , * ptr ;
char chr ;
ptr = * names ;
while ( types - - )
{
point_to_type - > name = 0 ;
point_to_type - > type_names = * array ;
if ( ( chr = * ptr ) ) /* Test if empty type */
{
while ( ( type_name = strchr ( ptr + 1 , chr ) ) ! = NullS )
{
* ( ( * array ) + + ) = ptr + 1 ;
* type_name = ' \0 ' ; /* End string */
ptr = type_name ;
}
2001-11-06 23:13:29 +01:00
ptr + = 2 ; /* Skip end mark and last 0 */
2000-07-31 21:29:14 +02:00
}
else
ptr + + ;
point_to_type - > count = ( uint ) ( * array - point_to_type - > type_names ) ;
point_to_type + + ;
* ( ( * array ) + + ) = NullS ; /* End of type */
}
* names = ptr ; /* Update end */
return ;
} /* fix_type_pointers */
2005-11-25 11:25:31 +01:00
TYPELIB * typelib ( MEM_ROOT * mem_root , List < String > & strings )
2000-07-31 21:29:14 +02:00
{
2005-11-25 11:25:31 +01:00
TYPELIB * result = ( TYPELIB * ) alloc_root ( mem_root , sizeof ( TYPELIB ) ) ;
2000-07-31 21:29:14 +02:00
if ( ! result )
return 0 ;
result - > count = strings . elements ;
result - > name = " " ;
2004-10-25 14:51:26 +02:00
uint nbytes = ( sizeof ( char * ) + sizeof ( uint ) ) * ( result - > count + 1 ) ;
2005-11-25 11:25:31 +01:00
if ( ! ( result - > type_names = ( const char * * ) alloc_root ( mem_root , nbytes ) ) )
2000-07-31 21:29:14 +02:00
return 0 ;
2004-10-25 14:51:26 +02:00
result - > type_lengths = ( uint * ) ( result - > type_names + result - > count + 1 ) ;
2000-07-31 21:29:14 +02:00
List_iterator < String > it ( strings ) ;
String * tmp ;
for ( uint i = 0 ; ( tmp = it + + ) ; i + + )
2004-10-25 14:51:26 +02:00
{
result - > type_names [ i ] = tmp - > ptr ( ) ;
result - > type_lengths [ i ] = tmp - > length ( ) ;
}
result - > type_names [ result - > count ] = 0 ; // End marker
result - > type_lengths [ result - > count ] = 0 ;
2000-07-31 21:29:14 +02:00
return result ;
}
2005-01-06 12:00:13 +01:00
/*
Search after a field with given start & length
If an exact field isn ' t found , return longest field with starts
at right position .
NOTES
This is needed because in some . frm fields ' fieldnr ' was saved wrong
RETURN
0 error
# field number +1
*/
2000-07-31 21:29:14 +02:00
static uint find_field ( TABLE * form , uint start , uint length )
{
Field * * field ;
2005-01-06 12:00:13 +01:00
uint i , pos , fields ;
2000-07-31 21:29:14 +02:00
pos = 0 ;
2005-01-06 12:00:13 +01:00
fields = form - > s - > fields ;
for ( field = form - > field , i = 1 ; i < = fields ; i + + , field + + )
2000-07-31 21:29:14 +02:00
{
if ( ( * field ) - > offset ( ) = = start )
{
if ( ( * field ) - > key_length ( ) = = length )
return ( i ) ;
if ( ! pos | | form - > field [ pos - 1 ] - > pack_length ( ) <
( * field ) - > pack_length ( ) )
pos = i ;
}
}
return ( pos ) ;
}
2004-10-07 00:45:06 +02:00
/* Check that the integer is in the internal */
2000-07-31 21:29:14 +02:00
int set_zone ( register int nr , int min_zone , int max_zone )
{
if ( nr < = min_zone )
return ( min_zone ) ;
if ( nr > = max_zone )
return ( max_zone ) ;
return ( nr ) ;
} /* set_zone */
/* Adjust number to next larger disk buffer */
ulong next_io_size ( register ulong pos )
{
reg2 ulong offset ;
if ( ( offset = pos & ( IO_SIZE - 1 ) ) )
return pos - offset + IO_SIZE ;
return pos ;
} /* next_io_size */
2003-12-16 14:39:33 +01:00
/*
Store an SQL quoted string .
SYNOPSIS
append_unescaped ( )
res result String
pos string to be quoted
length it ' s length
NOTE
This function works correctly with utf8 or single - byte charset strings .
May fail with some multibyte charsets though .
*/
2002-06-02 20:22:20 +02:00
2003-12-16 14:39:33 +01:00
void append_unescaped ( String * res , const char * pos , uint length )
2000-07-31 21:29:14 +02:00
{
2002-06-02 20:22:20 +02:00
const char * end = pos + length ;
res - > append ( ' \' ' ) ;
for ( ; pos ! = end ; pos + + )
2000-07-31 21:29:14 +02:00
{
2004-08-27 23:49:54 +02:00
# if defined(USE_MB) && MYSQL_VERSION_ID < 40100
2004-08-27 09:09:28 +02:00
uint mblen ;
if ( use_mb ( default_charset_info ) & &
( mblen = my_ismbchar ( default_charset_info , pos , end ) ) )
{
res - > append ( pos , mblen ) ;
pos + = mblen ;
continue ;
}
# endif
2000-07-31 21:29:14 +02:00
switch ( * pos ) {
case 0 : /* Must be escaped for 'mysql' */
res - > append ( ' \\ ' ) ;
res - > append ( ' 0 ' ) ;
break ;
case ' \n ' : /* Must be escaped for logs */
res - > append ( ' \\ ' ) ;
res - > append ( ' n ' ) ;
break ;
case ' \r ' :
2004-10-07 00:45:06 +02:00
res - > append ( ' \\ ' ) ; /* This gives better readability */
2000-07-31 21:29:14 +02:00
res - > append ( ' r ' ) ;
break ;
case ' \\ ' :
res - > append ( ' \\ ' ) ; /* Because of the sql syntax */
res - > append ( ' \\ ' ) ;
break ;
case ' \' ' :
res - > append ( ' \' ' ) ; /* Because of the sql syntax */
res - > append ( ' \' ' ) ;
break ;
default :
res - > append ( * pos ) ;
break ;
}
}
2002-06-02 20:22:20 +02:00
res - > append ( ' \' ' ) ;
2000-07-31 21:29:14 +02:00
}
/* Create a .frm file */
2005-07-28 16:09:54 +02:00
File create_frm ( THD * thd , my_string name , const char * db ,
const char * table , uint reclength , uchar * fileinfo ,
2000-07-31 21:29:14 +02:00
HA_CREATE_INFO * create_info , uint keys )
{
register File file ;
ulong length ;
char fill [ IO_SIZE ] ;
2005-03-03 19:51:29 +01:00
int create_flags = O_RDWR | O_TRUNC ;
if ( create_info - > options & HA_LEX_CREATE_TMP_TABLE )
create_flags | = O_EXCL | O_NOFOLLOW ;
2000-07-31 21:29:14 +02:00
2004-06-21 09:21:20 +02:00
/* Fix this when we have new .frm files; Current limit is 4G rows (QQ) */
2005-11-24 02:05:59 +01:00
if ( create_info - > max_rows > UINT_MAX32 )
create_info - > max_rows = UINT_MAX32 ;
if ( create_info - > min_rows > UINT_MAX32 )
create_info - > min_rows = UINT_MAX32 ;
2005-12-09 16:55:59 +01:00
2004-04-28 02:37:45 +02:00
/*
Ensure that raid_chunks can ' t be larger than 255 , as this would cause
problems with drop database
*/
set_if_smaller ( create_info - > raid_chunks , 255 ) ;
2000-07-31 21:29:14 +02:00
2005-07-22 05:08:54 +02:00
if ( ( file = my_create ( name , CREATE_MODE , create_flags , MYF ( 0 ) ) ) > = 0 )
2000-07-31 21:29:14 +02:00
{
2005-05-25 17:33:36 +02:00
uint key_length , tmp_key_length ;
uint tmp ;
2000-07-31 21:29:14 +02:00
bzero ( ( char * ) fileinfo , 64 ) ;
2004-12-06 01:00:37 +01:00
/* header */
fileinfo [ 0 ] = ( uchar ) 254 ;
fileinfo [ 1 ] = 1 ;
fileinfo [ 2 ] = FRM_VER + 3 + test ( create_info - > varchar ) ;
2005-06-17 23:14:44 +02:00
fileinfo [ 3 ] = ( uchar ) ha_checktype ( thd , create_info - > db_type , 0 , 0 ) ;
2000-07-31 21:29:14 +02:00
fileinfo [ 4 ] = 1 ;
int2store ( fileinfo + 6 , IO_SIZE ) ; /* Next block starts here */
key_length = keys * ( 7 + NAME_LEN + MAX_REF_PARTS * 9 ) + 16 ;
2005-10-10 20:01:45 +02:00
length = next_io_size ( ( ulong ) ( IO_SIZE + key_length + reclength +
create_info - > extra_size ) ) ;
2000-07-31 21:29:14 +02:00
int4store ( fileinfo + 10 , length ) ;
2005-05-25 17:33:36 +02:00
tmp_key_length = ( key_length < 0xffff ) ? key_length : 0xffff ;
int2store ( fileinfo + 14 , tmp_key_length ) ;
2000-07-31 21:29:14 +02:00
int2store ( fileinfo + 16 , reclength ) ;
int4store ( fileinfo + 18 , create_info - > max_rows ) ;
int4store ( fileinfo + 22 , create_info - > min_rows ) ;
fileinfo [ 27 ] = 2 ; // Use long pack-fields
create_info - > table_options | = HA_OPTION_LONG_BLOB_PTR ; // Use portable blob pointers
int2store ( fileinfo + 30 , create_info - > table_options ) ;
fileinfo [ 32 ] = 0 ; // No filename anymore
2005-03-22 14:48:06 +01:00
fileinfo [ 33 ] = 5 ; // Mark for 5.0 frm file
2000-07-31 21:29:14 +02:00
int4store ( fileinfo + 34 , create_info - > avg_row_length ) ;
2003-11-18 12:47:27 +01:00
fileinfo [ 38 ] = ( create_info - > default_table_charset ?
create_info - > default_table_charset - > number : 0 ) ;
2000-07-31 21:29:14 +02:00
fileinfo [ 40 ] = ( uchar ) create_info - > row_type ;
fileinfo [ 41 ] = ( uchar ) create_info - > raid_type ;
fileinfo [ 42 ] = ( uchar ) create_info - > raid_chunks ;
int4store ( fileinfo + 43 , create_info - > raid_chunksize ) ;
2005-05-25 17:33:36 +02:00
int4store ( fileinfo + 47 , key_length ) ;
tmp = MYSQL_VERSION_ID ; // Store to avoid warning from int4store
int4store ( fileinfo + 51 , tmp ) ;
2005-10-10 20:01:45 +02:00
int2store ( fileinfo + 55 , create_info - > extra_size ) ;
2000-07-31 21:29:14 +02:00
bzero ( fill , IO_SIZE ) ;
for ( ; length > IO_SIZE ; length - = IO_SIZE )
{
if ( my_write ( file , ( byte * ) fill , IO_SIZE , MYF ( MY_WME | MY_NABP ) ) )
{
VOID ( my_close ( file , MYF ( 0 ) ) ) ;
VOID ( my_delete ( name , MYF ( 0 ) ) ) ;
return ( - 1 ) ;
}
}
}
2005-07-22 05:08:54 +02:00
else
{
if ( my_errno = = ENOENT )
my_error ( ER_BAD_DB_ERROR , MYF ( 0 ) , db ) ;
else
my_error ( ER_CANT_CREATE_TABLE , MYF ( 0 ) , table , my_errno ) ;
}
2000-07-31 21:29:14 +02:00
return ( file ) ;
} /* create_frm */
void update_create_info_from_table ( HA_CREATE_INFO * create_info , TABLE * table )
{
2005-01-06 12:00:13 +01:00
TABLE_SHARE * share = table - > s ;
2001-09-30 04:47:35 +02:00
DBUG_ENTER ( " update_create_info_from_table " ) ;
2005-01-06 12:00:13 +01:00
create_info - > max_rows = share - > max_rows ;
create_info - > min_rows = share - > min_rows ;
create_info - > table_options = share - > db_create_options ;
create_info - > avg_row_length = share - > avg_row_length ;
create_info - > row_type = share - > row_type ;
create_info - > raid_type = share - > raid_type ;
create_info - > raid_chunks = share - > raid_chunks ;
create_info - > raid_chunksize = share - > raid_chunksize ;
create_info - > default_table_charset = share - > table_charset ;
2003-11-18 12:47:27 +01:00
create_info - > table_charset = 0 ;
2005-01-06 12:00:13 +01:00
2001-09-30 04:47:35 +02:00
DBUG_VOID_RETURN ;
2001-12-06 13:10:51 +01:00
}
2000-07-31 21:29:14 +02:00
int
rename_file_ext ( const char * from , const char * to , const char * ext )
{
char from_b [ FN_REFLEN ] , to_b [ FN_REFLEN ] ;
VOID ( strxmov ( from_b , from , ext , NullS ) ) ;
VOID ( strxmov ( to_b , to , ext , NullS ) ) ;
return ( my_rename ( from_b , to_b , MYF ( MY_WME ) ) ) ;
}
2003-05-29 23:47:31 +02:00
/*
Allocate string field in MEM_ROOT and return it as String
SYNOPSIS
get_field ( )
mem MEM_ROOT for allocating
field Field for retrieving of string
res result String
RETURN VALUES
2003-08-19 15:00:12 +02:00
1 string is empty
0 all ok
2003-05-29 23:47:31 +02:00
*/
bool get_field ( MEM_ROOT * mem , Field * field , String * res )
{
2003-08-19 15:00:12 +02:00
char buff [ MAX_FIELD_WIDTH ] , * to ;
2003-05-29 23:47:31 +02:00
String str ( buff , sizeof ( buff ) , & my_charset_bin ) ;
2003-08-19 15:00:12 +02:00
uint length ;
2004-04-06 21:35:26 +02:00
field - > val_str ( & str ) ;
2003-08-19 15:00:12 +02:00
if ( ! ( length = str . length ( ) ) )
2005-03-15 15:07:28 +01:00
{
res - > length ( 0 ) ;
2003-08-19 15:00:12 +02:00
return 1 ;
2005-03-15 15:07:28 +01:00
}
if ( ! ( to = strmake_root ( mem , str . ptr ( ) , length ) ) )
length = 0 ; // Safety fix
2003-08-19 15:00:12 +02:00
res - > set ( to , length , ( ( Field_str * ) field ) - > charset ( ) ) ;
return 0 ;
2003-05-29 23:47:31 +02:00
}
2003-08-19 15:00:12 +02:00
2000-07-31 21:29:14 +02:00
/*
2003-02-12 20:55:37 +01:00
Allocate string field in MEM_ROOT and return it as NULL - terminated string
SYNOPSIS
get_field ( )
mem MEM_ROOT for allocating
field Field for retrieving of string
RETURN VALUES
NullS string is empty
# pointer to NULL-terminated string value of field
2000-07-31 21:29:14 +02:00
*/
2003-02-12 20:55:37 +01:00
char * get_field ( MEM_ROOT * mem , Field * field )
2000-07-31 21:29:14 +02:00
{
2003-12-19 15:25:50 +01:00
char buff [ MAX_FIELD_WIDTH ] , * to ;
2003-03-07 10:39:53 +01:00
String str ( buff , sizeof ( buff ) , & my_charset_bin ) ;
2003-08-19 15:00:12 +02:00
uint length ;
2004-04-06 21:35:26 +02:00
field - > val_str ( & str ) ;
2003-12-19 15:25:50 +01:00
length = str . length ( ) ;
2003-12-09 20:49:48 +01:00
if ( ! length | | ! ( to = ( char * ) alloc_root ( mem , length + 1 ) ) )
2000-07-31 21:29:14 +02:00
return NullS ;
memcpy ( to , str . ptr ( ) , ( uint ) length ) ;
to [ length ] = 0 ;
return to ;
}
2003-01-29 17:56:34 +01:00
/*
Check if database name is valid
SYNPOSIS
check_db_name ( )
name Name of database
NOTES
If lower_case_table_names is set then database is converted to lower case
RETURN
0 ok
1 error
*/
bool check_db_name ( char * name )
2000-07-31 21:29:14 +02:00
{
2006-08-30 12:56:17 +02:00
uint name_length = 0 ; // name length in symbols
2004-03-16 21:41:30 +01:00
/* Used to catch empty names and names with end space */
bool last_char_is_space = TRUE ;
2003-01-29 17:56:34 +01:00
2004-04-06 12:31:25 +02:00
if ( lower_case_table_names & & name ! = any_db )
2003-02-07 14:47:24 +01:00
my_casedn_str ( files_charset_info , name ) ;
2003-01-29 17:56:34 +01:00
2000-07-31 21:29:14 +02:00
while ( * name )
{
# if defined(USE_MB) && defined(USE_MB_IDENT)
2006-03-20 11:43:02 +01:00
last_char_is_space = my_isspace ( system_charset_info , * name ) ;
2002-03-12 18:37:58 +01:00
if ( use_mb ( system_charset_info ) )
2000-07-31 21:29:14 +02:00
{
2002-03-12 18:37:58 +01:00
int len = my_ismbchar ( system_charset_info , name ,
2004-12-06 01:00:37 +01:00
name + system_charset_info - > mbmaxlen ) ;
2000-07-31 21:29:14 +02:00
if ( len )
{
2006-08-30 12:56:17 +02:00
name_length + + ;
2000-07-31 21:29:14 +02:00
name + = len ;
continue ;
}
}
2004-03-05 19:13:33 +01:00
# else
2004-03-12 14:55:33 +01:00
last_char_is_space = * name = = ' ' ;
2000-07-31 21:29:14 +02:00
# endif
2006-08-30 12:56:17 +02:00
name_length + + ;
2002-06-30 17:57:21 +02:00
if ( * name = = ' / ' | | * name = = ' \\ ' | | * name = = FN_LIBCHAR | |
* name = = FN_EXTCHAR )
2000-07-31 21:29:14 +02:00
return 1 ;
name + + ;
}
2006-08-30 12:56:17 +02:00
return ( last_char_is_space | | name_length > NAME_LEN ) ;
2000-07-31 21:29:14 +02:00
}
/*
Allow anything as a table name , as long as it doesn ' t contain an
a ' / ' , or a ' . ' character
2004-03-05 19:13:33 +01:00
or ' ' at the end
2000-07-31 21:29:14 +02:00
returns 1 on error
*/
bool check_table_name ( const char * name , uint length )
{
const char * end = name + length ;
2003-03-14 16:08:42 +01:00
if ( ! length | | length > NAME_LEN )
return 1 ;
2004-03-05 19:13:33 +01:00
# if defined(USE_MB) && defined(USE_MB_IDENT)
2004-03-12 14:55:33 +01:00
bool last_char_is_space = FALSE ;
2004-03-05 19:13:33 +01:00
# else
if ( name [ length - 1 ] = = ' ' )
return 1 ;
# endif
2000-07-31 21:29:14 +02:00
while ( name ! = end )
{
# if defined(USE_MB) && defined(USE_MB_IDENT)
2006-03-20 11:43:02 +01:00
last_char_is_space = my_isspace ( system_charset_info , * name ) ;
2002-03-12 18:37:58 +01:00
if ( use_mb ( system_charset_info ) )
2000-07-31 21:29:14 +02:00
{
2002-03-12 18:37:58 +01:00
int len = my_ismbchar ( system_charset_info , name , end ) ;
2000-07-31 21:29:14 +02:00
if ( len )
{
name + = len ;
continue ;
}
}
# endif
2003-03-17 18:06:14 +01:00
if ( * name = = ' / ' | | * name = = ' \\ ' | | * name = = FN_EXTCHAR )
2000-07-31 21:29:14 +02:00
return 1 ;
name + + ;
}
2004-03-05 19:13:33 +01:00
# if defined(USE_MB) && defined(USE_MB_IDENT)
2004-03-12 14:55:33 +01:00
return last_char_is_space ;
# else
2000-07-31 21:29:14 +02:00
return 0 ;
2004-03-12 14:55:33 +01:00
# endif
2000-07-31 21:29:14 +02:00
}
2004-03-12 14:56:28 +01:00
2000-07-31 21:29:14 +02:00
bool check_column_name ( const char * name )
{
2003-03-14 16:08:42 +01:00
const char * start = name ;
2004-03-16 21:41:30 +01:00
bool last_char_is_space = TRUE ;
2004-03-12 14:55:33 +01:00
2000-07-31 21:29:14 +02:00
while ( * name )
{
# if defined(USE_MB) && defined(USE_MB_IDENT)
2006-03-20 11:43:02 +01:00
last_char_is_space = my_isspace ( system_charset_info , * name ) ;
2002-03-12 18:37:58 +01:00
if ( use_mb ( system_charset_info ) )
2000-07-31 21:29:14 +02:00
{
2002-03-12 18:37:58 +01:00
int len = my_ismbchar ( system_charset_info , name ,
2004-12-06 01:00:37 +01:00
name + system_charset_info - > mbmaxlen ) ;
2000-07-31 21:29:14 +02:00
if ( len )
{
name + = len ;
continue ;
}
}
2004-03-05 19:13:33 +01:00
# else
2004-03-12 14:55:33 +01:00
last_char_is_space = * name = = ' ' ;
2000-07-31 21:29:14 +02:00
# endif
if ( * name = = NAMES_SEP_CHAR )
return 1 ;
name + + ;
}
2003-03-14 16:08:42 +01:00
/* Error if empty or too long column name */
2004-03-16 21:41:30 +01:00
return last_char_is_space | | ( uint ) ( name - start ) > NAME_LEN ;
2000-07-31 21:29:14 +02:00
}
/*
2005-09-22 00:11:21 +02:00
Create Item_field for each column in the table .
SYNPOSIS
st_table : : fill_item_list ( )
item_list a pointer to an empty list used to store items
DESCRIPTION
Create Item_field object for each column in the table and
initialize it with the corresponding Field . New items are
created in the current THD memory root .
RETURN VALUE
0 success
1 out of memory
*/
bool st_table : : fill_item_list ( List < Item > * item_list ) const
{
/*
All Item_field ' s created using a direct pointer to a field
are fixed in Item_field constructor .
*/
for ( Field * * ptr = field ; * ptr ; ptr + + )
{
Item_field * item = new Item_field ( * ptr ) ;
if ( ! item | | item_list - > push_back ( item ) )
return TRUE ;
}
return FALSE ;
}
/*
Reset an existing list of Item_field items to point to the
Fields of this table .
SYNPOSIS
st_table : : fill_item_list ( )
item_list a non - empty list with Item_fields
DESCRIPTION
This is a counterpart of fill_item_list used to redirect
Item_fields to the fields of a newly created table .
The caller must ensure that number of items in the item_list
is the same as the number of columns in the table .
*/
void st_table : : reset_item_list ( List < Item > * item_list ) const
{
List_iterator_fast < Item > it ( * item_list ) ;
for ( Field * * ptr = field ; * ptr ; ptr + + )
{
Item_field * item_field = ( Item_field * ) it + + ;
DBUG_ASSERT ( item_field ! = 0 ) ;
item_field - > reset_field ( * ptr ) ;
}
}
2000-07-31 21:29:14 +02:00
2004-07-16 00:15:55 +02:00
/*
calculate md5 of query
SYNOPSIS
st_table_list : : calc_md5 ( )
buffer buffer for md5 writing
*/
2004-09-03 20:43:04 +02:00
2004-07-16 00:15:55 +02:00
void st_table_list : : calc_md5 ( char * buffer )
{
my_MD5_CTX context ;
2004-09-03 20:43:04 +02:00
uchar digest [ 16 ] ;
my_MD5Init ( & context ) ;
my_MD5Update ( & context , ( uchar * ) query . str , query . length ) ;
my_MD5Final ( digest , & context ) ;
2004-07-16 00:15:55 +02:00
sprintf ( ( char * ) buffer ,
" %02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x " ,
digest [ 0 ] , digest [ 1 ] , digest [ 2 ] , digest [ 3 ] ,
digest [ 4 ] , digest [ 5 ] , digest [ 6 ] , digest [ 7 ] ,
digest [ 8 ] , digest [ 9 ] , digest [ 10 ] , digest [ 11 ] ,
digest [ 12 ] , digest [ 13 ] , digest [ 14 ] , digest [ 15 ] ) ;
}
/*
2005-10-27 23:18:23 +02:00
set underlying TABLE for table place holder of VIEW
2004-07-16 00:15:55 +02:00
2005-02-23 17:51:10 +01:00
DESCRIPTION
Replace all views that only uses one table with the table itself .
This allows us to treat the view as a simple table and even update
2005-10-27 23:18:23 +02:00
it ( it is a kind of optimisation )
2005-02-23 17:51:10 +01:00
2004-07-16 00:15:55 +02:00
SYNOPSIS
2005-10-27 23:18:23 +02:00
st_table_list : : set_underlying_merge ( )
2004-07-16 00:15:55 +02:00
*/
2004-09-03 20:43:04 +02:00
2005-10-27 23:18:23 +02:00
void st_table_list : : set_underlying_merge ( )
2004-07-16 00:15:55 +02:00
{
2005-02-23 17:51:10 +01:00
TABLE_LIST * tbl ;
2005-10-27 23:18:23 +02:00
if ( ( tbl = merge_underlying_list ) )
2004-11-21 19:08:12 +01:00
{
2005-02-23 17:51:10 +01:00
/* This is a view. Process all tables of view */
2005-10-27 23:18:23 +02:00
DBUG_ASSERT ( view & & effective_algorithm = = VIEW_ALGORITHM_MERGE ) ;
2005-02-23 17:51:10 +01:00
do
{
2005-10-27 23:18:23 +02:00
if ( tbl - > merge_underlying_list ) // This is a view
2005-02-23 17:51:10 +01:00
{
2005-10-27 23:18:23 +02:00
DBUG_ASSERT ( tbl - > view & &
tbl - > effective_algorithm = = VIEW_ALGORITHM_MERGE ) ;
2005-02-23 17:51:10 +01:00
/*
This is the only case where set_ancestor is called on an object
that may not be a view ( in which case ancestor is 0 )
*/
2005-10-27 23:18:23 +02:00
tbl - > merge_underlying_list - > set_underlying_merge ( ) ;
2005-02-23 17:51:10 +01:00
}
} while ( ( tbl = tbl - > next_local ) ) ;
2005-05-11 01:31:13 +02:00
if ( ! multitable_view )
2005-02-23 17:51:10 +01:00
{
2005-10-27 23:18:23 +02:00
table = merge_underlying_list - > table ;
schema_table = merge_underlying_list - > schema_table ;
2005-02-23 17:51:10 +01:00
}
2004-11-21 19:08:12 +01:00
}
2004-09-14 18:28:29 +02:00
}
2004-07-16 00:15:55 +02:00
/*
setup fields of placeholder of merged VIEW
SYNOPSIS
2005-10-27 23:18:23 +02:00
st_table_list : : setup_underlying ( )
2004-10-21 17:10:59 +02:00
thd - thread handler
2005-07-01 06:05:42 +02:00
2004-10-07 00:45:06 +02:00
DESCRIPTION
It is :
2005-07-01 06:05:42 +02:00
- preparing translation table for view columns
2004-10-07 00:45:06 +02:00
If there are underlying view ( s ) procedure first will be called for them .
2004-07-16 00:15:55 +02:00
RETURN
2005-02-23 17:51:10 +01:00
FALSE - OK
TRUE - error
2004-07-16 00:15:55 +02:00
*/
2004-09-03 20:43:04 +02:00
2005-10-27 23:18:23 +02:00
bool st_table_list : : setup_underlying ( THD * thd )
2004-07-16 00:15:55 +02:00
{
2005-10-27 23:18:23 +02:00
DBUG_ENTER ( " st_table_list::setup_underlying " ) ;
if ( ! field_translation & & merge_underlying_list )
2004-09-14 18:28:29 +02:00
{
2005-07-01 06:05:42 +02:00
Field_translator * transl ;
SELECT_LEX * select = & view - > select_lex ;
Item * item ;
TABLE_LIST * tbl ;
List_iterator_fast < Item > it ( select - > item_list ) ;
uint field_count = 0 ;
if ( check_stack_overrun ( thd , STACK_MIN_SIZE , ( char * ) & field_count ) )
{
2005-02-23 17:51:10 +01:00
DBUG_RETURN ( TRUE ) ;
2005-07-01 06:05:42 +02:00
}
2004-07-16 00:15:55 +02:00
2005-10-27 23:18:23 +02:00
for ( tbl = merge_underlying_list ; tbl ; tbl = tbl - > next_local )
2005-07-01 06:05:42 +02:00
{
2005-10-27 23:18:23 +02:00
if ( tbl - > merge_underlying_list & &
tbl - > setup_underlying ( thd ) )
2005-07-01 06:05:42 +02:00
{
DBUG_RETURN ( TRUE ) ;
}
}
2005-02-23 17:51:10 +01:00
2005-07-01 06:05:42 +02:00
/* Create view fields translation table */
if ( ! ( transl =
2005-09-02 15:21:19 +02:00
( Field_translator * ) ( thd - > stmt_arena - >
2005-07-01 06:05:42 +02:00
alloc ( select - > item_list . elements *
sizeof ( Field_translator ) ) ) ) )
2004-07-16 00:15:55 +02:00
{
2005-07-01 06:05:42 +02:00
DBUG_RETURN ( TRUE ) ;
2004-09-14 18:28:29 +02:00
}
2005-07-01 06:05:42 +02:00
while ( ( item = it + + ) )
2004-09-14 18:28:29 +02:00
{
2005-07-01 06:05:42 +02:00
transl [ field_count ] . name = item - > name ;
transl [ field_count + + ] . item = item ;
2004-09-14 18:28:29 +02:00
}
2005-07-01 06:05:42 +02:00
field_translation = transl ;
field_translation_end = transl + field_count ;
/* TODO: use hash for big number of fields */
2004-09-14 18:28:29 +02:00
2005-07-01 06:05:42 +02:00
/* full text function moving to current select */
if ( view - > select_lex . ftfunc_list - > elements )
2004-09-14 18:28:29 +02:00
{
2005-07-01 06:05:42 +02:00
Item_func_match * ifm ;
SELECT_LEX * current_select = thd - > lex - > current_select ;
List_iterator_fast < Item_func_match >
li ( * ( view - > select_lex . ftfunc_list ) ) ;
while ( ( ifm = li + + ) )
current_select - > ftfunc_list - > push_front ( ifm ) ;
2004-07-16 00:15:55 +02:00
}
}
2005-07-01 06:05:42 +02:00
DBUG_RETURN ( FALSE ) ;
}
2004-07-16 00:15:55 +02:00
2005-02-23 17:51:10 +01:00
2005-07-01 06:05:42 +02:00
/*
Prepare where expression of view
2004-07-21 03:26:20 +02:00
2005-07-01 06:05:42 +02:00
SYNOPSIS
st_table_list : : prep_where ( )
thd - thread handler
conds - condition of this JOIN
no_where_clause - do not build WHERE or ON outer qwery do not need it
( it is INSERT ) , we do not need conds if this flag is set
2004-07-23 08:20:58 +02:00
2005-07-01 06:05:42 +02:00
NOTE : have to be called befor CHECK OPTION preparation , because it makes
fix_fields for view WHERE clause
2004-07-16 00:15:55 +02:00
2005-07-01 06:05:42 +02:00
RETURN
FALSE - OK
TRUE - error
*/
2004-07-16 00:15:55 +02:00
2005-07-01 06:05:42 +02:00
bool st_table_list : : prep_where ( THD * thd , Item * * conds ,
bool no_where_clause )
{
DBUG_ENTER ( " st_table_list::prep_where " ) ;
2005-10-27 23:18:23 +02:00
for ( TABLE_LIST * tbl = merge_underlying_list ; tbl ; tbl = tbl - > next_local )
2004-09-14 18:28:29 +02:00
{
2005-07-01 06:05:42 +02:00
if ( tbl - > view & & tbl - > prep_where ( thd , conds , no_where_clause ) )
{
DBUG_RETURN ( TRUE ) ;
}
2004-09-14 18:28:29 +02:00
}
2004-09-10 21:39:04 +02:00
2005-07-01 06:05:42 +02:00
if ( where )
{
if ( ! where - > fixed & & where - > fix_fields ( thd , & where ) )
2004-07-16 00:15:55 +02:00
{
2005-07-01 06:05:42 +02:00
DBUG_RETURN ( TRUE ) ;
2004-07-16 00:15:55 +02:00
}
2004-10-04 12:45:35 +02:00
/*
check that it is not VIEW in which we insert with INSERT SELECT
( in this case we can ' t add view WHERE condition to main SELECT_LEX )
*/
2005-07-01 06:05:42 +02:00
if ( ! no_where_clause & & ! where_processed )
2004-07-16 00:15:55 +02:00
{
2005-07-01 06:05:42 +02:00
TABLE_LIST * tbl = this ;
2005-09-02 15:21:19 +02:00
Query_arena * arena = thd - > stmt_arena , backup ;
arena = thd - > activate_stmt_arena_if_needed ( & backup ) ; // For easier test
2005-07-01 06:05:42 +02:00
2004-10-04 12:45:35 +02:00
/* Go up to join tree and try to find left join */
for ( ; tbl ; tbl = tbl - > embedding )
2004-09-03 14:18:40 +02:00
{
2004-10-04 12:45:35 +02:00
if ( tbl - > outer_join )
{
/*
Store WHERE condition to ON expression for outer join , because
2004-10-07 00:45:06 +02:00
we can ' t use WHERE to correctly execute left joins on VIEWs and
2004-10-04 12:45:35 +02:00
this expression will not be moved to WHERE condition ( i . e . will
be clean correctly for PS / SP )
*/
tbl - > on_expr = and_conds ( tbl - > on_expr , where ) ;
break ;
}
2004-09-03 14:18:40 +02:00
}
2004-10-04 12:45:35 +02:00
if ( tbl = = 0 )
2005-07-01 06:05:42 +02:00
* conds = and_conds ( * conds , where ) ;
if ( arena )
2005-09-02 15:21:19 +02:00
thd - > restore_active_arena ( arena , & backup ) ;
2005-07-01 06:05:42 +02:00
where_processed = TRUE ;
2004-07-16 00:15:55 +02:00
}
}
2004-09-14 18:28:29 +02:00
2005-07-01 06:05:42 +02:00
DBUG_RETURN ( FALSE ) ;
}
/*
Prepare check option expression of table
SYNOPSIS
st_table_list : : prep_check_option ( )
thd - thread handler
check_opt_type - WITH CHECK OPTION type ( VIEW_CHECK_NONE ,
VIEW_CHECK_LOCAL , VIEW_CHECK_CASCADED )
we use this parameter instead of direct check of
effective_with_check to change type of underlying
views to VIEW_CHECK_CASCADED if outer view have
such option and prevent processing of underlying
view check options if outer view have just
VIEW_CHECK_LOCAL option .
NOTE
This method build check options for every call
( usual execution or every SP / PS call )
This method have to be called after WHERE preparation
( st_table_list : : prep_where )
2004-07-16 00:15:55 +02:00
2005-07-01 06:05:42 +02:00
RETURN
FALSE - OK
TRUE - error
*/
bool st_table_list : : prep_check_option ( THD * thd , uint8 check_opt_type )
{
DBUG_ENTER ( " st_table_list::prep_check_option " ) ;
2005-10-27 23:18:23 +02:00
for ( TABLE_LIST * tbl = merge_underlying_list ; tbl ; tbl = tbl - > next_local )
2004-09-14 18:28:29 +02:00
{
2005-07-01 06:05:42 +02:00
/* see comment of check_opt_type parameter */
if ( tbl - > view & &
tbl - > prep_check_option ( thd ,
( ( check_opt_type = = VIEW_CHECK_CASCADED ) ?
VIEW_CHECK_CASCADED :
VIEW_CHECK_NONE ) ) )
2004-09-14 18:28:29 +02:00
{
2005-07-01 06:05:42 +02:00
DBUG_RETURN ( TRUE ) ;
2004-09-14 18:28:29 +02:00
}
}
2004-07-16 00:15:55 +02:00
2005-07-01 06:05:42 +02:00
if ( check_opt_type )
2004-08-25 15:14:42 +02:00
{
2005-07-01 06:05:42 +02:00
Item * item = 0 ;
if ( where )
{
DBUG_ASSERT ( where - > fixed ) ;
item = where - > copy_andor_structure ( thd ) ;
}
if ( check_opt_type = = VIEW_CHECK_CASCADED )
{
2005-10-27 23:18:23 +02:00
for ( TABLE_LIST * tbl = merge_underlying_list ; tbl ; tbl = tbl - > next_local )
2005-07-01 06:05:42 +02:00
{
if ( tbl - > check_option )
item = and_conds ( item , tbl - > check_option ) ;
}
}
if ( item )
thd - > change_item_tree ( & check_option , item ) ;
}
if ( check_option )
{
const char * save_where = thd - > where ;
thd - > where = " check option " ;
if ( ! check_option - > fixed & &
check_option - > fix_fields ( thd , & check_option ) | |
check_option - > check_cols ( 1 ) )
{
DBUG_RETURN ( TRUE ) ;
}
thd - > where = save_where ;
2004-08-25 15:14:42 +02:00
}
2005-07-01 06:05:42 +02:00
DBUG_RETURN ( FALSE ) ;
}
2004-08-25 15:14:42 +02:00
2005-07-01 06:05:42 +02:00
/*
Hide errors which show view underlying table information
SYNOPSIS
st_table_list : : hide_view_error ( )
thd thread handler
2004-07-16 00:15:55 +02:00
2005-07-01 06:05:42 +02:00
*/
void st_table_list : : hide_view_error ( THD * thd )
{
2004-12-16 14:31:36 +01:00
/* Hide "Unknown column" or "Unknown function" error */
if ( thd - > net . last_errno = = ER_BAD_FIELD_ERROR | |
2005-10-27 23:18:23 +02:00
thd - > net . last_errno = = ER_SP_DOES_NOT_EXIST | |
thd - > net . last_errno = = ER_PROCACCESS_DENIED_ERROR | |
2006-05-26 10:47:53 +02:00
thd - > net . last_errno = = ER_COLUMNACCESS_DENIED_ERROR | |
thd - > net . last_errno = = ER_TABLEACCESS_DENIED_ERROR )
2004-07-21 03:26:20 +02:00
{
2005-10-27 23:18:23 +02:00
TABLE_LIST * top = top_table ( ) ;
2004-07-21 03:26:20 +02:00
thd - > clear_error ( ) ;
2005-10-27 23:18:23 +02:00
my_error ( ER_VIEW_INVALID , MYF ( 0 ) , top - > view_db . str , top - > view_name . str ) ;
2004-07-21 03:26:20 +02:00
}
2005-07-01 06:05:42 +02:00
else if ( thd - > net . last_errno = = ER_NO_DEFAULT_FOR_FIELD )
{
2005-10-27 23:18:23 +02:00
TABLE_LIST * top = top_table ( ) ;
2005-07-01 06:05:42 +02:00
thd - > clear_error ( ) ;
// TODO: make correct error message
2005-10-27 23:18:23 +02:00
my_error ( ER_NO_DEFAULT_FOR_VIEW_FIELD , MYF ( 0 ) ,
top - > view_db . str , top - > view_name . str ) ;
2005-07-01 06:05:42 +02:00
}
2004-07-16 00:15:55 +02:00
}
2005-04-03 00:23:45 +02:00
/*
Find underlying base tables ( TABLE_LIST ) which represent given
table_to_find ( TABLE )
SYNOPSIS
st_table_list : : find_underlying_table ( )
table_to_find table to find
RETURN
0 table is not found
found table reference
*/
st_table_list * st_table_list : : find_underlying_table ( TABLE * table_to_find )
{
/* is this real table and table which we are looking for? */
2005-10-27 23:18:23 +02:00
if ( table = = table_to_find & & merge_underlying_list = = 0 )
2005-04-03 00:23:45 +02:00
return this ;
2005-10-27 23:18:23 +02:00
for ( TABLE_LIST * tbl = merge_underlying_list ; tbl ; tbl = tbl - > next_local )
2005-04-03 00:23:45 +02:00
{
TABLE_LIST * result ;
if ( ( result = tbl - > find_underlying_table ( table_to_find ) ) )
return result ;
}
return 0 ;
}
2004-11-08 00:54:23 +01:00
/*
cleunup items belonged to view fields translation table
SYNOPSIS
st_table_list : : cleanup_items ( )
*/
void st_table_list : : cleanup_items ( )
{
if ( ! field_translation )
return ;
2005-07-01 06:05:42 +02:00
for ( Field_translator * transl = field_translation ;
transl < field_translation_end ;
transl + + )
2004-11-21 18:33:49 +01:00
transl - > item - > walk ( & Item : : cleanup_processor , 0 ) ;
2004-11-08 00:54:23 +01:00
}
2004-09-29 15:35:01 +02:00
/*
check CHECK OPTION condition
SYNOPSIS
check_option ( )
ignore_failure ignore check option fail
RETURN
VIEW_CHECK_OK OK
VIEW_CHECK_ERROR FAILED
VIEW_CHECK_SKIP FAILED , but continue
*/
int st_table_list : : view_check_option ( THD * thd , bool ignore_failure )
{
if ( check_option & & check_option - > val_int ( ) = = 0 )
{
2005-08-02 21:54:49 +02:00
TABLE_LIST * view = top_table ( ) ;
2004-09-29 15:35:01 +02:00
if ( ignore_failure )
{
push_warning_printf ( thd , MYSQL_ERROR : : WARN_LEVEL_ERROR ,
ER_VIEW_CHECK_FAILED , ER ( ER_VIEW_CHECK_FAILED ) ,
2005-05-11 01:31:13 +02:00
view - > view_db . str , view - > view_name . str ) ;
2004-09-29 15:35:01 +02:00
return ( VIEW_CHECK_SKIP ) ;
}
else
{
2005-05-11 01:31:13 +02:00
my_error ( ER_VIEW_CHECK_FAILED , MYF ( 0 ) , view - > view_db . str , view - > view_name . str ) ;
2004-09-29 15:35:01 +02:00
return ( VIEW_CHECK_ERROR ) ;
}
}
return ( VIEW_CHECK_OK ) ;
}
2004-09-15 22:42:56 +02:00
/*
2004-11-25 08:28:32 +01:00
Find table in underlying tables by mask and check that only this
2004-11-21 18:33:49 +01:00
table belong to given mask
2004-09-15 22:42:56 +02:00
SYNOPSIS
st_table_list : : check_single_table ( )
table reference on variable where to store found table
( should be 0 on call , to find table , or point to table for
unique test )
map bit mask of tables
2005-05-11 01:31:13 +02:00
view view for which we are looking table
2004-09-15 22:42:56 +02:00
RETURN
2004-11-21 18:33:49 +01:00
FALSE table not found or found only one
TRUE found several tables
2004-09-15 22:42:56 +02:00
*/
2005-05-11 01:31:13 +02:00
bool st_table_list : : check_single_table ( st_table_list * * table , table_map map ,
st_table_list * view )
2004-09-15 22:42:56 +02:00
{
2005-10-27 23:18:23 +02:00
for ( TABLE_LIST * tbl = merge_underlying_list ; tbl ; tbl = tbl - > next_local )
2004-09-15 22:42:56 +02:00
{
if ( tbl - > table )
{
if ( tbl - > table - > map & map )
{
if ( * table )
2004-11-21 18:33:49 +01:00
return TRUE ;
2005-06-01 15:35:09 +02:00
* table = tbl ;
tbl - > check_option = view - > check_option ;
2004-09-15 22:42:56 +02:00
}
}
2005-06-01 15:35:09 +02:00
else if ( tbl - > check_single_table ( table , map , view ) )
return TRUE ;
2004-09-15 22:42:56 +02:00
}
2004-11-21 18:33:49 +01:00
return FALSE ;
2004-09-15 22:42:56 +02:00
}
/*
Set insert_values buffer
SYNOPSIS
set_insert_values ( )
mem_root memory pool for allocating
RETURN
FALSE - OK
TRUE - out of memory
*/
bool st_table_list : : set_insert_values ( MEM_ROOT * mem_root )
{
if ( table )
{
if ( ! table - > insert_values & &
! ( table - > insert_values = ( byte * ) alloc_root ( mem_root ,
2005-01-06 12:00:13 +01:00
table - > s - > rec_buff_length ) ) )
2004-09-15 22:42:56 +02:00
return TRUE ;
}
else
{
2005-10-27 23:18:23 +02:00
DBUG_ASSERT ( view & & merge_underlying_list ) ;
for ( TABLE_LIST * tbl = merge_underlying_list ; tbl ; tbl = tbl - > next_local )
2004-09-15 22:42:56 +02:00
if ( tbl - > set_insert_values ( mem_root ) )
return TRUE ;
}
return FALSE ;
}
2005-08-12 16:57:19 +02:00
/*
Test if this is a leaf with respect to name resolution .
SYNOPSIS
st_table_list : : is_leaf_for_name_resolution ( )
DESCRIPTION
A table reference is a leaf with respect to name resolution if
it is either a leaf node in a nested join tree ( table , view ,
schema table , subquery ) , or an inner node that represents a
NATURAL / USING join , or a nested join with materialized join
columns .
RETURN
TRUE if a leaf , FALSE otherwise .
*/
bool st_table_list : : is_leaf_for_name_resolution ( )
{
return ( view | | is_natural_join | | is_join_columns_complete | |
! nested_join ) ;
}
/*
Retrieve the first ( left - most ) leaf in a nested join tree with
respect to name resolution .
SYNOPSIS
st_table_list : : first_leaf_for_name_resolution ( )
DESCRIPTION
Given that ' this ' is a nested table reference , recursively walk
down the left - most children of ' this ' until we reach a leaf
table reference with respect to name resolution .
IMPLEMENTATION
The left - most child of a nested table reference is the last element
in the list of children because the children are inserted in
reverse order .
RETURN
2005-08-18 02:12:42 +02:00
If ' this ' is a nested table reference - the left - most child of
2005-08-12 16:57:19 +02:00
the tree rooted in ' this ' ,
2005-08-18 02:12:42 +02:00
else return ' this '
2005-08-12 16:57:19 +02:00
*/
TABLE_LIST * st_table_list : : first_leaf_for_name_resolution ( )
{
2005-08-18 02:12:42 +02:00
TABLE_LIST * cur_table_ref ;
NESTED_JOIN * cur_nested_join ;
LINT_INIT ( cur_table_ref ) ;
2005-08-12 16:57:19 +02:00
2005-08-18 02:12:42 +02:00
if ( is_leaf_for_name_resolution ( ) )
2005-08-12 16:57:19 +02:00
return this ;
2005-08-18 02:12:42 +02:00
DBUG_ASSERT ( nested_join ) ;
2005-08-12 16:57:19 +02:00
2005-08-18 02:12:42 +02:00
for ( cur_nested_join = nested_join ;
cur_nested_join ;
cur_nested_join = cur_table_ref - > nested_join )
2005-08-12 16:57:19 +02:00
{
List_iterator_fast < TABLE_LIST > it ( cur_nested_join - > join_list ) ;
cur_table_ref = it + + ;
/*
2005-09-30 09:39:17 +02:00
If the current nested join is a RIGHT JOIN , the operands in
' join_list ' are in reverse order , thus the first operand is
already at the front of the list . Otherwise the first operand
is in the end of the list of join operands .
2005-08-12 16:57:19 +02:00
*/
if ( ! ( cur_table_ref - > outer_join & JOIN_TYPE_RIGHT ) )
{
2005-08-18 02:12:42 +02:00
TABLE_LIST * next ;
2005-08-12 16:57:19 +02:00
while ( ( next = it + + ) )
cur_table_ref = next ;
}
if ( cur_table_ref - > is_leaf_for_name_resolution ( ) )
break ;
}
return cur_table_ref ;
}
/*
Retrieve the last ( right - most ) leaf in a nested join tree with
respect to name resolution .
SYNOPSIS
st_table_list : : last_leaf_for_name_resolution ( )
DESCRIPTION
Given that ' this ' is a nested table reference , recursively walk
down the right - most children of ' this ' until we reach a leaf
table reference with respect to name resolution .
IMPLEMENTATION
The right - most child of a nested table reference is the first
element in the list of children because the children are inserted
in reverse order .
RETURN
- If ' this ' is a nested table reference - the right - most child of
the tree rooted in ' this ' ,
- else - ' this '
*/
TABLE_LIST * st_table_list : : last_leaf_for_name_resolution ( )
{
TABLE_LIST * cur_table_ref = this ;
2005-08-18 02:12:42 +02:00
NESTED_JOIN * cur_nested_join ;
2005-08-12 16:57:19 +02:00
2005-08-18 02:12:42 +02:00
if ( is_leaf_for_name_resolution ( ) )
2005-08-12 16:57:19 +02:00
return this ;
2005-08-18 02:12:42 +02:00
DBUG_ASSERT ( nested_join ) ;
2005-08-12 16:57:19 +02:00
2005-08-18 02:12:42 +02:00
for ( cur_nested_join = nested_join ;
cur_nested_join ;
cur_nested_join = cur_table_ref - > nested_join )
2005-08-12 16:57:19 +02:00
{
2005-09-30 09:39:17 +02:00
cur_table_ref = cur_nested_join - > join_list . head ( ) ;
2005-08-12 16:57:19 +02:00
/*
2005-09-30 09:39:17 +02:00
If the current nested is a RIGHT JOIN , the operands in
' join_list ' are in reverse order , thus the last operand is in the
end of the list .
2005-08-12 16:57:19 +02:00
*/
if ( ( cur_table_ref - > outer_join & JOIN_TYPE_RIGHT ) )
{
List_iterator_fast < TABLE_LIST > it ( cur_nested_join - > join_list ) ;
2005-08-18 02:12:42 +02:00
TABLE_LIST * next ;
2005-08-12 16:57:19 +02:00
cur_table_ref = it + + ;
while ( ( next = it + + ) )
cur_table_ref = next ;
}
if ( cur_table_ref - > is_leaf_for_name_resolution ( ) )
break ;
}
return cur_table_ref ;
}
2005-10-27 23:18:23 +02:00
/*
Register access mode which we need for underlying tables
SYNOPSIS
register_want_access ( )
want_access Acess which we require
*/
void st_table_list : : register_want_access ( ulong want_access )
{
/* Remove SHOW_VIEW_ACL, because it will be checked during making view */
want_access & = ~ SHOW_VIEW_ACL ;
if ( belong_to_view )
{
grant . want_privilege = want_access ;
if ( table )
table - > grant . want_privilege = want_access ;
}
for ( TABLE_LIST * tbl = merge_underlying_list ; tbl ; tbl = tbl - > next_local )
tbl - > register_want_access ( want_access ) ;
}
/*
2005-10-27 23:56:44 +02:00
Load security context information for this view
2005-10-27 23:18:23 +02:00
SYNOPSIS
st_table_list : : prepare_view_securety_context ( )
thd [ in ] thread handler
RETURN
FALSE OK
TRUE Error
*/
# ifndef NO_EMBEDDED_ACCESS_CHECKS
bool st_table_list : : prepare_view_securety_context ( THD * thd )
{
DBUG_ENTER ( " st_table_list::prepare_view_securety_context " ) ;
DBUG_PRINT ( " enter " , ( " table: %s " , alias ) ) ;
DBUG_ASSERT ( ! prelocking_placeholder & & view ) ;
if ( view_suid )
{
DBUG_PRINT ( " info " , ( " This table is suid view => load contest " ) ) ;
DBUG_ASSERT ( view & & view_sctx ) ;
if ( acl_getroot_no_password ( view_sctx ,
definer . user . str ,
definer . host . str ,
definer . host . str ,
thd - > db ) )
{
2006-05-26 10:49:39 +02:00
if ( thd - > lex - > sql_command = = SQLCOM_SHOW_CREATE )
{
push_warning_printf ( thd , MYSQL_ERROR : : WARN_LEVEL_NOTE ,
ER_NO_SUCH_USER ,
ER ( ER_NO_SUCH_USER ) ,
definer . user . str , definer . host . str ) ;
}
else
{
my_error ( ER_NO_SUCH_USER , MYF ( 0 ) , definer . user . str , definer . host . str ) ;
DBUG_RETURN ( TRUE ) ;
}
2005-10-27 23:18:23 +02:00
}
}
DBUG_RETURN ( FALSE ) ;
}
# endif
/*
Find security context of current view
SYNOPSIS
st_table_list : : find_view_security_context ( )
thd [ in ] thread handler
*/
# ifndef NO_EMBEDDED_ACCESS_CHECKS
Security_context * st_table_list : : find_view_security_context ( THD * thd )
{
Security_context * sctx ;
TABLE_LIST * upper_view = this ;
DBUG_ENTER ( " st_table_list::find_view_security_context " ) ;
DBUG_ASSERT ( view ) ;
while ( upper_view & & ! upper_view - > view_suid )
{
DBUG_ASSERT ( ! upper_view - > prelocking_placeholder ) ;
upper_view = upper_view - > referencing_view ;
}
if ( upper_view )
{
DBUG_PRINT ( " info " , ( " Securety context of view %s will be used " ,
upper_view - > alias ) ) ;
sctx = upper_view - > view_sctx ;
DBUG_ASSERT ( sctx ) ;
}
else
{
DBUG_PRINT ( " info " , ( " Current global context will be used " ) ) ;
sctx = thd - > security_ctx ;
}
DBUG_RETURN ( sctx ) ;
}
# endif
/*
Prepare security context and load underlying tables priveleges for view
SYNOPSIS
st_table_list : : prepare_security ( )
thd [ in ] thread handler
RETURN
FALSE OK
TRUE Error
*/
bool st_table_list : : prepare_security ( THD * thd )
{
List_iterator_fast < TABLE_LIST > tb ( * view_tables ) ;
TABLE_LIST * tbl ;
2005-11-01 20:59:24 +01:00
DBUG_ENTER ( " st_table_list::prepare_security " ) ;
2005-10-27 23:18:23 +02:00
# ifndef NO_EMBEDDED_ACCESS_CHECKS
Security_context * save_security_ctx = thd - > security_ctx ;
DBUG_ASSERT ( ! prelocking_placeholder ) ;
if ( prepare_view_securety_context ( thd ) )
DBUG_RETURN ( TRUE ) ;
thd - > security_ctx = find_view_security_context ( thd ) ;
while ( ( tbl = tb + + ) )
{
DBUG_ASSERT ( tbl - > referencing_view ) ;
char * db , * table_name ;
if ( tbl - > view )
{
db = tbl - > view_db . str ;
table_name = tbl - > view_name . str ;
}
else
{
db = tbl - > db ;
table_name = tbl - > table_name ;
}
fill_effective_table_privileges ( thd , & tbl - > grant , db , table_name ) ;
if ( tbl - > table )
tbl - > table - > grant = grant ;
}
thd - > security_ctx = save_security_ctx ;
# else
while ( ( tbl = tb + + ) )
tbl - > grant . privilege = ~ NO_ACCESS ;
# endif
2005-11-02 14:17:57 +01:00
DBUG_RETURN ( FALSE ) ;
2005-10-27 23:18:23 +02:00
}
2005-08-12 16:57:19 +02:00
Natural_join_column : : Natural_join_column ( Field_translator * field_param ,
TABLE_LIST * tab )
{
DBUG_ASSERT ( tab - > field_translation ) ;
view_field = field_param ;
table_field = NULL ;
table_ref = tab ;
is_common = FALSE ;
}
Natural_join_column : : Natural_join_column ( Field * field_param ,
TABLE_LIST * tab )
{
2005-08-19 14:22:30 +02:00
DBUG_ASSERT ( tab - > table = = field_param - > table ) ;
2005-08-12 16:57:19 +02:00
table_field = field_param ;
view_field = NULL ;
table_ref = tab ;
is_common = FALSE ;
}
const char * Natural_join_column : : name ( )
{
if ( view_field )
{
DBUG_ASSERT ( table_field = = NULL ) ;
return view_field - > name ;
}
2005-08-18 02:12:42 +02:00
return table_field - > field_name ;
2005-08-12 16:57:19 +02:00
}
Item * Natural_join_column : : create_item ( THD * thd )
{
if ( view_field )
{
DBUG_ASSERT ( table_field = = NULL ) ;
2005-08-18 02:12:42 +02:00
return create_view_field ( thd , table_ref , & view_field - > item ,
view_field - > name ) ;
2005-08-12 16:57:19 +02:00
}
2005-08-18 02:12:42 +02:00
return new Item_field ( thd , & thd - > lex - > current_select - > context , table_field ) ;
2005-08-12 16:57:19 +02:00
}
Field * Natural_join_column : : field ( )
{
if ( view_field )
{
DBUG_ASSERT ( table_field = = NULL ) ;
return NULL ;
}
2005-08-18 02:12:42 +02:00
return table_field ;
2005-08-12 16:57:19 +02:00
}
const char * Natural_join_column : : table_name ( )
{
return table_ref - > alias ;
}
const char * Natural_join_column : : db_name ( )
{
if ( view_field )
return table_ref - > view_db . str ;
2005-08-18 02:12:42 +02:00
2006-02-22 09:04:10 +01:00
/*
Test that TABLE_LIST : : db is the same as st_table_share : : db to
ensure consistency . An exception are I_S schema tables , which
are inconsistent in this respect .
*/
2005-08-18 02:12:42 +02:00
DBUG_ASSERT ( ! strcmp ( table_ref - > db ,
2006-02-22 09:04:10 +01:00
table_ref - > table - > s - > db ) | |
( table_ref - > schema_table & &
table_ref - > table - > s - > db [ 0 ] = = 0 ) ) ;
2005-08-18 02:12:42 +02:00
return table_ref - > db ;
2005-08-12 16:57:19 +02:00
}
GRANT_INFO * Natural_join_column : : grant ( )
{
if ( view_field )
return & ( table_ref - > grant ) ;
2005-08-18 02:12:42 +02:00
return & ( table_ref - > table - > grant ) ;
2005-08-12 16:57:19 +02:00
}
2004-07-16 00:15:55 +02:00
void Field_iterator_view : : set ( TABLE_LIST * table )
{
2005-08-12 16:57:19 +02:00
DBUG_ASSERT ( table - > field_translation ) ;
2005-07-01 06:05:42 +02:00
view = table ;
2004-07-16 00:15:55 +02:00
ptr = table - > field_translation ;
2005-07-01 06:05:42 +02:00
array_end = table - > field_translation_end ;
2004-07-16 00:15:55 +02:00
}
const char * Field_iterator_table : : name ( )
{
return ( * ptr ) - > field_name ;
}
2005-07-01 06:05:42 +02:00
Item * Field_iterator_table : : create_item ( THD * thd )
2004-07-16 00:15:55 +02:00
{
2005-07-01 06:05:42 +02:00
return new Item_field ( thd , & thd - > lex - > current_select - > context , * ptr ) ;
2004-07-16 00:15:55 +02:00
}
const char * Field_iterator_view : : name ( )
{
2004-09-14 18:28:29 +02:00
return ptr - > name ;
2004-07-16 00:15:55 +02:00
}
2005-07-01 06:05:42 +02:00
Item * Field_iterator_view : : create_item ( THD * thd )
{
return create_view_field ( thd , view , & ptr - > item , ptr - > name ) ;
}
Item * create_view_field ( THD * thd , TABLE_LIST * view , Item * * field_ref ,
const char * name )
{
bool save_wrapper = thd - > lex - > select_lex . no_wrap_view_item ;
Item * field = * field_ref ;
DBUG_ENTER ( " create_view_field " ) ;
if ( view - > schema_table_reformed )
{
/*
2005-11-28 20:57:50 +01:00
Translation table items are always Item_fields and already fixed
( ' mysql_schema_table ' function ) . So we can return directly the
field . This case happens only for ' show & where ' commands .
2005-07-01 06:05:42 +02:00
*/
DBUG_ASSERT ( field & & field - > fixed ) ;
DBUG_RETURN ( field ) ;
}
DBUG_ASSERT ( field ) ;
thd - > lex - > current_select - > no_wrap_view_item = TRUE ;
if ( ! field - > fixed )
{
if ( field - > fix_fields ( thd , field_ref ) )
{
thd - > lex - > current_select - > no_wrap_view_item = save_wrapper ;
DBUG_RETURN ( 0 ) ;
}
field = * field_ref ;
}
thd - > lex - > current_select - > no_wrap_view_item = save_wrapper ;
if ( thd - > lex - > current_select - > no_wrap_view_item )
{
DBUG_RETURN ( field ) ;
}
Item * item = new Item_direct_view_ref ( & view - > view - > select_lex . context ,
2005-10-01 08:35:30 +02:00
field_ref , view - > alias ,
2005-07-01 06:05:42 +02:00
name ) ;
DBUG_RETURN ( item ) ;
}
2005-08-12 16:57:19 +02:00
void Field_iterator_natural_join : : set ( TABLE_LIST * table_ref )
{
DBUG_ASSERT ( table_ref - > join_columns ) ;
2005-11-28 20:57:50 +01:00
column_ref_it . init ( * ( table_ref - > join_columns ) ) ;
cur_column_ref = column_ref_it + + ;
2005-08-12 16:57:19 +02:00
}
2005-08-19 14:22:30 +02:00
void Field_iterator_natural_join : : next ( )
{
2005-11-28 20:57:50 +01:00
cur_column_ref = column_ref_it + + ;
2005-08-22 00:13:37 +02:00
DBUG_ASSERT ( ! cur_column_ref | | ! cur_column_ref - > table_field | |
cur_column_ref - > table_ref - > table = =
cur_column_ref - > table_field - > table ) ;
2005-08-19 14:22:30 +02:00
}
2005-08-12 16:57:19 +02:00
void Field_iterator_table_ref : : set_field_iterator ( )
{
DBUG_ENTER ( " Field_iterator_table_ref::set_field_iterator " ) ;
/*
If the table reference we are iterating over is a natural join , or it is
an operand of a natural join , and TABLE_LIST : : join_columns contains all
the columns of the join operand , then we pick the columns from
TABLE_LIST : : join_columns , instead of the orginial container of the
columns of the join operator .
*/
if ( table_ref - > is_join_columns_complete )
{
/* Necesary, but insufficient conditions. */
DBUG_ASSERT ( table_ref - > is_natural_join | |
table_ref - > nested_join | |
table_ref - > join_columns & &
/* This is a merge view. */
( ( table_ref - > field_translation & &
table_ref - > join_columns - > elements = =
( ulong ) ( table_ref - > field_translation_end -
table_ref - > field_translation ) ) | |
/* This is stored table or a tmptable view. */
( ! table_ref - > field_translation & &
table_ref - > join_columns - > elements = =
table_ref - > table - > s - > fields ) ) ) ;
field_it = & natural_join_it ;
DBUG_PRINT ( " info " , ( " field_it for '%s' is Field_iterator_natural_join " ,
2005-08-18 10:28:50 +02:00
table_ref - > alias ) ) ;
2005-08-12 16:57:19 +02:00
}
/* This is a merge view, so use field_translation. */
else if ( table_ref - > field_translation )
{
DBUG_ASSERT ( table_ref - > view & &
table_ref - > effective_algorithm = = VIEW_ALGORITHM_MERGE ) ;
field_it = & view_field_it ;
DBUG_PRINT ( " info " , ( " field_it for '%s' is Field_iterator_view " ,
2005-08-18 10:28:50 +02:00
table_ref - > alias ) ) ;
2005-08-12 16:57:19 +02:00
}
/* This is a base table or stored view. */
else
{
DBUG_ASSERT ( table_ref - > table | | table_ref - > view ) ;
field_it = & table_field_it ;
DBUG_PRINT ( " info " , ( " field_it for '%s' is Field_iterator_table " ,
2005-08-18 10:28:50 +02:00
table_ref - > alias ) ) ;
2005-08-12 16:57:19 +02:00
}
2005-08-18 02:12:42 +02:00
field_it - > set ( table_ref ) ;
2005-08-12 16:57:19 +02:00
DBUG_VOID_RETURN ;
}
void Field_iterator_table_ref : : set ( TABLE_LIST * table )
{
DBUG_ASSERT ( table ) ;
first_leaf = table - > first_leaf_for_name_resolution ( ) ;
last_leaf = table - > last_leaf_for_name_resolution ( ) ;
DBUG_ASSERT ( first_leaf & & last_leaf ) ;
table_ref = first_leaf ;
set_field_iterator ( ) ;
}
void Field_iterator_table_ref : : next ( )
{
/* Move to the next field in the current table reference. */
field_it - > next ( ) ;
/*
If all fields of the current table reference are exhausted , move to
the next leaf table reference .
*/
if ( field_it - > end_of_fields ( ) & & table_ref ! = last_leaf )
{
table_ref = table_ref - > next_name_resolution_table ;
DBUG_ASSERT ( table_ref ) ;
set_field_iterator ( ) ;
}
}
const char * Field_iterator_table_ref : : table_name ( )
{
if ( table_ref - > view )
return table_ref - > view_name . str ;
else if ( table_ref - > is_natural_join )
return natural_join_it . column_ref ( ) - > table_name ( ) ;
2005-08-18 02:12:42 +02:00
DBUG_ASSERT ( ! strcmp ( table_ref - > table_name ,
table_ref - > table - > s - > table_name ) ) ;
return table_ref - > table_name ;
2005-08-12 16:57:19 +02:00
}
const char * Field_iterator_table_ref : : db_name ( )
{
if ( table_ref - > view )
return table_ref - > view_db . str ;
else if ( table_ref - > is_natural_join )
return natural_join_it . column_ref ( ) - > db_name ( ) ;
2005-08-18 02:12:42 +02:00
2006-02-22 09:04:10 +01:00
/*
Test that TABLE_LIST : : db is the same as st_table_share : : db to
ensure consistency . An exception are I_S schema tables , which
are inconsistent in this respect .
*/
DBUG_ASSERT ( ! strcmp ( table_ref - > db , table_ref - > table - > s - > db ) | |
( table_ref - > schema_table & &
table_ref - > table - > s - > db [ 0 ] = = 0 ) ) ;
2005-08-18 02:12:42 +02:00
return table_ref - > db ;
2005-08-12 16:57:19 +02:00
}
GRANT_INFO * Field_iterator_table_ref : : grant ( )
{
if ( table_ref - > view )
return & ( table_ref - > grant ) ;
else if ( table_ref - > is_natural_join )
return natural_join_it . column_ref ( ) - > grant ( ) ;
2005-08-18 02:12:42 +02:00
return & ( table_ref - > table - > grant ) ;
2005-08-12 16:57:19 +02:00
}
/*
Create new or return existing column reference to a column of a
natural / using join .
SYNOPSIS
Field_iterator_table_ref : : get_or_create_column_ref ( )
2006-03-02 10:50:15 +01:00
parent_table_ref the parent table reference over which the
iterator is iterating
2005-08-12 16:57:19 +02:00
DESCRIPTION
2006-03-02 10:50:15 +01:00
Create a new natural join column for the current field of the
iterator if no such column was created , or return an already
created natural join column . The former happens for base tables or
views , and the latter for natural / using joins . If a new field is
created , then the field is added to ' parent_table_ref ' if it is
given , or to the original table referene of the field if
parent_table_ref = = NULL .
NOTES
This method is designed so that when a Field_iterator_table_ref
walks through the fields of a table reference , all its fields
are created and stored as follows :
- If the table reference being iterated is a stored table , view or
natural / using join , store all natural join columns in a list
attached to that table reference .
- If the table reference being iterated is a nested join that is
not natural / using join , then do not materialize its result
fields . This is OK because for such table references
Field_iterator_table_ref iterates over the fields of the nested
table references ( recursively ) . In this way we avoid the storage
of unnecessay copies of result columns of nested joins .
2005-08-12 16:57:19 +02:00
RETURN
2005-08-18 02:12:42 +02:00
# Pointer to a column of a natural join (or its operand)
NULL No memory to allocate the column
2005-08-12 16:57:19 +02:00
*/
Natural_join_column *
2006-03-02 10:50:15 +01:00
Field_iterator_table_ref : : get_or_create_column_ref ( TABLE_LIST * parent_table_ref )
2005-08-12 16:57:19 +02:00
{
2005-08-18 02:12:42 +02:00
Natural_join_column * nj_col ;
2006-03-02 10:50:15 +01:00
bool is_created = TRUE ;
uint field_count ;
TABLE_LIST * add_table_ref = parent_table_ref ?
parent_table_ref : table_ref ;
2005-08-18 02:12:42 +02:00
2005-08-12 16:57:19 +02:00
if ( field_it = = & table_field_it )
2005-08-19 14:22:30 +02:00
{
/* The field belongs to a stored table. */
Field * field = table_field_it . field ( ) ;
nj_col = new Natural_join_column ( field , table_ref ) ;
2006-03-02 10:50:15 +01:00
field_count = table_ref - > table - > s - > fields ;
2005-08-19 14:22:30 +02:00
}
else if ( field_it = = & view_field_it )
{
/* The field belongs to a merge view or information schema table. */
Field_translator * translated_field = view_field_it . field_translator ( ) ;
nj_col = new Natural_join_column ( translated_field , table_ref ) ;
2006-03-02 10:50:15 +01:00
field_count = table_ref - > field_translation_end -
table_ref - > field_translation ;
2005-08-19 14:22:30 +02:00
}
else
{
/*
The field belongs to a NATURAL join , therefore the column reference was
already created via one of the two constructor calls above . In this case
we just return the already created column reference .
*/
2006-03-02 10:50:15 +01:00
DBUG_ASSERT ( table_ref - > is_join_columns_complete ) ;
is_created = FALSE ;
2005-08-19 14:22:30 +02:00
nj_col = natural_join_it . column_ref ( ) ;
DBUG_ASSERT ( nj_col ) ;
}
2005-08-22 00:13:37 +02:00
DBUG_ASSERT ( ! nj_col - > table_field | |
nj_col - > table_ref - > table = = nj_col - > table_field - > table ) ;
2006-03-02 10:50:15 +01:00
/*
If the natural join column was just created add it to the list of
natural join columns of either ' parent_table_ref ' or to the table
reference that directly contains the original field .
*/
if ( is_created )
{
/* Make sure not all columns were materialized. */
DBUG_ASSERT ( ! add_table_ref - > is_join_columns_complete ) ;
if ( ! add_table_ref - > join_columns )
{
/* Create a list of natural join columns on demand. */
if ( ! ( add_table_ref - > join_columns = new List < Natural_join_column > ) )
return NULL ;
add_table_ref - > is_join_columns_complete = FALSE ;
}
add_table_ref - > join_columns - > push_back ( nj_col ) ;
/*
If new fields are added to their original table reference , mark if
all fields were added . We do it here as the caller has no easy way
of knowing when to do it .
If the fields are being added to parent_table_ref , then the caller
must take care to mark when all fields are created / added .
*/
if ( ! parent_table_ref & &
add_table_ref - > join_columns - > elements = = field_count )
add_table_ref - > is_join_columns_complete = TRUE ;
}
2005-08-18 02:12:42 +02:00
return nj_col ;
2005-08-12 16:57:19 +02:00
}
2005-11-28 20:57:50 +01:00
/*
Return an existing reference to a column of a natural / using join .
SYNOPSIS
Field_iterator_table_ref : : get_natural_column_ref ( )
DESCRIPTION
The method should be called in contexts where it is expected that
all natural join columns are already created , and that the column
being retrieved is a Natural_join_column .
RETURN
# Pointer to a column of a natural join (or its operand)
NULL No memory to allocate the column
*/
Natural_join_column *
Field_iterator_table_ref : : get_natural_column_ref ( )
{
Natural_join_column * nj_col ;
DBUG_ASSERT ( field_it = = & natural_join_it ) ;
/*
The field belongs to a NATURAL join , therefore the column reference was
already created via one of the two constructor calls above . In this case
we just return the already created column reference .
*/
nj_col = natural_join_it . column_ref ( ) ;
DBUG_ASSERT ( nj_col & &
( ! nj_col - > table_field | |
nj_col - > table_ref - > table = = nj_col - > table_field - > table ) ) ;
return nj_col ;
}
2006-07-06 21:59:04 +02:00
/*
Cleanup this table for re - execution .
SYNOPSIS
st_table_list : : reinit_before_use ( )
*/
2006-07-11 21:39:51 +02:00
void st_table_list : : reinit_before_use ( THD * thd )
2006-07-06 21:59:04 +02:00
{
/*
Reset old pointers to TABLEs : they are not valid since the tables
were closed in the end of previous prepare or execute call .
*/
table = 0 ;
2006-07-11 21:39:51 +02:00
/* Reset is_schema_table_processed value(needed for I_S tables */
is_schema_table_processed = FALSE ;
TABLE_LIST * embedded ; /* The table at the current level of nesting. */
TABLE_LIST * embedding = this ; /* The parent nested table reference. */
do
{
embedded = embedding ;
if ( embedded - > prep_on_expr )
embedded - > on_expr = embedded - > prep_on_expr - > copy_andor_structure ( thd ) ;
embedding = embedded - > embedding ;
}
while ( embedding & &
embedding - > nested_join - > join_list . head ( ) = = embedded ) ;
2006-07-06 21:59:04 +02:00
}
2005-11-28 20:57:50 +01:00
2000-07-31 21:29:14 +02:00
/*****************************************************************************
* * Instansiate templates
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2005-06-22 11:08:28 +02:00
# ifdef HAVE_EXPLICIT_TEMPLATE_INSTANTIATION
2000-07-31 21:29:14 +02:00
template class List < String > ;
template class List_iterator < String > ;
# endif