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 ;
2000-07-31 21:29:14 +02:00
ulong pos ;
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
if ( memcmp ( head , " TYPE= " , 5 ) = = 0 )
{
// 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
}
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-01-06 12:00:13 +01:00
share - > db_type = ha_checktype ( ( enum db_type ) ( uint ) * ( head + 3 ) ) ;
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
2000-10-16 01:29:48 +02:00
/* Allocate handler */
2005-01-06 12:00:13 +01:00
if ( ! ( outparam - > file = get_new_handler ( outparam , 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-01-06 12:00:13 +01:00
if ( my_pread ( file , ( byte * ) record , ( uint ) share - > reclength ,
2003-10-21 00:13:17 +02:00
( ulong ) ( uint2korr ( head + 6 ) +
( ( uint2korr ( head + 14 ) = = 0xffff ?
2003-10-30 19:17:57 +01:00
uint4korr ( head + 47 ) : uint2korr ( head + 14 ) ) ) ) ,
2000-07-31 21:29:14 +02:00
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
}
2003-05-03 01:16:56 +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 ) ;
share - > comment = strdup_root ( & outparam - > mem_root , ( char * ) head + 47 ) ;
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-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
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 ;
2000-07-31 21:29:14 +02:00
if ( primary_key > = MAX_KEY & & ( keyinfo - > flags & HA_NOSAME ) )
{
/*
2003-12-12 21:26:58 +01:00
If the UNIQUE key doesn ' t have NULL columns and is not a part key
declare this as a primary key .
2000-07-31 21:29:14 +02:00
*/
primary_key = key ;
for ( i = 0 ; i < keyinfo - > key_parts ; i + + )
{
2003-12-12 21:26:58 +01:00
uint fieldnr = key_part [ i ] . fieldnr ;
if ( ! fieldnr | |
outparam - > field [ fieldnr - 1 ] - > null_ptr | |
outparam - > field [ fieldnr - 1 ] - > key_length ( ) ! =
key_part [ i ] . length )
2000-07-31 21:29:14 +02:00
{
primary_key = MAX_KEY ; // Can't be used
break ;
}
}
}
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 )
field - > flags | =
( ( keyinfo - > flags & HA_NOSAME ) & &
field - > key_length ( ) = =
keyinfo - > key_length ? UNIQUE_KEY_FLAG : MULTIPLE_KEY_FLAG ) ;
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 ( ) ) ;
key_part - > store_length - = ( key_part - > length - field - > key_length ( ) ) ;
key_part - > length = field - > key_length ( ) ;
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 ,
outparam ) ;
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
}
}
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 )
my_free ( ( gptr ) buf , MYF ( 0 ) ) ;
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
2004-11-13 18:35:51 +01:00
my_error ( ER_FILE_NOT_FOUND , errortype ,
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 */
TYPELIB * typelib ( List < String > & strings )
{
TYPELIB * result = ( TYPELIB * ) sql_alloc ( sizeof ( TYPELIB ) ) ;
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 ) ;
if ( ! ( result - > type_names = ( const char * * ) sql_alloc ( 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 */
File create_frm ( register my_string name , uint reclength , uchar * fileinfo ,
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
# if SIZEOF_OFF_T > 4
2004-06-21 09:21:20 +02:00
/* Fix this when we have new .frm files; Current limit is 4G rows (QQ) */
2000-07-31 21:29:14 +02:00
if ( create_info - > max_rows > ~ ( ulong ) 0 )
create_info - > max_rows = ~ ( ulong ) 0 ;
if ( create_info - > min_rows > ~ ( ulong ) 0 )
create_info - > min_rows = ~ ( ulong ) 0 ;
# endif
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-03-03 19:51:29 +01:00
if ( ( file = my_create ( name , CREATE_MODE , create_flags , MYF ( MY_WME ) ) ) > = 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 ) ;
2000-07-31 21:29:14 +02:00
fileinfo [ 3 ] = ( uchar ) ha_checktype ( create_info - > db_type ) ;
fileinfo [ 4 ] = 1 ;
int2store ( fileinfo + 6 , IO_SIZE ) ; /* Next block starts here */
key_length = keys * ( 7 + NAME_LEN + MAX_REF_PARTS * 9 ) + 16 ;
length = ( ulong ) next_io_size ( ( ulong ) ( IO_SIZE + key_length + reclength ) ) ;
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 ) ;
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 ) ;
}
}
}
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
{
2004-03-05 19:13:33 +01:00
char * start = name ;
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)
2004-03-12 14:55:33 +01:00
last_char_is_space = my_isspace ( default_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
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 + + ;
}
2004-03-12 14:55:33 +01:00
return last_char_is_space | | ( uint ) ( name - start ) > 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)
2004-03-12 14:55:33 +01:00
last_char_is_space = my_isspace ( default_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)
2004-03-12 14:55:33 +01:00
last_char_is_space = my_isspace ( default_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
}
/*
* * Get type of table from . frm file
*/
db_type get_table_type ( const char * name )
{
File file ;
uchar head [ 4 ] ;
int error ;
DBUG_ENTER ( " get_table_type " ) ;
DBUG_PRINT ( " enter " , ( " name: '%s' " , name ) ) ;
if ( ( file = my_open ( name , O_RDONLY , MYF ( 0 ) ) ) < 0 )
DBUG_RETURN ( DB_TYPE_UNKNOWN ) ;
error = my_read ( file , ( byte * ) head , 4 , MYF ( MY_NABP ) ) ;
my_close ( file , MYF ( 0 ) ) ;
if ( error | | head [ 0 ] ! = ( uchar ) 254 | | head [ 1 ] ! = 1 | |
2004-12-06 01:00:37 +01:00
( head [ 2 ] ! = FRM_VER & & head [ 2 ] ! = FRM_VER + 1 & &
( head [ 2 ] < FRM_VER + 3 | | head [ 2 ] > FRM_VER + 4 ) ) )
2000-07-31 21:29:14 +02:00
DBUG_RETURN ( DB_TYPE_UNKNOWN ) ;
DBUG_RETURN ( ha_checktype ( ( enum db_type ) ( uint ) * ( head + 3 ) ) ) ;
}
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 ] ) ;
}
/*
set ancestor TABLE for table place holder of VIEW
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
it
2004-07-16 00:15:55 +02:00
SYNOPSIS
st_table_list : : set_ancestor ( )
*/
2004-09-03 20:43:04 +02:00
2004-07-16 00:15:55 +02:00
void st_table_list : : set_ancestor ( )
{
2005-02-23 17:51:10 +01:00
TABLE_LIST * tbl ;
if ( ( tbl = ancestor ) )
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 */
DBUG_ASSERT ( view ) ;
do
{
if ( tbl - > ancestor ) // This is a view
{
/*
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 )
*/
tbl - > ancestor - > set_ancestor ( ) ;
}
2005-05-11 01:31:13 +02:00
if ( tbl - > multitable_view )
multitable_view = TRUE ;
if ( tbl - > table )
tbl - > table - > grant = grant ;
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
{
table = ancestor - > table ;
schema_table = ancestor - > schema_table ;
}
2004-11-21 19:08:12 +01:00
}
2004-09-14 18:28:29 +02:00
}
/*
Save old want_privilege and clear want_privilege
SYNOPSIS
save_and_clear_want_privilege ( )
*/
void st_table_list : : save_and_clear_want_privilege ( )
{
for ( TABLE_LIST * tbl = ancestor ; tbl ; tbl = tbl - > next_local )
{
if ( tbl - > table )
{
privilege_backup = tbl - > table - > grant . want_privilege ;
tbl - > table - > grant . want_privilege = 0 ;
}
else
{
tbl - > save_and_clear_want_privilege ( ) ;
}
}
}
/*
restore want_privilege saved by save_and_clear_want_privilege
SYNOPSIS
restore_want_privilege ( )
*/
void st_table_list : : restore_want_privilege ( )
{
for ( TABLE_LIST * tbl = ancestor ; tbl ; tbl = tbl - > next_local )
{
if ( tbl - > table )
tbl - > table - > grant . want_privilege = privilege_backup ;
else
{
tbl - > restore_want_privilege ( ) ;
}
}
2004-07-16 00:15:55 +02:00
}
/*
setup fields of placeholder of merged VIEW
SYNOPSIS
st_table_list : : setup_ancestor ( )
2004-10-21 17:10:59 +02:00
thd - thread handler
conds - condition of this JOIN
check_opt_type - WHITH CHECK OPTION type ( VIEW_CHECK_NONE ,
VIEW_CHECK_LOCAL , VIEW_CHECK_CASCADED )
2005-02-23 17:51:10 +01:00
NOTES
2005-04-03 00:23:45 +02:00
ancestor is list of tables and views used by view ( underlying tables / views )
2004-07-16 00:15:55 +02:00
2004-10-07 00:45:06 +02:00
DESCRIPTION
It is :
- preparing translation table for view columns ( fix_fields ( ) for every
call and creation for first call )
- preparing WHERE , ON and CHECK OPTION condition ( fix_fields ( ) for every
call and merging for first call ) .
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
2004-10-21 17:10:59 +02:00
bool st_table_list : : setup_ancestor ( THD * thd , Item * * conds ,
uint8 check_opt_type )
2004-07-16 00:15:55 +02:00
{
2004-09-14 18:28:29 +02:00
Field_translator * transl ;
2004-07-16 00:15:55 +02:00
SELECT_LEX * select = & view - > select_lex ;
2004-07-21 03:26:20 +02:00
SELECT_LEX * current_select_save = thd - > lex - > current_select ;
2005-02-10 22:01:59 +01:00
byte * main_table_list_save = select_lex - > table_list . first ;
2004-07-16 00:15:55 +02:00
Item * item ;
2004-09-14 18:28:29 +02:00
TABLE_LIST * tbl ;
2004-07-16 00:15:55 +02:00
List_iterator_fast < Item > it ( select - > item_list ) ;
uint i = 0 ;
2005-02-10 22:01:59 +01:00
enum sub_select_type linkage_save =
select_lex - > master_unit ( ) - > first_select ( ) - > linkage ;
2004-07-16 00:15:55 +02:00
bool save_set_query_id = thd - > set_query_id ;
2005-02-10 22:01:59 +01:00
bool save_wrapper = select_lex - > no_wrap_view_item ;
2004-08-24 19:29:44 +02:00
bool save_allow_sum_func = thd - > allow_sum_func ;
2005-02-23 17:51:10 +01:00
bool res = FALSE ;
2004-07-16 00:15:55 +02:00
DBUG_ENTER ( " st_table_list::setup_ancestor " ) ;
2005-05-31 12:06:15 +02:00
if ( check_stack_overrun ( thd , STACK_MIN_SIZE , ( char * ) & res ) )
2005-04-03 00:23:45 +02:00
return TRUE ;
2004-09-14 18:28:29 +02:00
for ( tbl = ancestor ; tbl ; tbl = tbl - > next_local )
{
2004-11-11 20:18:10 +01:00
if ( tbl - > ancestor & &
tbl - > setup_ancestor ( thd , conds ,
( check_opt_type = = VIEW_CHECK_CASCADED ?
VIEW_CHECK_CASCADED :
VIEW_CHECK_NONE ) ) )
2005-02-23 17:51:10 +01:00
DBUG_RETURN ( TRUE ) ;
2004-09-14 18:28:29 +02:00
}
2004-07-16 00:15:55 +02:00
2005-02-23 17:51:10 +01:00
/*
We have to ensure that inside the view we are not referring to any
table outside of the view . We do it by changing the pointers used
by fix_fields to look up tables so that only tables and views in
view are seen . We also set linkage to DERIVED_TABLE_TYPE as a barrier
so that we stop resolving fields as this level .
*/
thd - > lex - > current_select = select_lex ;
select_lex - > table_list . first = ( byte * ) ancestor ;
select_lex - > master_unit ( ) - > first_select ( ) - > linkage = DERIVED_TABLE_TYPE ;
2004-07-16 00:15:55 +02:00
if ( field_translation )
{
2005-01-05 15:48:23 +01:00
DBUG_PRINT ( " info " , ( " there are already translation table " ) ) ;
2005-02-10 22:01:59 +01:00
select_lex - > no_wrap_view_item = 1 ;
2005-01-18 20:58:12 +01:00
2004-07-16 00:15:55 +02:00
thd - > set_query_id = 1 ;
/* this view was prepared already on previous PS/SP execution */
2004-09-14 18:28:29 +02:00
Field_translator * end = field_translation + select - > item_list . elements ;
/* real rights will be checked in VIEW field */
save_and_clear_want_privilege ( ) ;
/* aggregate function are allowed */
thd - > allow_sum_func = 1 ;
for ( transl = field_translation ; transl < end ; transl + + )
2004-07-16 00:15:55 +02:00
{
2004-09-14 18:28:29 +02:00
if ( ! transl - > item - > fixed & &
transl - > item - > fix_fields ( thd , ancestor , & transl - > item ) )
2004-07-16 00:15:55 +02:00
goto err ;
2004-09-14 18:28:29 +02:00
}
for ( tbl = ancestor ; tbl ; tbl = tbl - > next_local )
{
if ( tbl - > on_expr & & ! tbl - > on_expr - > fixed & &
tbl - > on_expr - > fix_fields ( thd , ancestor , & tbl - > on_expr ) )
goto err ;
}
if ( where & & ! where - > fixed & & where - > fix_fields ( thd , ancestor , & where ) )
goto err ;
2005-01-04 17:04:16 +01:00
if ( check_option & & ! check_option - > fixed & &
2005-01-05 15:48:23 +01:00
check_option - > fix_fields ( thd , ancestor , & check_option ) )
2005-01-04 17:04:16 +01:00
goto err ;
2004-09-14 18:28:29 +02:00
restore_want_privilege ( ) ;
/* WHERE/ON resolved => we can rename fields */
for ( transl = field_translation ; transl < end ; transl + + )
{
transl - > item - > rename ( ( char * ) transl - > name ) ;
2004-07-16 00:15:55 +02:00
}
goto ok ;
}
2005-02-23 17:51:10 +01:00
/* Create view fields translation table */
2004-07-16 00:15:55 +02:00
if ( ! ( transl =
2004-09-14 18:28:29 +02:00
( Field_translator * ) ( thd - > current_arena - >
alloc ( select - > item_list . elements *
sizeof ( Field_translator ) ) ) ) )
2004-07-16 00:15:55 +02:00
{
2005-02-26 11:19:02 +01:00
res = TRUE ;
goto ok ; // Restore thd
2004-07-16 00:15:55 +02:00
}
2004-07-21 03:26:20 +02:00
2005-02-10 22:01:59 +01:00
select_lex - > no_wrap_view_item = 1 ;
2004-07-23 08:20:58 +02:00
2004-07-16 00:15:55 +02:00
/*
Resolve all view items against ancestor table .
TODO : do it only for real used fields " on demand " to mark really
used fields correctly .
*/
thd - > set_query_id = 1 ;
2004-09-14 18:28:29 +02:00
/* real rights will be checked in VIEW field */
save_and_clear_want_privilege ( ) ;
/* aggregate function are allowed */
thd - > allow_sum_func = 1 ;
2004-07-16 00:15:55 +02:00
while ( ( item = it + + ) )
{
2004-09-14 18:28:29 +02:00
/* save original name of view column */
char * name = item - > name ;
2005-01-05 15:48:23 +01:00
transl [ i ] . item = item ;
if ( ! item - > fixed & & item - > fix_fields ( thd , ancestor , & transl [ i ] . item ) )
2004-07-16 00:15:55 +02:00
goto err ;
2004-09-14 18:28:29 +02:00
/* set new item get in fix fields and original column name */
2005-01-05 15:48:23 +01:00
transl [ i + + ] . name = name ;
2004-07-16 00:15:55 +02:00
}
field_translation = transl ;
2004-09-03 20:43:04 +02:00
/* TODO: sort this list? Use hash for big number of fields */
2004-07-16 00:15:55 +02:00
2004-09-14 18:28:29 +02:00
for ( tbl = ancestor ; tbl ; tbl = tbl - > next_local )
{
if ( tbl - > on_expr & & ! tbl - > on_expr - > fixed & &
tbl - > on_expr - > fix_fields ( thd , ancestor , & tbl - > on_expr ) )
goto err ;
}
2004-10-21 12:30:25 +02:00
if ( where | |
2004-10-21 17:10:59 +02:00
( check_opt_type = = VIEW_CHECK_CASCADED & &
2004-10-21 12:30:25 +02:00
ancestor - > check_option ) )
2004-07-16 00:15:55 +02:00
{
2005-06-15 19:58:35 +02:00
Query_arena * arena = thd - > current_arena , backup ;
2004-09-10 21:39:04 +02:00
TABLE_LIST * tbl = this ;
2004-09-10 01:22:44 +02:00
if ( arena - > is_conventional ( ) )
2004-09-09 05:59:26 +02:00
arena = 0 ; // For easier test
2004-10-21 12:30:25 +02:00
if ( where & & ! where - > fixed & & where - > fix_fields ( thd , ancestor , & where ) )
2004-07-16 00:15:55 +02:00
goto err ;
if ( arena )
2004-09-03 20:43:04 +02:00
thd - > set_n_backup_item_arena ( arena , & backup ) ;
2004-09-10 21:39:04 +02:00
2004-10-21 17:10:59 +02:00
if ( check_opt_type )
2004-07-16 00:15:55 +02:00
{
2004-10-21 12:30:25 +02:00
if ( where )
check_option = where - > copy_andor_structure ( thd ) ;
2004-10-21 17:10:59 +02:00
if ( check_opt_type = = VIEW_CHECK_CASCADED )
2004-09-10 21:39:04 +02:00
{
2004-09-03 14:18:40 +02:00
check_option = and_conds ( check_option , ancestor - > check_option ) ;
2004-09-10 21:39:04 +02:00
}
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 )
*/
2004-10-21 12:30:25 +02:00
if ( where & & ! no_where_clause )
2004-07-16 00:15:55 +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 )
2004-09-03 14:18:40 +02:00
{
2004-10-04 12:45:35 +02:00
if ( 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 )
*/
on_expr = and_conds ( on_expr , where ) ;
}
else
{
/*
It is conds of JOIN , but it will be stored in
st_select_lex : : prep_where for next reexecution
*/
* conds = and_conds ( * conds , where ) ;
}
2004-09-03 14:18:40 +02:00
}
2004-07-16 00:15:55 +02:00
}
2004-09-10 21:39:04 +02:00
2004-07-16 00:15:55 +02:00
if ( arena )
thd - > restore_backup_item_arena ( arena , & backup ) ;
}
2004-09-14 18:28:29 +02:00
restore_want_privilege ( ) ;
2004-09-03 14:18:40 +02:00
/*
fix_fields do not need tables , because new are only AND operation and we
just need recollect statistics
*/
if ( check_option & & ! check_option - > fixed & &
check_option - > fix_fields ( thd , 0 , & check_option ) )
goto err ;
2004-07-16 00:15:55 +02:00
2004-09-14 18:28:29 +02:00
/* WHERE/ON resolved => we can rename fields */
{
Field_translator * end = field_translation + select - > item_list . elements ;
for ( transl = field_translation ; transl < end ; transl + + )
{
transl - > item - > rename ( ( char * ) transl - > name ) ;
}
}
2004-07-16 00:15:55 +02:00
2004-08-25 15:14:42 +02:00
/* full text function moving to current select */
if ( view - > select_lex . ftfunc_list - > elements )
{
2005-06-15 19:58:35 +02:00
Query_arena * arena = thd - > current_arena , backup ;
2005-01-04 17:04:16 +01:00
if ( arena - > is_conventional ( ) )
arena = 0 ; // For easier test
else
thd - > set_n_backup_item_arena ( arena , & backup ) ;
2004-08-25 15:14:42 +02:00
Item_func_match * ifm ;
List_iterator_fast < Item_func_match >
li ( * ( view - > select_lex . ftfunc_list ) ) ;
while ( ( ifm = li + + ) )
current_select_save - > ftfunc_list - > push_front ( ifm ) ;
2005-01-04 17:04:16 +01:00
if ( arena )
thd - > restore_backup_item_arena ( arena , & backup ) ;
2004-08-25 15:14:42 +02:00
}
2005-02-23 17:51:10 +01:00
goto ok ;
2004-07-16 00:15:55 +02:00
err :
2005-02-23 17:51:10 +01:00
res = TRUE ;
2004-12-16 14:31:36 +01:00
/* Hide "Unknown column" or "Unknown function" error */
if ( thd - > net . last_errno = = ER_BAD_FIELD_ERROR | |
thd - > net . last_errno = = ER_SP_DOES_NOT_EXIST )
2004-07-21 03:26:20 +02:00
{
thd - > clear_error ( ) ;
my_error ( ER_VIEW_INVALID , MYF ( 0 ) , view_db . str , view_name . str ) ;
}
2005-02-23 17:51:10 +01:00
ok :
2005-02-10 22:01:59 +01:00
select_lex - > no_wrap_view_item = save_wrapper ;
2004-07-21 03:26:20 +02:00
thd - > lex - > current_select = current_select_save ;
2005-02-10 22:01:59 +01:00
select_lex - > table_list . first = main_table_list_save ;
select_lex - > master_unit ( ) - > first_select ( ) - > linkage = linkage_save ;
2004-07-16 00:15:55 +02:00
thd - > set_query_id = save_set_query_id ;
2004-08-24 19:29:44 +02:00
thd - > allow_sum_func = save_allow_sum_func ;
2005-02-23 17:51:10 +01:00
DBUG_RETURN ( res ) ;
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? */
if ( table = = table_to_find & & ancestor = = 0 )
return this ;
for ( TABLE_LIST * tbl = ancestor ; tbl ; tbl = tbl - > next_local )
{
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 ;
2004-11-21 18:33:49 +01:00
Field_translator * end = ( field_translation +
view - > select_lex . item_list . elements ) ;
for ( Field_translator * transl = field_translation ; transl < end ; transl + + )
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-05-11 01:31:13 +02:00
TABLE_LIST * view = ( belong_to_view ? belong_to_view : this ) ;
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
{
for ( TABLE_LIST * tbl = ancestor ; tbl ; tbl = tbl - > next_local )
{
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-05-11 01:31:13 +02:00
DBUG_ASSERT ( view & & ancestor ) ;
2004-09-15 22:42:56 +02:00
for ( TABLE_LIST * tbl = ancestor ; tbl ; tbl = tbl - > next_local )
if ( tbl - > set_insert_values ( mem_root ) )
return TRUE ;
}
return FALSE ;
}
2004-07-16 00:15:55 +02:00
void Field_iterator_view : : set ( TABLE_LIST * table )
{
ptr = table - > field_translation ;
array_end = ptr + table - > view - > select_lex . item_list . elements ;
}
const char * Field_iterator_table : : name ( )
{
return ( * ptr ) - > field_name ;
}
Item * Field_iterator_table : : item ( THD * thd )
{
return new Item_field ( thd , * ptr ) ;
}
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
}
2000-07-31 21:29:14 +02:00
/*****************************************************************************
* * Instansiate templates
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
# ifdef __GNUC__
template class List < String > ;
template class List_iterator < String > ;
# endif