mirror of
https://github.com/MariaDB/server.git
synced 2025-07-16 00:42:55 +03:00
System Versioning 1.0 pre5 [closes #407]
Merge branch '10.3' into trunk Both field_visibility and VERS_HIDDEN_FLAG exist independently. TODO: VERS_HIDDEN_FLAG should be replaced with SYSTEM_INVISIBLE (or COMPLETELY_INVISIBLE?).
This commit is contained in:
182
sql/sql_table.cc
182
sql/sql_table.cc
@ -65,12 +65,16 @@
|
||||
|
||||
const char *primary_key_name="PRIMARY";
|
||||
|
||||
static bool check_if_keyname_exists(const char *name,KEY *start, KEY *end);
|
||||
static int check_if_keyname_exists(const char *name,KEY *start, KEY *end);
|
||||
static char *make_unique_key_name(THD *thd, const char *field_name, KEY *start,
|
||||
KEY *end);
|
||||
static void make_unique_constraint_name(THD *thd, LEX_CSTRING *name,
|
||||
List<Virtual_column_info> *vcol,
|
||||
uint *nr);
|
||||
static const
|
||||
char * make_unique_invisible_field_name(THD *thd, const char *field_name,
|
||||
List<Create_field> *fields);
|
||||
|
||||
static int copy_data_between_tables(THD *thd, TABLE *from,TABLE *to,
|
||||
List<Create_field> &create, bool ignore,
|
||||
uint order_num, ORDER *order,
|
||||
@ -3304,8 +3308,70 @@ bool Column_definition::prepare_stage1_check_typelib_default()
|
||||
}
|
||||
return false;
|
||||
}
|
||||
/*
|
||||
This function adds a invisible field to field_list
|
||||
SYNOPSIS
|
||||
mysql_add_invisible_field()
|
||||
thd Thread Object
|
||||
field_list list of all table fields
|
||||
field_name name/prefix of invisible field
|
||||
( Prefix in the case when it is
|
||||
*COMPLETELY_INVISIBLE*
|
||||
and given name is duplicate)
|
||||
type_handler field data type
|
||||
field_visibility
|
||||
default value
|
||||
RETURN VALUE
|
||||
Create_field pointer
|
||||
*/
|
||||
int mysql_add_invisible_field(THD *thd, List<Create_field> * field_list,
|
||||
const char *field_name, Type_handler *type_handler,
|
||||
field_visible_type field_visibility, Item* default_value)
|
||||
{
|
||||
Create_field *fld= new(thd->mem_root)Create_field();
|
||||
const char *new_name= NULL;
|
||||
/* Get unique field name if field_visibility == COMPLETELY_INVISIBLE */
|
||||
if (field_visibility == COMPLETELY_INVISIBLE)
|
||||
{
|
||||
if ((new_name= make_unique_invisible_field_name(thd, field_name,
|
||||
field_list)))
|
||||
{
|
||||
fld->field_name.str= new_name;
|
||||
fld->field_name.length= strlen(new_name);
|
||||
}
|
||||
else
|
||||
return 1; //Should not happen
|
||||
}
|
||||
else
|
||||
{
|
||||
fld->field_name.str= thd->strmake(field_name, strlen(field_name));
|
||||
fld->field_name.length= strlen(field_name);
|
||||
}
|
||||
fld->set_handler(type_handler);
|
||||
fld->field_visibility= field_visibility;
|
||||
if (default_value)
|
||||
{
|
||||
Virtual_column_info *v= new (thd->mem_root) Virtual_column_info();
|
||||
v->expr= default_value;
|
||||
v->utf8= 0;
|
||||
fld->default_value= v;
|
||||
}
|
||||
field_list->push_front(fld, thd->mem_root);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
Key *
|
||||
mysql_add_invisible_index(THD *thd, List<Key> *key_list,
|
||||
LEX_CSTRING* field_name, enum Key::Keytype type)
|
||||
{
|
||||
Key *key= NULL;
|
||||
key= new (thd->mem_root) Key(type, &null_clex_str, HA_KEY_ALG_UNDEF,
|
||||
false, DDL_options(DDL_options::OPT_NONE));
|
||||
key->columns.push_back(new(thd->mem_root) Key_part_spec(field_name, 0),
|
||||
thd->mem_root);
|
||||
key_list->push_back(key, thd->mem_root);
|
||||
return key;
|
||||
}
|
||||
/*
|
||||
Preparation for table creation
|
||||
|
||||
@ -3353,6 +3419,23 @@ mysql_prepare_create_table(THD *thd, HA_CREATE_INFO *create_info,
|
||||
bool tmp_table= create_table_mode == C_ALTER_TABLE;
|
||||
DBUG_ENTER("mysql_prepare_create_table");
|
||||
|
||||
DBUG_EXECUTE_IF("test_pseudo_invisible",{
|
||||
mysql_add_invisible_field(thd, &alter_info->create_list,
|
||||
"invisible", &type_handler_long, SYSTEM_INVISIBLE,
|
||||
new (thd->mem_root)Item_int(thd, 9));
|
||||
});
|
||||
DBUG_EXECUTE_IF("test_completely_invisible",{
|
||||
mysql_add_invisible_field(thd, &alter_info->create_list,
|
||||
"invisible", &type_handler_long, COMPLETELY_INVISIBLE,
|
||||
new (thd->mem_root)Item_int(thd, 9));
|
||||
});
|
||||
DBUG_EXECUTE_IF("test_invisible_index",{
|
||||
LEX_CSTRING temp;
|
||||
temp.str= "invisible";
|
||||
temp.length= strlen("invisible");
|
||||
mysql_add_invisible_index(thd, &alter_info->key_list
|
||||
, &temp, Key::MULTIPLE);
|
||||
});
|
||||
LEX_CSTRING* connect_string = &create_info->connect_string;
|
||||
if (connect_string->length != 0 &&
|
||||
connect_string->length > CONNECT_STRING_MAXLEN &&
|
||||
@ -3482,7 +3565,6 @@ mysql_prepare_create_table(THD *thd, HA_CREATE_INFO *create_info,
|
||||
while ((sql_field=it++))
|
||||
{
|
||||
DBUG_ASSERT(sql_field->charset != 0);
|
||||
|
||||
if (sql_field->prepare_stage2(file, file->ha_table_flags()))
|
||||
DBUG_RETURN(TRUE);
|
||||
if (sql_field->real_field_type() == MYSQL_TYPE_VARCHAR)
|
||||
@ -3502,8 +3584,18 @@ mysql_prepare_create_table(THD *thd, HA_CREATE_INFO *create_info,
|
||||
*/
|
||||
if (sql_field->stored_in_db())
|
||||
record_offset+= sql_field->pack_length;
|
||||
if (sql_field->field_visibility == USER_DEFINED_INVISIBLE &&
|
||||
sql_field->flags & NOT_NULL_FLAG &&
|
||||
sql_field->flags & NO_DEFAULT_VALUE_FLAG)
|
||||
{
|
||||
my_error(ER_INVISIBLE_NOT_NULL_WITHOUT_DEFAULT, MYF(0),
|
||||
sql_field->field_name.str);
|
||||
DBUG_RETURN(TRUE);
|
||||
}
|
||||
}
|
||||
/* Update virtual fields' offset*/
|
||||
/* Update virtual fields' offset and give error if
|
||||
All fields are invisible */
|
||||
bool is_all_invisible= true;
|
||||
it.rewind();
|
||||
while ((sql_field=it++))
|
||||
{
|
||||
@ -3512,6 +3604,13 @@ mysql_prepare_create_table(THD *thd, HA_CREATE_INFO *create_info,
|
||||
sql_field->offset= record_offset;
|
||||
record_offset+= sql_field->pack_length;
|
||||
}
|
||||
if (sql_field->field_visibility == NOT_INVISIBLE)
|
||||
is_all_invisible= false;
|
||||
}
|
||||
if (is_all_invisible)
|
||||
{
|
||||
my_error(ER_TABLE_MUST_HAVE_COLUMNS, MYF(0));
|
||||
DBUG_RETURN(TRUE);
|
||||
}
|
||||
if (auto_increment > 1)
|
||||
{
|
||||
@ -3762,11 +3861,21 @@ mysql_prepare_create_table(THD *thd, HA_CREATE_INFO *create_info,
|
||||
&column->field_name,
|
||||
&sql_field->field_name))
|
||||
field++;
|
||||
/*
|
||||
Either field is not present or field visibility is >
|
||||
USER_DEFINED_INVISIBLE
|
||||
*/
|
||||
if (!sql_field)
|
||||
{
|
||||
my_error(ER_KEY_COLUMN_DOES_NOT_EXITS, MYF(0), column->field_name.str);
|
||||
DBUG_RETURN(TRUE);
|
||||
}
|
||||
if (sql_field->field_visibility > USER_DEFINED_INVISIBLE &&
|
||||
!key->invisible && DBUG_EVALUATE_IF("test_invisible_index", 0, 1))
|
||||
{
|
||||
my_error(ER_KEY_COLUMN_DOES_NOT_EXITS, MYF(0), column->field_name.str);
|
||||
DBUG_RETURN(TRUE);
|
||||
}
|
||||
while ((dup_column= cols2++) != column)
|
||||
{
|
||||
if (!lex_string_cmp(system_charset_info,
|
||||
@ -5146,17 +5255,36 @@ err:
|
||||
|
||||
/*
|
||||
** Give the key name after the first field with an optional '_#' after
|
||||
@returns
|
||||
0 if keyname does not exists
|
||||
[1..) index + 1 of duplicate key name
|
||||
**/
|
||||
|
||||
static bool
|
||||
static int
|
||||
check_if_keyname_exists(const char *name, KEY *start, KEY *end)
|
||||
{
|
||||
for (KEY *key=start ; key != end ; key++)
|
||||
uint i= 1;
|
||||
for (KEY *key=start; key != end ; key++, i++)
|
||||
if (!my_strcasecmp(system_charset_info, name, key->name.str))
|
||||
return 1;
|
||||
return i;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
Returns 1 if field name exists otherwise 0
|
||||
*/
|
||||
static bool
|
||||
check_if_field_name_exists(const char *name, List<Create_field> * fields)
|
||||
{
|
||||
Create_field *fld;
|
||||
List_iterator<Create_field>it(*fields);
|
||||
while ((fld = it++))
|
||||
{
|
||||
if (!my_strcasecmp(system_charset_info, fld->field_name.str, name))
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static char *
|
||||
make_unique_key_name(THD *thd, const char *field_name,KEY *start,KEY *end)
|
||||
@ -5214,6 +5342,33 @@ static void make_unique_constraint_name(THD *thd, LEX_CSTRING *name,
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
COMPLETELY_INVISIBLE are internally created. They are completely invisible
|
||||
to Alter command (Opposite of SYSTEM_INVISIBLE which throws an
|
||||
error when same name column is added by Alter). So in the case of when
|
||||
user added a same column name as of COMPLETELY_INVISIBLE , we change
|
||||
COMPLETELY_INVISIBLE column name.
|
||||
*/
|
||||
static const
|
||||
char * make_unique_invisible_field_name(THD *thd, const char *field_name,
|
||||
List<Create_field> *fields)
|
||||
{
|
||||
if (!check_if_field_name_exists(field_name, fields))
|
||||
return field_name;
|
||||
char buff[MAX_FIELD_NAME], *buff_end;
|
||||
buff_end= strmake_buf(buff, field_name);
|
||||
if (buff_end - buff < 5)
|
||||
return NULL; // Should not happen
|
||||
|
||||
for (uint i=1 ; i < 10000; i++)
|
||||
{
|
||||
char *real_end= int10_to_str(i, buff_end, 10);
|
||||
if (check_if_field_name_exists(buff, fields))
|
||||
continue;
|
||||
return (const char *)thd->strmake(buff, real_end - buff);
|
||||
}
|
||||
return NULL; //Should not happen
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
** Alter a table definition
|
||||
@ -7732,6 +7887,8 @@ mysql_prepare_alter_table(THD *thd, TABLE *table,
|
||||
bitmap_clear_all(&table->tmp_set);
|
||||
for (f_ptr=table->field ; (field= *f_ptr) ; f_ptr++)
|
||||
{
|
||||
if (field->field_visibility == COMPLETELY_INVISIBLE)
|
||||
continue;
|
||||
Alter_drop *drop;
|
||||
if (field->type() == MYSQL_TYPE_VARCHAR)
|
||||
create_info->varchar= TRUE;
|
||||
@ -7743,7 +7900,7 @@ mysql_prepare_alter_table(THD *thd, TABLE *table,
|
||||
!my_strcasecmp(system_charset_info,field->field_name.str, drop->name))
|
||||
break;
|
||||
}
|
||||
if (drop)
|
||||
if (drop && field->field_visibility < SYSTEM_INVISIBLE)
|
||||
{
|
||||
/* Reset auto_increment value if it was dropped */
|
||||
if (MTYP_TYPENR(field->unireg_check) == Field::NEXT_NUMBER &&
|
||||
@ -7768,7 +7925,7 @@ mysql_prepare_alter_table(THD *thd, TABLE *table,
|
||||
&def->change))
|
||||
break;
|
||||
}
|
||||
if (def)
|
||||
if (def && field->field_visibility < SYSTEM_INVISIBLE)
|
||||
{ // Field is changed
|
||||
def->field=field;
|
||||
/*
|
||||
@ -7823,12 +7980,12 @@ mysql_prepare_alter_table(THD *thd, TABLE *table,
|
||||
def_it.rewind();
|
||||
while ((def=def_it++)) // Add new columns
|
||||
{
|
||||
Create_field *find;
|
||||
if (def->change.str && ! def->field)
|
||||
{
|
||||
/*
|
||||
Check if there is modify for newly added field.
|
||||
*/
|
||||
Create_field *find;
|
||||
find_it.rewind();
|
||||
while((find=find_it++))
|
||||
{
|
||||
@ -7868,7 +8025,6 @@ mysql_prepare_alter_table(THD *thd, TABLE *table,
|
||||
new_create_list.push_back(def, thd->mem_root);
|
||||
else
|
||||
{
|
||||
Create_field *find;
|
||||
if (def->change.str)
|
||||
{
|
||||
find_it.rewind();
|
||||
@ -7955,9 +8111,11 @@ mysql_prepare_alter_table(THD *thd, TABLE *table,
|
||||
Collect all keys which isn't in drop list. Add only those
|
||||
for which some fields exists.
|
||||
*/
|
||||
|
||||
|
||||
for (uint i=0 ; i < table->s->keys ; i++,key_info++)
|
||||
{
|
||||
if (key_info->flags & HA_INVISIBLE_KEY)
|
||||
continue;
|
||||
const char *key_name= key_info->name.str;
|
||||
Alter_drop *drop;
|
||||
drop_it.rewind();
|
||||
|
Reference in New Issue
Block a user