MDEV-19317 TEXT column accepts too long literals as a default value
Adding new virtual methods in Field: - make_empty_rec_store_default_value() - make_empty_rec_reset() This simplifies the logic for every Field type, and makes the code more friendly to pluggable data types.
This commit is contained in:
parent
baadbe9601
commit
ca7fbcea6c
@ -1093,3 +1093,34 @@ drop table t1;
|
|||||||
#
|
#
|
||||||
# End of 10.2 test
|
# End of 10.2 test
|
||||||
#
|
#
|
||||||
|
#
|
||||||
|
# Start of 10.4 test
|
||||||
|
#
|
||||||
|
#
|
||||||
|
# MDEV-19317 TEXT column accepts too long literals as a default value
|
||||||
|
#
|
||||||
|
EXECUTE IMMEDIATE 'CREATE OR REPLACE TABLE t1 (a TINYTEXT DEFAULT ?)' USING REPEAT('a', 255);
|
||||||
|
INSERT INTO t1 VALUES ();
|
||||||
|
SELECT LENGTH(a), LENGTH(DEFAULT(a)) FROM t1;
|
||||||
|
LENGTH(a) LENGTH(DEFAULT(a))
|
||||||
|
255 255
|
||||||
|
DROP TABLE t1;
|
||||||
|
EXECUTE IMMEDIATE 'CREATE OR REPLACE TABLE t1 (a TINYTEXT DEFAULT ?)' USING REPEAT('a', 256);
|
||||||
|
ERROR 42000: Invalid default value for 'a'
|
||||||
|
CREATE OR REPLACE TABLE t1 (a TINYTEXT DEFAULT 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa');
|
||||||
|
ERROR 42000: Invalid default value for 'a'
|
||||||
|
EXECUTE IMMEDIATE 'CREATE OR REPLACE TABLE t1 (a TEXT DEFAULT ?)' USING REPEAT('a', 256);
|
||||||
|
INSERT INTO t1 VALUES ();
|
||||||
|
SELECT LENGTH(a), LENGTH(DEFAULT(a)) FROM t1;
|
||||||
|
LENGTH(a) LENGTH(DEFAULT(a))
|
||||||
|
256 256
|
||||||
|
DROP TABLE t1;
|
||||||
|
CREATE OR REPLACE TABLE t1 (a TEXT DEFAULT 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa');
|
||||||
|
INSERT INTO t1 VALUES ();
|
||||||
|
SELECT LENGTH(a), LENGTH(DEFAULT(a)) FROM t1;
|
||||||
|
LENGTH(a) LENGTH(DEFAULT(a))
|
||||||
|
256 256
|
||||||
|
DROP TABLE t1;
|
||||||
|
#
|
||||||
|
# End of 10.4 test
|
||||||
|
#
|
||||||
|
@ -702,3 +702,39 @@ drop table t1;
|
|||||||
--echo #
|
--echo #
|
||||||
--echo # End of 10.2 test
|
--echo # End of 10.2 test
|
||||||
--echo #
|
--echo #
|
||||||
|
|
||||||
|
|
||||||
|
--echo #
|
||||||
|
--echo # Start of 10.4 test
|
||||||
|
--echo #
|
||||||
|
|
||||||
|
--echo #
|
||||||
|
--echo # MDEV-19317 TEXT column accepts too long literals as a default value
|
||||||
|
--echo #
|
||||||
|
|
||||||
|
EXECUTE IMMEDIATE 'CREATE OR REPLACE TABLE t1 (a TINYTEXT DEFAULT ?)' USING REPEAT('a', 255);
|
||||||
|
INSERT INTO t1 VALUES ();
|
||||||
|
SELECT LENGTH(a), LENGTH(DEFAULT(a)) FROM t1;
|
||||||
|
DROP TABLE t1;
|
||||||
|
|
||||||
|
--error ER_INVALID_DEFAULT
|
||||||
|
EXECUTE IMMEDIATE 'CREATE OR REPLACE TABLE t1 (a TINYTEXT DEFAULT ?)' USING REPEAT('a', 256);
|
||||||
|
|
||||||
|
--error ER_INVALID_DEFAULT
|
||||||
|
CREATE OR REPLACE TABLE t1 (a TINYTEXT DEFAULT 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa');
|
||||||
|
|
||||||
|
|
||||||
|
EXECUTE IMMEDIATE 'CREATE OR REPLACE TABLE t1 (a TEXT DEFAULT ?)' USING REPEAT('a', 256);
|
||||||
|
INSERT INTO t1 VALUES ();
|
||||||
|
SELECT LENGTH(a), LENGTH(DEFAULT(a)) FROM t1;
|
||||||
|
DROP TABLE t1;
|
||||||
|
|
||||||
|
CREATE OR REPLACE TABLE t1 (a TEXT DEFAULT 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa');
|
||||||
|
INSERT INTO t1 VALUES ();
|
||||||
|
SELECT LENGTH(a), LENGTH(DEFAULT(a)) FROM t1;
|
||||||
|
DROP TABLE t1;
|
||||||
|
|
||||||
|
|
||||||
|
--echo #
|
||||||
|
--echo # End of 10.4 test
|
||||||
|
--echo #
|
||||||
|
20
sql/field.cc
20
sql/field.cc
@ -1382,6 +1382,14 @@ error:
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool Field::make_empty_rec_store_default_value(THD *thd, Item *item)
|
||||||
|
{
|
||||||
|
DBUG_ASSERT(!(flags & BLOB_FLAG));
|
||||||
|
int res= item->save_in_field(this, true);
|
||||||
|
return res != 0 && res != 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Numeric fields base class constructor.
|
Numeric fields base class constructor.
|
||||||
*/
|
*/
|
||||||
@ -8773,6 +8781,18 @@ void Field_blob::make_send_field(Send_field *field)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool Field_blob::make_empty_rec_store_default_value(THD *thd, Item *item)
|
||||||
|
{
|
||||||
|
DBUG_ASSERT(flags & BLOB_FLAG);
|
||||||
|
int res= item->save_in_field(this, true);
|
||||||
|
DBUG_ASSERT(res != 3); // Field_blob never returns 3
|
||||||
|
if (res)
|
||||||
|
return true; // E.g. truncation happened
|
||||||
|
reset(); // Clear the pointer to a String, it should not be written to frm
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
int Field_blob_compressed::store(const char *from, size_t length,
|
int Field_blob_compressed::store(const char *from, size_t length,
|
||||||
CHARSET_INFO *cs)
|
CHARSET_INFO *cs)
|
||||||
{
|
{
|
||||||
|
21
sql/field.h
21
sql/field.h
@ -782,6 +782,11 @@ public:
|
|||||||
@retval false - conversion is needed
|
@retval false - conversion is needed
|
||||||
*/
|
*/
|
||||||
virtual bool memcpy_field_possible(const Field *from) const= 0;
|
virtual bool memcpy_field_possible(const Field *from) const= 0;
|
||||||
|
virtual bool make_empty_rec_store_default_value(THD *thd, Item *item);
|
||||||
|
virtual void make_empty_rec_reset(THD *thd)
|
||||||
|
{
|
||||||
|
reset();
|
||||||
|
}
|
||||||
virtual int store(const char *to, size_t length,CHARSET_INFO *cs)=0;
|
virtual int store(const char *to, size_t length,CHARSET_INFO *cs)=0;
|
||||||
virtual int store_hex_hybrid(const char *str, size_t length);
|
virtual int store_hex_hybrid(const char *str, size_t length);
|
||||||
virtual int store(double nr)=0;
|
virtual int store(double nr)=0;
|
||||||
@ -3895,6 +3900,7 @@ public:
|
|||||||
!compression_method() == !from->compression_method() &&
|
!compression_method() == !from->compression_method() &&
|
||||||
!table->copy_blobs;
|
!table->copy_blobs;
|
||||||
}
|
}
|
||||||
|
bool make_empty_rec_store_default_value(THD *thd, Item *item);
|
||||||
int store(const char *to, size_t length, CHARSET_INFO *charset);
|
int store(const char *to, size_t length, CHARSET_INFO *charset);
|
||||||
using Field_str::store;
|
using Field_str::store;
|
||||||
double val_real(void);
|
double val_real(void);
|
||||||
@ -4212,6 +4218,16 @@ public:
|
|||||||
return save_in_field_str(to);
|
return save_in_field_str(to);
|
||||||
}
|
}
|
||||||
bool memcpy_field_possible(const Field *from) const { return false; }
|
bool memcpy_field_possible(const Field *from) const { return false; }
|
||||||
|
void make_empty_rec_reset(THD *thd)
|
||||||
|
{
|
||||||
|
if (flags & NOT_NULL_FLAG)
|
||||||
|
{
|
||||||
|
set_notnull();
|
||||||
|
store((longlong) 1, true);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
reset();
|
||||||
|
}
|
||||||
int store(const char *to,size_t length,CHARSET_INFO *charset);
|
int store(const char *to,size_t length,CHARSET_INFO *charset);
|
||||||
int store(double nr);
|
int store(double nr);
|
||||||
int store(longlong nr, bool unsigned_val);
|
int store(longlong nr, bool unsigned_val);
|
||||||
@ -4278,6 +4294,11 @@ public:
|
|||||||
{
|
{
|
||||||
flags=(flags & ~ENUM_FLAG) | SET_FLAG;
|
flags=(flags & ~ENUM_FLAG) | SET_FLAG;
|
||||||
}
|
}
|
||||||
|
void make_empty_rec_reset(THD *thd)
|
||||||
|
{
|
||||||
|
Field::make_empty_rec_reset(thd);
|
||||||
|
}
|
||||||
|
|
||||||
int store_field(Field *from) { return from->save_in_field(this); }
|
int store_field(Field *from) { return from->save_in_field(this); }
|
||||||
int store(const char *to,size_t length,CHARSET_INFO *charset);
|
int store(const char *to,size_t length,CHARSET_INFO *charset);
|
||||||
int store(double nr) { return Field_set::store((longlong) nr, FALSE); }
|
int store(double nr) { return Field_set::store((longlong) nr, FALSE); }
|
||||||
|
@ -974,13 +974,36 @@ static bool pack_fields(uchar **buff_arg, List<Create_field> &create_fields,
|
|||||||
DBUG_RETURN(0);
|
DBUG_RETURN(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static bool make_empty_rec_store_default(THD *thd, Field *regfield,
|
||||||
|
Virtual_column_info *default_value)
|
||||||
|
{
|
||||||
|
if (default_value && !default_value->flags)
|
||||||
|
{
|
||||||
|
Item *expr= default_value->expr;
|
||||||
|
// may be already fixed if ALTER TABLE
|
||||||
|
if (expr->fix_fields_if_needed(thd, &expr))
|
||||||
|
return true;
|
||||||
|
DBUG_ASSERT(expr == default_value->expr); // Should not change
|
||||||
|
if (regfield->make_empty_rec_store_default_value(thd, expr))
|
||||||
|
{
|
||||||
|
my_error(ER_INVALID_DEFAULT, MYF(0), regfield->field_name.str);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
regfield->make_empty_rec_reset(thd);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/* save an empty record on start of formfile */
|
/* save an empty record on start of formfile */
|
||||||
|
|
||||||
static bool make_empty_rec(THD *thd, uchar *buff, uint table_options,
|
static bool make_empty_rec(THD *thd, uchar *buff, uint table_options,
|
||||||
List<Create_field> &create_fields,
|
List<Create_field> &create_fields,
|
||||||
uint reclength, ulong data_offset)
|
uint reclength, ulong data_offset)
|
||||||
{
|
{
|
||||||
int error= 0;
|
int error= false;
|
||||||
uint null_count;
|
uint null_count;
|
||||||
uchar *null_pos;
|
uchar *null_pos;
|
||||||
TABLE table;
|
TABLE table;
|
||||||
@ -1020,7 +1043,7 @@ static bool make_empty_rec(THD *thd, uchar *buff, uint table_options,
|
|||||||
field->flags);
|
field->flags);
|
||||||
if (!regfield)
|
if (!regfield)
|
||||||
{
|
{
|
||||||
error= 1;
|
error= true;
|
||||||
goto err; // End of memory
|
goto err; // End of memory
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1037,37 +1060,11 @@ static bool make_empty_rec(THD *thd, uchar *buff, uint table_options,
|
|||||||
!f_bit_as_char(field->pack_flag))
|
!f_bit_as_char(field->pack_flag))
|
||||||
null_count+= field->length & 7;
|
null_count+= field->length & 7;
|
||||||
|
|
||||||
if (field->default_value && !field->default_value->flags &&
|
error= make_empty_rec_store_default(thd, regfield, field->default_value);
|
||||||
(!(field->flags & BLOB_FLAG) ||
|
delete regfield; // Avoid memory leaks
|
||||||
field->real_field_type() == MYSQL_TYPE_GEOMETRY))
|
if (error)
|
||||||
{
|
|
||||||
Item *expr= field->default_value->expr;
|
|
||||||
// may be already fixed if ALTER TABLE
|
|
||||||
int res= expr->fix_fields_if_needed(thd, &expr);
|
|
||||||
if (!res)
|
|
||||||
res= expr->save_in_field(regfield, 1);
|
|
||||||
if (!res && (field->flags & BLOB_FLAG))
|
|
||||||
regfield->reset();
|
|
||||||
|
|
||||||
/* If not ok or warning of level 'note' */
|
|
||||||
if (res != 0 && res != 3)
|
|
||||||
{
|
|
||||||
my_error(ER_INVALID_DEFAULT, MYF(0), regfield->field_name.str);
|
|
||||||
error= 1;
|
|
||||||
delete regfield; //To avoid memory leak
|
|
||||||
goto err;
|
goto err;
|
||||||
}
|
}
|
||||||
delete regfield; //To avoid memory leak
|
|
||||||
}
|
|
||||||
else if (regfield->real_type() == MYSQL_TYPE_ENUM &&
|
|
||||||
(field->flags & NOT_NULL_FLAG))
|
|
||||||
{
|
|
||||||
regfield->set_notnull();
|
|
||||||
regfield->store((longlong) 1, TRUE);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
regfield->reset();
|
|
||||||
}
|
|
||||||
DBUG_ASSERT(data_offset == ((null_count + 7) / 8));
|
DBUG_ASSERT(data_offset == ((null_count + 7) / 8));
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
Loading…
x
Reference in New Issue
Block a user