summaryrefslogtreecommitdiff
path: root/sql/field.cc
diff options
context:
space:
mode:
authorunknown <anozdrin@mysql.com>2005-12-07 17:01:17 +0300
committerunknown <anozdrin@mysql.com>2005-12-07 17:01:17 +0300
commit6b2f13098a59d9ad520828dca4cb63da8c86b5e3 (patch)
tree82814a574624a8e813cc8dfad8c31d3fa4adf898 /sql/field.cc
parent29eac312cda3bebddeb7f5ab7a2af6b81ea89205 (diff)
downloadmariadb-git-6b2f13098a59d9ad520828dca4cb63da8c86b5e3.tar.gz
Patch for WL#2894: Make stored routine variables work
according to the standard. The idea is to use Field-classes to implement stored routines variables. Also, we should provide facade to Item-hierarchy by Item_field class (it is necessary, since SRVs take part in expressions). The patch fixes the following bugs: - BUG#8702: Stored Procedures: No Error/Warning shown for inappropriate data type matching; - BUG#8768: Functions: For any unsigned data type, -ve values can be passed and returned; - BUG#8769: Functions: For Int datatypes, out of range values can be passed and returned; - BUG#9078: STORED PROCDURE: Decimal digits are not displayed when we use DECIMAL datatype; - BUG#9572: Stored procedures: variable type declarations ignored; - BUG#12903: upper function does not work inside a function; - BUG#13705: parameters to stored procedures are not verified; - BUG#13808: ENUM type stored procedure parameter accepts non-enumerated data; - BUG#13909: Varchar Stored Procedure Parameter always BINARY string (ignores CHARACTER SET); - BUG#14161: Stored procedure cannot retrieve bigint unsigned; - BUG#14188: BINARY variables have no 0x00 padding; - BUG#15148: Stored procedure variables accept non-scalar values; mysql-test/r/ctype_ujis.result: Explicitly specify correct charset. mysql-test/r/schema.result: Drop our test database to not affect this test if some test left it cause of failure. mysql-test/r/show_check.result: Drop our test database to not affect this test if some test left it cause of failure. mysql-test/r/skip_name_resolve.result: Ignore columns with unpredictable values. mysql-test/r/sp-big.result: Add cleanup statement. mysql-test/r/sp-dynamic.result: Add cleanup statements. mysql-test/r/sp.result: Update result file. mysql-test/r/sum_distinct-big.result: Update result file. mysql-test/r/type_newdecimal-big.result: Update result file. mysql-test/t/ctype_ujis.test: Explicitly specify correct charset. mysql-test/t/schema.test: Drop our test database to not affect this test if some test left it cause of failure. mysql-test/t/show_check.test: Drop our test database to not affect this test if some test left it cause of failure. mysql-test/t/skip_name_resolve.test: Ignore columns with unpredictable values. mysql-test/t/sp-big.test: Add cleanup statement. mysql-test/t/sp-dynamic.test: Add cleanup statements. mysql-test/t/sp.test: Non-scalar values prohibited for assignment to SP-vars; polishing. mysql-test/t/type_newdecimal-big.test: Update type specification so that the variables can contain the large values used in the test. sql/field.cc: Extract create_field::init() to initialize an existing instance of create_field from new_create_field(). sql/field.h: Extract create_field::init() to initialize an existing instance of create_field from new_create_field(). sql/item.cc: - Introduce a new class: Item_sp_variable -- a base class of stored-routine-variables classes; - Introduce Item_case_expr -- an Item, which is used to access to the expression of CASE statement; sql/item.h: - Introduce a new class: Item_sp_variable -- a base class of stored-routine-variables classes; - Introduce Item_case_expr -- an Item, which is used to access to the expression of CASE statement; sql/item_func.cc: Pass the Field (instead of Item) for the return value of a function to the function execution routine. sql/item_func.h: Pass the Field (instead of Item) for the return value of a function to the function execution routine. sql/mysql_priv.h: Move create_virtual_tmp_table() out of sql_select.h. sql/sp.cc: Use create_result_field() instead of make_field(). sql/sp_head.cc: - Add a function to map enum_field_types to Item::Type; - Add sp_instr_push_case_expr instruction -- an instruction to push CASE expression into the active running context; - Add sp_instr_pop_case_expr instruction -- an instruction to pop CASE expression from the active running context; - Adapt the SP-execution code to using Fields instead of Items for SP-vars; - Use create_field structure for field description instead of a set of members. sql/sp_head.h: - Add a function to map enum_field_types to Item::Type; - Add sp_instr_push_case_expr instruction -- an instruction to push CASE expression into the active running context; - Add sp_instr_pop_case_expr instruction -- an instruction to pop CASE expression from the active running context; - Adapt the SP-execution code to using Fields instead of Items for SP-vars; - Use create_field structure for field description instead of a set of members. sql/sp_pcontext.cc: - Change rules to assign an index of SP-variable: use transparent index; - Add an operation to retrieve a list of defined SP-vars from the processing context recursively. sql/sp_pcontext.h: - Change rules to assign an index of SP-variable: use transparent index; - Add an operation to retrieve a list of defined SP-vars from the processing context recursively. sql/sp_rcontext.cc: - Change rules to assign an index of SP-variable: use transparent index; - Use a tmp virtual table to store SP-vars instead of Items; - Provide operations to work with CASE expresion. sql/sp_rcontext.h: - Change rules to assign an index of SP-variable: use transparent index; - Use a tmp virtual table to store SP-vars instead of Items; - Provide operations to work with CASE expresion. sql/sql_class.cc: - Reflect Item_splocal ctor changes; - Item_splocal::get_offset() has been renamed to get_var_idx(). sql/sql_class.h: Polishing. sql/sql_parse.cc: Extract create_field::init() to initialize an existing instance of create_field from new_create_field(). sql/sql_select.cc: Take care of BLOB columns in create_virtual_tmp_table(). sql/sql_select.h: Move create_virtual_tmp_table() out of sql_select.h. sql/sql_trigger.cc: Use boolean constants for boolean type instead of numerical ones. sql/sql_yacc.yy: Provide an instance of create_field for each SP-var. mysql-test/include/sp-vars.inc: The definitions of common-procedures, which are created under different circumstances. mysql-test/r/sp-vars.result: Result file for the SP-vars test. mysql-test/sp-vars.test: A new test for checking SP-vars functionality.
Diffstat (limited to 'sql/field.cc')
-rw-r--r--sql/field.cc347
1 files changed, 347 insertions, 0 deletions
diff --git a/sql/field.cc b/sql/field.cc
index 6de2a731030..53596f1cf79 100644
--- a/sql/field.cc
+++ b/sql/field.cc
@@ -6748,7 +6748,10 @@ Field_blob::Field_blob(char *ptr_arg, uchar *null_ptr_arg, uchar null_bit_arg,
{
flags|= BLOB_FLAG;
if (table)
+ {
table->s->blob_fields++;
+ /* TODO: why do not fill table->s->blob_field array here? */
+ }
}
@@ -8272,6 +8275,350 @@ void create_field::init_for_tmp_table(enum_field_types sql_type_arg,
}
+/*
+ Initialize field definition for create
+
+ SYNOPSIS
+ thd Thread handle
+ fld_name Field name
+ fld_type Field type
+ fld_length Field length
+ fld_decimals Decimal (if any)
+ fld_type_modifier Additional type information
+ fld_default_value Field default value (if any)
+ fld_on_update_value The value of ON UPDATE clause
+ fld_comment Field comment
+ fld_change Field change
+ fld_interval_list Interval list (if any)
+ fld_charset Field charset
+ fld_geom_type Field geometry type (if any)
+
+ RETURN
+ FALSE on success
+ TRUE on error
+*/
+
+bool create_field::init(THD *thd, char *fld_name, enum_field_types fld_type,
+ char *fld_length, char *fld_decimals,
+ uint fld_type_modifier, Item *fld_default_value,
+ Item *fld_on_update_value, LEX_STRING *fld_comment,
+ char *fld_change, List<String> *fld_interval_list,
+ CHARSET_INFO *fld_charset, uint fld_geom_type)
+{
+ uint sign_len, allowed_type_modifier= 0;
+ ulong max_field_charlength= MAX_FIELD_CHARLENGTH;
+
+ DBUG_ENTER("create_field::init()");
+
+ field= 0;
+ field_name= fld_name;
+ def= fld_default_value;
+ flags= fld_type_modifier;
+ unireg_check= (fld_type_modifier & AUTO_INCREMENT_FLAG ?
+ Field::NEXT_NUMBER : Field::NONE);
+ decimals= fld_decimals ? (uint)atoi(fld_decimals) : 0;
+ if (decimals >= NOT_FIXED_DEC)
+ {
+ my_error(ER_TOO_BIG_SCALE, MYF(0), decimals, fld_name,
+ NOT_FIXED_DEC-1);
+ DBUG_RETURN(TRUE);
+ }
+
+ sql_type= fld_type;
+ length= 0;
+ change= fld_change;
+ interval= 0;
+ pack_length= key_length= 0;
+ charset= fld_charset;
+ geom_type= (Field::geometry_type) fld_geom_type;
+ interval_list.empty();
+
+ comment= *fld_comment;
+ /*
+ Set flag if this field doesn't have a default value
+ */
+ if (!fld_default_value && !(fld_type_modifier & AUTO_INCREMENT_FLAG) &&
+ (fld_type_modifier & NOT_NULL_FLAG) && fld_type != FIELD_TYPE_TIMESTAMP)
+ flags|= NO_DEFAULT_VALUE_FLAG;
+
+ if (fld_length && !(length= (uint) atoi(fld_length)))
+ fld_length= 0; /* purecov: inspected */
+ sign_len= fld_type_modifier & UNSIGNED_FLAG ? 0 : 1;
+
+ switch (fld_type) {
+ case FIELD_TYPE_TINY:
+ if (!fld_length)
+ length= MAX_TINYINT_WIDTH+sign_len;
+ allowed_type_modifier= AUTO_INCREMENT_FLAG;
+ break;
+ case FIELD_TYPE_SHORT:
+ if (!fld_length)
+ length= MAX_SMALLINT_WIDTH+sign_len;
+ allowed_type_modifier= AUTO_INCREMENT_FLAG;
+ break;
+ case FIELD_TYPE_INT24:
+ if (!fld_length)
+ length= MAX_MEDIUMINT_WIDTH+sign_len;
+ allowed_type_modifier= AUTO_INCREMENT_FLAG;
+ break;
+ case FIELD_TYPE_LONG:
+ if (!fld_length)
+ length= MAX_INT_WIDTH+sign_len;
+ allowed_type_modifier= AUTO_INCREMENT_FLAG;
+ break;
+ case FIELD_TYPE_LONGLONG:
+ if (!fld_length)
+ length= MAX_BIGINT_WIDTH;
+ allowed_type_modifier= AUTO_INCREMENT_FLAG;
+ break;
+ case FIELD_TYPE_NULL:
+ break;
+ case FIELD_TYPE_NEWDECIMAL:
+ if (!fld_length && !decimals)
+ length= 10;
+ if (length > DECIMAL_MAX_PRECISION)
+ {
+ my_error(ER_TOO_BIG_PRECISION, MYF(0), length, fld_name,
+ DECIMAL_MAX_PRECISION);
+ DBUG_RETURN(TRUE);
+ }
+ if (length < decimals)
+ {
+ my_error(ER_M_BIGGER_THAN_D, MYF(0), fld_name);
+ DBUG_RETURN(TRUE);
+ }
+ length=
+ my_decimal_precision_to_length(length, decimals,
+ fld_type_modifier & UNSIGNED_FLAG);
+ pack_length=
+ my_decimal_get_binary_size(length, decimals);
+ break;
+ case MYSQL_TYPE_VARCHAR:
+ /*
+ Long VARCHAR's are automaticly converted to blobs in mysql_prepare_table
+ if they don't have a default value
+ */
+ max_field_charlength= MAX_FIELD_VARCHARLENGTH;
+ break;
+ case MYSQL_TYPE_STRING:
+ break;
+ case FIELD_TYPE_BLOB:
+ case FIELD_TYPE_TINY_BLOB:
+ case FIELD_TYPE_LONG_BLOB:
+ case FIELD_TYPE_MEDIUM_BLOB:
+ case FIELD_TYPE_GEOMETRY:
+ if (fld_default_value)
+ {
+ /* Allow empty as default value. */
+ String str,*res;
+ res= fld_default_value->val_str(&str);
+ if (res->length())
+ {
+ my_error(ER_BLOB_CANT_HAVE_DEFAULT, MYF(0),
+ fld_name); /* purecov: inspected */
+ DBUG_RETURN(TRUE);
+ }
+ def= 0;
+ }
+ flags|= BLOB_FLAG;
+ break;
+ case FIELD_TYPE_YEAR:
+ if (!fld_length || length != 2)
+ length= 4; /* Default length */
+ flags|= ZEROFILL_FLAG | UNSIGNED_FLAG;
+ break;
+ case FIELD_TYPE_FLOAT:
+ /* change FLOAT(precision) to FLOAT or DOUBLE */
+ allowed_type_modifier= AUTO_INCREMENT_FLAG;
+ if (fld_length && !fld_decimals)
+ {
+ uint tmp_length= length;
+ if (tmp_length > PRECISION_FOR_DOUBLE)
+ {
+ my_error(ER_WRONG_FIELD_SPEC, MYF(0), fld_name);
+ DBUG_RETURN(TRUE);
+ }
+ else if (tmp_length > PRECISION_FOR_FLOAT)
+ {
+ sql_type= FIELD_TYPE_DOUBLE;
+ length= DBL_DIG+7; /* -[digits].E+### */
+ }
+ else
+ length= FLT_DIG+6; /* -[digits].E+## */
+ decimals= NOT_FIXED_DEC;
+ break;
+ }
+ if (!fld_length && !fld_decimals)
+ {
+ length= FLT_DIG+6;
+ decimals= NOT_FIXED_DEC;
+ }
+ if (length < decimals &&
+ decimals != NOT_FIXED_DEC)
+ {
+ my_error(ER_M_BIGGER_THAN_D, MYF(0), fld_name);
+ DBUG_RETURN(TRUE);
+ }
+ break;
+ case FIELD_TYPE_DOUBLE:
+ allowed_type_modifier= AUTO_INCREMENT_FLAG;
+ if (!fld_length && !fld_decimals)
+ {
+ length= DBL_DIG+7;
+ decimals= NOT_FIXED_DEC;
+ }
+ if (length < decimals &&
+ decimals != NOT_FIXED_DEC)
+ {
+ my_error(ER_M_BIGGER_THAN_D, MYF(0), fld_name);
+ DBUG_RETURN(TRUE);
+ }
+ break;
+ case FIELD_TYPE_TIMESTAMP:
+ if (!fld_length)
+ length= 14; /* Full date YYYYMMDDHHMMSS */
+ else if (length != 19)
+ {
+ /*
+ We support only even TIMESTAMP lengths less or equal than 14
+ and 19 as length of 4.1 compatible representation.
+ */
+ length= ((length+1)/2)*2; /* purecov: inspected */
+ length= min(length,14); /* purecov: inspected */
+ }
+ flags|= ZEROFILL_FLAG | UNSIGNED_FLAG;
+ if (fld_default_value)
+ {
+ /* Grammar allows only NOW() value for ON UPDATE clause */
+ if (fld_default_value->type() == Item::FUNC_ITEM &&
+ ((Item_func*)fld_default_value)->functype() == Item_func::NOW_FUNC)
+ {
+ unireg_check= (fld_on_update_value ? Field::TIMESTAMP_DNUN_FIELD:
+ Field::TIMESTAMP_DN_FIELD);
+ /*
+ We don't need default value any longer moreover it is dangerous.
+ Everything handled by unireg_check further.
+ */
+ def= 0;
+ }
+ else
+ unireg_check= (fld_on_update_value ? Field::TIMESTAMP_UN_FIELD:
+ Field::NONE);
+ }
+ else
+ {
+ /*
+ If we have default TIMESTAMP NOT NULL column without explicit DEFAULT
+ or ON UPDATE values then for the sake of compatiblity we should treat
+ this column as having DEFAULT NOW() ON UPDATE NOW() (when we don't
+ have another TIMESTAMP column with auto-set option before this one)
+ or DEFAULT 0 (in other cases).
+ So here we are setting TIMESTAMP_OLD_FIELD only temporary, and will
+ replace this value by TIMESTAMP_DNUN_FIELD or NONE later when
+ information about all TIMESTAMP fields in table will be availiable.
+
+ If we have TIMESTAMP NULL column without explicit DEFAULT value
+ we treat it as having DEFAULT NULL attribute.
+ */
+ unireg_check= (fld_on_update_value ? Field::TIMESTAMP_UN_FIELD :
+ (flags & NOT_NULL_FLAG ? Field::TIMESTAMP_OLD_FIELD :
+ Field::NONE));
+ }
+ break;
+ case FIELD_TYPE_DATE:
+ /* Old date type. */
+ if (protocol_version != PROTOCOL_VERSION-1)
+ sql_type= FIELD_TYPE_NEWDATE;
+ /* fall trough */
+ case FIELD_TYPE_NEWDATE:
+ length= 10;
+ break;
+ case FIELD_TYPE_TIME:
+ length= 10;
+ break;
+ case FIELD_TYPE_DATETIME:
+ length= 19;
+ break;
+ case FIELD_TYPE_SET:
+ {
+ if (fld_interval_list->elements > sizeof(longlong)*8)
+ {
+ my_error(ER_TOO_BIG_SET, MYF(0), fld_name); /* purecov: inspected */
+ DBUG_RETURN(TRUE);
+ }
+ pack_length= get_set_pack_length(fld_interval_list->elements);
+
+ List_iterator<String> it(*fld_interval_list);
+ String *tmp;
+ while ((tmp= it++))
+ interval_list.push_back(tmp);
+ /*
+ Set fake length to 1 to pass the below conditions.
+ Real length will be set in mysql_prepare_table()
+ when we know the character set of the column
+ */
+ length= 1;
+ break;
+ }
+ case FIELD_TYPE_ENUM:
+ {
+ /* Should be safe. */
+ pack_length= get_enum_pack_length(fld_interval_list->elements);
+
+ List_iterator<String> it(*fld_interval_list);
+ String *tmp;
+ while ((tmp= it++))
+ interval_list.push_back(tmp);
+ length= 1; /* See comment for FIELD_TYPE_SET above. */
+ break;
+ }
+ case MYSQL_TYPE_VAR_STRING:
+ DBUG_ASSERT(0); /* Impossible. */
+ break;
+ case MYSQL_TYPE_BIT:
+ {
+ if (!fld_length)
+ length= 1;
+ if (length > MAX_BIT_FIELD_LENGTH)
+ {
+ my_error(ER_TOO_BIG_DISPLAYWIDTH, MYF(0), fld_name,
+ MAX_BIT_FIELD_LENGTH);
+ DBUG_RETURN(TRUE);
+ }
+ pack_length= (length + 7) / 8;
+ break;
+ }
+ case FIELD_TYPE_DECIMAL:
+ DBUG_ASSERT(0); /* Was obsolete */
+ }
+
+ if (!(flags & BLOB_FLAG) &&
+ ((length > max_field_charlength && fld_type != FIELD_TYPE_SET &&
+ fld_type != FIELD_TYPE_ENUM &&
+ (fld_type != MYSQL_TYPE_VARCHAR || fld_default_value)) ||
+ (!length &&
+ fld_type != MYSQL_TYPE_STRING &&
+ fld_type != MYSQL_TYPE_VARCHAR && fld_type != FIELD_TYPE_GEOMETRY)))
+ {
+ my_error((fld_type == MYSQL_TYPE_VAR_STRING ||
+ fld_type == MYSQL_TYPE_VARCHAR ||
+ fld_type == MYSQL_TYPE_STRING) ? ER_TOO_BIG_FIELDLENGTH :
+ ER_TOO_BIG_DISPLAYWIDTH,
+ MYF(0),
+ fld_name, max_field_charlength); /* purecov: inspected */
+ DBUG_RETURN(TRUE);
+ }
+ fld_type_modifier&= AUTO_INCREMENT_FLAG;
+ if ((~allowed_type_modifier) & fld_type_modifier)
+ {
+ my_error(ER_WRONG_FIELD_SPEC, MYF(0), fld_name);
+ DBUG_RETURN(TRUE);
+ }
+
+ DBUG_RETURN(FALSE); /* success */
+}
+
+
enum_field_types get_blob_type_from_length(ulong length)
{
enum_field_types type;