Skip to content
/ server Public
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions mysql-test/main/varchar_no_length.cnf
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
# Use default conf to set collation and charset
!include include/default_my.cnf
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

seems like a junk config

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I only used it to set a default charset/collation to have consistency for the tests.
If the default charset/collation changes in the future, this may cause this test to fail, even when the logic is still correct (maybe it's better to have it fail and the dev should verify anyway?).
Also, I wasn't sure if the server's choice for the default charset changes based on the machine settings (such as language), in that case the test my fail for other machines, so I thought having it set in the .opt is better.
What do you think?

101 changes: 101 additions & 0 deletions mysql-test/main/varchar_no_length.result
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
#
# SQL Standard T081: VARCHAR without explicit length specification
#
#
# Basic test: CREATE TABLE with VARCHAR without length or charset (scenario 1a)
#
CREATE TABLE t1 (a VARCHAR);
SHOW CREATE TABLE t1;
Table Create Table
t1 CREATE TABLE `t1` (
`a` varchar(16383) DEFAULT NULL
) ENGINE=MyISAM DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_uca1400_ai_ci
DROP TABLE t1;

#
# Basic test: CREATE TABLE with charset (scenario 1b)
#
CREATE TABLE t1 (a VARCHAR CHARSET latin1);
SHOW CREATE TABLE t1;
Table Create Table
t1 CREATE TABLE `t1` (
`a` varchar(65532) CHARACTER SET latin1 COLLATE latin1_swedish_ci DEFAULT NULL
) ENGINE=MyISAM DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_uca1400_ai_ci
DROP TABLE t1;

#
# Test VARCHAR without length with specific column charsets or collations (scenario 2a)
#
CREATE TABLE t1 (a VARCHAR CHARSET utf8mb4);
SHOW CREATE TABLE t1;
Table Create Table
t1 CREATE TABLE `t1` (
`a` varchar(16383) DEFAULT NULL
) ENGINE=MyISAM DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_uca1400_ai_ci
DROP TABLE t1;

CREATE TABLE t1 (a VARCHAR COLLATE utf8mb4_general_ci);
SHOW CREATE TABLE t1;
Table Create Table
t1 CREATE TABLE `t1` (
`a` varchar(16383) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL
) ENGINE=MyISAM DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_uca1400_ai_ci
DROP TABLE t1;

CREATE TABLE t1 (a VARCHAR CHARSET latin1);
SHOW CREATE TABLE t1;
Table Create Table
t1 CREATE TABLE `t1` (
`a` varchar(65532) CHARACTER SET latin1 COLLATE latin1_swedish_ci DEFAULT NULL
) ENGINE=MyISAM DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_uca1400_ai_ci
DROP TABLE t1;

CREATE TABLE t1 (a VARCHAR COLLATE latin1_general_ci);
SHOW CREATE TABLE t1;
Table Create Table
t1 CREATE TABLE `t1` (
`a` varchar(65532) CHARACTER SET latin1 COLLATE latin1_general_ci DEFAULT NULL
) ENGINE=MyISAM DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_uca1400_ai_ci
DROP TABLE t1;

#
# Test VARCHAR without length with specific column charsets and collations (scenario 2b)
#
CREATE TABLE t1 (a VARCHAR CHARSET utf8mb4 COLLATE utf8mb4_general_ci);
SHOW CREATE TABLE t1;
Table Create Table
t1 CREATE TABLE `t1` (
`a` varchar(16383) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL
) ENGINE=MyISAM DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_uca1400_ai_ci
DROP TABLE t1;

CREATE TABLE t1 (a VARCHAR CHARSET latin1 COLLATE latin1_general_ci);
SHOW CREATE TABLE t1;
Table Create Table
t1 CREATE TABLE `t1` (
`a` varchar(65532) CHARACTER SET latin1 COLLATE latin1_general_ci DEFAULT NULL
) ENGINE=MyISAM DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_uca1400_ai_ci
DROP TABLE t1;

#
# Basic test: CREATE TABLE with charset (Scenario 3)
#
CREATE TABLE t1 (a VARCHAR) CHARSET latin1;
SHOW CREATE TABLE t1;
Table Create Table
t1 CREATE TABLE `t1` (
`a` varchar(65532) DEFAULT NULL
) ENGINE=MyISAM DEFAULT CHARSET=latin1 COLLATE=latin1_swedish_ci
DROP TABLE t1;

#
# Test ALTER TABLE MODIFY COLUMN with VARCHAR without length
#
CREATE TABLE t1 (id VARCHAR(1));
ALTER TABLE t1 MODIFY id VARCHAR;
SHOW CREATE TABLE t1;
Table Create Table
t1 CREATE TABLE `t1` (
`id` varchar(16383) DEFAULT NULL
) ENGINE=MyISAM DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_uca1400_ai_ci
DROP TABLE t1;
90 changes: 90 additions & 0 deletions mysql-test/main/varchar_no_length.test
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
#
# MDEV-31414
# Test for SQL Standard T081: "Optional string types maximum length"
# This tests the feature that allows VARCHAR columns to be created without
# specifying a length, defaulting to the maximum VARCHAR length (65535)
#
# We have 3 scenarios for resolving charset and collation
# 1. Empty
# 2. Precisely Typed
# 3. Contextually typed
#
# Check the comment section in "lex_charset.cc" at
# CHARSET_INFO *Lex_exact_charset_extended_collation_attrs_st::
# resolved_to_character_set

--echo #
--echo # SQL Standard T081: VARCHAR without explicit length specification
--echo #

--echo #
--echo # Basic test: CREATE TABLE with VARCHAR without length or charset (scenario 1a)
--echo #

CREATE TABLE t1 (a VARCHAR);
SHOW CREATE TABLE t1;
DROP TABLE t1;

--echo
--echo #
--echo # Basic test: CREATE TABLE with charset (scenario 1b)
--echo #

CREATE TABLE t1 (a VARCHAR CHARSET latin1);
SHOW CREATE TABLE t1;
DROP TABLE t1;

--echo
--echo #
--echo # Test VARCHAR without length with specific column charsets or collations (scenario 2a)
--echo #

CREATE TABLE t1 (a VARCHAR CHARSET utf8mb4);
SHOW CREATE TABLE t1;
DROP TABLE t1;

--echo
CREATE TABLE t1 (a VARCHAR COLLATE utf8mb4_general_ci);
SHOW CREATE TABLE t1;
DROP TABLE t1;

--echo
CREATE TABLE t1 (a VARCHAR CHARSET latin1);
SHOW CREATE TABLE t1;
DROP TABLE t1;

--echo
CREATE TABLE t1 (a VARCHAR COLLATE latin1_general_ci);
SHOW CREATE TABLE t1;
DROP TABLE t1;

--echo
--echo #
--echo # Test VARCHAR without length with specific column charsets and collations (scenario 2b)
--echo #

CREATE TABLE t1 (a VARCHAR CHARSET utf8mb4 COLLATE utf8mb4_general_ci);
SHOW CREATE TABLE t1;
DROP TABLE t1;

--echo
CREATE TABLE t1 (a VARCHAR CHARSET latin1 COLLATE latin1_general_ci);
SHOW CREATE TABLE t1;
DROP TABLE t1;

--echo
--echo #
--echo # Basic test: CREATE TABLE with charset (Scenario 3)
--echo #
CREATE TABLE t1 (a VARCHAR) CHARSET latin1;
SHOW CREATE TABLE t1;
DROP TABLE t1;

--echo
--echo #
--echo # Test ALTER TABLE MODIFY COLUMN with VARCHAR without length
--echo #
CREATE TABLE t1 (id VARCHAR(1));
ALTER TABLE t1 MODIFY id VARCHAR;
SHOW CREATE TABLE t1;
DROP TABLE t1;
17 changes: 14 additions & 3 deletions sql/field.cc
Original file line number Diff line number Diff line change
Expand Up @@ -10764,9 +10764,16 @@ void
Column_definition_attributes::set_length_and_dec(const Lex_length_and_dec_st
&type)
{
if (type.has_explicit_length())
if (type.has_explicit_length())
{
length= type.length_overflowed() ? (ulonglong) UINT_MAX32 + 1 :
(ulonglong) type.length();
has_explicit_length= true;
}
else {
length= 0;
has_explicit_length= false;
}

if (type.has_explicit_dec())
decimals= type.dec();
Expand Down Expand Up @@ -11128,7 +11135,8 @@ Column_definition_attributes::Column_definition_attributes(const Field *field)
charset(field->charset()), // May be NULL ptr
pack_flag(0),
decimals(field->decimals()),
unireg_check(field->unireg_check)
unireg_check(field->unireg_check),
has_explicit_length(true)
{}


Expand All @@ -11139,7 +11147,8 @@ Column_definition_attributes::
charset(attr.collation.collation),
pack_flag(attr.unsigned_flag ? 0 : FIELDFLAG_DECIMAL),
decimals(attr.decimals),
unireg_check(Field::NONE)
unireg_check(Field::NONE),
has_explicit_length(true)
{}


Expand All @@ -11163,6 +11172,7 @@ Column_definition::Column_definition(THD *thd, Field *old_field,
invisible= old_field->invisible;
interval_list.empty(); // prepare_interval_field() needs this
char_length= (uint) length;
has_explicit_length= true;

if (orig_field)
{
Expand Down Expand Up @@ -11255,6 +11265,7 @@ Column_definition::redefine_stage1_common(const Column_definition *dup_field,
comment= dup_field->comment;
option_list= dup_field->option_list;
versioning= dup_field->versioning;
has_explicit_length= dup_field->has_explicit_length;
}


Expand Down
4 changes: 3 additions & 1 deletion sql/field.h
Original file line number Diff line number Diff line change
Expand Up @@ -5339,12 +5339,14 @@ class Column_definition_attributes: public Type_extra_attributes
uint32 pack_flag;
decimal_digits_t decimals;
Field::utype unireg_check;
bool has_explicit_length;
Column_definition_attributes()
:length(0),
charset(&my_charset_bin),
pack_flag(0),
decimals(0),
unireg_check(Field::NONE)
unireg_check(Field::NONE),
has_explicit_length(true)
{ }
Column_definition_attributes(const Field *field);
Column_definition_attributes(const Type_all_attributes &attr);
Expand Down
8 changes: 7 additions & 1 deletion sql/sql_table.cc
Original file line number Diff line number Diff line change
Expand Up @@ -2581,6 +2581,12 @@ bool Column_definition::prepare_stage1_typelib(THD *thd,
bool Column_definition::prepare_stage1_string(THD *thd,
MEM_ROOT *mem_root)
{
if (real_field_type() == MYSQL_TYPE_VARCHAR && !this->has_explicit_length)
{
char_length= (MAX_FIELD_VARCHARLENGTH) / (charset->mbmaxlen);
length= char_length;
}

if (real_field_type() == FIELD_TYPE_STRING &&
length*charset->mbmaxlen > 1024)
{
Expand Down Expand Up @@ -3220,7 +3226,7 @@ static bool mysql_prepare_create_table_stage1(THD *thd,
COLUMN_DEFINITION_TABLE_FIELD,
&dattr))
DBUG_RETURN(true);

DBUG_ASSERT(sql_field->charset);

if (check_column_name(sql_field->field_name))
Expand Down
8 changes: 7 additions & 1 deletion sql/sql_type.cc
Original file line number Diff line number Diff line change
Expand Up @@ -2862,8 +2862,14 @@ Type_handler_varchar::Column_definition_set_attributes(
}
break;
case COLUMN_DEFINITION_ROUTINE_LOCAL:
case COLUMN_DEFINITION_TABLE_FIELD:
break;
case COLUMN_DEFINITION_TABLE_FIELD:
/*
Support SQL Standard T081: "Optional string types maximum length"
Allows users to specify VARCHAR fields without a length
In this case, has_explicit_length is false.
*/
return false;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This line is likely correct though.

}
thd->parse_error();
return true;
Expand Down