summaryrefslogtreecommitdiff
path: root/sql
diff options
context:
space:
mode:
authorAlexander Barkov <bar@mariadb.com>2019-04-24 15:47:49 +0400
committerAlexander Barkov <bar@mariadb.com>2019-04-25 08:26:08 +0400
commitca7fbcea6c4fe13c295cf43b80d05351aba59e95 (patch)
tree1237b6661132b0e1da3797b320d9bced440d1ec6 /sql
parentbaadbe96019b205164167928d80e836ebbb6bcfe (diff)
downloadmariadb-git-ca7fbcea6c4fe13c295cf43b80d05351aba59e95.tar.gz
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.
Diffstat (limited to 'sql')
-rw-r--r--sql/field.cc20
-rw-r--r--sql/field.h21
-rw-r--r--sql/unireg.cc61
3 files changed, 70 insertions, 32 deletions
diff --git a/sql/field.cc b/sql/field.cc
index e899a1ec4d6..1056a99a498 100644
--- a/sql/field.cc
+++ b/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.
*/
@@ -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,
CHARSET_INFO *cs)
{
diff --git a/sql/field.h b/sql/field.h
index c5195fe4a60..a1fae26dfcc 100644
--- a/sql/field.h
+++ b/sql/field.h
@@ -782,6 +782,11 @@ public:
@retval false - conversion is needed
*/
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_hex_hybrid(const char *str, size_t length);
virtual int store(double nr)=0;
@@ -3895,6 +3900,7 @@ public:
!compression_method() == !from->compression_method() &&
!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);
using Field_str::store;
double val_real(void);
@@ -4212,6 +4218,16 @@ public:
return save_in_field_str(to);
}
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(double nr);
int store(longlong nr, bool unsigned_val);
@@ -4278,6 +4294,11 @@ public:
{
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(const char *to,size_t length,CHARSET_INFO *charset);
int store(double nr) { return Field_set::store((longlong) nr, FALSE); }
diff --git a/sql/unireg.cc b/sql/unireg.cc
index 1d6bb0cdfce..02d876e1455 100644
--- a/sql/unireg.cc
+++ b/sql/unireg.cc
@@ -974,13 +974,36 @@ static bool pack_fields(uchar **buff_arg, List<Create_field> &create_fields,
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 */
static bool make_empty_rec(THD *thd, uchar *buff, uint table_options,
List<Create_field> &create_fields,
uint reclength, ulong data_offset)
{
- int error= 0;
+ int error= false;
uint null_count;
uchar *null_pos;
TABLE table;
@@ -1020,7 +1043,7 @@ static bool make_empty_rec(THD *thd, uchar *buff, uint table_options,
field->flags);
if (!regfield)
{
- error= 1;
+ error= true;
goto err; // End of memory
}
@@ -1037,36 +1060,10 @@ static bool make_empty_rec(THD *thd, uchar *buff, uint table_options,
!f_bit_as_char(field->pack_flag))
null_count+= field->length & 7;
- if (field->default_value && !field->default_value->flags &&
- (!(field->flags & BLOB_FLAG) ||
- field->real_field_type() == MYSQL_TYPE_GEOMETRY))
- {
- 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;
- }
- 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();
+ error= make_empty_rec_store_default(thd, regfield, field->default_value);
+ delete regfield; // Avoid memory leaks
+ if (error)
+ goto err;
}
DBUG_ASSERT(data_offset == ((null_count + 7) / 8));