All pages
Powered by GitBook
1 of 38

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Data Definition (DDL)

Learn data definition language (DDL) statements in MariaDB Server. This section covers SQL commands for creating, altering, and dropping databases, tables, indexes, and other schema objects.

ALTER FUNCTION

Change stored function characteristics. This statement allows modifying the security context or comments of a stored function without dropping it.

Syntax

Description

This statement can be used to change the characteristics of a stored function. More than one change may be specified in an ALTER FUNCTION statement. However, you cannot change the parameters or body of a stored function using this statement; to make such changes, you must drop and re-create the function using and .

You must have the ALTER ROUTINE privilege for the function. (That privilege is granted automatically to the function creator.) If binary logging is enabled, the ALTER FUNCTION statement might also require the SUPER privilege, as described in .

Example

See Also

This page is licensed: GPLv2, originally from

CREATE TABLESPACE

Create a tablespace for data storage. This command defines a physical file container for storing table data, primarily for InnoDB or NDB engines.

The CREATE TABLESPACE statement is not supported by MariaDB. It was originally inherited from MySQL NDB Cluster. In MySQL 5.7 and later, the statement is also supported for InnoDB. However, MariaDB has chosen not to include that specific feature. See MDEV-19294 for more information.

This page is licensed: GPLv2, originally from fill_help_tables.sql

CREATE

Explore the CREATE statements used to define new database objects. This guide covers syntax for creating databases, tables, indexes, views, and stored routines.

ALTER FUNCTION func_name [characteristic ...]

characteristic:
    { CONTAINS SQL | NO SQL | READS SQL DATA | MODIFIES SQL DATA }
  | SQL SECURITY { DEFINER | INVOKER }
  | COMMENT 'string'
CREATE CATALOG
CREATE DATABASE
CREATE EVENT
CREATE FUNCTION
CREATE FUNCTION UDF
CREATE INDEX
CREATE LOGFILE GROUP
CREATE PACKAGE
CREATE PACKAGE BODY
CREATE PROCEDURE
CREATE ROLE
CREATE SEQUENCE
CREATE SERVER
CREATE TABLE
CREATE TABLE with Vectors
CREATE TABLESPACE
CREATE TRIGGER
CREATE USER
CREATE VIEW

ALTER

Access the reference for ALTER statements. This section lists commands to modify existing database objects, including tables, databases, users, and servers.

DROP

Find statements to remove database objects. This section details the syntax for deleting databases, tables, users, and other entities when they are no longer needed.

Information Schema ROUTINES Table
DROP FUNCTION
CREATE FUNCTION
Binary Logging of Stored Routines
CREATE FUNCTION
SHOW CREATE FUNCTION
DROP FUNCTION
SHOW FUNCTION STATUS
fill_help_tables.sql

Atomic DDL

Learn about crash-safe DDL operations in MariaDB. This feature ensures data definition statements are either fully committed or completely rolled back, preventing metadata inconsistency.

We improved readability for DDL (Data Definition Language) operations to make most of them atomic, and the rest crash-safe, even if the server crashes in the middle of an operation.

These improvements were made in MariaDB 10.6.1.

The design of Atomic/Crash-safe DDL (MDEV-17567) allows it to work with all storage engines.

Definitions

  • Atomic means that either the operation succeeds (and is logged to the or is completely reversed.

  • Crash-safe means that in case of a crash, after the server has restarted, all tables are consistent, there are no temporary files or tables on disk and the binary log matches the status of the server.

  • DDL Data definition language.

  • DML Data manipulation language.

Background

Before 10.6, in case of a crash, there was a small possibility that one of the following things could happen:

  • There could be temporary tables starting with #sql-alter or #sql-shadow or temporary files ending with '' left.

  • The table in the storage engine and the table's .frm file could be out of sync.

  • During a multi-table rename, only some of the tables were renamed.

Which DDL Operations are Now Atomic

  • , except when used with , which is only crash safe.

  • and .

Which DDL Operations are Now Crash Safe

DROP TABLE of Multiple Tables.

over multiple tables is treated as if every DROP is a separate, atomic operation. This means that after a crash, all fully, or partly, dropped tables will be dropped and logged to the binary log. The undropped tables will be left untouched.

CREATE OR REPLACE TABLE

is implemented as:

This means that if there is a crash during CREATE TABLE then the original table 'foo' will be dropped even if the new table was not created. If the table was not re-created, the binary log will contain theDROP TABLE.

DROP DATABASE

is implemented as:

Each is atomic, but in case of a crash, things will work the same way as with multiple tables.

Atomic with Different Storage Engines

Atomic/Crash-safe DDL works with all storage engines that either have atomic DDLs internally or are able to re-execute DROP or RENAME in case of failure.

This should be true for most storage engines. The ones that still need some work are:

  • The .

  • The . Partitioning should be atomic for most cases, but there are still some known issues that need to be tested and fixed.

The DDL Log Recovery File

The new startup option (ddl_recovery.log by default) can be used to specify the place for the DDL log file. This is mainly useful in the case when one has a filesystem on persistent memory, as there is a lot of sync on this file during DDL operations.

This file contains all DDL operations that are in progress.

At MariaDB server startup, the DDL log file is copied to a file with the same base name but with a backup.log suffix. This is mainly done to be able to find out what went wrong if recovery fails.

If the server crashes during recovery (unlikely but possible), the recovery will continue where it was before. The recovery will retry each entry up to 3 times before giving up and proceeding with the next entry.

Conclusions

  • We believe that a clean separation of layers leads to an easier-to-maintain solution. The Atomic DDL implementation in introduced minimal changes to the storage engine API, mainly for native ALTER TABLE.

  • In our InnoDB implementation, no file format changes were needed on top of the RENAME undo log that was introduced in for a backup-safe TRUNCATE re-implementation. Correct use of sound design principles (write-ahead logging and transactions; also file creation now follows the ARIES protocol) is sufficient. We removed the hacks (at most one CREATE or DROP per transaction) and correctly implemented rollback and purge triggers for the InnoDB SYS_INDEXES table.

  • Numerous DDL recovery bugs in InnoDB were found and fixed quickly thanks to

Thanks to Atomic/Crash-safe DDL, the MariaDB server is now much more stable and reliable in unstable environments. There is still ongoing work to fix the few remaining issues mentioned above to make all DDL operations Atomic.

See Also

  • Atomic DDL. This MDEV entry links to all other entries related to Atomic operations that contains a lot of information how things are implemented.

This page is licensed: CC BY-SA / Gnu FDL

ALTER SERVER

Modify server definitions. Update connection information for external servers defined with CREATE SERVER, primarily used by the Federated engine.

Syntax

ALTER SERVER server_name
    OPTIONS (option [, option] ...)

Description

Alters the server information for server_name, adjusting the specified options as per the CREATE SERVER command. The corresponding fields in the are updated accordingly. This statement requires the privilege or, from , the privilege.

ALTER SERVER is not written to the , irrespective of the being used. From MariaDB 10.1.13, replicates the , ALTER SERVER and statements.

Examples

See Also

This page is licensed: GPLv2, originally from

DROP LOGFILE GROUP

Remove a log file group. This statement, primarily for NDB Cluster, deletes the undo log files associated with the specified log file group.

The DROP LOGFILE GROUP statement is not supported by MariaDB. It was originally inherited from MySQL NDB Cluster. See MDEV-19295 for more information.

This page is licensed: CC BY-SA / Gnu FDL

ALTER LOGFILE GROUP

Understand the support status of this statement. Originally designed for NDB Cluster, it is not currently supported in MariaDB Server.

The ALTER LOGFILE GROUP statement is not supported by MariaDB. It was originally inherited from MySQL NDB Cluster. See MDEV-19295 for more information.

Syntax

ALTER LOGFILE GROUP logfile_group
    ADD UNDOFILE 'file_name'
    [INITIAL_SIZE [=] size]
    [WAIT]
    ENGINE [=] engine_name

This page is licensed: GPLv2, originally from

DROP PACKAGE

Remove a stored package completely. This command deletes both the package specification (interface) and its body (implementation) from the database.

Syntax

Description

The DROP PACKAGE

DROP PACKAGE BODY

Delete the body of a stored package. This command removes the implementation logic while preserving the package specification and interface.

Syntax

Description

The DROP PACKAGE BODY

DROP EVENT

Remove a scheduled event from the server. This command stops the event from executing and deletes its definition from the system tables.

Syntax

Description

This statement drops the named event_name

DROP TABLESPACE

Delete a tablespace. This command removes the physical file container used for storing table data, applicable to engines like InnoDB or NDB.

The DROP TABLESPACE statement is not supported by MariaDB. It was originally inherited from MySQL NDB Cluster. In MySQL 5.7 and later, the statement is also supported for InnoDB. However, MariaDB has chosen not to include that specific feature. See for more information.

This page is licensed: GPLv2, originally from

ALTER TABLESPACE

Understand the status of tablespace management. This statement, originally for NDB, is not supported in MariaDB for InnoDB tablespaces.

The ALTER TABLESPACE statement is not supported by MariaDB. It was originally inherited from MySQL NDB Cluster. In MySQL 5.7 and later, the statement is also supported for InnoDB. However, MariaDB has chosen not to include that specific feature. See for more information.

This page is licensed: GPLv2, originally from

ALTER FUNCTION hello SQL SECURITY INVOKER;

'DDL recovery log' or 'DDL log' for short, is the new log file, ddl_recovery.log by default, that stores all DDL operations in progress. This is used to recover the state of the server in case of sudden crash.

CREATE TRIGGER

  • DROP TRIGGER

  • DROP TABLE and DROP VIEW. Dropping multiple tables is only crash safe.

  • ALTER TABLE

  • ALTER SEQUENCE is not listed above as it is internally implemented as a DML.

  • . We are still working on one: data files must not be deleted before the DDL transaction is committed.
    binary log
    CREATE TABLE
    CREATE OR REPLACE
    RENAME TABLE
    RENAME TABLES
    CREATE VIEW
    CREATE SEQUENCE
    DROP TABLE
    CREATE OR REPLACE TABLE foo
    DROP DATABASE
    DROP TABLE
    DROP TABLE
    S3 storage engine
    partitioning engine
    --log-ddl-recovery=path
    MariaDB 10.6
    MDEV-17567
    rr-project.org
    statement can be used when
    is set.

    The DROP PACKAGE statement drops a stored package entirely:

    • Drops the package specification (earlier created using the CREATE PACKAGE statement).

    • Drops the package implementation, if the implementation was already created using the CREATE PACKAGE BODY statement.

    See Also

    • SHOW CREATE PACKAGE

    • CREATE PACKAGE

    • CREATE PACKAGE BODY

    • DROP PACKAGE BODY

    This page is licensed: CC BY-SA / Gnu FDL

    statement can be used when
    is set.

    The DROP PACKAGE BODY statement drops the package body (that is, the implementation) which was created using the CREATE PACKAGE BODY statement.

    Note, DROP PACKAGE BODY drops only the package implementation, but does not drop the package specification. Use DROP PACKAGE to drop the package entirely (i.e. both implementation and specification).

    See also

    • CREATE PACKAGE

    • SHOW CREATE PACKAGE

    • DROP PACKAGE

    • CREATE PACKAGE BODY

    This page is licensed: CC BY-SA / Gnu FDL

    . The event immediately ceases being active, and is deleted completely from the server.

    If the event does not exist, the errorERROR 1517 (HY000): Unknown event 'event_name' results. You can override this and cause the statement to generate a NOTE for non-existent events instead by usingIF EXISTS. See SHOW WARNINGS.

    This statement requires the EVENT privilege.

    Examples

    Using the IF EXISTS clause:

    See also

    • Events Overview

    • CREATE EVENT

    • SHOW CREATE EVENT

    • ALTER EVENT

    This page is licensed: GPLv2, originally from fill_help_tables.sql

    event
    mysql.servers table
    SUPER
    FEDERATED ADMIN
    binary log
    binary log format
    CREATE SERVER
    DROP SERVER
    CREATE SERVER
    DROP SERVER
    Spider Storage Engine
    mysql.servers table
    fill_help_tables.sql
    Galera
    fill_help_tables.sql
    MDEV-19294
    fill_help_tables.sql
    MDEV-19294
    fill_help_tables.sql

    ALTER DATABASE

    Modify database characteristics. Learn how to change global properties like the default character set and collation for a specific database.

    Syntax

    Description

    ALTER DATABASE enables you to change the overall characteristics of a database. These characteristics are stored in the db.opt file in the database directory. To use ALTER DATABASE, you need the ALTER privilege on the database. ALTER SCHEMA is a synonym for ALTER DATABASE.

    The CHARACTER SET clause changes the default database character set. The COLLATE clause changes the default database collation. See for more.

    You can see what character sets and collations are available using, respectively, the and statements.

    Changing the default character set/collation of a database does not change the character set/collation of any or that were previously created, and relied on the defaults. These need to be dropped and recreated in order to apply the character set/collation changes.

    The database name can be omitted from the first syntax, in which case the statement applies to the default database.

    The syntax that includes the UPGRADE DATA DIRECTORY NAME clause. It updates the name of the directory associated with the database to use the encoding implemented in MySQL for mapping database names to database directory names (see ). This clause is for use under these conditions:

    • It is intended when upgrading MySQL from older versions.

    • It is intended to update a database directory name to the current encoding format if the name contains special characters that need encoding.

    • The statement is used by (as invoked by ).

    For example, if a database in MySQL 5.0 has a name of a-b-c, the name contains instance of the `-' character. In 5.0, the database directory is also named a-b-c, which is not necessarily safe for all file systems. In MySQL, the same database name is encoded as a@002db@002dc to produce a file-system-neutral directory name.

    When a MySQL installation is upgraded from an older version, the server displays a name such as a-b-c (which is in the old format) as #mysql50#a-b-c, and you must refer to the name using the #mysql50# prefix. Use UPGRADE DATA DIRECTORY NAME in this case to explicitly tell the server to re-encode the database directory name to the current encoding format:

    After executing this statement, you can refer to the database as a-b-c without the special #mysql50 prefix.

    MariaDB starting with

    From , it is possible to add a comment of a maximum of 1024 bytes. If the comment length exceeds this length, a error/warning code 4144 is thrown. The database comment is also added to the db.opt file, as well as to the .

    Examples

    See Also

    This page is licensed: GPLv2, originally from

    Renaming Databases

    Learn the supported methods for renaming a database. Since RENAME DATABASE is not available, this guide outlines safe workarounds like dumping and reloading or moving tables.

    There is no RENAME DATABASE statement. To rename a database, use one of the following procedures.

    Using RENAME TABLE

    Use this procedure only if your tables have neither triggers nor views or events.

    To move your tables from a database named db1 to one named db2, run these statements:

    Privileges are neither dropped for db1, nor are they "copied" to db2. Use to see which privileges are related to db1, then to db2.

    Renaming Databases Manually

    To overcome the limitations of the previous procedure, you can do the following.

    In the following steps, the source database is named PROD , and the destination database TEST.

    • Full Backup and Restore: If restoring to a different server, use to create a full backup, then restore it to the intended server. (This step is optional. It is not necessary if your renamed database is to reside on the same computer.)

    1

    Dump Logical Objects.

    RENAME TABLE does not work for triggers, events, and routines. You need to dump these logical objects separately.

    2

    Generate RENAME TABLE Commands.

    Run the following query to generate a script with the necessary RENAME TABLE statements. This is much faster than a full logical dump.

    3

    DROP INDEX

    Remove an existing index from a table. This command deletes the index structure, potentially impacting query performance but freeing storage.

    Syntax

    Description

    DROP INDEX drops the named index_name from the table tbl_name. This statement is mapped to an ALTER TABLE statement to drop the index.

    If another connection is using the table, a is active, and this statement will wait until the lock is released. This is also true for non-transactional tables.

    See .

    Another shortcut, , allows the creation of an index.

    To remove the primary key, PRIMARY must be specified as index_name. Note that are necessary, because PRIMARY is a keyword.

    Privileges

    Executing the DROP INDEX statement requires the privilege for the table or the database.

    Online DDL

    Online DDL is used by default with InnoDB, when the drop index operation supports it.

    See for more information on online DDL with .

    DROP INDEX IF EXISTS ...

    If the IF EXISTS clause is used, then MariaDB will return a warning instead of an error if the index does not exist.

    WAIT/NOWAIT

    Sets the lock wait timeout. See .

    Progress Reporting

    MariaDB provides progress reporting for DROP INDEX statement for clients that support the new progress reporting protocol. For example, if you were using the client, then the progress report might look like this::

    See Also

    This page is licensed: GPLv2, originally from

    DROP DATABASE

    Delete a database and all its contents. This command permanently removes the database directory and all tables, routines, and data within it.

    Syntax

    Description

    DROP DATABASE drops all tables in the database and deletes the database. Be very careful with this statement! To use DROP DATABASE, you need the on the database. DROP SCHEMA is a synonym for DROP DATABASE.

    Important: When a database is dropped, user privileges on the database are not automatically dropped. See .

    IF EXISTS

    Use IF EXISTS to prevent an error from occurring for databases that do not exist. A NOTE is generated for each non-existent database when using IF EXISTS. See .

    Atomic DDL

    supports .DROP DATABASE is implemented as

    Each individual is atomic while DROP DATABASE as a whole is crash-safe.

    Atomic DROP is not available.

    Examples

    See Also

    This page is licensed: GPLv2, originally from

    CONSTRAINT

    Understand the syntax and usage of constraints in table definitions. This guide covers primary keys, foreign keys, unique, and check constraints to enforce data integrity.

    MariaDB supports the implementation of constraints at the table-level using either or statements. A table constraint restricts the data you can add to the table. If you attempt to insert invalid data on a column, MariaDB throws an error.

    Syntax

    DROP SERVER

    Remove a server definition. This command deletes the connection details for a remote server used by the FEDERATED or SPIDER storage engines.

    Syntax

    Description

    Drops the server definition for the server named server_name. The corresponding row within the will be deleted. This statement requires the

    CREATE DATABASE

    Create a new database container. This command initializes a new database namespace with optional character set and collation settings.

    Syntax

    Description

    CREATE DATABASE

    DROP TRIGGER

    Remove a trigger from a table. This command deletes the trigger definition, preventing it from firing on future INSERT, UPDATE, or DELETE events.

    Syntax

    Description

    This statement drops a . The schema (database) name is optional. If the schema is omitted, the trigger is dropped from the default schema. Its use requires the

    DROP TABLE IF EXISTS foo;
    CREATE TABLE foo ...
      DROP TABLE table
    LOOP OVER ALL tables
    DROP PACKAGE [IF EXISTS]  [ db_name . ] package_name
    DROP PACKAGE BODY [IF EXISTS]  [ db_name . ] package_name
    DROP EVENT [IF EXISTS] event_name
    DROP EVENT myevent3;
    DROP EVENT IF EXISTS myevent3;
    Query OK, 0 rows affected, 1 warning (0.01 sec)
    
    SHOW WARNINGS;
    +-------+------+-------------------------------+
    | Level | Code | Message                       |
    +-------+------+-------------------------------+
    | Note  | 1305 | Event myevent3 does not exist |
    +-------+------+-------------------------------+
    ALTER SERVER s OPTIONS (USER 'sally');
    ALTER {DATABASE | SCHEMA} [db_name]
        alter_specification ...
    ALTER {DATABASE | SCHEMA} db_name
        UPGRADE DATA DIRECTORY NAME
    
    alter_specification:
        [DEFAULT] CHARACTER SET [=] charset_name
      | [DEFAULT] COLLATE [=] collation_name
      | COMMENT [=] 'comment'
    DROP INDEX [IF EXISTS] index_name ON tbl_name 
        [WAIT n |NOWAIT]
    DROP {DATABASE | SCHEMA} [IF EXISTS] db_name
    index
    metadata lock
    ALTER TABLE
    CREATE INDEX
    the quotes
    INDEX
    InnoDB Online DDL Overview
    InnoDB
    WAIT and NOWAIT
    mariadb
    Getting Started with Indexes
    CREATE INDEX
    ALTER TABLE
    fill_help_tables.sql
    SHOW CREATE DATABASE
    DROP privilege
    GRANT
    SHOW WARNINGS
    MariaDB 10.6.1
    Atomic DDL
    DROP TABLE
    CREATE DATABASE
    ALTER DATABASE
    SHOW DATABASES
    Information Schema SCHEMATA Table
    fill_help_tables.sql
    LOOP OVER ALL tables
      DROP TABLE tbl
    Description

    Constraints provide restrictions on the data you can add to a table. This allows you to enforce data integrity from MariaDB, rather than through application logic. When a statement violates a constraint, MariaDB throws an error.

    There are four types of table constraints:

    Constraint
    Description

    PRIMARY KEY

    Sets the column for referencing rows. Values must be unique and not null.

    FOREIGN KEY

    Sets the column to reference the primary key on another table.

    UNIQUE

    Requires values in column or columns only occur once in the table.

    CHECK

    Checks whether the data meets the given condition.

    The Information Schema TABLE_CONSTRAINTS Table contains information about tables that have constraints.

    FOREIGN KEY Constraints

    InnoDB supports foreign key constraints. The syntax for a foreign key constraint definition in InnoDB looks like this:

    The Information Schema REFERENTIAL_CONSTRAINTS table has more information about foreign keys.

    From MariaDB 12.1, constraints are improved to allow constraints that haven't been named for multiple table references.

    Consider this example, which creates two tables, then adds constraints to them:

    Previously, the last statement failed because of duplicate constraint names:

    Now, the statement works, because internally, names are assigned that aren't duplicates. (User-visible names can be duplicates, but internally they're prefixed with the schema and table names.)

    CHECK Constraints

    Constraints are enforced. You can define constraints in 2 different ways:

    • CHECK(expression) given as part of a column definition.

    • CONSTRAINT [constraint_name] CHECK (expression)

    Before a row is inserted or updated, all constraints are evaluated in the order they are defined. If any constraint expression returns false, then the row is not inserted or updated. You can use most deterministic functions in a constraint, including UDFs.

    If you use the second format and you don't give a name to the constraint, the constraint gets an automatically generated name. This is done so that you can later delete the constraint with ALTER TABLE DROP constraint_name.

    You can disable all constraint expression checks by setting the check_constraint_checks variable to OFF. This is useful for example when loading a table that violates some constraints that you want to later find and fix in SQL.

    Replication

    In row-based replication, only the master checks constraints, and failed statements are not replicated. In statement-based replication, the slaves also check constraints. Constraints should therefore be identical, as well as deterministic, in a replication environment.

    Auto_increment

    auto_increment columns are not permitted in check constraints.

    Examples

    Numeric constraints and comparisons:

    Dropping a constraint:

    Adding a constraint:

    Date comparisons and character length:

    A misplaced parenthesis:

    Compare the definition of table t2 to table t3. CHAR_LENGTH(name)>2 is very different to CHAR_LENGTH(name>2) as the latter mistakenly performs a numeric comparison on the name field, leading to unexpected results.

    See Also

    • Foreign Keys

    This page is licensed: GPLv2, originally from fill_help_tables.sql

    CREATE TABLE
    ALTER TABLE
    DROP DATABASE bufg;
    Query OK, 0 rows affected (0.39 sec)
    
    DROP DATABASE bufg;
    ERROR 1008 (HY000): Can't drop database 'bufg'; database doesn't exist
    
     \W
    SHOW warnings enabled.
    
    DROP DATABASE IF EXISTS bufg;
    Query OK, 0 rows affected, 1 warning (0.00 sec)
    Note (Code 1008): Can't DROP DATABASE 'bufg'; DATABASE doesn't exist
    [CONSTRAINT [symbol]] constraint_expression
    
    constraint_expression:
      | PRIMARY KEY [index_type] (index_col_name, ...) [index_option] ...
      | FOREIGN KEY [index_name] (index_col_name, ...) 
           REFERENCES tbl_name (index_col_name, ...)
           [ON DELETE reference_option]
           [ON UPDATE reference_option]
      | UNIQUE [INDEX|KEY] [index_name]
           [index_type] (index_col_name, ...) [index_option] ...
      | CHECK (check_constraints)
    
    index_type:
      USING {BTREE | HASH | RTREE}
    
    index_col_name:
      col_name [(length)] [ASC | DESC]
    
    index_option:
      | KEY_BLOCK_SIZE [=] value
      | index_type
      | WITH PARSER parser_name
      | COMMENT 'string'
      | CLUSTERING={YES|NO}
    
    reference_option:
      RESTRICT | CASCADE | SET NULL | NO ACTION | SET DEFAULT
    [CONSTRAINT [symbol]] FOREIGN KEY
        [index_name] (index_col_name, ...)
        REFERENCES tbl_name (index_col_name,...)
        [ON DELETE reference_option]
        [ON UPDATE reference_option]
    
    reference_option:
        RESTRICT | CASCADE | SET NULL | NO ACTION
    CREATE TABLE t1(a int, b int, key(a),key(b))engine=innodb;
    CREATE TABLE t2(a int, b int, key(a),key(b))engine=innodb;
    ALTER TABLE t2 ADD CONSTRAINT c FOREIGN KEY (b) REFERENCES t1(a);
    ALTER TABLE t1 ADD CONSTRAINT c FOREIGN KEY (b) REFERENCES t2(a);
    mysqltest: At line 5: query 'alter table t1 add constraint c foreign key (b) references t2(a)' failed: ER_CANT_CREATE_TABLE (1005): Can't create table `test`.`t1` (errno: 121 "Duplicate key on write or update")
    CREATE TABLE t1 (a INT CHECK (a>2), b INT CHECK (b>2), CONSTRAINT a_greater CHECK (a>b));
    CREATE TABLE product (category INT NOT NULL, id INT NOT NULL,
                          price DECIMAL,
                          PRIMARY KEY(category, id)) ENGINE=INNODB;
    CREATE TABLE customer (id INT NOT NULL,
                           PRIMARY KEY (id)) ENGINE=INNODB;
    CREATE TABLE product_order (NO INT NOT NULL AUTO_INCREMENT,
                                product_category INT NOT NULL,
                                product_id INT NOT NULL,
                                customer_id INT NOT NULL,
                                PRIMARY KEY(NO),
                                INDEX (product_category, product_id),
                                FOREIGN KEY (product_category, product_id)
                                  REFERENCES product(category, id)
                                  ON UPDATE CASCADE ON DELETE RESTRICT,
                                INDEX (customer_id),
                                FOREIGN KEY (customer_id)
                                  REFERENCES customer(id)) ENGINE=INNODB;
    CREATE TABLE t1 (a INT CHECK (a>2), b INT CHECK (b>2), CONSTRAINT a_greater CHECK (a>b));
    
    INSERT INTO t1(a) VALUES (1);
    ERROR 4022 (23000): CONSTRAINT `a` failed for `test`.`t1`
    
    INSERT INTO t1(a,b) VALUES (3,4);
    ERROR 4022 (23000): CONSTRAINT `a_greater` failed for `test`.`t1`
    
    INSERT INTO t1(a,b) VALUES (4,3);
    Query OK, 1 row affected (0.04 sec)
    ALTER TABLE t1 DROP CONSTRAINT a_greater;
    ALTER TABLE t1 ADD CONSTRAINT a_greater CHECK (a>b);
    CREATE TABLE t2 (name VARCHAR(30) CHECK (CHAR_LENGTH(name)>2), start_date DATE, 
      end_date DATE CHECK (start_date IS NULL OR end_date IS NULL OR start_date<end_date));
    
    INSERT INTO t2(name, start_date, end_date) VALUES('Ione', '2003-12-15', '2014-11-09');
    Query OK, 1 row affected (0.04 sec)
    
    INSERT INTO t2(name, start_date, end_date) VALUES('Io', '2003-12-15', '2014-11-09');
    ERROR 4022 (23000): CONSTRAINT `name` failed for `test`.`t2`
    
    INSERT INTO t2(name, start_date, end_date) VALUES('Ione', NULL, '2014-11-09');
    Query OK, 1 row affected (0.04 sec)
    
    INSERT INTO t2(name, start_date, end_date) VALUES('Ione', '2015-12-15', '2014-11-09');
    ERROR 4022 (23000): CONSTRAINT `end_date` failed for `test`.`t2`
    CREATE TABLE t3 (name VARCHAR(30) CHECK (CHAR_LENGTH(name>2)), start_date DATE, 
      end_date DATE CHECK (start_date IS NULL OR end_date IS NULL OR start_date<end_date));
    Query OK, 0 rows affected (0.32 sec)
    
    INSERT INTO t3(name, start_date, end_date) VALUES('Io', '2003-12-15', '2014-11-09');
    Query OK, 1 row affected, 1 warning (0.04 sec)
    
    SHOW WARNINGS;
    +---------+------+----------------------------------------+
    | Level   | Code | Message                                |
    +---------+------+----------------------------------------+
    | Warning | 1292 | Truncated incorrect DOUBLE value: 'Io' |
    +---------+------+----------------------------------------+
    Character Sets and Collations
  • Information Schema SCHEMATA Table

  • Character Sets and Collations
    SHOW CHARACTER SET
    SHOW COLLATION
    stored procedures
    stored functions
    Identifier to File Name Mapping
    mariadb-check
    mariadb-upgrade
    information_schema.schemata table
    CREATE DATABASE
    DROP DATABASE
    SHOW CREATE DATABASE
    SHOW DATABASES
    fill_help_tables.sql

    List all Existing Objects.

    4

    Create the new Database.

    5

    Run the rename_table Script.

    6

    Restore Logical Objects.

    After the rename script completes, restore the triggers, routines, and events into the new database.

    7

    Verify all Objects are Restored.

    Verify that all objects have been correctly moved to the new TEST database.

    8

    Cleanup.

    Once you have confirmed everything looks good, you can drop the old PROD database.

    Privileges are neither dropped for PROD, nor are they "copied" to TEST. Use SHOW PRIVILEGES to see which privileges are related to PROD, then to TEST.

    SHOW PRIVILEGES
    apply those privileges
    mariadb-backup
    privilege or, from
    , the
    privilege.

    Dropping a server for a table does not affect any FederatedX, FEDERATED, Connect or Spider tables that used this connection information when they were created.

    DROP SERVER is not written to the binary log, irrespective of the binary log format being used. From , replicates the CREATE SERVER, ALTER SERVER and DROP SERVER statements.

    IF EXISTS

    If the IF EXISTS clause is used, MariaDB will not return an error if the server does not exist. Unlike all other statements, DROP SERVER IF EXISTS does not issue a note if the server does not exist. See MDEV-9400.

    Examples

    IF EXISTS:

    See Also

    • CREATE SERVER

    • ALTER SERVER

    • Spider Storage Engine

    • FederatedX Storage Engine

    This page is licensed: GPLv2, originally from fill_help_tables.sql

    mysql.servers table
    SUPER
    FEDERATED ADMIN
    creates a database with the given name. To use this statement, you need the
    for the database. CREATE SCHEMA is a synonym for CREATE DATABASE.

    For valid identifiers to use as database names, see Identifier Names.

    OR REPLACE

    If the optional OR REPLACE clause is used, it acts as a shortcut for:

    IF NOT EXISTS

    When the IF NOT EXISTS clause is used, MariaDB will return a warning instead of an error if the specified database already exists.

    COMMENT

    The maximum length of a comment is 1024 bytes. If the comment length exceeds this length, an error/warning code 4144 is thrown. The database comment is also added to the db.opt file, as well as to the information_schema.schemata table.

    Comments added for databases do not exist.

    Examples

    Setting the character sets and collation. See Setting Character Sets and Collations for more details.

    See Also

    • Identifier Names

    • DROP DATABASE

    • SHOW CREATE DATABASE

    • ALTER DATABASE

    This page is licensed: GPLv2, originally from fill_help_tables.sql

    CREATE privilege
    TRIGGER
    privilege for the table associated with the trigger.

    Use IF EXISTS to prevent an error from occurring for a trigger that does not exist. A NOTE is generated for a non-existent trigger when using IF EXISTS. See SHOW WARNINGS.

    Note: Triggers for a table are also dropped if you drop the table.

    Atomic DDL

    DROP TRIGGER is atomic.

    DROP TRIGGER is not atomic.

    Examples

    Using the IF EXISTS clause:

    See Also

    • Trigger Overview

    • CREATE TRIGGER

    • Information Schema TRIGGERS Table

    • SHOW TRIGGERS

    This page is licensed: GPLv2, originally from fill_help_tables.sql

    trigger
    SHOW CREATE PACKAGE BODY

    Invisible Columns

    Explains how to define columns that are hidden from wildcard SELECT queries but remain accessible when explicitly referenced, facilitating schema changes without breaking existing applications.

    Invisible columns (sometimes also called hidden columns) are hidden in certain contexts.

    Columns can be given an INVISIBLE attribute in a CREATE TABLE or ALTER TABLE statement. These columns will then not be listed in the results of a SELECT * statement, nor do they need to be assigned a value in an INSERT statement, unless INSERT explicitly mentions them by name.

    Since SELECT * does not return the invisible columns, new tables or views created in this manner will have no trace of the invisible columns. If specifically referenced in the SELECT statement, the columns will be brought into the view/new table, but the INVISIBLE attribute will not.

    Invisible columns can be declared as NOT NULL, but then require a DEFAULT value.

    It is not possible for all columns in a table to be invisible.

    Examples

    Creating a view from a table with hidden columns:

    Adding a Surrogate Primary Key:

    This page is licensed: CC BY-SA / Gnu FDL

    RENAME TABLE

    Change the name of one or more tables atomically. This command moves tables within or between databases while preserving their data and structure.

    Syntax

    Description

    This statement renames one or more tables or views, but not the privileges associated with them. For InnoDB tables, it also triggers a reload of InnoDB statistics.

    IF EXISTS

    If this clause is used, you don't get an error if the table to be renamed doesn't exist.

    The rename operation is done atomically, which means that no other session can access any of the tables while the rename is running. For example, if you have an existing table old_table, you can create another table new_table that has the same structure but is empty, and then replace the existing table with the empty one as follows (assuming that backup_table does not already exist):

    Moving Tables to Another Database

    tbl_name can optionally be specified as db_name.tbl_name. See . This allows to use RENAME to move a table from a database to another (as long as they are on the same filesystem):

    Limitations of Moving Tables to Another Database

    Note that moving a table to another database is not possible if it has .

    Trying to do so produces the following error:

    Views cannot be moved to another database.

    Trying to do so produces the following error:

    Renaming Multiple Tables at Once

    Multiple tables can be renamed in a single statement. The presence or absence of the optional S (RENAME TABLE or RENAME TABLES) has no impact, whether a single or multiple tables are being renamed.

    If a RENAME TABLE renames more than one table and one renaming fails, all renames executed by the same statement are rolled back.

    Renames are always executed in the specified order. Knowing this, it is also possible to swap two tables' names:

    WAIT/NOWAIT

    Set the lock wait timeout. See .

    Privileges

    Executing the RENAME TABLE statement requires the , and privileges for the table or the database.

    Atomic RENAME TABLE

    RENAME TABLE is atomic for most storage engines, including InnoDB, MyRocks, MyISAM and Aria ().

    This means that if there is a crash (server down or power outage) during RENAME TABLE, all tables revert to their original names and any changes to trigger files are reverted. See for more information.

    RENAME TABLE is not atomic.

    There is a small chance that, during a server crash happening in the middle of RENAME TABLE, some tables could have been renamed (in the worst case partly) while others would not be renamed.

    CREATE PACKAGE

    Define the interface for a stored package. This Oracle-compatible statement declares the public variables and subroutines of a package.

    The CREATE PACKAGE statement can be used in any mode.

    The CREATE PACKAGE statement can be used when is set.

    In , the PL/SQL dialect is used, while if Oracle mode is not set (the default), SQL/PSM is used.

    Syntax (Oracle mode)

    Syntax (non-Oracle mode)

    Description

    CREATE PACKAGE creates the specification for a stored package (a collection of logically related stored objects). A stored package specification declares public routines (procedures and functions) of the package, but does not implement these routines.

    A package whose specification was created by the CREATE PACKAGE statement, should later be implemented using the statement.

    Function parameter quantifiers IN | OUT | INOUT | IN OUT

    MariaDB starting with

    The function parameter quantifiers for IN, OUT, INOUT, and IN OUT are supported anywhere.

    The function parameter quantifiers for IN, OUT, INOUT, and IN OUT are supported only in procedures.

    OUT, INOUT and its equivalent IN OUT, are only valid if called from SET and not SELECT. These quantifiers are especially useful for creating functions and procedures with more than one return value. This allows functions and procedures to be more complex and nested.

    Examples

    See Also

    This page is licensed: CC BY-SA / Gnu FDL

    CREATE PACKAGE BODY

    Implement the logic for a stored package. This statement defines the private variables and code for the subroutines declared in the package specification.

    The CREATE PACKAGE BODY statement can be used in any mode.

    The CREATE PACKAGE BODY statement can be used in .

    In Oracle mode, the PL/SQL dialect is used, while in non-Oracle mode, SQL/PSM is used.

    ALTER DATABASE `#mysql50#a-b-c` UPGRADE DATA DIRECTORY NAME;
    ALTER DATABASE p COMMENT='Presentations';
    ALTER DATABASE test CHARACTER SET='utf8'  COLLATE='utf8_bin';
    SELECT TABLE_SCHEMA, TABLE_NAME FROM INFORMATION_SCHEMA.TABLES 
           WHERE TABLE_SCHEMA = 'PROD';
    SELECT EVENT_SCHEMA, EVENT_NAME FROM INFORMATION_SCHEMA.EVENTS 
           WHERE EVENT_SCHEMA = 'PROD';
    SELECT ROUTINE_SCHEMA, ROUTINE_NAME FROM INFORMATION_SCHEMA.ROUTINES 
           WHERE ROUTINE_SCHEMA = 'PROD';
    SELECT TRIGGER_SCHEMA, TRIGGER_NAME FROM INFORMATION_SCHEMA.TRIGGERS 
     WHERE TRIGGER_SCHEMA = 'PROD';
    CREATE DATABASE TEST;
    mysql TEST < PROD_rename_table.sql
    mysql TEST < PROD_routines_triggers_events.sql
    SELECT TABLE_SCHEMA, TABLE_NAME FROM INFORMATION_SCHEMA.TABLES 
           WHERE TABLE_SCHEMA = 'TEST';
    SELECT EVENT_SCHEMA, EVENT_NAME FROM INFORMATION_SCHEMA.EVENTS 
           WHERE EVENT_SCHEMA = 'TEST';
    SELECT ROUTINE_SCHEMA, ROUTINE_NAME FROM INFORMATION_SCHEMA.ROUTINES 
           WHERE ROUTINE_SCHEMA = 'TEST';
    SELECT TRIGGER_SCHEMA, TRIGGER_NAME FROM INFORMATION_SCHEMA.TRIGGERS 
           WHERE TRIGGER_SCHEMA = 'TEST';
    CREATE DATABASE db2;
    # Do this for every table in database db1
    RENAME TABLE db1.t TO db2.t;
    # When no table is left in database db1, optionally drop it
    DROP DATABASE db1;
    mariadb-dump PROD --no-data --routines --triggers --events \
    > PROD_routines_triggers_events.sql
    mysql -ss -e"SELECT CONCAT('RENAME TABLE PROD.', TABLE_NAME, ' TO TEST.', \
    TABLE_NAME, ';') FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA = 'PROD'" \
    > PROD_rename_table.sql
    DROP SERVER [ IF EXISTS ] server_name
    DROP SERVER s;
    DROP SERVER s;
    ERROR 1477 (HY000): The foreign server name you are trying to reference 
      does not exist. Data source error:  s
    
    DROP SERVER IF EXISTS s;
    Query OK, 0 rows affected (0.00 sec)
    CREATE [OR REPLACE] {DATABASE | SCHEMA} [IF NOT EXISTS] db_name
        [create_specification] ...
    
    create_specification:
        [DEFAULT] CHARACTER SET [=] charset_name
      | [DEFAULT] COLLATE [=] collation_name
      | COMMENT [=] 'comment'
    DROP DATABASE IF EXISTS db_name;
    CREATE DATABASE db_name ...;
    CREATE DATABASE db1;
    Query OK, 1 row affected (0.18 sec)
    
    CREATE DATABASE db1;
    ERROR 1007 (HY000): Can't create database 'db1'; database exists
    
    CREATE OR REPLACE DATABASE db1;
    Query OK, 2 rows affected (0.00 sec)
    
    CREATE DATABASE IF NOT EXISTS db1;
    Query OK, 1 row affected, 1 warning (0.01 sec)
    
    SHOW WARNINGS;
    +-------+------+----------------------------------------------+
    | Level | Code | Message                                      |
    +-------+------+----------------------------------------------+
    | Note  | 1007 | Can't create database 'db1'; database exists |
    +-------+------+----------------------------------------------+
    CREATE DATABASE czech_slovak_names 
      CHARACTER SET = 'keybcs2'
      COLLATE = 'keybcs2_bin';
    CREATE DATABASE presentations COMMENT 'Presentations for conferences';
    DROP TRIGGER [IF EXISTS] [schema_name.]trigger_name
    DROP TRIGGER test.example_trigger;
    DROP TRIGGER IF EXISTS test.example_trigger;
    Query OK, 0 rows affected, 1 warning (0.01 sec)
    
    SHOW WARNINGS;
    +-------+------+------------------------+
    | Level | Code | Message                |
    +-------+------+------------------------+
    | Note  | 1360 | Trigger does not exist |
    +-------+------+------------------------+
    RENAME TABLE[S] [IF EXISTS] tbl_name 
      [WAIT n | NOWAIT]
      TO new_tbl_name
        [, tbl_name2 TO new_tbl_name2] ...
    apply those privileges
    SHOW DATABASES
    Character Sets and Collations
    Information Schema SCHEMATA Table
    SHOW CREATE TRIGGER
    Trigger Limitations
    CREATE TABLE t (x INT INVISIBLE);
    ERROR 1113 (42000): A table must have at least 1 column
    
    CREATE TABLE t (x INT, y INT INVISIBLE, z INT INVISIBLE NOT NULL);
    ERROR 4106 (HY000): Invisible column `z` must have a default value
    
    CREATE TABLE t (x INT, y INT INVISIBLE, z INT INVISIBLE NOT NULL DEFAULT 4);
    
    INSERT INTO t VALUES (1),(2);
    
    INSERT INTO t (x,y) VALUES (3,33);
    
    SELECT * FROM t;
    +------+
    | x    |
    +------+
    |    1 |
    |    2 |
    |    3 |
    +------+
    
    SELECT x,y,z FROM t;
    +------+------+---+
    | x    | y    | z |
    +------+------+---+
    |    1 | NULL | 4 |
    |    2 | NULL | 4 |
    |    3 |   33 | 4 |
    +------+------+---+
    
    DESC t;
    +-------+---------+------+-----+---------+-----------+
    | Field | Type    | Null | Key | Default | Extra     |
    +-------+---------+------+-----+---------+-----------+
    | x     | int(11) | YES  |     | NULL    |           |
    | y     | int(11) | YES  |     | NULL    | INVISIBLE |
    | z     | int(11) | NO   |     | 4       | INVISIBLE |
    +-------+---------+------+-----+---------+-----------+
    
    ALTER TABLE t MODIFY x INT INVISIBLE, MODIFY y INT, MODIFY z INT NOT NULL DEFAULT 4;
    
    DESC t;
    +-------+---------+------+-----+---------+-----------+
    | Field | Type    | Null | Key | Default | Extra     |
    +-------+---------+------+-----+---------+-----------+
    | x     | int(11) | YES  |     | NULL    | INVISIBLE |
    | y     | int(11) | YES  |     | NULL    |           |
    | z     | int(11) | NO   |     | 4       |           |
    +-------+---------+------+-----+---------+-----------+
    CREATE VIEW v1 AS SELECT * FROM t;
    
    DESC v1;
    +-------+---------+------+-----+---------+-------+
    | Field | Type    | Null | Key | Default | Extra |
    +-------+---------+------+-----+---------+-------+
    | y     | int(11) | YES  |     | NULL    |       |
    | z     | int(11) | NO   |     | 4       |       |
    +-------+---------+------+-----+---------+-------+
    
    CREATE VIEW v2 AS SELECT x,y,z FROM t;
    
    DESC v2;
    +-------+---------+------+-----+---------+-------+
    | Field | Type    | Null | Key | Default | Extra |
    +-------+---------+------+-----+---------+-------+
    | x     | int(11) | YES  |     | NULL    |       |
    | y     | int(11) | YES  |     | NULL    |       |
    | z     | int(11) | NO   |     | 4       |       |
    +-------+---------+------+-----+---------+-------+
    CREATE TABLE t1 (x BIGINT UNSIGNED NOT NULL, y VARCHAR(16), z TEXT);
    
    INSERT INTO t1 VALUES (123, 'qq11', 'ipsum');
    
    INSERT INTO t1 VALUES (123, 'qq22', 'lorem');
    
    ALTER TABLE t1 ADD pkid SERIAL PRIMARY KEY invisible FIRST;
    
    INSERT INTO t1 VALUES (123, 'qq33', 'amet');
    
    SELECT * FROM t1;
    +-----+------+-------+
    | x   | y    | z     |
    +-----+------+-------+
    | 123 | qq11 | ipsum |
    | 123 | qq22 | lorem |
    | 123 | qq33 | amet  |
    +-----+------+-------+
    
    SELECT pkid, z FROM t1;
    +------+-------+
    | pkid | z     |
    +------+-------+
    |    1 | ipsum |
    |    2 | lorem |
    |    3 | amet  |
    +------+-------+
    Syntax (Oracle mode)

    Description

    The CREATE PACKAGE BODY statement creates the package body for a stored package. The package specification must be previously created using the CREATE PACKAGE statement.

    A package body provides implementations of the package public routines and can optionally have:

    • package-wide private variables

    • package private routines

    • forward declarations for private routines

    • an executable initialization section

    Examples

    See Also

    • CREATE PACKAGE

    • SHOW CREATE PACKAGE BODY

    • DROP PACKAGE BODY

    This page is licensed: CC BY-SA / Gnu FDL

    Identifier Qualifiers
    triggers
    WAIT and NOWAIT
    DROP
    CREATE
    INSERT
    MDEV-23842
    Atomic DDL
    CREATE PACKAGE BODY
    CREATE PACKAGE BODY
    SHOW CREATE PACKAGE
    DROP PACKAGE
    Connect Storage Engine
    mysql.servers table

    CREATE EVENT

    Schedule a new event for automatic execution. This statement defines a scheduled task that runs SQL commands at specific times or intervals.

    Syntax

    Description

    This statement creates and schedules a new event. It requires the EVENT privilege for the schema in which the event is to be created.

    The minimum requirements for a valid CREATE EVENT statement are as follows:

    • The keywords CREATE EVENT plus an event name, which uniquely identifies the event in the current schema.

    • An ON SCHEDULE clause, which determines when and how often the event executes.

    • A DO clause, which contains the SQL statement to be executed by an event.

    Here is an example of a minimal CREATE EVENT statement:

    The previous statement creates an event named myevent. This event executes once — one hour following its creation — by running an SQL statement that increments the value of the myschema.mytable table's mycol column by 1.

    The event_name must be a valid MariaDB identifier with a maximum length of 64 characters. It may be delimited using back ticks, and may be qualified with the name of a database schema. An event is associated with both a MariaDB user (the definer) and a schema, and its name must be unique among names of events within that schema. In general, the rules governing event names are the same as those for names of stored routines. See .

    If no schema is indicated as part of event_name, the default (current) schema is assumed.

    For valid identifiers to use as event names, see .

    OR REPLACE

    The OR REPLACE clause works like this: If the event already exists, instead of an error being returned, the existing event will be dropped and replaced by the newly defined event.

    The OR REPLACE clause is not available.

    IF NOT EXISTS

    If the IF NOT EXISTS clause is used, MariaDB will return a warning instead of an error if the event already exists. Cannot be used together with OR REPLACE.

    ON SCHEDULE

    The ON SCHEDULE clause can be used to specify when the event must be triggered.

    AT

    If you want to execute the event only once (one time event), you can use the AT keyword, followed by a timestamp. If you use , the event acts as soon as it is created. As a convenience, you can add one or more intervals to that timestamp. You can also specify a timestamp in the past, so that the event is stored but not triggered, until you modify it via .

    The following example shows how to create an event that will be triggered tomorrow at a certain time:

    You can also specify that an event must be triggered at a regular interval (recurring event). In such cases, use the EVERY clause followed by the interval.

    If an event is recurring, you can specify when the first execution must happen via the STARTS clause and a maximum time for the last execution via the ENDS clause. STARTS and ENDS clauses are followed by a timestamp and, optionally, one or more intervals. The ENDS clause can specify a timestamp in the past, so that the event is stored but not executed until you modify it via .

    In the following example, next month a recurring event will be triggered hourly for a week:

    Intervals consist of a quantity and a time unit. The time units are the same used for other statements and time functions, except that you can't use microseconds for events. For simple time units, like HOUR or MINUTE, the quantity is an integer number, for example '10 MINUTE'. For composite time units, like HOUR_MINUTE or HOUR_SECOND, the quantity must be a string with all involved simple values and their separators, for example '2:30' or '2:30:30'.

    ON COMPLETION [NOT] PRESERVE

    The ON COMPLETION clause can be used to specify if the event must be deleted after its last execution (that is, after its AT or ENDS timestamp is past). By default, events are dropped when they are expired. To explicitly state that this is the desired behaviour, you can use ON COMPLETION NOT PRESERVE. Instead, if you want the event to be preserved, you can use ON COMPLETION PRESERVE.

    In you specify ON COMPLETION NOT PRESERVE, and you specify a timestamp in the past for AT or ENDS clause, the event will be immediately dropped. In such cases, you will get a Note 1558: "Event execution time is in the past and ON COMPLETION NOT PRESERVE is set. The event was dropped immediately after creation".

    ENABLE/DISABLE/DISABLE ON SLAVE

    Events are ENABLEd by default. If you want to stop MariaDB from executing an event, you may specify DISABLE. When it is ready to be activated, you may enable it using . Another option is DISABLE ON SLAVE, which indicates that an event was created on a master and has been replicated to the slave, which is prevented from executing the event. If DISABLE ON SLAVE is specifically set, the event will be disabled everywhere. It will not be executed on the master or the replicas.

    COMMENT

    The COMMENT clause may be used to set a comment for the event. Maximum length for comments is 64 characters. The comment is a string, so it must be quoted. To see events comments, you can query the (the column is named EVENT_COMMENT).

    Examples

    Minimal CREATE EVENT statement:

    An event that will be triggered tomorrow at a certain time:

    Next month a recurring event will be triggered hourly for a week:

    OR REPLACE and IF NOT EXISTS:

    See Also

    This page is licensed: GPLv2, originally from

    Silent Column Changes

    Explore Silent Column Changes in MariaDB. Learn when the server automatically modifies column definitions or data types during table creation to ensure engine compatibility.

    When a CREATE TABLE or ALTER TABLE command is issued, MariaDB silently changes a column specification in the following cases:

    • PRIMARY KEY columns are always NOT NULL.

    • Any trailing spaces from SET and ENUM values are discarded.

    • TIMESTAMP columns are always NOT NULL, and display sizes are discarded.

    • A row-size limit of 65535 bytes applies.

    • If is not enabled (by default, it is), a column longer than 65535 become , and a columns longer than 65535 becomes a . If strict mode is enabled the silent changes will not be made, and an error will occur.

    • If a USING clause specifies an index that's not permitted by the storage engine, the engine will instead use another available index type that can be applied without affecting results.

    • If the CHARACTER SET binary attribute is specified, the column is created as the matching binary data type. A TEXT becomes a BLOB, CHAR a BINARY and VARCHAR a VARBINARY. ENUMs and SETs are created as defined.

    To ease imports from other RDBMSs, MariaDB also silently maps the following data types:

    Other Vendor Type
    MariaDB Type

    Currently, all MySQL types are supported in MariaDB.

    For type mapping between Cassandra and MariaDB, see .

    Example

    Silent changes in action:

    This page is licensed: CC BY-SA / Gnu FDL

    DROP TABLE

    Delete one or more tables. This command removes the table definitions and all stored data permanently, and can also delete temporary tables.

    Syntax

    Description

    DROP TABLE removes one or more tables. You must have the

    CREATE SERVER

    Define a connection to a remote server. This command registers server details for use with the FEDERATED or SPIDER storage engines.

    Syntax

    Description

    This statement creates the definition of a server for use with the

    Online Schema Change

    Modify table structures. This guide covers adding columns, changing data types, managing indexes, and other schema changes for existing tables.

    Generally speaking, “online” refers to the ability to update the table schema without blocking concurrent DML for the duration of the copy.

    Suppose we have a table item featuring columns (id SERIAL, name TEXT).

    Now, it can be ALTERed by adding a TIMESTAMP field in one connection, while having a concurrent connection inserting a new row.

    CREATE LOGFILE GROUP

    Create a log file group for NDB Cluster. This command allocates undo log space on disk for NDB Disk Data tables.

    The CREATE LOGFILE GROUP statement is not supported by MariaDB. It was originally inherited from MySQL NDB Cluster. See for more information.

    This page is licensed: CC BY-SA / Gnu FDL

    CREATE [ OR REPLACE ]
        [DEFINER = { user | CURRENT_USER | role | CURRENT_ROLE }]
        PACKAGE BODY
        [ IF NOT EXISTS ]
        [ db_name . ] package_name
        [ package_characteristic... ]
    { AS | IS }
        package_implementation_declare_section
        package_implementation_executable_section
    END [ package_name]
    
    
    package_implementation_declare_section:
        package_implementation_item_declaration
          [ package_implementation_item_declaration... ]
          [ package_implementation_routine_definition... ]
      | package_implementation_routine_definition
          [ package_implementation_routine_definition...]
    
    package_implementation_item_declaration:
        variable_declaration ;
    
    variable_declaration:
        variable_name[,...] type [:= expr ]
    
    package_implementation_routine_definition:
        FUNCTION package_specification_function
           [ package_implementation_function_body ] ;
      | PROCEDURE package_specification_procedure
           [ package_implementation_procedure_body ] ;
    
    
    package_implementation_function_body:
        { AS | IS } package_routine_body [func_name]
    
    package_implementation_procedure_body:
        { AS | IS } package_routine_body [proc_name]
    
    package_routine_body:
        [ package_routine_declarations ]
        BEGIN
          statements [ EXCEPTION exception_handlers ]
        END
    
    
    package_routine_declarations:
        package_routine_declaration ';' [package_routine_declaration ';']...
    
    
    package_routine_declaration:
              variable_declaration
            | condition_name CONDITION FOR condition_value
            | user_exception_name EXCEPTION
            | CURSOR_SYM cursor_name
              [ ( cursor_formal_parameters ) ]
              IS select_statement
            ;
    
    
    package_implementation_executable_section:
              END
            | BEGIN
                statement ; [statement ; ]...
              [EXCEPTION exception_handlers]
              END
    
    exception_handlers:
               exception_handler [exception_handler...]
    
    exception_handler:
              WHEN_SYM condition_value [, condition_value]...
                THEN_SYM statement ; [statement ;]...
    
    condition_value:
              condition_name
            | user_exception_name
            | SQLWARNING
            | SQLEXCEPTION
            | NOT FOUND
            | OTHERS_SYM
            | SQLSTATE [VALUE] sqlstate_value
            | mariadb_error_code
    SET sql_mode=ORACLE; # unnecessary from MariaDB 11.4
    DELIMITER $$
    CREATE OR REPLACE PACKAGE employee_tools AS
      FUNCTION getSalary(eid INT) RETURN DECIMAL(10,2);
      PROCEDURE raiseSalary(eid INT, amount DECIMAL(10,2));
      PROCEDURE raiseSalaryStd(eid INT);
      PROCEDURE hire(ename TEXT, esalary DECIMAL(10,2));
    END;
    $$
    CREATE PACKAGE BODY employee_tools AS
      -- package body variables
      stdRaiseAmount DECIMAL(10,2):=500;
    
      -- private routines
      PROCEDURE log (eid INT, ecmnt TEXT) AS
      BEGIN
        INSERT INTO employee_log (id, cmnt) VALUES (eid, ecmnt);
      END;
    
      -- public routines
      PROCEDURE hire(ename TEXT, esalary DECIMAL(10,2)) AS
        eid INT;
      BEGIN
        INSERT INTO employee (name, salary) VALUES (ename, esalary);
        eid:= last_insert_id();
        log(eid, 'hire ' || ename);
      END;
    
      FUNCTION getSalary(eid INT) RETURN DECIMAL(10,2) AS
        nSalary DECIMAL(10,2);
      BEGIN
        SELECT salary INTO nSalary FROM employee WHERE id=eid;
        log(eid, 'getSalary id=' || eid || ' salary=' || nSalary);
        RETURN nSalary;
      END;
    
      PROCEDURE raiseSalary(eid INT, amount DECIMAL(10,2)) AS
      BEGIN
        UPDATE employee SET salary=salary+amount WHERE id=eid;
        log(eid, 'raiseSalary id=' || eid || ' amount=' || amount);
      END;
    
      PROCEDURE raiseSalaryStd(eid INT) AS
      BEGIN
        raiseSalary(eid, stdRaiseAmount);
        log(eid, 'raiseSalaryStd id=' || eid);
      END;
    
    BEGIN
      -- This code is executed when the current session
      -- accesses any of the package routines for the first time
      log(0, 'Session ' || connection_id() || ' ' || current_user || ' started');
    END;
    $$
    
    DELIMITER ;
    CREATE TABLE new_table (...);
    RENAME TABLE old_table TO backup_table, new_table TO old_table;
    RENAME TABLE db1.t TO db2.t;
    ERROR 1435 (HY000): Trigger in wrong schema
    ERROR 1450 (HY000): Changing schema from 'old_db' to 'new_db' is not allowed.
    RENAME TABLE t1 TO tmp_table,
        t2 TO t1,
        tmp_table TO t2;
    CREATE
        [ OR REPLACE]
        [DEFINER = { user | CURRENT_USER | role | CURRENT_ROLE }]
        PACKAGE [ IF NOT EXISTS ]
        [ db_name . ] package_name
        [ package_characteristic ... ]
    { AS | IS }
        [ package_specification_element ... ]
    END [ package_name ]
    
    
    package_characteristic:
        COMMENT 'string'
      | SQL SECURITY { DEFINER | INVOKER }
    
    
    package_specification_element:
        FUNCTION_SYM package_specification_function ;
      | PROCEDURE_SYM package_specification_procedure ;
    
    
    package_specification_function:
        func_name [ ( func_param [, func_param]... ) ]
        RETURN type
        [ package_routine_characteristic... ]
    
    package_specification_procedure:
        proc_name [ ( proc_param [, proc_param]... ) ]
        [ package_routine_characteristic... ]
    
    func_param:
        param_name [ IN | OUT | INOUT | IN OUT ] type
    
    proc_param:
        param_name [ IN | OUT | INOUT | IN OUT ] type
    
    type:
        Any valid MariaDB explicit or anchored data type
    
    
    package_routine_characteristic:
          COMMENT  'string'
        | LANGUAGE SQL
        | { CONTAINS SQL | NO SQL | READS SQL DATA | MODIFIES SQL DATA }
        | SQL SECURITY { DEFINER | INVOKER }
    CREATE
        [ OR REPLACE]
        [DEFINER = { user | CURRENT_USER | role | CURRENT_ROLE }]
        PACKAGE [ IF NOT EXISTS ]
        [ db_name . ] package_name
        [ package_characteristic ... ]
        [ package_specification_element ... ]
    END
    
    
    package_characteristic:
        COMMENT 'string'
      | SQL SECURITY { DEFINER | INVOKER }
    
    
    package_specification_element:
        FUNCTION_SYM package_specification_function ;
      | PROCEDURE_SYM package_specification_procedure ;
    
    
    package_specification_function:
        func_name [ ( func_param [, func_param]... ) ]
        RETURNS type
        [ package_routine_characteristic... ]
    
    package_specification_procedure:
        proc_name [ ( proc_param [, proc_param]... ) ]
        [ package_routine_characteristic... ]
    
    func_param:
        param_name [ IN | OUT | INOUT | IN OUT ] type
    
    proc_param:
        param_name [ IN | OUT | INOUT | IN OUT ] type
    
    type:
        Any valid MariaDB explicit or anchored data type
    
    
    package_routine_characteristic:
          COMMENT  'string'
        | LANGUAGE SQL
        | { CONTAINS SQL | NO SQL | READS SQL DATA | MODIFIES SQL DATA }
        | SQL SECURITY { DEFINER | INVOKER }
    SET sql_mode=ORACLE; # unnecessary from MariaDB 11.4
    DELIMITER $$
    CREATE OR REPLACE PACKAGE employee_tools AS
      FUNCTION getSalary(eid INT) RETURN DECIMAL(10,2);
      PROCEDURE raiseSalary(eid INT, amount DECIMAL(10,2));
      PROCEDURE raiseSalaryStd(eid INT);
      PROCEDURE hire(ename TEXT, esalary DECIMAL(10,2));
    END;
    $$
    DELIMITER ;
    CREATE [OR REPLACE]
        [DEFINER = { user | CURRENT_USER | role | CURRENT_ROLE }]
        EVENT 
        [IF NOT EXISTS]
        event_name    
        ON SCHEDULE schedule
        [ON COMPLETION [NOT] PRESERVE]
        [ENABLE | DISABLE | DISABLE ON SLAVE]
        [COMMENT 'comment']
        DO sql_statement;
    
    schedule:
        AT timestamp [+ INTERVAL interval] ...
      | EVERY interval 
        [STARTS timestamp [+ INTERVAL interval] ...] 
        [ENDS timestamp [+ INTERVAL interval] ...]
    
    interval:
        quantity {YEAR | QUARTER | MONTH | DAY | HOUR | MINUTE |
                  WEEK | SECOND | YEAR_MONTH | DAY_HOUR | DAY_MINUTE |
                  DAY_SECOND | HOUR_MINUTE | HOUR_SECOND | MINUTE_SECOND}
    MDEV-19295
    ALTER EVENT
  • DROP EVENT

  • Identifier Names
    Identifier Names
    CURRENT_TIMESTAMP
    ALTER EVENT
    ALTER EVENT
    ALTER EVENT
    INFORMATION_SCHEMA.EVENTS table
    Event Limitations
    Identifier Names
    Events Overview
    SHOW CREATE EVENT
    fill_help_tables.sql
    CREATE EVENT myevent
        ON SCHEDULE AT CURRENT_TIMESTAMP + INTERVAL 1 HOUR
        DO
          UPDATE myschema.mytable SET mycol = mycol + 1;
    CREATE EVENT example
    ON SCHEDULE AT CURRENT_TIMESTAMP + INTERVAL 1 DAY + INTERVAL 3 HOUR
    DO something;
    CREATE EVENT example
    ON SCHEDULE EVERY 1 HOUR
    STARTS CURRENT_TIMESTAMP + INTERVAL 1 MONTH
    ENDS CURRENT_TIMESTAMP + INTERVAL 1 MONTH + INTERVAL 1 WEEK
    DO some_task;
    CREATE EVENT myevent
        ON SCHEDULE AT CURRENT_TIMESTAMP + INTERVAL 1 HOUR
        DO
          UPDATE myschema.mytable SET mycol = mycol + 1;
    CREATE EVENT example
    ON SCHEDULE AT CURRENT_TIMESTAMP + INTERVAL 1 DAY + INTERVAL 3 HOUR
    DO something;
    CREATE EVENT example
    ON SCHEDULE EVERY 1 HOUR
    STARTS CURRENT_TIMESTAMP + INTERVAL 1 MONTH
    ENDS CURRENT_TIMESTAMP + INTERVAL 1 MONTH + INTERVAL 1 WEEK
    DO some_task;
    CREATE EVENT myevent
        ON SCHEDULE AT CURRENT_TIMESTAMP + INTERVAL 1 HOUR
        DO
          UPDATE myschema.mytable SET mycol = mycol + 1;
    ERROR 1537 (HY000): Event 'myevent' already exists
    
    CREATE OR REPLACE EVENT myevent
        ON SCHEDULE AT CURRENT_TIMESTAMP + INTERVAL 1 HOUR
        DO
          UPDATE myschema.mytable SET mycol = mycol + 1;;
    Query OK, 0 rows affected (0.00 sec)
    
    CREATE EVENT IF NOT EXISTS myevent
        ON SCHEDULE AT CURRENT_TIMESTAMP + INTERVAL 1 HOUR
        DO
          UPDATE myschema.mytable SET mycol = mycol + 1;
    Query OK, 0 rows affected, 1 warning (0.00 sec)
    
     SHOW WARNINGS;
    +-------+------+--------------------------------+
    | Level | Code | Message                        |
    +-------+------+--------------------------------+
    | Note  | 1537 | Event 'myevent' already exists |
    +-------+------+--------------------------------+

    INT1

    INT2

    INT3

    INT4

    INT8

    LONG VARBINARY

    LONG VARCHAR

    LONG

    MIDDLEINT

    NUMERIC

    BOOL

    TINYINT

    BOOLEAN

    TINYINT

    CHARACTER VARYING(M)

    VARCHAR(M)

    FIXED

    DECIMAL

    FLOAT4

    FLOAT

    FLOAT8

    DOUBLE

    strict SQL mode
    VARCHAR
    TEXT
    VARBINARY
    BLOB
    Cassandra storage engine
    DROP
    privilege for each table. All table data and the table definition are removed, as well as
    associated to the table, so be careful with this statement! If any of the tables named in the argument list do not exist, MariaDB returns an error indicating by name which non-existing tables it was unable to drop, but it also drops all of the tables in the list that do exist.

    Important: When a table is dropped, user privileges on the table are not automatically dropped. See GRANT.

    If another thread is using the table in an explicit transaction or an autocommit transaction, then the thread acquires a metadata lock (MDL) on the table. The DROP TABLE statement will wait in the "Waiting for table metadata lock" thread state until the MDL is released. MDLs are released in the following cases:

    • If an MDL is acquired in an explicit transaction, then the MDL will be released when the transaction ends.

    • If an MDL is acquired in an autocommit transaction, then the MDL will be released when the statement ends.

    • Transactional and non-transactional tables are handled the same.

    Note that for a partitioned table, DROP TABLE permanently removes the table definition, all of its partitions, and all of the data which was stored in those partitions. It also removes the partitioning definition (.par) file associated with the dropped table.

    For each referenced table, DROP TABLE drops a temporary table with that name, if it exists. If it does not exist, and the TEMPORARY keyword is not used, it drops a non-temporary table with the same name, if it exists. The TEMPORARY keyword ensures that a non-temporary table will not accidentally be dropped.

    Use IF EXISTS to prevent an error from occurring for tables that do not exist. A NOTE is generated for each non-existent table when usingIF EXISTS. See SHOW WARNINGS.

    If a foreign key references this table, the table cannot be dropped. In this case, it is necessary to drop the foreign key first.

    RESTRICT and CASCADE are allowed to make porting from other database systems easier. In MariaDB, they do nothing.

    The comment before the table names (/*COMMENT TO SAVE*/) is stored in the binary log. That feature can be used by replication tools to send their internal messages.

    It is possible to specify table names as db_name.tab_name. This is useful to delete tables from multiple databases with one statement. See Identifier Qualifiers for details.

    The DROP privilege is required to use DROP TABLE on non-temporary tables. For temporary tables, no privilege is required, because such tables are only visible for the current session.

    Note: DROP TABLE automatically commits the current active transaction, unless you use the TEMPORARY keyword.

    DROP TABLE reliably deletes table remnants inside a storage engine even if the .frm file is missing.

    DROP TABLE does not reliably delete table remnants inside a storage engine even if the .frm file is missing. A missing .frm file will result in the statement failing.

    WAIT/NOWAIT

    Set the lock wait timeout. See WAIT and NOWAIT.

    DROP TABLE in replication

    DROP TABLE has the following characteristics in replication:

    • DROP TABLE IF EXISTS are always logged.

    • DROP TABLE without IF EXISTS for tables that don't exist are not written to the binary log.

    • Dropping of TEMPORARY tables are prefixed in the log with TEMPORARY. These drops are only logged when running or replication.

    • One DROP TABLE statement can be logged with up to 3 different DROP statements:

      • DROP TEMPORARY TABLE list_of_non_transactional_temporary_tables

      • DROP TEMPORARY TABLE list_of_transactional_temporary_tables

    DROP TABLE on the primary is treated on the replica as DROP TABLE IF EXISTS. You can change that by setting slave-ddl-exec-mode to STRICT.

    Dropping an Internal #sql-... Table

    DROP TABLE is atomic.

    if the mariadbd process is killed during an ALTER TABLE, you may find a table named #sql-... in your data directory. These temporary tables will always be deleted automatically.

    If you want to delete one of these tables explicitly you can do so by using the following syntax:

    When running an ALTER TABLE…ALGORITHM=INPLACE that rebuilds the table, InnoDB will create an internal #sql-ib table.

    The same name as the .frm file is used for the intermediate copy of the table. The #sql-ib names are used by TRUNCATE and delayed DROP.

    The #sql-ib tables will be deleted automatically.

    Dropping All Tables in a Database

    The best way to drop all tables in a database is by executing DROP DATABASE, which will drop the database itself, and all tables in it.

    However, if you want to drop all tables in the database, but you also want to keep the database itself and any other non-table objects in it, then you would need to execute DROP TABLE to drop each individual table. You can construct these DROP TABLE commands by querying the TABLES table in the information_schema database. For example:

    Atomic DROP TABLE

    MariaDB starting with 10.6.1

    DROP TABLE for a single table is atomic (MDEV-25180) for most engines, including InnoDB, MyRocks, MyISAM and Aria. This means that if there is a crash (server down or power outage) during DROP TABLE, all tables that have been processed so far will be completely dropped, including related trigger files and status entries, and the binary log will include a DROP TABLE statement for the dropped tables. Tables for which the drop had not started will be left intact.DROP TABLE was extended to be able to delete a table that was only partly dropped (MDEV-11412), as explained above. Atomic DROP TABLE is the final piece to make DROP TABLE fully reliable. Dropping multiple tables is crash-safe. See Atomic DDL for more information.

    There is a small chance that, during a server crash happening in the middle of DROP TABLE, some storage engines that were using multiple storage files, like , could have only a part of its internal files dropped. In , DROP TABLE was extended to be able to delete a table that was only partly dropped () as explained above. Atomic DROP TABLE is the final piece to make DROP TABLE fully reliable. Dropping multiple tables is crash-safe. See for more information.

    Examples

    Notes

    Beware that DROP TABLE can drop both tables and sequences. This is mainly done to allow old tools like mariadb-dump (previously mysqldump) to work with sequences.

    See Also

    • CREATE TABLE

    • ALTER TABLE

    • SHOW CREATE TABLE

    • DROP SEQUENCE

    • Variable .

    This page is licensed: GPLv2, originally from fill_help_tables.sql

    triggers
    ,
    ,
    , or
    storage engine. The CREATE SERVER statement creates a new row in the
    table within the mysql database. This statement requires the
    privilege.

    This statement creates the definition of a server for use with the Spider, Connect, FEDERATED, or FederatedX storage engine. The CREATE SERVER statement creates a new row in the servers table within the mysql database. This statement requires the SUPER privilege.

    The server_name should be a unique reference to the server. Server definitions are global within the scope of the server, it is not possible to qualify the server definition to a specific database. server_name has a maximum length of 64 characters (names longer than 64 characters are silently truncated), and is case-insensitive. You may specify the name as a quoted string.

    The wrapper_name may be quoted with single quotes. Supported values are:

    • mysql

    • mariadb (from )

    For each option you must specify either a character literal or numeric literal. Character literals are UTF-8, support a maximum length of 64 characters and default to a blank (empty) string. String literals are silently truncated to 64 characters. Numeric literals must be a number between 0 and 9999, default value is 0.

    Note: The OWNER option is currently not applied, and has no effect on the ownership or operation of the server connection that is created.

    The CREATE SERVER statement creates an entry in the mysql.servers table that can later be used with the CREATE TABLE statement when creating a Spider, Connect, FederatedX or FEDERATED table. The options that you specify will be used to populate the columns in the mysql.servers table. The table columns are Server_name, Host, Db, Username, Password, Port and Socket.

    DROP SERVER removes a previously created server definition.

    CREATE SERVER is not written to the binary log, irrespective of the binary log format being used and therefore will not replicate.

    Galera replicates the CREATE SERVER, ALTER SERVER and DROP SERVER statements.

    Galera does not replicate the CREATE SERVER, ALTER SERVER and DROP SERVER statements.

    For valid identifiers to use as server names, see Identifier Names.

    The SHOW CREATE SERVER statement can be used to show the CREATE SERVER statement that created a given server definition.

    The SHOW CREATE SERVER statement cannot be used to show the CREATE SERVER statement that created a given server definition.

    OR REPLACE

    If the optional OR REPLACE clause is used, it acts as a shortcut for:

    IF NOT EXISTS

    If the IF NOT EXISTS clause is used, MariaDB will return a warning instead of an error if the server already exists. Cannot be used together with OR REPLACE.

    Examples

    OR REPLACE and IF NOT EXISTS:

    See Also

    • Identifier Names

    • ALTER SERVER

    • DROP SERVER

    • Spider Storage Engine

    This page is licensed: GPLv2, originally from fill_help_tables.sql

    Spider
    Connect
    FEDERATED
    FederatedX
    servers
    FEDERATED ADMIN
    Connection 1:

    Connection 2:

    If the INSERT statement begins its execution after ALTER TABLE is issued, it will not be blocked and will proceed normally, and thus it may finish before ALTER TABLE.

    ALTER TABLE always allows concurrent SELECT statements. If the LOCK=NONE locking strategy is chosen, it will allow concurrent modifications (INSERT/DELETE/UPDATE). Namely, LOCK=NONE was supported by InnoDB and the Partition engine when ALGORITHM=NOCOPY is chosen and is a default locking strategy when available.

    With the new release, LOCK=NONE support is added for ALGORITHM=COPY, thus almost all ALTER TABLE operations (a few exceptions are given below) now allow concurrent DML.

    The Mechanism

    LOCK=NONE adds one extra step to the copy algorithm. It introduces a new internal entity, the online change buffer.

    • First, a new table is created using the old table content as it was at the beginning of the ALTER TABLE statement. For InnoDB and other transactional engines it means copying in REPEATABLE READ isolation mode.

      • In the meantime, every concurrent change is written in the old table and is duplicated to the online change buffer.

    • Then, ALTER TABLE applies the changes accumulated in that online change buffer.

    Note that while all copying and online changes application happens without blocking concurrent DML, in the end it acquires an EXCLUSIVE lock on the table for a short amount of time, to synchronize with all parallel operations that are not yet finished.

    Supported Engines

    The requirement for an engine is to allow concurrent writes, while another connection can read and have a repeatable-read behavior.

    MyISAM/Aria

    MyISAM is capable of concurrent INSERTs and also supports concurrent inserts while reading: we can’t say it supports REPEATABLE READ transaction isolation layer, but the newly inserted data is not seen by the readers until the end of the statement, so it satisfies the criterion, however it is not transactional.

    An attempt to invoke any statement that can update or delete a row will be blocked until the end of ALTER TABLE (or will evaluate before ALTER TABLE acquires a lock, if it started earlier).

    InnoDB

    InnoDB supports REPEATABLE READ isolation layer and allows concurrent writes, so it is also supported by Online schema change, broadly enhancing its online ability represented by INPLACE and INSTANT algorithms. By default, an engine-native algorithm will be chosen whenever possible. If InnoDB will not be capable of holding the schema change natively, then, if possible, a COPY algorithm with Online schema change will be applied. A more detailed comparison follows below.

    Other Engines

    MariaDB ColumnStore does not support REPEATABLE READ isolation layer, therefore it cannot support online schema change.

    LOCK=NONE is naturally disabled for engines like BLACKHOLE, as well as for SEQUENCE engine, and sequences, and for read-only engines like S3.

    CONNECT cannot read concurrently to writes, so it is also not capable of making ALTER TABLE online.

    SPIDER storage engine does not really do a copy, but rather just reassigns a table with a new metadata.

    Comparison to InnoDB’s INPLACE capabilities

    Everything that can be done by InnoDB’s INPLACE, can be done by online COPY, except that tables with foreign keys with cascade operations are not supported. See the limitations section.

    • Changing the column’s data type is now possible.

    • A column can be modified too NOT NULL.

    • A column with non-constant DEFAULT value can be added.

    • A STORED generated column can be added.

    • A CHECK constraint can be added.

    • PRIMARY KEY can be dropped.

    • No key is required in the resulting table.

    • A table can be changed to partitioned, or otherwise, partitioning can be removed.

    • SYSTEM VERSIONING can be added.

    • AUTO_INCREMENT can be added to the existing column but see limitations.

    Limitations

    We have come across a number of limitations apart from the engine support, while we were testing. Some of them just lack a proper implementation, and some are also theoretically infeasible without relaxing the rules we have defined. If you feel that some of these limitations affect you, please leave a comment and tell us about it.

    Now, a complete list of limitations we are aware of follows:

    • Adding an AUTO_INCREMENT column is forbidden. Same applies to DEFAULT (…NEXTVAL(…)). We found that we can end up with the undefined behavior in this case, depending on when the concurrent DML is evaluated. Changing an existing column to become AUTO_INCREMENT is allowed, though. The two following conditions should be met:

      • A column should be NOT NULL in the old schema

      • NO_AUTO_VALUE_ON_ZERO mode should be unset.

      • At least one UNIQUE NOT NULL key should be in the old schema, and it should remain unchanged.

    • Support for ALTER IGNORE TABLE is not implemented. This operation can make the altered table have fewer rows than the original one (because duplicates are skipped), and the online copy algorithm doesn’t support operations that change the number of rows in the table.

    • ALTER TABLE DROP SYSTEM VERSIONING is not supported either, for the similar reason.

    • Tables with foreign keys with CASCADE/SET NULL/SET DEFAULT operations can’t go online under ALGORITHM=COPY — similar to disallowing CHECK constraints and stored generated columns, cascade operations are done internally by the storage engine, so they bypass the online changes buffer. However, most operations are allowed by InnoDB’s INPLACE algorithm. Again, for every DDL request the most optimal algorithm will be chosen automatically.

    • Transaction-versioned tables can also be only changed “online” under INPLACE/INSTANT ALTER TABLE algorithms.

    • All the constraints (CHECK, UNIQUE, FOREIGN KEY) are evaluated for each row change that is applied from the online change buffer. This means that all the changes that are made during ALTER TABLE’s main phase should not violate the final table schema at any point in time. As always, the checks can be disabled by setting check_constraint_checks and FOREIGN_KEY_CHECKS to OFF.

    • ALTER TABLE … ORDER BY cannot be supported, because changes from the buffer are applied at the end and they might break the strict ordering of rows.

    • It is not available in embedded MariaDB Server due to replication libraries that are not present in the embedded version.

    Switching back

    Online copy is the default mode whenever NOCOPY does not apply. In case of any problem with it, it can be disabled by specifying LOCK=SHARED to force the usual COPY algorithm.

    To better support existing workflows, a new old_mode flag was also added. The following statement disables online copy by default:

    It can still be forced to use the new feature under this mode by explicitly specifying LOCK=NONE in the ALTER TABLE statement.

    Server-wide online schema change expands MariaDB Server’s capability for the LOCK=NONE approach broadly. The change is made in the core Server operation, which interferes with many components, so it took quite a while to get our approach right. This is still an early version of the feature so please note the limitations that we outlined above.

    For more information, refer to,

    Online copy is not the default mode.

    CREATE INDEX

    Add an index to an existing table. This statement improves query performance by creating a data structure for rapid lookups on specific columns.

    Syntax

    Description

    The CREATE INDEX statement is used to add indexes to a table. Indexes can be created at the same as the table, with the statement. In some cases, such as for InnoDB primary keys, doing so during creation is preferable, as adding a primary key will involve rebuilding the table.

    The statement is mapped to an ALTER TABLE statement to create . See . CREATE INDEX cannot be used to create a ; use ALTER TABLE instead.

    If another connection is using the table, a is active, and this statement will wait until the lock is released. This is also true for non-transactional tables.

    Another shortcut, , allows the removal of an index.

    For valid identifiers to use as index names, see .

    For limits on InnoDB indexes, see .

    Note that KEY_BLOCK_SIZE is currently ignored in CREATE INDEX, although it is included in the output of .

    Privileges

    Executing the CREATE INDEX statement requires the privilege for the table or the database.

    Online DDL

    Online DDL is supported with the and clauses.

    See for more information on online DDL with InnoDB.

    CREATE OR REPLACE INDEX

    If the OR REPLACE clause is used and if the index already exists, then instead of returning an error, the server will drop the existing index and replace it with the newly defined index.

    CREATE INDEX IF NOT EXISTS

    If the IF NOT EXISTS clause is used, then the index will only be created if an index with the same name does not already exist. If the index already exists, then a warning will be triggered by default.

    Index Definitions

    See for information about index definitions.

    WAIT/NOWAIT

    Set the lock wait timeout. See .

    ALGORITHM

    See for more information.

    LOCK

    See for more information.

    Progress Reporting

    MariaDB provides progress reporting for CREATE INDEX statement for clients that support the new progress reporting protocol. For example, if you were using the client, then the progress report might look like this::

    The progress report is also shown in the output of the statement and in the contents of the table.

    See for more information.

    WITHOUT OVERLAPS

    The WITHOUT OVERLAPS clause allows you to constrain a primary or unique index such that cannot overlap. It can be used like this:

    WITHOUT OVERLAPS is not available.

    Examples

    Creating a unique index:

    OR REPLACE and IF NOT EXISTS:

    See Also

    This page is licensed: GPLv2, originally from

    CREATE TABLE SilenceIsGolden
       (
        f1 TEXT CHARACTER SET BINARY,
        f2 VARCHAR(15) CHARACTER SET BINARY,
        f3 CHAR CHARACTER SET BINARY,
        f4 ENUM('x','y','z') CHARACTER SET BINARY,
        f5 VARCHAR (65536),
        f6 VARBINARY (65536),
        f7 INT1
       );
    Query OK, 0 rows affected, 2 warnings (0.31 sec)
    
    SHOW WARNINGS;
    +-------+------+-----------------------------------------------+
    | Level | Code | Message                                       |
    +-------+------+-----------------------------------------------+
    | Note  | 1246 | Converting column 'f5' from VARCHAR to TEXT   |
    | Note  | 1246 | Converting column 'f6' from VARBINARY to BLOB |
    +-------+------+-----------------------------------------------+
    
    DESCRIBE SilenceIsGolden;
    +-------+-------------------+------+-----+---------+-------+
    | Field | Type              | Null | Key | Default | Extra |
    +-------+-------------------+------+-----+---------+-------+
    | f1    | blob              | YES  |     | NULL    |       |
    | f2    | varbinary(15)     | YES  |     | NULL    |       |
    | f3    | binary(1)         | YES  |     | NULL    |       |
    | f4    | enum('x','y','z') | YES  |     | NULL    |       |
    | f5    | mediumtext        | YES  |     | NULL    |       |
    | f6    | mediumblob        | YES  |     | NULL    |       |
    | f7    | tinyint(4)        | YES  |     | NULL    |       |
    +-------+-------------------+------+-----+---------+-------+
    DROP TABLE `#mysql50##sql-...`;
    DROP [TEMPORARY] TABLE [IF EXISTS] [/*COMMENT TO SAVE*/]
        tbl_name [, tbl_name] ...
        [WAIT n|NOWAIT]
        [RESTRICT | CASCADE]
    SELECT CONCAT('DROP TABLE IF EXISTS `', TABLE_SCHEMA, '`.`', TABLE_NAME, '`;')
    FROM information_schema.TABLES
    WHERE TABLE_SCHEMA = 'mydb';
    DROP TABLE Employees, Customers;
    CREATE [OR REPLACE] SERVER [IF NOT EXISTS] server_name
        FOREIGN DATA WRAPPER wrapper_name
        OPTIONS (option [, option] ...)
    
    option: <= MariaDB 11.6
      { HOST character-literal
      | DATABASE character-literal
      | USER character-literal
      | PASSWORD character-literal
      | SOCKET character-literal
      | OWNER character-literal
      | PORT numeric-literal }
    
    option: >= MariaDB 11.7
      { HOST character-literal
      | DATABASE character-literal
      | USER character-literal
      | PASSWORD character-literal
      | SOCKET character-literal
      | OWNER character-literal
      | PORT numeric-literal
      | PORT quoted-numerical-literal
      | identifier character-literal}
    DROP SERVER IF EXISTS name;
    CREATE SERVER server_name ...;
    CREATE SERVER s
    FOREIGN DATA WRAPPER mariadb
    OPTIONS (USER 'Remote', HOST '192.168.1.106', DATABASE 'test');
    CREATE SERVER s 
    FOREIGN DATA WRAPPER mariadb 
    OPTIONS (USER 'Remote', HOST '192.168.1.106', DATABASE 'test');
    ERROR 1476 (HY000): The foreign server, s, you are trying to create already exists
    
    CREATE OR REPLACE SERVER s 
    FOREIGN DATA WRAPPER mariadb 
    OPTIONS (USER 'Remote', HOST '192.168.1.106', DATABASE 'test');
    Query OK, 0 rows affected (0.00 sec)
    
    CREATE SERVER IF NOT EXISTS s 
    FOREIGN DATA WRAPPER mariadb 
    OPTIONS (USER 'Remote', HOST '192.168.1.106', DATABASE 'test');
    Query OK, 0 rows affected, 1 warning (0.00 sec)
    
    SHOW WARNINGS;
    +-------+------+----------------------------------------------------------------+
    | Level | Code | Message                                                        |
    +-------+------+----------------------------------------------------------------+
    | Note  | 1476 | The foreign server, s, you are trying to create already exists |
    +-------+------+----------------------------------------------------------------+
    set old_mode= LOCK_ALTER_TABLE_COPY;
    ALTER TABLE items 
    
                ADD ts TIMESTAMP DEFAULT CURRENT_TIMESTAMP; # Start ALTER TABLE
    INSERT INTO items(name) VALUES (“New item”);
    CREATE [OR REPLACE] [UNIQUE|FULLTEXT|SPATIAL] INDEX 
      [IF NOT EXISTS] index_name
        [index_type]
        ON tbl_name (index_col_name,...)
        [WAIT n | NOWAIT]
        [index_option]
        [algorithm_option | lock_option] ...
    
    index_col_name:
        col_name [(length)] [ASC | DESC]
    
    index_type:
        USING {BTREE | HASH | RTREE}
    
    index_option:
        [ KEY_BLOCK_SIZE [=] value
      | index_type
      | WITH PARSER parser_name
      | COMMENT 'string'
      | CLUSTERING={YES| NO} ]
      [ IGNORED | NOT IGNORED ]
    
    algorithm_option:
        ALGORITHM [=] {DEFAULT|INPLACE|COPY|NOCOPY|INSTANT}
    
    lock_option:
        LOCK [=] {DEFAULT|NONE|SHARED|EXCLUSIVE}
    TINYINT
    SMALLINT
    MEDIUMINT
    INT
    BIGINT
    MEDIUMBLOB
    MEDIUMTEXT
    MEDIUMTEXT
    MEDIUMINT
    DECIMAL
    Reduced operational downtime with new ALTER TABLE

    DROP TABLE list_of_normal_tables

    statement
    mixed mode
    MyISAM
    MDEV-11412
    Atomic DDL
    slave-ddl-exec-mode
    SHOW INDEX
  • SPATIAL INDEX

  • Full-text Indexes

  • WITHOUT OVERLAPS

  • Ignored Indexes

  • InnoDB Limitations

  • CREATE TABLE
    indexes
    ALTER TABLE
    PRIMARY KEY
    metadata lock
    DROP INDEX
    Identifier Names
    InnoDB Limitations
    SHOW CREATE TABLE
    INDEX
    ALGORITHM
    LOCK
    InnoDB Online DDL Overview
    CREATE TABLE: Index Definitions
    WAIT and NOWAIT
    ALTER TABLE: ALGORITHM
    ALTER TABLE: LOCK
    mariadb
    SHOW PROCESSLIST
    information_schema.PROCESSLIST
    application-time periods
    Identifier Names
    Getting Started with Indexes
    ALTER TABLE
    DROP INDEX
    fill_help_tables.sql
    Connect Storage Engine
    mysql.servers table
    SHOW CREATE SERVER
    CREATE INDEX i ON tab (num);
    Stage: 1 of 2 'copy to tmp table'    46% of stage
    CREATE UNIQUE INDEX u ON rooms (room_number, p WITHOUT OVERLAPS);
    CREATE UNIQUE INDEX HomePhone ON Employees(Home_Phone);
    CREATE INDEX xi ON xx5 (x);
    Query OK, 0 rows affected (0.03 sec)
    
    CREATE INDEX xi ON xx5 (x);
    ERROR 1061 (42000): Duplicate key name 'xi'
    
    CREATE OR REPLACE INDEX xi ON xx5 (x);
    Query OK, 0 rows affected (0.03 sec)
    
    CREATE INDEX IF NOT EXISTS xi ON xx5 (x);
    Query OK, 0 rows affected, 1 warning (0.00 sec)
    
    SHOW WARNINGS;
    +-------+------+-------------------------+
    | Level | Code | Message                 |
    +-------+------+-------------------------+
    | Note  | 1061 | Duplicate key name 'xi' |
    +-------+------+-------------------------+

    CREATE FUNCTION

    Define a stored function. This command creates a routine that accepts parameters, executes logic, and returns a single value for use in SQL expressions.

    Syntax

    Description

    Use the CREATE FUNCTION statement to create a new . You must have the database privilege to use CREATE FUNCTION. A function takes any number of arguments and returns a value from the function body. The function body can be any valid SQL expression as you would use, for example, in any select expression. If you have the appropriate privileges, you can call the function exactly as you would any built-in function. See below for details on privileges.

    You can also use a variant of the CREATE FUNCTION statement to install a user-defined function (UDF) defined by a plugin. See for details.

    You can use a statement for the function body by enclosing it in parentheses, exactly as you would to use a subselect for any other expression. The SELECT statement must return a single value. If more than one column is returned when the function is called, error 1241 results. If more than one row is returned when the function is called, error 1242 results. Use a LIMIT clause to ensure only one row is returned.

    You can also replace the RETURN clause with a compound statement. The compound statement must contain a RETURN statement. When the function is called, the RETURN statement immediately returns its result, and any statements after RETURN are effectively ignored.

    By default, a function is associated with the current database. To associate the function explicitly with a given database, specify the fully-qualified name as db_name.func_name when you create it. If the function name is the same as the name of a built-in function, you must use the fully qualified name when you call it.

    The parameter list enclosed within parentheses must always be present. If there are no parameters, an empty parameter list of () should be used. Parameter names are not case-sensitive.

    Each parameter can be declared to use any valid data type, except that the COLLATE attribute cannot be used.

    For valid identifiers to use as function names, see .

    RETURN

    The RETURN clause can return a function body. In newer versions of MariaDB, it can also return a cursor (using SYS_REFCURSOR).

    RETURN func_body

    The RETURN clause can return a function body (a valid SQL PROCEDURE statement).

    RETURN SYS_REFCURSOR

    It can also return a cursor, if the function was declared with a SYS_REFCURSOR variable, like this:

    Alternatively, a cursor can be returned in an OUT parameter, see .

    AGGREGATE

    It is possible to create stored aggregate functions as well. See for details.

    IN | OUT | INOUT | IN OUT

    OUT, INOUT and its equivalent IN OUT, are only valid if called from SET and not SELECT. These quantifiers are especially useful for creating functions with more than one return value. This allows functions to be more complex and nested.

    Quantifiers are not available.

    A cursor can be returned, like this:

    This feature is not available.

    RETURNS

    The RETURNS clause specifies the return type of the function. NULL values are permitted with all return types.

    What happens if the RETURN clause returns a value of a different type? It depends on the in effect at the moment of the function creation.

    If the SQL_MODE is strict (STRICT_ALL_TABLES or STRICT_TRANS_TABLES flags are specified), a 1366 error will be produced.

    Otherwise, the value is coerced to the proper type. For example, if a function specifies an ENUM or SET value in the RETURNS clause, but the RETURN clause returns an integer, the value returned from the function is the string for the corresponding ENUM member of set of SET members.

    MariaDB stores the SQL_MODE system variable setting that is in effect at the time a routine is created, and always executes the routine with this setting in force, regardless of the server SQL mode in effect when the routine is invoked.

    LANGUAGE SQL

    LANGUAGE SQL is a standard SQL clause which can be used in MariaDB for portability. However that clause has no meaning, because SQL is the only supported language for stored functions.

    A function is deterministic if it can produce only one result for a given list of parameters. If the result may be affected by stored data, server variables, random numbers or any value that is not explicitly passed, then the function is not deterministic. Also, a function is non-deterministic if it uses nondeterministic functions like or . The optimizer may choose a faster execution plan if it known that the function is deterministic. In such cases, you should declare the routine using the DETERMINISTIC keyword. If you want to explicitly state that the function is not deterministic (which is the default) you can use the NOT DETERMINISTIC keywords.

    If you declare a non-deterministic function as DETERMINISTIC, you may get incorrect results. If you declare a deterministic function as NOT DETERMINISTIC, in some cases the queries will be slower.

    OR REPLACE

    If the optional OR REPLACE clause is used, it acts as a shortcut for:

    with the exception that any existing for the function are not dropped.

    IF NOT EXISTS

    If the IF NOT EXISTS clause is used, MariaDB will return a warning instead of an error if the function already exists. Cannot be used together with OR REPLACE.

    [NOT] DETERMINISTIC

    The [NOT] DETERMINISTIC clause also affects , because the STATEMENT format can not be used to store or replicate non-deterministic statements.

    CONTAINS SQL, NO SQL, READS SQL DATA, and MODIFIES SQL DATA are informative clauses that tell the server what the function does. MariaDB does not check in any way whether the specified clause is correct. If none of these clauses are specified, CONTAINS SQL is used by default.

    MODIFIES SQL DATA

    MODIFIES SQL DATA means that the function contains statements that may modify data stored in databases. This happens if the function contains statements like , , , or DDL.

    READS SQL DATA

    READS SQL DATA means that the function reads data stored in databases, but does not modify any data. This happens if statements are used, but there no write operations are executed.

    CONTAINS SQL

    CONTAINS SQL means that the function contains at least one SQL statement, but it does not read or write any data stored in a database. Examples include or .

    NO SQL

    NO SQL means nothing, because MariaDB does not currently support any language other than SQL.

    Oracle Mode

    A subset of Oracle's PL/SQL language is supported in addition to the traditional SQL/PSM-based MariaDB syntax. See for details on changes when running Oracle mode.

    Security

    You must have the privilege on a function to call it. MariaDB automatically grants the EXECUTE and ALTER ROUTINE privileges to the account that called CREATE FUNCTION, even if the DEFINER clause was used.

    Each function has an account associated as the definer. By default, the definer is the account that created the function. Use the DEFINER clause to specify a different account as the definer. You must have the privilege to use the DEFINER clause. See for details on specifying accounts.

    The SQL SECURITY clause specifies what privileges are used when a function is called. If SQL SECURITY is INVOKER, the function body will be evaluated using the privileges of the user calling the function. If SQL SECURITY is DEFINER, the function body is always evaluated using the privileges of the definer account. DEFINER is the default.

    This allows you to create functions that grant limited access to certain data. For example, say you have a table that stores some employee information, and that you've granted SELECT privileges to the user account roger.

    To allow the user the get the maximum salary for a department, define a function and grant the EXECUTE privilege:

    Since SQL SECURITY defaults to DEFINER, whenever the user roger calls this function, the subselect will execute with your privileges. As long as you have privileges to select the salary of each employee, the caller of the function will be able to get the maximum salary for each department without being able to see individual salaries.

    Character Sets and Collations

    Function return types can be declared to use any valid . If used, the COLLATE attribute needs to be preceded by a CHARACTER SET attribute.

    If the character set and collation are not specifically set in the statement, the database defaults at the time of creation will be used. If the database defaults change at a later stage, the stored function character set/collation will not be changed at the same time; the stored function needs to be dropped and recreated to ensure the same character set/collation as the database is used.

    Examples

    The following example function takes a parameter, performs an operation using an SQL function, and returns the result.

    You can use a compound statement in a function to manipulate data with statements like INSERT and UPDATE. The following example creates a counter function that uses a temporary table to store the current value. Because the compound statement contains statements terminated with semicolons, you have to first change the statement delimiter with the DELIMITER statement to allow the semicolon to be used in the function body. See for more.

    Character set and collation:

    See Also

    This page is licensed: GPLv2, originally from

    CREATE [OR REPLACE]
        [DEFINER = {user | CURRENT_USER | role | CURRENT_ROLE }]
        [AGGREGATE] FUNCTION [IF NOT EXISTS] func_name ([func_parameter[,...]])
        RETURNS type
        [characteristic ...]
        RETURN func_body
        [RETURN SYS_REFCURSOR]
    
    func_parameter:
        [ IN | OUT | INOUT | IN OUT ]  param_name type
    
    type:
        Any valid MariaDB data type
    
    characteristic:
        LANGUAGE SQL
      | [NOT] DETERMINISTIC
      | { CONTAINS SQL | NO SQL | READS SQL DATA | MODIFIES SQL DATA }
      | SQL SECURITY { DEFINER | INVOKER }
      | COMMENT 'string'
    
    func_body:
        Valid SQL procedure statement

    RETURN func_body

    The RETURN clause can return a function body (a valid SQL PROCEDURE statement).

    ALTER FUNCTION
  • DROP FUNCTION

  • SHOW FUNCTION STATUS

  • Stored Routine Privileges

  • Information Schema ROUTINES Table

  • stored function
    CREATE ROUTINE
    Security
    CREATE FUNCTION (UDF)
    SELECT
    BEGIN...END
    Identifier Names
    this section
    Stored Aggregate Functions
    SQL_MODE
    NOW()
    CURRENT_TIMESTAMP()
    privileges
    binary logging
    DELETE
    UPDATE
    INSERT
    REPLACE
    SELECT
    SET
    DO
    EXECUTE
    SET USER
    Account Names
    only on certain columns
    character set and collation
    Delimiters in the mariadb client
    Identifier Names
    Stored Aggregate Functions
    CREATE FUNCTION (UDF)
    SHOW CREATE FUNCTION
    fill_help_tables.sql
    CREATE FUNCTION f1 RETURN SYS_REFCURSOR AS
      c SYS_REFCURSOR;
    BEGIN
      OPEN c FOR SELECT a FROM t1 ORDER BY a;
      RETURN c;
    END;
    /
    DELIMITER $$
    CREATE FUNCTION add_func3(IN a INT, IN b INT, OUT c INT) RETURNS INT
    BEGIN
      SET c = 100;
      RETURN a + b;
    END;
    $$
    DELIMITER ;
     
    SET @a = 2;
    SET @b = 3;
    SET @c = 0;
    SET @res= add_func3(@a, @b, @c);
    
    SELECT add_func3(@a, @b, @c);
    ERROR 4186 (HY000): OUT or INOUT argument 3 for function add_func3 is not allowed here
    
    DELIMITER $$
    CREATE FUNCTION add_func4(IN a INT, IN b INT, d INT) RETURNS INT
    BEGIN
      DECLARE c, res INT;
      SET res = add_func3(a, b, c) + d;
      if (c > 99) then
        return  3;
      else
        return res;
      end if;
    END;
    $$
    
    DELIMITER ;
    
    SELECT add_func4(1,2,3);
    +------------------+
    | add_func4(1,2,3) |
    +------------------+
    |                3 |
    +------------------+
    CREATE TABLE t1 (a INT);
    INSERT INTO t1 VALUES (10),(20);
     
    CREATE FUNCTION f1 RETURN SYS_REFCURSOR AS
      c SYS_REFCURSOR;
    BEGIN
      OPEN c FOR SELECT a FROM t1 ORDER BY a;
      RETURN c;
    END;
    /
     
    CREATE PROCEDURE p1 AS
      a INT;
      c SYS_REFCURSOR DEFAULT f1();
    BEGIN
      LOOP
        FETCH c INTO a;
        EXIT WHEN c%NOTFOUND;
        dbms_output.put_line(a);
      END LOOP;
      CLOSE c;
      END;
    /
     
    CALL p1();
    DROP FUNCTION IF EXISTS function_name;
    CREATE FUNCTION function_name ...;
    CREATE TABLE employees (name TINYTEXT, dept TINYTEXT, salary INT);
    GRANT SELECT (name, dept) ON employees TO roger;
    CREATE FUNCTION max_salary (dept TINYTEXT) RETURNS INT RETURN
      (SELECT MAX(salary) FROM employees WHERE employees.dept = dept);
    GRANT EXECUTE ON FUNCTION max_salary TO roger;
    CREATE FUNCTION hello (s CHAR(20))
        RETURNS CHAR(50) DETERMINISTIC
        RETURN CONCAT('Hello, ',s,'!');
    
    SELECT hello('world');
    +----------------+
    | hello('world') |
    +----------------+
    | Hello, world!  |
    +----------------+
    CREATE TEMPORARY TABLE counter (c INT);
    INSERT INTO counter VALUES (0);
    DELIMITER //
    CREATE FUNCTION counter () RETURNS INT
      BEGIN
        UPDATE counter SET c = c + 1;
        RETURN (SELECT c FROM counter LIMIT 1);
      END //
    DELIMITER ;
    CREATE FUNCTION hello2 (s CHAR(20))
      RETURNS CHAR(50) CHARACTER SET 'utf8' COLLATE 'utf8_bin' DETERMINISTIC
      RETURN CONCAT('Hello, ',s,'!');

    Generated Columns

    Generated columns can be virtual or persistent (stored).

    Syntax

    MariaDB's generated columns syntax is designed to be similar to the syntax for Microsoft SQL Server's computed columns and Oracle Database's virtual columns. The syntax is also compatible with the syntax for MySQL's generated columns.

    MariaDB's generated columns syntax is designed to be similar to the syntax for Microsoft SQL Server's computed columns and Oracle Database's virtual columns. The syntax is not compatible with the syntax for MySQL's generated columns.

    Description

    A generated column is a column in a table that cannot explicitly be set to a specific value in a . Instead, its value is automatically generated based on an expression. This expression might generate the value based on the values of other columns in the table, or it might generate the value by calling or .

    There are two types of generated columns:

    • PERSISTENT (a.k.a. STORED): This type's value is actually stored in the table.

    • VIRTUAL: This type's value is not stored at all. Instead, the value is generated dynamically when the table is queried. This type is the default.

    Generated columns are also sometimes called computed columns or virtual columns.

    Supported Features

    Storage Engine Support

    • Generated columns can only be used with storage engines which support them. If you try to use a storage engine that does not support them, then you will see an error similar to the following:

    • , , and support generated columns.

    • A column in a table can be built on a PERSISTENT generated column.

      • However, a column in a MERGE table can not be defined as a VIRTUAL and PERSISTENT generated column.

    Data Type Support

    All data types are supported when defining generated columns.

    Using the column option is supported when defining generated columns.

    Using the column option is not supported when defining generated columns.

    Using the column option is supported when defining generated columns.

    It does not work correctly, though. See .

    Index Support

    Using a generated column as a table's primary key is not supported. See for more information. If you try to use one as a primary key, then you will see an error similar to the following:

    Using PERSISTENT generated columns as part of a is supported.

    Referencing PERSISTENT generated columns as part of a is also supported.

    However, using the ON UPDATE CASCADE, ON UPDATE SET NULL, or ON DELETE SET NULL clauses is not supported. If you try to use an unsupported clause, then you will see an error similar to the following:

    Defining indexes on both VIRTUAL and PERSISTENT generated columns is supported.

    If an index is defined on a generated column, then the optimizer considers using it in the same way as indexes based on "real" columns.

    The optimizer can recognize use of indexed virtual column expressions in the WHERE clause and use them to construct range and ref(const) accesses. See .

    The optimizer cannot recognize use of indexed virtual column expressions in the WHERE clause and use them to construct range and ref(const) accesses. See .

    Statement Support

    Generated columns are used in just as if they were "real" columns.

    • However, VIRTUAL and PERSISTENT generated columns differ in how their data is stored.

      • Values for PERSISTENT generated columns are generated whenever a inserts or updates the row with the special DEFAULT value. This generates the columns value, and it is stored in the table like the other "real" columns. This value can be read by other just like the other "real" columns.

    The statement supports generated columns.

    Generated columns can be referenced in the , , and statements.

    • However, VIRTUAL or PERSISTENT generated columns cannot be explicitly set to any other values than NULL or . If a generated column is explicitly set to any other value, then the outcome depends on whether is enabled in . If it is not enabled, then a warning will be raised and the default generated value will be used instead. If it is enabled, then an error will be raised instead.

    The statement has limited support for generated columns.

    • It supports defining generated columns in a new table.

    • It supports using generated columns to .

    • It does not support using the with generated columns.

    The statement has limited support for generated columns.

    • It supports the MODIFY and CHANGE clauses for PERSISTENT generated columns.

    • It does not support the MODIFY clause for VIRTUAL generated columns if is not set to COPY. See for more information.

    The statement supports generated columns.

    The statement can be used to check whether a table has generated columns.

    • You can tell which columns are generated by looking for the ones where the Extra column is set to either VIRTUAL or PERSISTENT. For example:

    Generated columns can be properly referenced in the NEW and OLD rows in .

    support generated columns.

    The statement supports generated columns.

    Expression Support

    Most legal, deterministic expressions which can be calculated are supported in expressions for generated columns.

    Most are supported in expressions for generated columns.

    • However, some can't be supported for technical reasons. For example, If you try to use an unsupported function in an expression, an error is generated similar to the following:

    are not supported in expressions for generated columns because the underlying data can change.

    Using anything that depends on data outside the row is not supported in expressions for generated columns.

    are not supported in expressions for generated columns. See for more information.

    Non-deterministic are supported in expressions for not indexed VIRTUAL generated columns.

    Non-deterministic are not supported in expressions for PERSISTENT or indexed VIRTUAL generated columns.

    are supported in expressions for generated columns.

    • However, MariaDB can't check whether a UDF is deterministic, so it is up to the user to be sure that they do not use non-deterministic UDFs with VIRTUAL generated columns.

    Defining a generated column based on other generated columns defined before it in the table definition is supported. For example:

    However, defining a generated column based on other generated columns defined after in the table definition is not supported in expressions for generation columns because generated columns are calculated in the order they are defined.

    Using an expression that exceeds 255 characters in length is supported in expressions for generated columns. The new limit for the entire table definition, including all expressions for generated columns, is 65,535 bytes.

    Using constant expressions is supported in expressions for generated columns. For example:

    Making Stored Values Consistent

    When a generated column is PERSISTENT or indexed, the value of the expression needs to be consistent regardless of the flags in the current session. If it is not, then the table will be seen as corrupted when the value that should actually be returned by the computed expression and the value that was previously stored and/or indexed using a different setting disagree.

    There are currently two affected classes of inconsistencies: character padding and unsigned subtraction:

    • For a VARCHAR or TEXT generated column the length of the value returned can vary depending on the PAD_CHAR_TO_FULL_LENGTH flag. To make the value consistent, create the generated column using an RTRIM() or RPAD() function. Alternately, create the generated column as a CHAR column so that its data is always fully padded.

    • If a SIGNED generated column is based on the subtraction of an UNSIGNED value, the resulting value can vary depending on how large the value is and the NO_UNSIGNED_SUBTRACTION flag. To make the value consistent, use to ensure that each UNSIGNED

    A fatal error is generated when trying to create a generated column whose value can change depending on the when its data is PERSISTENT or indexed. For an existing generated column that has a potentially inconsistent value, a warning about a bad expression is generated the first time it is used (if warnings are enabled).

    For an existing generated column that has a potentially inconsistent value, a warning about a bad expression is generated the first time it is used (if warnings are enabled).

    A potentially inconsistent generated column outputs a warning when created or first used (without restricting the creation).

    A potentially inconsistent generated column does not output a warning when created or first used.

    Here is an example of two tables that are warned about:

    The warnings look like this:

    To work around the issue, force the padding or type to make the generated column's expression return a consistent value. For example:

    Here is an example of two tables whose creation is rejected:

    MySQL Compatibility Support

    • The STORED keyword is supported as an alias for the PERSISTENT keyword.

    • Tables created with MySQL 5.7 or later that contain can be imported into MariaDB without a dump and restore.

    Implementation Differences

    Generated columns are subject to various constraints in other DBMSs that are not present in MariaDB's implementation. Generated columns may also be called computed columns or virtual columns in different implementations. The various details for a specific implementation can be found in the documentation for each specific DBMS.

    Implementation Differences Compared to Microsoft SQL Server

    MariaDB's generated columns implementation does not enforce the following restrictions that are present in implementation:

    • MariaDB allows in generated column expressions, including those that change dynamically, such as .

    • MariaDB allows the function to be called with a named as an argument, even though time zone names and time offsets are configurable.

    • MariaDB allows the function to be used with non-unicode , even though character sets are configurable and differ between binaries/versions.

    Microsoft SQL Server enforces the above restrictions by doing one of the following things:

    • Refusing to create computed columns.

    • Refusing to allow updates to a table containing them.

    • Refusing to use an index over such a column if it can not be guaranteed that the expression is fully deterministic.

    In MariaDB, as long as the , language, and other settings that were in effect during the CREATE TABLE remain unchanged, the generated column expression will always be evaluated the same. If any of these things change, then please be aware that the generated column expression might not be evaluated the same way as it previously was.

    If you try to update a virtual column, you will get an error if the default is enabled in , or a warning otherwise.

    Development History

    Generated columns was originally developed by Andrey Zhakov. It was then modified by Sanja Byelkin and Igor Babaev at Monty Program for inclusion in MariaDB. Monty did the work on to lift some of the limitations.

    Examples

    Here is an example table that uses both VIRTUAL andPERSISTENT virtual columns:

    If you describe the table, you can easily see which columns are virtual by looking in the "Extra" column:

    To find out what function(s) generate the value of the virtual column you can use SHOW CREATE TABLE:

    If you try to insert non-default values into a virtual column, you will receive a warning and what you tried to insert will be ignored and the derived value inserted instead:

    If the ZEROFILL clause is specified, it should be placed directly after the type definition, before the AS (<expression>):

    You can also use virtual columns to implement a "poor man's partial index". See example at the end of .

    See Also

    • on the mariadb.com blog.

    This page is licensed: CC BY-SA / Gnu FDL

    Galera
    <type>  [GENERATED ALWAYS]  AS   ( <expression> )
    [VIRTUAL | PERSISTENT | STORED]  [UNIQUE] [UNIQUE KEY] [COMMENT <text>]
    Values for VIRTUAL generated columns are not stored in the table. Instead, the value is generated dynamically whenever the column is queried. If other columns in a row are queried, but the VIRTUAL generated column is not one of the queried columns, then the column's value is not generated.

    It does not support the CHANGE clause for VIRTUAL generated columns if ALGORITHM is not set to COPY. See MDEV-17035 for more information.

  • It does not support altering a table if ALGORITHM is not set to COPY if the table has a VIRTUAL generated column that is indexed. See MDEV-14046 for more information.

  • It does not support adding a VIRTUAL generated column with the ADD clause if the same statement is also adding other columns if ALGORITHM is not set to COPY. See MDEV-17468 for more information.

  • It also does not support altering an existing column into a VIRTUAL generated column.

  • It supports using generated columns to partition tables.

  • It does not support using the versioning clauses with generated columns.

  • operand is
    SIGNED
    before the subtraction.
    MariaDB allows
    expressions to be used in generated columns. Microsoft SQL Server considers these expressions to be "imprecise" due to potential cross-platform differences in floating-point implementations and precision.
  • Microsoft SQL Server requires the ARITHABORT mode to be set, so that division by zero returns an error, and not a NULL.

  • Microsoft SQL Server requires QUOTED_IDENTIFIER to be set in sql_mode. In MariaDB, if data is inserted without ANSI_QUOTES set in sql_mode, then it will be processed and stored differently in a generated column that contains quoted identifiers.

  • DML query
    built-in functions
    user-defined functions (UDFs)
    InnoDB
    Aria
    MyISAM
    CONNECT
    MERGE
    ZEROFILL
    AUTO_INCREMENT
    AUTO_INCREMENT
    MDEV-11117
    MDEV-5590
    foreign key
    foreign key
    Virtual Column Support in the Optimizer
    Virtual Column Support in the Optimizer
    DML queries
    DML queries
    DML queries
    SELECT
    INSERT
    UPDATE
    DELETE
    DEFAULT
    strict mode
    sql_mode
    CREATE TABLE
    partition tables
    versioning clauses
    ALTER TABLE
    ALGORITHM
    MDEV-15476
    SHOW CREATE TABLE
    DESCRIBE
    triggers
    Stored procedures
    HANDLER
    built-in functions
    built-in functions
    Subqueries
    Stored functions
    MDEV-17587
    built-in functions
    built-in functions
    User-defined functions (UDFs)
    SQL Mode
    sql_mode
    sql_mode
    sql_mode
    CAST()
    SQL Mode
    MySQL's generated columns
    Microsoft SQL Server's computed columns
    server variables
    warning_count
    CONVERT_TZ()
    time zone
    CAST()
    character sets
    sql_mode
    strict mode
    sql_mode
    Unique Index
    Putting Virtual Columns to good use
    FLOAT
    ERROR 1910 (HY000): TokuDB storage engine does not support computed columns
    ERROR 1903 (HY000): Primary key cannot be defined upon a computed column
    ERROR 1905 (HY000): Cannot define foreign key with ON UPDATE SET NULL clause on a computed column
    DESCRIBE table1;
    +-------+-------------+------+-----+---------+------------+
    | Field | Type        | Null | Key | Default | Extra      |
    +-------+-------------+------+-----+---------+------------+
    | a     | int(11)     | NO   |     | NULL    |            |
    | b     | varchar(32) | YES  |     | NULL    |            |
    | c     | int(11)     | YES  |     | NULL    | VIRTUAL    |
    | d     | varchar(5)  | YES  |     | NULL    | PERSISTENT |
    +-------+-------------+------+-----+---------+------------+
    ERROR 1901 (HY000): Function or expression 'dayname()' cannot be used in the GENERATED ALWAYS AS clause of `v`
    CREATE TABLE t1 (a INT AS (1), b INT AS (a));
    CREATE TABLE t1 (a int as (1));
    CREATE TABLE bad_pad (
      txt CHAR(5),
      -- CHAR -> VARCHAR or CHAR -> TEXT can't be persistent or indexed:
      vtxt VARCHAR(5) AS (txt) PERSISTENT
    );
    
    CREATE TABLE bad_sub (
      num1 BIGINT UNSIGNED,
      num2 BIGINT UNSIGNED,
      -- The resulting value can vary for some large values
      vnum BIGINT AS (num1 - num2) VIRTUAL,
      KEY(vnum)
    );
    Warning (Code 1901): Function or expression '`txt`' cannot be used in the GENERATED ALWAYS AS clause of `vtxt`
    Warning (Code 1105): Expression depends on the @@sql_mode value PAD_CHAR_TO_FULL_LENGTH
    
    Warning (Code 1901): Function or expression '`num1` - `num2`' cannot be used in the GENERATED ALWAYS AS clause of `vnum`
    Warning (Code 1105): Expression depends on the @@sql_mode value NO_UNSIGNED_SUBTRACTION
    CREATE TABLE good_pad (
      txt CHAR(5),
      -- Using RTRIM() or RPAD() makes the value consistent:
      vtxt VARCHAR(5) AS (RTRIM(txt)) PERSISTENT,
      -- When not persistent or indexed, it is OK for the value to vary by mode:
      vtxt2 VARCHAR(5) AS (txt) VIRTUAL,
      -- CHAR -> CHAR is always OK:
      txt2 CHAR(5) AS (txt) PERSISTENT
    );
    
    CREATE TABLE good_sub (
      num1 BIGINT UNSIGNED,
      num2 BIGINT UNSIGNED,
      -- The indexed value will always be consistent in this expression:
      vnum BIGINT AS (CAST(num1 AS SIGNED) - CAST(num2 AS SIGNED)) VIRTUAL,
      KEY(vnum)
    );
    CREATE TABLE bad_pad (
      txt CHAR(5),
      -- CHAR -> VARCHAR or CHAR -> TEXT can't be persistent or indexed:
      vtxt VARCHAR(5) AS (txt) PERSISTENT
    );
    
    CREATE TABLE bad_sub (
      num1 BIGINT UNSIGNED,
      num2 BIGINT UNSIGNED,
      -- The resulting value can vary for some large values
      vnum BIGINT AS (num1 - num2) VIRTUAL,
      KEY(vnum)
    );
    USE TEST;
    
    CREATE TABLE table1 (
         a INT NOT NULL,
         b VARCHAR(32),
         c INT AS (a MOD 10) VIRTUAL,
         d VARCHAR(5) AS (LEFT(b,5)) PERSISTENT);
    DESCRIBE table1;
    +-------+-------------+------+-----+---------+------------+
    | Field | Type        | Null | Key | Default | Extra      |
    +-------+-------------+------+-----+---------+------------+
    | a     | int(11)     | NO   |     | NULL    |            |
    | b     | varchar(32) | YES  |     | NULL    |            |
    | c     | int(11)     | YES  |     | NULL    | VIRTUAL    |
    | d     | varchar(5)  | YES  |     | NULL    | PERSISTENT |
    +-------+-------------+------+-----+---------+------------+
    SHOW CREATE TABLE table1;
    
    | table1 | CREATE TABLE `table1` (
      `a` int(11) NOT NULL,
      `b` varchar(32) DEFAULT NULL,
      `c` int(11) AS (a mod 10) VIRTUAL,
      `d` varchar(5) AS (left(b,5)) PERSISTENT
    ) ENGINE=MyISAM DEFAULT CHARSET=latin1 |
    WARNINGS;
    Show warnings enabled.
    
    INSERT INTO table1 VALUES (1, 'some text',default,default);
    Query OK, 1 row affected (0.00 sec)
    
    INSERT INTO table1 VALUES (2, 'more text',5,default);
    Query OK, 1 row affected, 1 warning (0.00 sec)
    
    Warning (Code 1645): The value specified for computed column 'c' in table 'table1' has been ignored.
    
    INSERT INTO table1 VALUES (123, 'even more text',default,'something');
    Query OK, 1 row affected, 2 warnings (0.00 sec)
    
    Warning (Code 1645): The value specified for computed column 'd' in table 'table1' has been ignored.
    Warning (Code 1265): Data truncated for column 'd' at row 1
    
    SELECT * FROM table1;
    +-----+----------------+------+-------+
    | a   | b              | c    | d     |
    +-----+----------------+------+-------+
    |   1 | some text      |    1 | some  |
    |   2 | more text      |    2 | more  |
    | 123 | even more text |    3 | even  |
    +-----+----------------+------+-------+
    3 rows in set (0.00 sec)
    CREATE TABLE table2 (a INT, b INT ZEROFILL AS (a*2) VIRTUAL);
    INSERT INTO table2 (a) VALUES (1);
    
    SELECT * FROM table2;
    +------+------------+
    | a    | b          |
    +------+------------+
    |    1 | 0000000002 |
    +------+------------+
    1 row in set (0.00 sec)

    ALTER TABLE

    Modify table structures. This guide covers adding columns, changing data types, managing indexes, and other schema changes for existing tables.

    Syntax

    In the syntax, these options are the same as for the CREATE TABLE statement:

    • table_option

    • column_definition

    • partition_options

    • partition_definition

    Description

    ALTER TABLE enables you to change the structure of an existing table. For example, you can add or delete columns, create or destroy indexes, change the type of existing columns, or rename columns or the table itself. You can also change the comment for the table and the storage engine of the table.

    If another connection is using the table, a is active, and this statement will wait until the lock is released. This is also true for non-transactional tables.

    When adding a UNIQUE index on a column (or a set of columns) which have duplicated values, an error will be produced and the statement will be stopped. To suppress the error and force the creation of UNIQUE indexes, discarding duplicates, the option can be specified. This can be useful if a column (or a set of columns) should be UNIQUE but it contains duplicate values; however, this technique provides no control on which rows are preserved and which are deleted. Also, note that IGNORE is accepted but ignored in ALTER TABLE ... EXCHANGE PARTITION statements.

    This statement can also be used to rename a table. For details see .

    When an index is created, the storage engine may use a configurable buffer in the process. Incrementing the buffer speeds up the index creation. and allocate a buffer whose size is defined by or , also used for . allocates three buffers whose size is defined by .

    Privileges

    Executing the ALTER TABLE statement generally requires at least the privilege for the table or the database. If you are renaming a table, this also requires the , and privileges for the table or the database.

    Online DDL

    Online DDL is supported with the and clauses.

    See for more information on online DDL with .

    ALTER ONLINE TABLE

    ALTER ONLINE TABLE also works for partitioned tables.

    Online ALTER TABLE is available by executing the following:

    See the alter specification for more information.

    WAIT/NOWAIT

    Set the lock wait timeout. See .

    IF EXISTS

    The IF EXISTS and IF NOT EXISTS clauses are available for the following clauses:

    When IF EXISTS and IF NOT EXISTS are used in clauses, queries will not report errors when the condition is triggered for that clause. A warning with the same message text will be issued and the ALTER will move on to the next clause in the statement (or end if finished).

    If this is directive is used after ALTER ... TABLE, you don't get an error if the table doesn't exist. Example:

    Column Definitions

    See for information about column definitions.

    Index Definitions

    See for information about index definitions.

    The and statements can also be used to add or remove an index.

    Character Sets and Collations

    See for details on setting the .

    Alter Specifications

    Table Options

    See for information about table options.

    ADD COLUMN

    Adds a column to the table. The syntax is the same as in . If you are using IF NOT_EXISTS the column will not be added if it was not there already. This is very useful when doing scripts to modify tables.

    The FIRST and AFTER clauses affect the physical order of columns in the datafile. Use FIRST to add a column in the first (leftmost) position, or AFTER followed by a column name to add the new column in any other position. Note that, nowadays, the physical position of a column is usually irrelevant.

    See also .

    DROP COLUMN

    Drops the column from the table. If you are using IF EXISTS you will not get an error if the column didn't exist. If the column is part of any index, the column will be dropped from them, except if you add a new column with identical name at the same time. The index will be dropped if all columns from the index were dropped. If the column was used in a view or trigger, you will get an error next time the view or trigger is accessed. Dropping a column that is part of a multi-column UNIQUE constraint is not permitted. For example:

    The reason is that dropping column a would result in the new constraint that all values in column b be unique. In order to drop the column, an explicit DROP PRIMARY KEY and ADD PRIMARY KEY would be required.

    MariaDB supports instant DROP COLUMN. DROP COLUMN of an indexed column would imply (and in the case of a non-UNIQUE multi-column index, possibly ADD INDEX). These will not be allowed with , but unlike prior versions, they can be allowed with

    RESTRICT and CASCADE are allowed to make porting from other database systems easier. In MariaDB, they do nothing.

    MODIFY COLUMN

    Allows you to modify the type of a column. The column will be at the same place as the original column and all indexes on the column will be kept. Note that when modifying column, you should specify all attributes for the new column.

    CHANGE COLUMN

    Works like MODIFY COLUMN except that you can also change the name of the column. The column will be at the same place as the original column and all index on the column will be kept.

    ALTER COLUMN

    This lets you change column options.

    RENAME INDEX/KEY

    {% tabs %} {% tab title="Current" %} You can rename an index using the RENAME INDEX (or RENAME KEY) syntax, for example:

    {% endtab %}

    {% tab title="< 10.5.3" %} RENAME INDEX/KEY is not available. {% endtab %} {% endtabs %}

    RENAME COLUMN

    {% tabs %} {% tab title="Current" %} You can rename a column using the RENAME COLUMN syntax, for example:

    {% endtab %}

    {% tab title="< 10.5.3" %} RENAME COLUMN is not available. {% endtab %} {% endtabs %}

    ADD PRIMARY KEY

    Adds a primary key. For PRIMARY KEY indexes, you can specify a name for the index, but it is silently ignored, and the name of the index is always PRIMARY. See for more information.

    DROP PRIMARY KEY

    Drops a primary key. For PRIMARY KEY indexes, you can specify a name for the index, but it is silently ignored, and the name of the index is always PRIMARY. See for more information.

    ADD FOREIGN KEY

    Adds a foreign key. For FOREIGN KEY indexes, a reference definition must be provided. For FOREIGN KEY indexes, you can specify a name for the constraint, using the CONSTRAINT keyword. That name will be used in error messages.

    First, you have to specify the name of the target (parent) table and a column or a column list which must be indexed and whose values must match to the foreign key's values. The MATCH clause is accepted to improve the compatibility with other DBMS's, but has no meaning in MariaDB. The ON DELETE and ON UPDATE clauses specify what must be done when a DELETE (or a REPLACE) statements attempts to delete a referenced row from the parent table, and when an UPDATE statement attempts to modify the referenced foreign key columns in a parent table row, respectively. The following options are allowed:

    • RESTRICT: The delete/update operation is not performed. The statement terminates with a 1451 error (SQLSTATE '2300').

    • NO ACTION: Synonym for RESTRICT.

    • CASCADE: The delete/update operation is performed in both tables.

    If either clause is omitted, the default behavior for the omitted clause is RESTRICT.

    See for more information.

    DROP FOREIGN KEY

    Drops a foreign key. See for more information.

    ADD INDEX

    Adds a plain index. Plain indexes are regular indexes that are not unique, and are not acting as a primary key or a foreign key. They are also not the "specialized" FULLTEXT or SPATIAL indexes. For limits on InnoDB indexes, see . See for more information.

    DROP INDEX

    Drops a plain index. Plain indexes are regular indexes that are not unique, and are not acting as a primary key or a foreign key. They are also not the "specialized" FULLTEXT or SPATIAL indexes. See for more information.

    ADD UNIQUE INDEX

    Adds a unique index. The UNIQUE keyword means that the index will not accept duplicated values, except for NULLs. An error will raise if you try to insert duplicate values in a UNIQUE index. For UNIQUE indexes, you can specify a name for the constraint, using the CONSTRAINT keyword. That name will be used in error messages. See for more information.

    DROP UNIQUE INDEX

    Drops a unique index. The UNIQUE keyword means that the index will not accept duplicated values, except for NULLs. An error will raise if you try to insert duplicate values in a UNIQUE index. For UNIQUE indexes, you can specify a name for the constraint, using the CONSTRAINT keyword. That name will be used in error messages. See for more information.

    ADD FULLTEXT INDEX

    Adds a FULLTEXT index. See for more information.

    DROP FULLTEXT INDEX

    Drops a FULLTEXT index. See for more information.

    ADD SPATIAL INDEX

    Adds a SPATIAL index. See for more information.

    DROP SPATIAL INDEX

    Drops a SPATIAL index. See for more information.

    ENABLE/ DISABLE KEYS

    DISABLE KEYS disables all non unique keys for the table for storage engines that support this (at least MyISAM and Aria). This can be used to into empty tables. ENABLE KEYS enables all disabled keys.

    RENAME TO

    Renames a table. See also .

    ADD CONSTRAINT

    Modifies the table adding a on a particular column or columns.

    Before a row is inserted or updated, all constraints are evaluated in the order they are defined. If any constraint fails, then the row will not be updated. One can use most deterministic functions in a constraint, including .

    The constraint_name is optional. If you don't provide one in the ALTER TABLE statement, MariaDB auto-generates a name for you. This is done so that you can remove it later using clause.

    You can disable all constraint expression checks by setting the variable to OFF. You may find this useful when loading a table that violates some constraints that you want to later find and fix in SQL.

    To view constraints on a table, query :

    DROP CONSTRAINT

    DROP CONSTRAINT for UNIQUE and FOREIGN KEY and DROP CONSTRAINT for CHECK constraints were introduced in an earlier version of MariaDB.

    Modifies the table, removing the given constraint.

    When you add a constraint to a table, whether through a or statement, you can either set a constraint_name yourself, or allow MariaDB to auto-generate one for you. To view constraints on a table, query . For instance,

    To remove a constraint from the table, issue an ALTER TABLE...DROP CONSTRAINT statement. For example:

    ADD SYSTEM VERSIONING

    Adds system versioning. See .

    DROP SYSTEM VERSIONING

    Drops system versioning. See .

    ADD PERIOD FOR

    See , or .

    FORCE

    ALTER TABLE ... FORCE forces MariaDB to rebuild the table.

    With InnoDB, the table rebuild only reclaims unused space (i.e. the space previously used for deleted rows) if the system variable is set to ON (the default). If the system variable is OFF, the space will not be reclaimed, but it will be re-used for new data that's later added.

    The rebuild may fail if conditions are violated due to a change in the . For example:

    Partitions

    ADD PARTITION

    See for details.

    ANALYZE PARTITION

    See for details.

    CHECK PARTITION

    See for details.

    COALESCE PARTITION

    Reduces the number of HASH or KEY partitions in a table. See .

    CONVERT PARTITION / TABLE

    {% tabs %} {% tab title="Current" %} CONVERT PARTITION can be used to remove a partition from a table and make this an ordinary table. For example:

    CONVERT TABLE will take an existing table and move this to another table as its own partition with a specified . For example the following moves normal_table to a partition of partitioned_table with a definition that its values, based on the PARTITION BY of the partitioned_table, are less than 12345.

    The optional [{WITH | WITHOUT} VALIDATION] is permitted.

    See for more details. {% endtab %}

    {% tab title="< 11.4" %} CONVERT PARTITION can be used to remove a partition from a table and make this an ordinary table. For example:

    CONVERT TABLE will take an existing table and move this to another table as its own partition with a specified . For example the following moves normal_table to a partition of partitioned_table with a definition that its values, based on the PARTITION BY of the partitioned_table, are less than 12345.

    The optional clause [{WITH | WITHOUT} VALIDATION] is not available.

    See for more details. {% endtab %}

    {% tab title="< 10.7.1" %} CONVERT PARTITION and CONVERT TABLE are not available. {% endtab %} {% endtabs %}

    DROP PARTITION

    Used to drop specific partitions (and discard all data within the specified partitions) for and partitions. See .

    EXCHANGE PARTITION

    {% tabs %} {% tab title="Current" %} This clause is used to exchange the contents of a partition with another table. This is performed by swapping the tablespaces of the partition with the other table.

    The optional [{WITH | WITHOUT} VALIDATION] is permitted.

    See for more details.

    See also . {% endtab %}

    {% tab title="< 11.4" %} This clause is used to exchange the contents of a partition with another table. This is performed by swapping the tablespaces of the partition with the other table.

    The optional [{WITH | WITHOUT} VALIDATION] is not permitted.

    See for more details.

    See also . {% endtab %} {% endtabs %}

    OPTIMIZE PARTITION

    See for details.

    REMOVE PARTITIONING

    See .

    REORGANIZE PARTITION

    See .

    TRUNCATE PARTITION

    See .

    DISCARD TABLESPACE

    This is used to discard an InnoDB table's tablespace.

    See for more information.

    IMPORT TABLESPACE

    This is used to import an InnoDB table's tablespace. The tablespace should have been copied from its original server after executing .

    See for more information.

    ALTER TABLE ... IMPORT only applies to InnoDB tables. Most other popular storage engines, such as Aria and MyISAM, will recognize their data files as soon as they've been placed in the proper directory under the datadir, and no special DDL is required to import them.

    ALGORITHM

    The ALTER TABLE statement supports the ALGORITHM clause. This clause is one of the clauses that is used to implement online DDL. ALTER TABLE supports several different algorithms. An algorithm can be explicitly chosen for an ALTER TABLE operation by setting the ALGORITHM clause. The supported values are:

    • ALGORITHM=DEFAULT - This implies the default behavior for the specific statement, such as if no ALGORITHM clause is specified.

    • ALGORITHM=COPY

    • ALGORITHM=INPLACE

    See for information on how the ALGORITHM clause affects InnoDB.

    ALGORITHM=DEFAULT

    The default behavior, which occurs if ALGORITHM=DEFAULT is specified, or if ALGORITHM is not specified at all, usually only makes a copy if the operation doesn't support being done in-place at all. In this case, the most efficient available algorithm will usually be used.

    The system variable is deprecated. Instead, the system variable defines the default algorithm for ALTER TABLE operations. This was removed in for the following reasons:

    • alter_algorithm was introduced as a replacement for the old_alter_table that was used to force the usage of the original alter table algorithm (copy) in cases where the new alter algorithm did not work. The new option was added as a way to force the usage of a specific algorithm when it should instead have made it possible to disable algorithms that would not work for some reason.

    • alter_algorithm introduced some cases where ALTER TABLE would not work without specifying the ALGORITHM=XXX option together with ALTER TABLE.

    • Having different values of alter_algorithm on the primary and replica could cause replicas to stop unexpectedly.

    ALGORITHM=COPY

    ALGORITHM=COPY is the name for the original algorithm from early MariaDB versions.

    When ALGORITHM=COPY is set, MariaDB essentially does the following operations:

    This algorithm is very inefficient, but it is generic, so it works for all storage engines.

    If ALGORITHM=COPY is specified, then the copy algorithm will be used even if it is not necessary. This can result in a lengthy table copy. If multiple operations are required that each require the table to be rebuilt, then it is best to specify all operations in a single statement, so that the table is only rebuilt once.

    {% tabs %} {% tab title="Current" %} ALTER TABLE can perform most operations with ALGORITHM=COPY, LOCK=NONE. See . {% endtab %}

    {% tab title="< 11.2" %} ALTER TABLE cannot perform operations with ALGORITHM=COPY, LOCK=NONE. {% endtab %} {% endtabs %}

    ALGORITHM=INPLACE

    ALGORITHM=COPY can be incredibly slow, because the whole table has to be copied and rebuilt. ALGORITHM=INPLACE was introduced as a way to avoid this by performing operations in-place and avoiding the table copy and rebuild, when possible.

    When ALGORITHM=INPLACE is set, the underlying storage engine uses optimizations to perform the operation while avoiding the table copy and rebuild. However, INPLACE is a bit of a misnomer, since some operations may still require the table to be rebuilt for some storage engines. Regardless, several operations can be performed without a full copy of the table for some storage engines.

    A more accurate name would have been ALGORITHM=ENGINE, where ENGINE refers to an "engine-specific" algorithm.

    If an operation supports ALGORITHM=INPLACE, then it can be performed using optimizations by the underlying storage engine, but it may rebuilt.

    See for more.

    ALGORITHM=NOCOPY

    ALGORITHM=INPLACE can sometimes be surprisingly slow in instances where it has to rebuild the clustered index, because when the clustered index has to be rebuilt, the whole table has to be rebuilt. ALGORITHM=NOCOPY was introduced as a way to avoid this.

    If an ALTER TABLE operation supports ALGORITHM=NOCOPY, then it can be performed without rebuilding the clustered index.

    If ALGORITHM=NOCOPY is specified for an ALTER TABLE operation that does not support ALGORITHM=NOCOPY, then an error will be raised. In this case, raising an error is preferable, if the alternative is for the operation to rebuild the clustered index, and perform unexpectedly slowly.

    See for more.

    ALGORITHM=INSTANT

    ALGORITHM=INPLACE can sometimes be surprisingly slow in instances where it has to modify data files. ALGORITHM=INSTANT was introduced as a way to avoid this.

    If an ALTER TABLE operation supports ALGORITHM=INSTANT, then it can be performed without modifying any data files.

    If ALGORITHM=INSTANT is specified for an ALTER TABLE operation that does not support ALGORITHM=INSTANT, then an error will be raised. In this case, raising an error is preferable, if the alternative is for the operation to modify data files, and perform unexpectedly slowly.

    See for more.

    LOCK

    The ALTER TABLE statement supports the LOCK clause. This clause is one of the clauses that is used to implement online DDL. ALTER TABLE supports several different locking strategies. A locking strategy can be explicitly chosen for an ALTER TABLE operation by setting the LOCK clause. The supported values are:

    DEFAULT

    Acquire the least restrictive lock on the table that is supported for the specific operation. Permit the maximum amount of concurrency that is supported for the specific operation.

    NONE

    Acquire no lock on the table. Permit all concurrent DML. If this locking strategy is not permitted for an operation, then an error is raised. From , ALTER TABLE can do most operations with ALGORITHM=COPY, LOCK=NONE, that is, in most cases, unless the algorithm and lock level are explicitly specified, ALTER TABLE will be performed using the COPY algorithm while simultaneously allowing concurrent DML statements on the altered table. If this is not desired, one can explicitly specify a different lock level or set old_mode to that will make ALGORITHM=COPY use LOCK=SHARED by default (but still allowing LOCK=NONE to be specified explicitly).

    SHARED

    Acquire a read lock on the table. Permit read-only concurrent DML. If this locking strategy is not permitted for an operation, then an error is raised.

    EXCLUSIVE

    Acquire a write lock on the table. Do not permit concurrent DML.

    Different storage engines support different locking strategies for different operations. If a specific locking strategy is chosen for an ALTER TABLE operation, and that table's storage engine does not support that locking strategy for that specific operation, then an error will be raised.

    If the LOCK clause is not explicitly set, then the operation uses LOCK=DEFAULT.

    is equivalent to LOCK=NONE. Therefore, the statement can be used to ensure that your ALTER TABLE operation allows all concurrent DML.

    See for information on how the LOCK clause affects InnoDB.

    Index Options

    See page for meaning of the index options.

    Progress Reporting

    MariaDB provides progress reporting for ALTER TABLE statement for clients that support the new progress reporting protocol. For example, if you were using the client, then the progress report might look like this::

    The progress report is also shown in the output of the statement and in the contents of the table.

    See for more information.

    Aborting ALTER TABLE Operations

    If an ALTER TABLE operation is being performed and the connection is killed, the changes will be rolled back in a controlled manner. The rollback can be a slow operation as the time it takes is relative to how far the operation has progressed.

    Aborting ALTER TABLE ... ALGORITHM=COPY was made faster by removing excessive undo logging (). This significantly shortened the time it takes to abort a running ALTER TABLE operation, compared with earlier releases.

    Atomic ALTER TABLE

    {% tabs %} {% tab title="Current" %} ALTER TABLE is atomic for most engines, including InnoDB, MyRocks, MyISAM and Aria (). This means that if there is a crash (server down or power outage) during an ALTER TABLE operation, after recovery, either the old table and associated triggers and status will be intact, or the new table will be active. In older MariaDB versions one could get leftover #sql-alter..', '#sql-backup..' or 'table_name.frm˝' files if the system crashed during the ALTER TABLE operation.

    See for more information. {% endtab %}

    {% tab title="< 10.6.1" %} Atomic ALTER TABLE is not available. {% endtab %} {% endtabs %}

    Replication

    {% tabs %} {% tab title="Current" %} ALTER TABLE got fully executed on the primary first, and only then was it replicated and started executing on replicas. was added to replicate sooner and begin executing on replicas, directly when it starts executing on the primary, not when it finishes. This way the replication lag caused by a heavy ALTER TABLE can be completely eliminated (). {% endtab %}

    {% tab title="< 10.8.1" %} The option is not available. {% endtab %} {% endtabs %}

    Examples

    Adding a new column:

    Dropping a column:

    Modifying the type of a column:

    Changing the name and type of a column:

    Combining multiple clauses in a single ALTER TABLE statement, separated by commas:

    Changing the storage engine and adding a comment:

    Rebuilding the table (the previous example will also rebuild the table if it was already InnoDB):

    Dropping an index:

    Adding a unique index:

    Adding a primary key for an with a constraint:

    {% tabs %} {% tab title="Current" %} An ALTER query can be replicated faster with this statement, which must be run before the ALTER statement:

    Binlog would contain two event groups, of which the first one gets delivered to replicas before ALTER is taken to actual execution on the primary:

    {% endtab %}

    {% tab title="< 10.8.1" %} This statement is not available:

    See Also

    This page is licensed: GPLv2, originally from

    SET NULL: The update or delete goes ahead in the parent table, and the corresponding foreign key fields in the child table are set to NULL. (They must not be defined as NOT NULL for this to succeed).

  • SET DEFAULT: This option is implemented only for the legacy PBXT storage engine, which is disabled by default and no longer maintained. It sets the child table's foreign key fields to their DEFAULT values when the referenced parent table key entries are updated or deleted.

  • ALGORITHM=NOCOPY

  • ALGORITHM=INSTANT

  • ALTER TABLE FORCE, as used by mariadb-upgrade, would not always work if alter_algorithm was set for the server.
  • As part of MDEV-33449 "improving repair of tables" it became clear that alter-algorithm made it harder to provide a better and more consistent ALTER TABLE FORCE and REPAIR TABLE, and it would be better to remove it.

  • Instant ADD COLUMN for InnoDB
    metadata lock
    IGNORE
    RENAME TABLE
    Aria
    MyISAM
    aria_sort_buffer_size
    myisam_sort_buffer_size
    REPAIR TABLE
    InnoDB
    innodb_sort_buffer_size
    ALTER
    DROP
    CREATE
    INSERT
    ALGORITHM
    LOCK
    InnoDB Online DDL Overview
    InnoDB
    LOCK
    WAIT and NOWAIT
    CREATE TABLE: Column Definitions
    CREATE TABLE: Index Definitions
    CREATE INDEX
    DROP INDEX
    Setting Character Sets and Collations
    character sets and collations
    CREATE TABLE: Table Options
    CREATE TABLE
    Instant ADD COLUMN for InnoDB
    DROP INDEX
    ALGORITHM=INSTANT
    ALGORITHM=NOCOPY
    Getting Started with Indexes: Primary Key
    Getting Started with Indexes: Primary Key
    Foreign Keys
    Foreign Keys
    InnoDB Limitations
    Getting Started with Indexes: Plain Indexes
    Getting Started with Indexes: Plain Indexes
    Getting Started with Indexes: Unique Index
    Getting Started with Indexes: Unique Index
    Full-Text Indexes
    Full-Text Indexes
    SPATIAL INDEX
    SPATIAL INDEX
    speed up inserts
    RENAME TABLE
    constraint
    UDF's
    DROP CONSTRAINT
    check_constraint_checks
    information_schema.TABLE_CONSTRAINTS
    constraints
    CREATE TABLE
    ALTER TABLE...ADD CONSTRAINT
    information_schema.TABLE_CONSTRAINTS
    System-versioned tables
    System-versioned tables
    System-versioned tables
    Application-time-period tables
    Bitemporal Tables
    innodb_file_per_table
    sql_mode
    Partitioning Overview: Adding Partitions
    Partitioning Overview: Analyzing Partitions
    Partitioning Overview: Checking Partitions
    Partitioning Overview: Coalescing Partitions
    partition definition
    Partitioning Overview: Converting Partitions to/from Tables
    partition definition
    Partitioning Overview: Converting Partitions to/from Tables
    RANGE
    LIST
    Partitioning Overview: Dropping Partitions
    Partitioning Overview: Exchanging Partitions
    copying InnoDB's transportable tablespaces
    Partitioning Overview: Exchanging Partitions
    copying InnoDB's transportable tablespaces
    Partitioning Overview: Optimizing Partitions
    Partitioning Overview: Removing Partitioning
    Partitioning Overview: Reorganizing Partitions
    Partitioning Overview: Truncating Partitions
    copying InnoDB's transportable tablespaces
    FLUSH TABLES FOR EXPORT
    copying InnoDB's transportable tablespaces
    InnoDB Online DDL Overview: ALGORITHM
    old_alter_table
    alter_algorithm
    ALTER TABLE
    ALTER TABLE
    ALTER TABLE
    LOCK=NONE
    ALTER TABLE
    InnoDB Online DDL Operations with ALGORITHM=INPLACE
    InnoDB Online DDL Operations with ALGORITHM=NOCOPY
    InnoDB Online DDL Operations with ALGORITHM=INSTANT
    LOCK_ALTER_TABLE_COPY
    ALTER ONLINE TABLE
    ALTER ONLINE TABLE
    InnoDB Online DDL Overview: LOCK
    CREATE TABLE
    mariadb
    SHOW PROCESSLIST
    information_schema.PROCESSLIST
    Progress Reporting
    MDEV-11415
    MDEV-25180
    Atomic DDL
    An option
    MDEV-11675
    binlog_alter_two_phase
    application-time period table
    WITHOUT OVERLAPS
    CREATE TABLE
    DROP TABLE
    Character Sets and Collations
    SHOW CREATE TABLE
    fill_help_tables.sql
    ALTER [ONLINE] [IGNORE] TABLE [IF EXISTS] tbl_name
        [WAIT n | NOWAIT]
        alter_specification [, alter_specification] ...
    
    alter_specification:
        table_option ...
      | ADD [COLUMN] [IF NOT EXISTS] col_name column_definition
            [FIRST | AFTER col_name ]
      | ADD [COLUMN] [IF NOT EXISTS] (col_name column_definition, ...)
      | ADD {INDEX|KEY} [IF NOT EXISTS] [index_name]
            [index_type] (index_col_name,...) [index_option] ...
      | ADD [CONSTRAINT [symbol]] PRIMARY KEY [IF NOT EXISTS]
            [index_type] (index_col_name,...) [index_option] ...
      | ADD [CONSTRAINT [symbol]]
            UNIQUE [INDEX|KEY] [IF NOT EXISTS] [index_name]
            [index_type] (index_col_name,...) [index_option] ...
      | ADD FULLTEXT [INDEX|KEY] [IF NOT EXISTS [index_name]
            (index_col_name,...) [index_option] ...
      | ADD SPATIAL [INDEX|KEY] [IF NOT EXISTS [index_name]
            (index_col_name,...) [index_option] ...
      | ADD VECTOR [INDEX|KEY] [IF NOT EXISTS [index_name]
            (index_col_name,...) [index_option] ...
      | ADD [CONSTRAINT [symbol]]
            FOREIGN KEY [IF NOT EXISTS] [index_name] (index_col_name,...)
            reference_definition
      | ADD PERIOD FOR [time_period_name|SYSTEM_TIME] (start_column_name, end_column_name)
      | ALTER [COLUMN] col_name SET DEFAULT literal | (expression)
      | ALTER [COLUMN] col_name DROP DEFAULT
      | ALTER {INDEX|KEY} [IF EXISTS] index_name [NOT] IGNORED
      | CHANGE [COLUMN] [IF EXISTS] old_col_name new_col_name column_definition
            [FIRST|AFTER col_name]
      | MODIFY [COLUMN] [IF EXISTS] col_name column_definition
            [FIRST | AFTER col_name]
      | DROP [COLUMN] [IF EXISTS] col_name [RESTRICT|CASCADE]
      | DROP [CONSTRAINT] PRIMARY KEY
      | DROP {INDEX|KEY} [IF EXISTS] index_name
      | DROP FOREIGN KEY [IF EXISTS] fk_symbol
      | DROP CONSTRAINT [IF EXISTS] constraint_name
      | DISABLE KEYS
      | ENABLE KEYS
      | RENAME [TO] new_tbl_name
      | ORDER BY col_name [, col_name] ...
      | RENAME COLUMN [IF EXISTS] old_col_name TO new_col_name
      | RENAME {INDEX|KEY} old_index_name TO new_index_name
      | CONVERT TO CHARACTER SET charset_name [COLLATE collation_name]
      | [DEFAULT] CHARACTER SET [=] charset_name
      | [DEFAULT] COLLATE [=] collation_name
      | DISCARD TABLESPACE
      | IMPORT TABLESPACE
      | ALGORITHM [=] {DEFAULT|INPLACE|COPY|NOCOPY|INSTANT}
      | LOCK [=] {DEFAULT|NONE|SHARED|EXCLUSIVE}
      | FORCE
      | partition_options
      | CONVERT TABLE normal_table TO partition_definition [{WITH | WITHOUT} VALIDATION]
      | CONVERT PARTITION partition_name TO TABLE tbl_name
      | ADD PARTITION [IF NOT EXISTS] (partition_definition)
      | DROP PARTITION [IF EXISTS] partition_names
      | TRUNCATE PARTITION partition_names
      | COALESCE PARTITION number
      | REORGANIZE PARTITION [partition_names INTO (partition_definitions)]
      | ANALYZE PARTITION partition_names
      | CHECK PARTITION partition_names
      | OPTIMIZE PARTITION partition_names
      | REBUILD PARTITION partition_names
      | REPAIR PARTITION partition_names
      | EXCHANGE PARTITION partition_name WITH TABLE tbl_name [{WITH | WITHOUT} VALIDATION]
      | REMOVE PARTITIONING
      | ADD SYSTEM VERSIONING
      | DROP SYSTEM VERSIONING
    
    index_col_name:
        col_name [(length)] [ASC | DESC]
    
    index_type:
        USING {BTREE | HASH | RTREE}
    
    index_option:
      [ KEY_BLOCK_SIZE [=] value
      | index_type
      | WITH PARSER parser_name
      | VISIBLE
      | COMMENT 'string'
      | CLUSTERING={YES| NO} ]
      [ IGNORED | NOT IGNORED ]
    
      table_option [[,] table_option] ...
    
    ALTER ONLINE TABLE ...;
    </code></pre>
    
    This statement is equivalent to the following:
    
    ```sql
    ALTER TABLE ... LOCK=NONE;
    ADD COLUMN       [IF NOT EXISTS]
    ADD INDEX        [IF NOT EXISTS]
    ADD FOREIGN KEY  [IF NOT EXISTS]
    ADD PARTITION    [IF NOT EXISTS]
    CREATE INDEX     [IF NOT EXISTS]
    DROP COLUMN      [IF EXISTS]
    DROP INDEX       [IF EXISTS]
    DROP FOREIGN KEY [IF EXISTS]
    DROP PARTITION   [IF EXISTS]
    CHANGE COLUMN    [IF EXISTS]
    MODIFY COLUMN    [IF EXISTS]
    DROP INDEX       [IF EXISTS]
    CREATE TABLE t (i INT);
    ALTER TABLE IF EXISTS t RENAME COLUMN IF EXISTS i TO k;
    CONVERT TO CHARACTER SET charset_name [COLLATE collation_name]
    [DEFAULT] CHARACTER SET [=] charset_name
    [DEFAULT] COLLATE [=] collation_name
    ... ADD COLUMN [IF NOT EXISTS]  (col_name [column_definition](../create/create-table.md#column-definitions),...)
    ... DROP COLUMN [IF EXISTS] col_name [CASCADE|RESTRICT]
    CREATE TABLE a (
      a int,
      b int,
      primary key (a,b)
    );
    
    ALTER TABLE x DROP COLUMN a;
    [42000][1072] Key column 'A' doesn't exist in table
    CREATE TABLE t1 (a INT UNSIGNED AUTO_INCREMENT, PRIMARY KEY((a));
    ALTER TABLE t1 MODIFY a BIGINT UNSIGNED AUTO_INCREMENT;
    CREATE TABLE t1 (a INT UNSIGNED AUTO_INCREMENT, PRIMARY KEY(a));
    ALTER TABLE t1 CHANGE a b BIGINT UNSIGNED AUTO_INCREMENT;
    CREATE TABLE t1 (a INT UNSIGNED AUTO_INCREMENT, b varchar(50), PRIMARY KEY(a));
    ALTER TABLE t1 ALTER b SET DEFAULT 'hello';
    ALTER TABLE t1 RENAME INDEX i_old TO i_new;
    ALTER TABLE t1 RENAME COLUMN c_old TO c_new;
    ALTER TABLE table_name 
    ADD CONSTRAINT [constraint_name] CHECK(expression);
    CREATE TABLE account_ledger (
    	id INT PRIMARY KEY AUTO_INCREMENT,
    	transaction_name VARCHAR(100),
    	credit_account VARCHAR(100),
    	credit_amount INT,
    	debit_account VARCHAR(100),
    	debit_amount INT);
    
    ALTER TABLE account_ledger 
    ADD CONSTRAINT is_balanced 
        CHECK((debit_amount + credit_amount) = 0);
    SELECT CONSTRAINT_NAME, TABLE_NAME, CONSTRAINT_TYPE 
    FROM information_schema.TABLE_CONSTRAINTS
    WHERE TABLE_NAME = 'account_ledger';
    
    +-----------------+----------------+-----------------+
    | CONSTRAINT_NAME | TABLE_NAME     | CONSTRAINT_TYPE |
    +-----------------+----------------+-----------------+
    | is_balanced     | account_ledger | CHECK           |
    +-----------------+----------------+-----------------+
    ALTER TABLE table_name
    DROP CONSTRAINT constraint_name;
    CREATE TABLE t (
       a INT,
       b INT,
       c INT,
       CONSTRAINT CHECK(a > b),
       CONSTRAINT check_equals CHECK(a = c)); 
    
    SELECT CONSTRAINT_NAME, TABLE_NAME, CONSTRAINT_TYPE 
    FROM information_schema.TABLE_CONSTRAINTS
    WHERE TABLE_NAME = 't';
    
    +-----------------+----------------+-----------------+
    | CONSTRAINT_NAME | TABLE_NAME     | CONSTRAINT_TYPE |
    +-----------------+----------------+-----------------+
    | check_equals    | t              | CHECK           |
    | CONSTRAINT_1    | t              | CHECK           |
    +-----------------+----------------+-----------------+
    ALTER TABLE t DROP CONSTRAINT is_unique;
    ALTER TABLE tab_name FORCE;
    CREATE OR REPLACE TABLE x (d DATE DEFAULT '0000-00-00');
    
    SET SQL_MODE='NO_ZERO_DATE';
    
    ALTER TABLE x FORCE;
    ERROR 1067 (42000): Invalid default value for 'd'
    ALTER TABLE partitioned_table CONVERT PARTITION part1 TO TABLE normal_table;
    ALTER TABLE partitioned_table CONVERT TABLE normal_table 
      TO PARTITION part1 VALUES LESS THAN (12345);
    ALTER TABLE partitioned_table CONVERT PARTITION part1 TO TABLE normal_table;
    ALTER TABLE partitioned_table CONVERT TABLE normal_table 
      TO PARTITION part1 VALUES LESS THAN (12345);
    -- Create a temporary table with the new definition
    CREATE TEMPORARY TABLE tmp_tab (
    ...
    );
    
    -- Copy the data from the original table
    INSERT INTO tmp_tab
       SELECT * FROM original_tab;
    
    -- Drop the original table
    DROP TABLE original_tab;
    
    -- Rename the temporary table, so that it replaces the original one
    RENAME TABLE tmp_tab TO original_tab;
    ALTER TABLE test ENGINE=Aria;
    Stage: 1 of 2 'copy to tmp table'    46% of stage
    ALTER TABLE t1 ADD x INT;
    ALTER TABLE t1 DROP x;
    ALTER TABLE t1 MODIFY x bigint unsigned;
    ALTER TABLE t1 CHANGE a b bigint unsigned auto_increment;
    ALTER TABLE t1 DROP x, ADD x2 INT,  CHANGE y y2 INT;
    ALTER TABLE t1 
      ENGINE = InnoDB 
      COMMENT = 'First of three tables containing usage info';
    ALTER TABLE t1 FORCE;
    ALTER TABLE rooms DROP INDEX u;
    ALTER TABLE rooms ADD UNIQUE INDEX u(room_number);
    ALTER TABLE rooms ADD PRIMARY KEY(room_number, p WITHOUT OVERLAPS);
    SET @@SESSION.binlog_alter_two_phase = TRUE;
    | master-bin.000001 | 495 | Gtid              |         1 |         537 | GTID 0-1-2 START ALTER                                        |
    | master-bin.000001 | 537 | Query             |         1 |         655 | use `test`; alter table t add column b int, algorithm=inplace |
    | master-bin.000001 | 655 | Gtid              |         1 |         700 | GTID 0-1-3 COMMIT ALTER id=2                                  |
    | master-bin.000001 | 700 | Query             |         1 |    
    
    sql
    SET @@SESSION.binlog_alter_two_phase = true;

    This page is licensed: GPLv2, originally from fill_help_tables.sql

    Progress Reporting

    CREATE TABLE

    Define a new table structure. This fundamental command specifies columns, data types, indexes, and storage engine options for storing data.

    Syntax

    Description

    Use the CREATE TABLE statement to create a table with the given name.

    In its most basic form, the CREATE TABLE statement provides a table name followed by a list of columns, indexes, and constraints. By default, the table is created in the default database. Specify a database with db_name.tbl_name. If you quote the table name, you must quote the database name and table name separately as `db_name`.`tbl_name`. This is particularly useful for , because it allows to create a table into a database, which contains data from other databases. See .

    If a table with the same name exists, error 1050 results. Use to suppress this error and issue a note instead. Use to see notes.

    The CREATE TABLE statement automatically commits the current transaction, except when using the keyword.

    For valid identifiers to use as table names, see .

    If the default_storage_engine is set to ColumnStore , it needs setting on all UMs. Otherwise when the tables using the default engine are replicated across UMs, they will use the wrong engine. You should therefore not use this option as a session variable with ColumnStore.

    can be between 0-6. If no precision is specified it is assumed to be 0, for backward compatibility reasons.

    Privileges

    Executing the CREATE TABLE statement requires the privilege for the table or the database.

    CREATE OR REPLACE

    If the OR REPLACE clause is used and the table already exists, then instead of returning an error, the server will drop the existing table and replace it with the newly defined table.

    This syntax was originally added to make more robust if it has to rollback and repeat statements such as CREATE ... SELECT on replicas.

    is basically the same as:

    with the following exceptions:

    • If table_name was locked with it will continue to be locked after the statement.

    • Temporary tables are only dropped if the TEMPORARY keyword was used. (With , temporary tables are preferred to be dropped before normal tables).

    Things to be Aware of With CREATE OR REPLACE

    • The table is dropped first (if it existed), after that the CREATE is done. Because of this, if the CREATE fails, then the table will not exist anymore after the statement. If the table was used with LOCK TABLES it will be unlocked.

    • One can't use OR REPLACE together with IF EXISTS.

    CREATE TABLE IF NOT EXISTS

    If the IF NOT EXISTS clause is used, then the table will only be created if a table with the same name does not already exist. If the table already exists, then a warning will be triggered by default.

    CREATE TEMPORARY TABLE

    Use the TEMPORARY keyword to create a temporary table that is only available to the current session. Temporary tables are dropped when the session ends. Temporary table names are specific to the session. They will not conflict with other temporary tables from other sessions even if they share the same name. They will shadow names of non-temporary tables or views, if they are identical. A temporary table can have the same name as a non-temporary table which is located in the same database. In that case, their name will reference the temporary table when used in SQL statements. You must have the privilege on the database to create temporary tables. If no storage engine is specified, the setting will determine the engine.

    temporary tables cannot be created by setting the system variable, or using CREATE TEMPORARY TABLE LIKE. If you try, an error is returned. Explicitly creating a temporary table with ENGINE=ROCKSDB has never been permitted.

    temporary tables cannot be created by setting the system variable, or using CREATE TEMPORARY TABLE LIKE. They can be specified, but fail silently, and a MyISAM table is created instead. Explicitly creating a temporary table with ENGINE=ROCKSDB has never been permitted.

    Replicating temporary tables

    By default, temporary tables are only created on the replica if the primary is using the .

    The new deterministic rules for logging of temporary tables are:

    • The STATEMENT binlog format is used. If it is binlogged, 1 is stored in TABLE_SHARE->table_creation_was_logged. The user can change this behavior by setting to MIXED, STATEMENT in which case the create is logged in statement format also in MIXED mode (as before).

    CREATE TABLE ... LIKE

    Use the LIKE clause instead of a full table definition to create an empty table with the same definition as another table, including columns, indexes, and table options. Foreign key definitions, as well as any DATA DIRECTORY or INDEX DIRECTORY table options specified on the original table, will not be created.

    LIKE does not preserve the TEMPORARY status of the original table. To make the new table TEMPORARY as well, use CREATE TEMPORARY TABLE ... LIKE.

    LIKE does not work with , only base tables. Attempting to use it on a view will result in an error:

    The same version of the table storage format as found in the original table is used for the new table.

    CREATE TABLE ... LIKE performs the same checks as CREATE TABLE. So a statement may fail if a change in the renders it invalid. For example:

    CREATE TABLE ... SELECT

    You can create a table containing data from other tables using the CREATE ... SELECT statement. Columns will be created in the table for each field returned by the SELECT query.

    You can also define some columns normally and add other columns from a SELECT. You can also create columns in the normal way and assign them some values using the query, this is done to force a certain type or other field characteristics. The columns that are not named in the query will be placed before the others. For example:

    Remember that the query just returns data. If you want to use the same indexes, or the same columns attributes ([NOT] NULL, DEFAULT, AUTO_INCREMENT, CHECK constraints) in the new table, you need to specify them manually. Types and sizes are not automatically preserved if no data returned by the SELECT requires the full size, and VARCHAR could be converted into CHAR. The function can be used to force the new table to use certain types.

    Aliases (AS) are taken into account, and they should always be used when you SELECT an expression (function, arithmetical operation, etc).

    If an error occurs during the query, the table will not be created at all.

    If the new table has a primary key or UNIQUE indexes, you can use the or REPLACE keywords to handle duplicate key errors during the query. IGNORE means that the newer values must not be inserted an identical value exists in the index. REPLACE means that older values must be overwritten.

    If the columns in the new table are more than the rows returned by the query, the columns populated by the query will be placed after other columns. Note that if the strict SQL_MODE is on, and the columns that are not names in the query do not have a DEFAULT value, an error will raise and no rows will be copied.

    are not used during the execution of a CREATE ... SELECT.

    If the table already exists, an error similar to the following will be returned:

    If the IF NOT EXISTS clause is used and the table exists, a note will be produced instead of an error.

    To insert rows from a query into an existing table, can be used.

    Column Definitions

    Note:

    MariaDB accepts the shortcut format with a REFERENCES clause only in ALTER TABLE and CREATE TABLE statements, but that syntax does nothing. For example:

    MariaDB will attempt to apply the constraint. See .

    MariaDB accepts the shortcut format with a REFERENCES clause only in ALTER TABLE and CREATE TABLE statements, but that syntax does nothing. For example:

    Each definition either creates a column in the table or specifies and index or constraint on one or more columns. See below for details on creating indexes.

    Create a column by specifying a column name and a data type, optionally followed by column options. See for a full list of data types allowed in MariaDB.

    NULL and NOT NULL

    Use the NULL or NOT NULL options to specify that values in the column may or may not be NULL, respectively. By default, values may be NULL. See also .

    DEFAULT Column Option

    Specify a default value using the DEFAULT clause. If you don't specify DEFAULT then the following rules apply:

    • If the column is not defined with NOT NULL, AUTO_INCREMENT or TIMESTAMP, an explicit DEFAULT NULL will be added. Note that in MySQL, you may get an explicit DEFAULT for primary key parts, if not specified with NOT NULL.

    The default value will be used if you a row without specifying a value for that column, or if you specify for that column.

    may also be used as the default value for a

    You can use most functions in DEFAULT. Expressions should have parentheses around them. If you use a non deterministic function in DEFAULT then all inserts to the table will be in . You can even refer to earlier columns in the DEFAULT expression (excluding AUTO_INCREMENT columns):

    The DEFAULT clause cannot contain any or , and a column used in the clause must already have been defined earlier in the statement.

    It is possible to assign or columns a DEFAULT value.

    You can also use DEFAULT ().

    AUTO_INCREMENT Column Option

    Use to create a column whose value can be set automatically from a simple counter. You can only use AUTO_INCREMENT on a column with an integer type. The column must be a key, and there can only be one AUTO_INCREMENT column in a table. If you insert a row without specifying a value for that column (or if you specify 0, NULL, or as the value), the actual value will be taken from the counter, with each insertion incrementing the counter by one. You can still insert a value explicitly. If you insert a value that is greater than the current counter value, the counter is set based on the new value. An AUTO_INCREMENT column is implicitly NOT NULL. Use to get the value most recently used by an statement.

    ZEROFILL Column Option

    If the ZEROFILL column option is specified for a column using a data type, then the column will be set to UNSIGNED and the spaces used by default to pad the field are replaced with zeros. ZEROFILL is ignored in expressions or as part of a , , or . ZEROFILL is a non-standard MariaDB and MySQL extension.

    PRIMARY KEY Column Option

    Use PRIMARY KEY to make a column a primary key. A primary key is a special type of a unique key. There can be at most one primary key per table, and it is implicitly NOT NULL.

    Specifying a column as a unique key creates a unique index on that column. See the section below for more information.

    UNIQUE KEY Column Option

    Use UNIQUE KEY (or just UNIQUE) to specify that all values in the column must be distinct from each other. Unless the column is NOT NULL, there may be multiple rows with NULL in the column.

    When any inserts or updates occur in the table, reading the binlog shows the hidden column (@3). it causes confusion for the user; we can document these behaviours.

    See the section below for more information.

    COMMENT Column Option

    You can provide a comment for each column using the COMMENT clause. The maximum length is 1024 characters. Use the statement to see column comments.

    REF_SYSTEM_ID

    REF_SYSTEM_ID can be used to specify Spatial Reference System IDs for spatial data type columns. For example:

    Generated Columns

    A generated column is a column in a table that cannot explicitly be set to a specific value in a . Instead, its value is automatically generated based on an expression. This expression might generate the value based on the values of other columns in the table, or it might generate the value by calling or .

    There are two types of generated columns:

    • PERSISTENT or STORED: This type's value is actually stored in the table.

    • VIRTUAL: This type's value is not stored at all. Instead, the value is generated dynamically when the table is queried. This type is the default.

    Generated columns are also sometimes called computed columns or virtual columns.

    For a complete description about generated columns and their limitations, see .

    COMPRESSED

    Certain columns may be compressed. See .

    INVISIBLE

    Columns may be made invisible, and hidden in certain contexts. See .

    WITH SYSTEM VERSIONING Column Option

    Columns may be explicitly marked as included from system versioning. See for details.

    WITHOUT SYSTEM VERSIONING Column Option

    Columns may be explicitly marked as excluded from system versioning. See for details.

    Index Definitions

    INDEX and KEY are synonyms.

    Index names are optional, if not specified an automatic name will be assigned. Index name are needed to drop indexes and appear in error messages when a constraint is violated.

    For limits on InnoDB indexes, see .

    Index Categories

    Plain Indexes

    Plain indexes are regular indexes that are not unique, and are not acting as a primary key or a foreign key. They are also not the "specialized" FULLTEXT or SPATIAL indexes.

    See for more information.

    PRIMARY KEY

    For PRIMARY KEY indexes, you can specify a name for the index, but it is ignored, and the name of the index is always PRIMARY. A warning is explicitly issued if a name is specified. Before then, the name was silently ignored.

    See for more information.

    UNIQUE

    The UNIQUE keyword means that the index will not accept duplicated values, except for NULLs. An error will raise if you try to insert duplicate values in a UNIQUE index.

    For UNIQUE indexes, you can specify a name for the constraint, using the CONSTRAINT keyword. That name will be used in error messages.

    Unique, if index type is not specified, is normally a BTREE index that can also be used by the optimizer to find rows. If the key is longer than the max key length for the used storage engine, a HASH key will be created. This enables MariaDB to enforce uniqueness for any type or number of columns.

    -

    See for more information.

    FOREIGN KEY

    For FOREIGN KEY indexes, a reference definition must be provided.

    For FOREIGN KEY indexes, you can specify a name for the constraint, using the CONSTRAINT keyword. That name will be used in error messages.

    First, you have to specify the name of the target (parent) table and a column or a column list which must be indexed and whose values must match to the foreign key's values. The MATCH clause is accepted to improve the compatibility with other DBMS's, but has no meaning in MariaDB. The ON DELETE and ON UPDATE clauses specify what must be done when a DELETE (or a REPLACE) statements attempts to delete a referenced row from the parent table, and when an UPDATE statement attempts to modify the referenced foreign key columns in a parent table row, respectively. The following options are allowed:

    • RESTRICT: The delete/update operation is not performed. The statement terminates with a 1451 error (SQLSTATE '2300').

    • NO ACTION: Synonym for RESTRICT.

    • CASCADE: The delete/update operation is performed in both tables.

    If either clause is omitted, the default behavior for the omitted clause is RESTRICT.

    See for more information.

    FULLTEXT

    Use the FULLTEXT keyword to create full-text indexes.

    See for more information.

    SPATIAL

    Use the SPATIAL keyword to create geometric indexes.

    See for more information.

    Index Options

    KEY_BLOCK_SIZE Index Option

    The KEY_BLOCK_SIZE index option is similar to the table option.

    With the storage engine, if you specify a non-zero value for the KEY_BLOCK_SIZE table option for the whole table, then the table will implicitly be created with the table option set to COMPRESSED. However, this does not happen if you just set the KEY_BLOCK_SIZE index option for one or more indexes in the table. The storage engine ignores the KEY_BLOCK_SIZE index option. However, the statement may still report it for the index.

    For information about the KEY_BLOCK_SIZE index option, see the table option below.

    Index Types

    Each storage engine supports some or all index types. See for details on permitted index types for each storage engine.

    Different index types are optimized for different kind of operations:

    • BTREE is the default type, and normally is the best choice. It is supported by all storage engines. It can be used to compare a column's value with a value using the =, >, >=, <, <=, BETWEEN, and LIKE operators. BTREE can also be used to find NULL values. Searches against an index prefix are possible.

    • HASH is only supported by the MEMORY storage engine. HASH indexes can only be used for =, <=, and >= comparisons. It can not be used for the

    Index columns names are listed between parenthesis. After each column, a prefix length can be specified. If no length is specified, the whole column will be indexed. ASC and DESC can be specified. Individual columns in the index can be explicitly sorted in ascending or descending order. This can be useful for optimizing certain ORDER BY cases (, , , ). Not only ascending, but also descending, indexes can be used to optimize and ().

    Index columns names are listed between parenthesis. After each column, a prefix length can be specified. If no length is specified, the whole column will be indexed. ASC and DESC can be specified. Prior to , this was only for compatibility with other DBMSs, but had no meaning in MariaDB. From , individual columns in the index can now be explicitly sorted in ascending or descending order. This can be useful for optimizing certain ORDER BY cases (, , , ). From , not only ascending, but also descending, indexes can now be used to optimize

    The maximum number of parts in an index is 32.

    WITH PARSER Index Option

    The WITH PARSER index option only applies to indexes and contains the fulltext parser name. The fulltext parser must be an installed plugin.

    VISIBLE Index Option

    Indexes can be declared visible. This is the default and it shows up in .

    Indexes cannot be declared visible.

    COMMENT Index Option

    A comment of up to 1024 characters is permitted with the COMMENT index option.

    The COMMENT index option allows you to specify a comment with user-readable text describing what the index is for. This information is not used by the server itself.

    CLUSTERING Index Option

    The CLUSTERING index option is only valid for tables using the storage engine.

    IGNORED / NOT IGNORED

    Indexes can be specified to be ignored by the optimizer. See .

    Indexes can be specified to be ignored by the optimizer. See .

    Periods

    MariaDB supports , or .

    Constraint Expressions

    MariaDB introduced two ways to define a constraint:

    • CHECK(expression) given as part of a column definition.

    • CONSTRAINT [constraint_name] CHECK (expression)

    Before a row is inserted or updated, all constraints are evaluated in the order they are defined. If any constraints fails, then the row will not be updated. One can use most deterministic functions in a constraint, including .

    If you use the second format and you don't give a name to the constraint, then the constraint will get a auto generated name. This is done so that you can later delete the constraint with .

    One can disable all constraint expression checks by setting the variable check_constraint_checks to OFF. This is useful for example when loading a table that violates some constraints that you want to later find and fix in SQL.

    See for more information.

    Table Options

    For each individual table you create (or alter), you can set some table options. The general syntax for setting options is:

    The equal sign is optional.

    Some options are supported by the server and can be used for all tables, no matter what storage engine they use; other options can be specified for all storage engines, but have a meaning only for some engines. Also, engines can .

    If the IGNORE_BAD_TABLE_OPTIONS is enabled, wrong table options generate a warning; otherwise, they generate an error.

    [STORAGE] ENGINE

    [STORAGE] ENGINE specifies a for the table. If this option is not used, the default storage engine is used instead. That is, the session option value if it is set, or the value specified for the --default-storage-engine , or the default storage engine, . If the specified storage engine is not installed and active, the default value will be used, unless the NO_ENGINE_SUBSTITUTION is set (default). This is only true for CREATE TABLE, not for ALTER TABLE. For a list of storage engines that are present in your server, issue a .

    AUTO_INCREMENT

    AUTO_INCREMENT specifies the initial value for the primary key. This works for MyISAM, Aria, InnoDB, MEMORY, and ARCHIVE tables. You can change this option with ALTER TABLE, but in that case the new value must be higher than the highest value which is present in the AUTO_INCREMENT column. If the storage engine does not support this option, you can insert (and then delete) a row having the wanted value - 1 in the AUTO_INCREMENT column.

    AVG_ROW_LENGTH

    AVG_ROW_LENGTH is the average rows size. It only applies to tables using and storage engines that have the table option set to FIXED format.

    MyISAM uses MAX_ROWS and AVG_ROW_LENGTH to decide the maximum size of a table (default: 256TB, or the maximum file size allowed by the system).

    [DEFAULT] CHARACTER SET/CHARSET

    [DEFAULT] CHARACTER SET (or [DEFAULT] CHARSET) is used to set a default character set for the table. This is the character set used for all columns where an explicit character set is not specified. If this option is omitted or DEFAULT is specified, the database's default character set will be used (except for the , which is utf8mb4 by default). See for details on setting the .

    CHECKSUM/TABLE_CHECKSUM

    CHECKSUM (or TABLE_CHECKSUM) can be set to 1 to maintain a live checksum for all table's rows. This makes write operations slower, but will be very fast. This option is only supported for and .

    [DEFAULT] COLLATE

    [DEFAULT] COLLATE is used to set a default collation for the table. This is the collation used for all columns where an explicit character set is not specified. If this option is omitted or DEFAULT is specified, the database's default option will be used (except for the , which uses utf8mb4_bin by default). See for details on setting the

    COMMENT

    COMMENT is a comment for the table. The maximum length is 2048 characters. Also used to define table parameters when creating a table.

    CONNECTION

    CONNECTION is used to specify a server name or a connection string for a , , .

    DATA DIRECTORY/INDEX DIRECTORY

    DATA DIRECTORY and INDEX DIRECTORY are supported for MyISAM and Aria, and DATA DIRECTORY is also supported by InnoDB if the server system variable is enabled, but only in CREATE TABLE, not in . So, carefully choose a path for InnoDB tables at creation time, because it cannot be changed without dropping and re-creating the table. These options specify the paths for data files and index files, respectively. If these options are omitted, the database's directory will be used to store data files and index files. Note that these table options do not work for tables (use the partition options instead), or if the server has been invoked with the . To avoid the overwriting of old files with the same name that could be present in the directories, you can use (an error will be issued if files already exist). These options are ignored if the NO_DIR_IN_CREATE is enabled (useful for replicas). Also note that symbolic links cannot be used for InnoDB tables.

    DATA DIRECTORY works by creating symlinks from where the table would normally have been (inside the ) to where the option specifies. For security reasons, to avoid bypassing the privilege system, the server does not permit symlinks inside the datadir. Therefore, DATA DIRECTORY cannot be used to specify a location inside the datadir. An attempt to do so will result in an error 1210 (HY000) Incorrect arguments to DATA DIRECTORY.

    DELAY_KEY_WRITE

    DELAY_KEY_WRITE is supported by MyISAM and Aria, and can be set to 1 to speed up write operations. In that case, when data are modified, the indexes are not updated until the table is closed. Writing the changes to the index file altogether can be much faster. However, note that this option is applied only if the delay_key_write server variable is set to 'ON'. If it is 'OFF' the delayed index writes are always disabled, and if it is 'ALL' the delayed index writes are always used, disregarding the value of DELAY_KEY_WRITE.

    ENCRYPTED

    The ENCRYPTED table option can be used to manually set the encryption status of an table. See for more information.

    Aria does not support the ENCRYPTED table option. See .

    See for more information.

    ENCRYPTION_KEY_ID

    The ENCRYPTION_KEY_ID table option can be used to manually set the encryption key of an table. See for more information.

    Aria does not support the ENCRYPTION_KEY_ID table option. See .

    See for more information.

    IETF_QUOTES

    For the storage engine, the IETF_QUOTES option, when set to YES, enables IETF-compatible parsing of embedded quote and comma characters. Enabling this option for a table improves compatibility with other tools that use CSV, but is not compatible with MySQL CSV tables, or MariaDB CSV tables created without this option. Disabled by default.

    INSERT_METHOD

    INSERT_METHOD is only used with tables. This option determines in which underlying table the new rows should be inserted. If you set it to 'NO' (which is the default) no new rows can be added to the table (but you will still be able to perform INSERTs directly against the underlying tables). FIRST means that the rows are inserted into the first table, and LAST means that thet are inserted into the last table.

    KEY_BLOCK_SIZE

    KEY_BLOCK_SIZE is used to determine the size of key blocks, in bytes or kilobytes. However, this value is just a hint, and the storage engine could modify or ignore it. If KEY_BLOCK_SIZE is set to 0, the storage engine's default value will be used.

    With the storage engine, if you specify a non-zero value for the KEY_BLOCK_SIZE table option for the whole table, then the table will implicitly be created with the table option set to COMPRESSED.

    MIN_ROWS/MAX_ROWS

    MIN_ROWS and MAX_ROWS let the storage engine know how many rows you are planning to store as a minimum and as a maximum. These values will not be used as real limits, but they help the storage engine to optimize the table. MIN_ROWS is only used by MEMORY storage engine to decide the minimum memory that is always allocated. MAX_ROWS is used to decide the minimum size for indexes.

    PACK_KEYS

    PACK_KEYS can be used to determine whether the indexes will be compressed. Set it to 1 to compress all keys. With a value of 0, compression will not be used. With the DEFAULT value, only long strings will be compressed. Uncompressed keys are faster.

    PAGE_CHECKSUM

    PAGE_CHECKSUM is only applicable to tables, and determines whether indexes and data should use page checksums for extra safety.

    PAGE_COMPRESSED

    PAGE_COMPRESSED is used to enable for tables.

    PAGE_COMPRESSION_LEVEL

    PAGE_COMPRESSION_LEVEL is used to set the compression level for for tables. The table must also have the table option set to 1.

    Valid values for PAGE_COMPRESSION_LEVEL are 1 (the best speed) through 9 (the best compression), .

    PASSWORD

    PASSWORD is unused.

    RAID_TYPE

    RAID_TYPE is an obsolete option, as the raid support has been disabled since MySQL 5.0.

    ROW_FORMAT

    The ROW_FORMAT table option specifies the row format for the data file. Possible values are engine-dependent.

    Supported MyISAM Row Formats

    For , the supported row formats are:

    • FIXED

    • DYNAMIC

    • COMPRESSED

    The COMPRESSED row format can only be set by the command line tool.

    See for more information.

    Supported Aria Row Formats

    For , the supported row formats are:

    • PAGE

    • FIXED

    • DYNAMIC.

    See for more information.

    Supported InnoDB Row Formats

    For , the supported row formats are:

    • COMPACT

    • REDUNDANT

    • COMPRESSED

    • DYNAMIC

    If the ROW_FORMAT table option is set to FIXED for an InnoDB table, then the server will either return an error or a warning depending on the value of the system variable. If the system variable is set to OFF, then a warning is issued, and MariaDB will create the table using the default row format for the specific MariaDB server version. If the system variable is set to ON, then an error will be raised.

    See for more information.

    Other Storage Engines and ROW_FORMAT

    Other storage engines do not support the ROW_FORMAT table option.

    SEQUENCE

    If the table is a , then it will have the SEQUENCE set to 1.

    STATS_AUTO_RECALC

    STATS_AUTO_RECALC indicates whether to automatically recalculate persistent statistics (see STATS_PERSISTENT, below) for an InnoDB table. If set to 1, statistics will be recalculated when more than 10% of the data has changed. When set to 0, stats will be recalculated only when an is run. If set to DEFAULT, or left out, the value set by the system variable applies. See .

    STATS_PERSISTENT

    STATS_PERSISTENT indicates whether the InnoDB statistics created by will remain on disk or not. It can be set to 1 (on disk), 0 (not on disk, the pre-MariaDB 10 behavior), or DEFAULT (the same as leaving out the option), in which case the value set by the system variable will apply. Persistent statistics stored on disk allow the statistics to survive server restarts, and provide better query plan stability. See .

    STATS_SAMPLE_PAGES

    STATS_SAMPLE_PAGES indicates how many pages are used to sample index statistics. If 0 or DEFAULT, the default value, the value is used. See .

    TRANSACTIONAL

    TRANSACTIONAL is only applicable for Aria tables. In future Aria tables created with this option will be fully transactional, but currently this provides a form of crash protection. See for more details.

    UNION

    UNION must be specified when you create a MERGE table. This option contains a comma-separated list of MyISAM tables which are accessed by the new table. The list is enclosed between parenthesis. Example: UNION = (t1,t2)

    WITH SYSTEM VERSIONING

    WITH SYSTEM VERSIONING is used for creating .

    Partitions

    If the PARTITION BY clause is used, the table will be . A partition method must be explicitly indicated for partitions and subpartitions. Partition methods are:

    • [LINEAR] creates a hash key which will be used to read and write rows. The partition function can be any valid SQL expression which returns an INTEGER number. Thus, it is possible to use the HASH method on an integer column, or on functions which accept integer columns as an argument. However, VALUES LESS THAN and VALUES IN clauses can not be used with HASH. An example:

    [LINEAR] can be used for subpartitions, too.

    • [LINEAR] is similar to HASH, but the index has an even distribution of data. Also, the expression can only be a column or a list of columns. VALUES LESS THAN and VALUES IN clauses can not be used with KEY.

    • partitions the rows using on a range of values, using the VALUES LESS THAN operator. VALUES IN is not allowed with RANGE

    Only and can be used for subpartitions, and they can be [LINEAR].

    It is possible to define up to 8092 partitions and subpartitions.

    The number of defined partitions can be optionally specified as PARTITION count. This can be done to avoid specifying all partitions individually. But you can also declare each individual partition and, additionally, specify a PARTITIONS count clause; in the case, the number of PARTITIONs must equal count.

    Also see .

    The PARTITION keyword is optional as part of the partition definition. Instead of this:

    The following can be used:

    The PARTITION keyword is not optional as part of the partition definition. You must use this syntax:

    Sequences

    CREATE TABLE can also be used to create a . See and .

    Atomic DDL

    MariaDB supports . CREATE TABLE is atomic, except for CREATE OR REPLACE, which are only crash-safe.

    -

    Examples

    This example shows a couple of things:

    • Usage of IF NOT EXISTS; If the table already existed, it will not be created. There will not be any error for the client, just a warning.

    • How to create a PRIMARY KEY that is .

    • How to specify a table-specific and another for a column.

    The following clauses will work:

    See Also

    This page is licensed: GPLv2, originally from

    CREATE [OR REPLACE] [TEMPORARY] TABLE [IF NOT EXISTS] tbl_name
        (create_definition,...) [table_options    ]... [partition_options]
    CREATE [OR REPLACE] [TEMPORARY] TABLE [IF NOT EXISTS] tbl_name
        [(create_definition,...)] [table_options   ]... [partition_options]
        select_statement
    CREATE [OR REPLACE] [TEMPORARY] TABLE [IF NOT EXISTS] tbl_name
       { LIKE old_table_name | (LIKE old_table_name) }
    
    select_statement:
        [IGNORE | REPLACE] [AS] SELECT ...   (Some legal select statement)
    Replicas will by default use CREATE OR REPLACE when replicating CREATE statements that don''t use IF EXISTS. This can be changed by setting the variable slave-ddl-exec-mode to STRICT.

    Changes to temporary tables are only binlogged if and only if the CREATE was logged. The logging happens under STATEMENT or MIXED. If binlog_format=ROW, temporary table changes are not binlogged. A temporary table that is changed under ROW is marked as 'not up to date in binlog' and no future row changes are logged. Any usage of this temporary table will force row logging of other tables in any future statements using the temporary table to be row logged.

  • DROP TEMPORARY is binlogged only if the CREATE was binlogged.

  • In some contexts, temporary tables on the primary and replica can become inconsistent. One example is if a temporary table is updated with the value of a non deterministic function like UUID(), in which the change is never sent to the replica.

    In some other contexts, while using MIXED mode, all changes will be logged in ROW mode while the user has any active temporary tables, even if the temporary tables are not used in the query. This depends on in which format some previous independent commands were logged.

    There are many other pitfalls with logging temporary table to the replica.

    SET NULL: The update or delete goes ahead in the parent table, and the corresponding foreign key fields in the child table are set to NULL. (They must not be defined as NOT NULL for this to succeed).

  • SET DEFAULT: This option is currently implemented only for the PBXT storage engine, which is disabled by default and no longer maintained. It sets the child table's foreign key fields to their DEFAULT values when the referenced parent table key entries are updated or deleted.

  • ORDER BY
    clause. Searches against an index prefix are not possible.
  • RTREE is the default for SPATIAL indexes, but if the storage engine does not support it BTREE can be used.

  • and
    (
    ).
    .
    . The partition function can be any valid SQL expression which returns a single value.
  • LIST assigns partitions based on a table's column with a restricted set of possible values. It is similar to RANGE, but VALUES IN must be used for at least 1 columns, and VALUES LESS THAN is disallowed.

  • SYSTEM_TIME partitioning is used for System-versioned tables to store historical data separately from current data.

  • How to create an index (name) that is only partly indexed (to save space).
    SHOW CREATE TABLE
  • CREATE TABLE with Vectors

  • Storage engines can add their own attributes for columns, indexes and tables

  • Variable slave-ddl-exec-mode

  • InnoDB Limitations

  • CREATE TABLE ... SELECT
    Identifier Qualifiers
    IF NOT EXISTS
    SHOW WARNINGS
    TEMPORARY
    Identifier Names
    Microsecond precision
    CREATE
    replication
    LOCK TABLES
    DROP TABLE
    CREATE TEMPORARY TABLES
    default_tmp_storage_engine
    ROCKSDB
    default_tmp_storage_engine
    ROCKSDB
    default_tmp_storage_engine
    STATEMENT binary log format
    create_temporary_table_binlog_formats
    views
    SQL_MODE
    CAST()
    IGNORE
    Concurrent inserts
    INSERT ... SELECT
    Foreign Keys examples
    Indexes
    Data Types
    NULL Values in MariaDB
    INSERT
    DEFAULT
    CURRENT_TIMESTAMP
    DATETIME
    replicated
    row mode
    stored functions
    subqueries
    BLOB
    TEXT
    NEXT VALUE FOR sequence
    AUTO_INCREMENT
    DEFAULT
    LAST_INSERT_ID
    AUTO_INCREMENT
    INSERT
    numeric
    UNION
    INTERSECT
    EXCEPT
    Index Definitions
    Index Definitions
    SHOW FULL COLUMNS
    DML query
    built-in functions
    user-defined functions (UDFs)
    Generated (Virtual and Persistent/Stored) Columns
    Storage-Engine Independent Column Compression
    Invisible Columns
    System-versioned tables
    System-versioned tables
    InnoDB Limitations
    Getting Started with Indexes: Plain Indexes
    Getting Started with Indexes: Primary Key
    Getting Started with Indexes: Unique Index
    Foreign Keys
    Full-Text Indexes
    SPATIAL INDEX
    KEY_BLOCK_SIZE
    InnoDB
    ROW_FORMAT
    InnoDB
    SHOW CREATE TABLE
    KEY_BLOCK_SIZE
    Storage Engine Index Types
    MDEV-13756
    MDEV-26938
    MDEV-26939
    MDEV-26996
    MIN()
    MAX()
    MDEV-27576
    MDEV-13756
    MDEV-26938
    MDEV-26939
    MDEV-26996
    MariaDB 11.4.0
    MIN()
    FULLTEXT
    SHOW CREATE TABLE
    TokuDB
    Ignored Indexes
    Ignored Indexes
    System-versioned tables
    Application-time-period tables
    Bitemporal Tables
    UDFs
    ALTER TABLE DROP constraint_name
    CONSTRAINT
    extend CREATE TABLE with new options
    SQL_MODE
    storage engine
    default_storage_engine
    mariadbd startup option
    InnoDB
    SQL MODE
    SHOW ENGINES
    AUTO_INCREMENT
    MyISAM
    Aria
    ROW_FORMAT
    JSON data type
    Setting Character Sets and Collations
    character sets
    CHECKSUM TABLE
    MyISAM
    Aria tables
    JSON data type
    Setting Character Sets and Collations
    collations
    Spider
    Spider
    CONNECT
    Federated or FederatedX table
    innodb_file_per_table
    ALTER TABLE
    partitioned
    --skip-symbolic-links startup option
    the --keep_files_on_create option
    SQL_MODE
    datadir
    InnoDB
    InnoDB Encryption
    MDEV-18049
    Data-at-Rest Encryption
    InnoDB
    InnoDB Encryption
    MDEV-18049
    Data-at-Rest Encryption
    CSV
    MERGE
    InnoDB
    ROW_FORMAT
    Aria
    InnoDB page compression
    InnoDB
    InnoDB page compression
    InnoDB
    PAGE_COMPRESSED
    MyISAM
    myisampack
    MyISAM Storage Formats
    Aria
    Aria Storage Formats
    InnoDB
    innodb_strict_mode
    innodb_strict_mode
    innodb_strict_mode
    InnoDB Storage Formats
    sequence
    ANALYZE TABLE
    innodb_stats_auto_recalc
    InnoDB Persistent Statistics
    ANALYZE TABLE
    innodb_stats_persistent
    InnoDB Persistent Statistics
    innodb_stats_sample_pages
    InnoDB Persistent Statistics
    Aria Storage Engine
    System-versioned tables
    partitioned
    HASH
    HASH
    KEY
    RANGE
    HASH
    KEY
    Partitioning Types Overview
    SEQUENCE
    CREATE SEQUENCE
    Sequence Overview
    Atomic DDL
    automatically generated
    character set
    Identifier Names
    ALTER TABLE
    DROP TABLE
    Character Sets and Collations
    fill_help_tables.sql
    MAX()
    MDEV-27576
    CREATE OR REPLACE TABLE table_name (a INT);
    DROP TABLE IF EXISTS TABLE_NAME;
    CREATE TABLE TABLE_NAME (a INT);
    CREATE VIEW v (mycol) AS SELECT 'abc';
    
    CREATE TABLE v2 LIKE v;
    ERROR 1347 (HY000): 'test.v' is not of type 'BASE TABLE'
    CREATE OR REPLACE TABLE x (d DATE DEFAULT '0000-00-00');
    
    SET SQL_MODE='NO_ZERO_DATE';
    
    CREATE OR REPLACE TABLE y LIKE x;
    ERROR 1067 (42000): Invalid default value for 'd'
    CREATE TABLE test (a INT NOT NULL, b CHAR(10)) ENGINE=MyISAM
        SELECT 5 AS b, c, d FROM another_table;
    ERROR 1050 (42S01): Table 't' already exists
    create_definition:
      { col_name column_definition | index_definition | period_definition | CHECK (expr) }
    
    column_definition:
      data_type
        [NOT NULL | NULL] [DEFAULT default_value | (expression)]
        [ON UPDATE [NOW | CURRENT_TIMESTAMP] [(precision)]]
        [AUTO_INCREMENT] [ZEROFILL] [UNIQUE [KEY] | [PRIMARY] KEY]
        [INVISIBLE] [{WITH|WITHOUT} SYSTEM VERSIONING]
        [COMMENT 'string'] [REF_SYSTEM_ID = value]
        [reference_definition]
      | data_type [GENERATED ALWAYS] 
      AS [ ROW {START|END} [NOT NULL ENABLE] [[PRIMARY] KEY]
            | (expression) [VIRTUAL | PERSISTENT | STORED] ]
          [INVISIBLE] [UNIQUE [KEY]] [COMMENT 'string']
    
    constraint_definition:
       CONSTRAINT [constraint_name] CHECK (expression)
    CREATE TABLE b(for_key INT REFERENCES a(not_key));
    CREATE TABLE b(for_key INT REFERENCES a(not_key));
    CREATE TABLE t1 (a INT DEFAULT (1+1), b INT DEFAULT (a+1));
    CREATE TABLE t2 (a BIGINT PRIMARY KEY DEFAULT UUID_SHORT());
    ### INSERT INTO `securedb`.`t_long_keys`
    ### SET
    ###   @1=1 /* INT meta=0 nullable=0 is_null=0 */
    ###   @2='a' /* VARSTRING(4073) meta=4073 nullable=1 is_null=0 */
    ###   @3=580 /* LONGINT meta=0 nullable=1 is_null=0 */
    CREATE TABLE t_long_keys (   a INT PRIMARY KEY,   b  VARCHAR(4073),   UNIQUE KEY `uk_b` (b) ) ENGINE=InnoDB;
    Query OK, 0 rows affected (0.022 sec)
    
    show create table t_long_keys\G
    *************************** 1. row ***************************
           Table: t_long_keys
    Create Table: CREATE TABLE `t_long_keys` (
      `a` int(11) NOT NULL,
      `b` varchar(4073) DEFAULT NULL,
      PRIMARY KEY (`a`),
      UNIQUE KEY `uk_b` (`b`) USING HASH
    ) ENGINE=InnoDB DEFAULT CHARSET=latin1 COLLATE=latin1_swedish_ci
    1 row in set (0.001 sec)
    
    select * from information_schema.INNODB_SYS_TABLES where name like '%t_long_keys%';;
    +----------+----------------------+------+--------+-------+------------+---------------+------------+
    | TABLE_ID | NAME                 | FLAG | N_COLS | SPACE | ROW_FORMAT | ZIP_PAGE_SIZE | SPACE_TYPE |
    +----------+----------------------+------+--------+-------+------------+---------------+------------+
    |       64 | securedb/t_long_keys |   33 |      5 |    43 | Dynamic    |             0 | Single     |
    +----------+----------------------+------+--------+-------+------------+---------------+------------+
    1 row in set (0.003 sec)
    
    
    
    select * from information_schema.INNODB_SYS_COLUMNS where TABLE_ID=64;
    +----------+---------------+-------+-------+--------+------+
    | TABLE_ID | NAME          | POS   | MTYPE | PRTYPE | LEN  |
    +----------+---------------+-------+-------+--------+------+
    |       64 | a             |     0 |     6 |   1283 |    4 |
    |       64 | b             |     1 |     1 | 528399 | 4073 |
    |       64 | DB_ROW_HASH_1 | 65538 |     6 |   9736 |    8 |
    +----------+---------------+-------+-------+--------+------+
    
    CREATE TABLE t1(g GEOMETRY(9,4) REF_SYSTEM_ID=101);
    index_definition:
        {INDEX|KEY} [index_name] [index_type] (index_col_name,...) [index_option] ...
      {{{|}}} {FULLTEXT|SPATIAL} [INDEX|KEY] [index_name] (index_col_name,...) [index_option] ...
      {{{|}}} [CONSTRAINT [symbol]] PRIMARY KEY [index_type] (index_col_name,...) [index_option] ...
      {{{|}}} [CONSTRAINT [symbol]] UNIQUE [INDEX|KEY] [index_name] [index_type] (index_col_name,...) [index_option] ...
      {{{|}}} [CONSTRAINT [symbol]] FOREIGN KEY [index_name] (index_col_name,...) reference_definition
    
    index_col_name:
        col_name [(length)] [ASC | DESC]
    
    index_type:
        USING {BTREE | HASH | RTREE}
    
    index_option:
        [ KEY_BLOCK_SIZE [=] value
      {{{|}}} index_type
      {{{|}}} WITH PARSER parser_name
      {{{|}}} VISIBLE
      {{{|}}} COMMENT 'string'
      {{{|}}} CLUSTERING={YES| NO} ]
      [ IGNORED | NOT IGNORED ]
    
    reference_definition:
        REFERENCES tbl_name (index_col_name,...)
          [MATCH FULL | MATCH PARTIAL | MATCH SIMPLE]
          [ON DELETE reference_option]
          [ON UPDATE reference_option]
    
    reference_option:
        RESTRICT | CASCADE | SET NULL | NO ACTION
    period_definition:
        PERIOD FOR [time_period_name | SYSTEM_TIME] (start_column_name, end_column_name)
    CREATE TABLE t1 (a INT CHECK(a>0) ,b INT CHECK (b> 0), CONSTRAINT abc CHECK (a>b));
    <OPTION_NAME> = <option_value>, [<OPTION_NAME> = <option_value> ...]
    table_option:    
        [STORAGE] ENGINE [=] engine_name
      | AUTO_INCREMENT [=] number
      | AVG_ROW_LENGTH [=] number
      | [DEFAULT] CHARACTER SET [=] <a data-footnote-ref href="#user-content-fn-7">charset_name</a>
      | CHECKSUM [=] {0 | 1}
      | [DEFAULT] COLLATE [=] <a data-footnote-ref href="#user-content-fn-7">collation_name</a>
      | COMMENT [=] 'string'
      | CONNECTION [=] 'connect_string'
      | DATA DIRECTORY [=] 'absolute path to directory'
      | DELAY_KEY_WRITE [=] {0 | 1}
      | ENCRYPTED [=] {YES | NO}
      | ENCRYPTION_KEY_ID [=] number
      | IETF_QUOTES [=] {YES | NO}
      | INDEX DIRECTORY [=] 'absolute path to directory'
      | INSERT_METHOD [=] { NO | FIRST | LAST }
      | KEY_BLOCK_SIZE [=] number
      | MAX_ROWS [=] number
      | MIN_ROWS [=] number
      | PACK_KEYS [=] {0 | 1 | DEFAULT}
      | PAGE_CHECKSUM [=] {0 | 1}
      | PAGE_COMPRESSED [=] {0 | 1}
      | PAGE_COMPRESSION_LEVEL [=] {0 .. 9}
      | PASSWORD [=] 'string'
      | ROW_FORMAT [=] {DEFAULT|DYNAMIC|FIXED|COMPRESSED|REDUNDANT|COMPACT|PAGE}
      | SEQUENCE [=] {0|1}
      | STATS_AUTO_RECALC [=] {DEFAULT|0|1}
      | STATS_PERSISTENT [=] {DEFAULT|0|1}
      | STATS_SAMPLE_PAGES [=] {DEFAULT|number}
      | TABLESPACE tablespace_name
      | TRANSACTIONAL [=]  {0 | 1}
      | UNION [=] (tbl_name[,tbl_name]...)
      | WITH SYSTEM VERSIONING
    partition_options:
        PARTITION BY
            { [LINEAR] HASH(expr)
            | [LINEAR] KEY(column_list)
            | RANGE(expr)
            | LIST(expr)
            | SYSTEM_TIME [INTERVAL time_quantity <a data-footnote-ref href="#user-content-fn-8">time_unit</a>] [LIMIT num] }
        [PARTITIONS num]
        [SUBPARTITION BY
            { [LINEAR] HASH(expr)
            | [LINEAR] KEY(column_list) }
          [SUBPARTITIONS num]
        ]
        [(partition_definition [, partition_definition] ...)]
    
    
    partition_definition:
        [PARTITION] partition_name
            [VALUES {LESS THAN {(expr) | MAXVALUE} | IN (value_list)}]
            [[STORAGE] ENGINE [=] engine_name]
            [COMMENT [=] 'comment_text' ]
            [DATA DIRECTORY [=] 'data_dir']
            [INDEX DIRECTORY [=] 'index_dir']
            [MAX_ROWS [=] max_number_of_rows]
            [MIN_ROWS [=] min_number_of_rows]
            [TABLESPACE [=] tablespace_name]
            [NODEGROUP [=] node_group_id]
            [(subpartition_definition [, subpartition_definition] ...)]
    
    
    subpartition_definition:
        SUBPARTITION logical_name
            [[STORAGE] ENGINE [=] engine_name]
            [COMMENT [=] 'comment_text' ]
            [DATA DIRECTORY [=] 'data_dir']
            [INDEX DIRECTORY [=] 'index_dir']
            [MAX_ROWS [=] max_number_of_rows]
            [MIN_ROWS [=] min_number_of_rows]
            [TABLESPACE [=] tablespace_name]
            [NODEGROUP [=] node_group_id]
    CREATE TABLE t1 (a INT, b CHAR(5), c DATETIME)
        PARTITION BY HASH ( YEAR(c) );
    CREATE OR REPLACE TABLE t1 (x INT)
      PARTITION BY RANGE(x) (
        PARTITION p1 VALUES LESS THAN (10),
        PARTITION p2 VALUES LESS THAN (20),
        PARTITION p3 VALUES LESS THAN (30),
        PARTITION p4 VALUES LESS THAN (40),
        PARTITION p5 VALUES LESS THAN (50),
        PARTITION pn VALUES LESS THAN MAXVALUE);
    CREATE OR REPLACE TABLE t1 (x INT)
      PARTITION BY RANGE(x) (
        p1 VALUES LESS THAN (10),
        p2 VALUES LESS THAN (20),
        p3 VALUES LESS THAN (30),
        p4 VALUES LESS THAN (40),
        p5 VALUES LESS THAN (50),
        pn VALUES LESS THAN MAXVALUE);
    CREATE OR REPLACE TABLE t1 (x INT)
      PARTITION BY RANGE(x) (
        PARTITION p1 VALUES LESS THAN (10),
        PARTITION p2 VALUES LESS THAN (20),
        PARTITION p3 VALUES LESS THAN (30),
        PARTITION p4 VALUES LESS THAN (40),
        PARTITION p5 VALUES LESS THAN (50),
        PARTITION pn VALUES LESS THAN MAXVALUE);
    CREATE TABLE IF NOT EXISTS test (
    a BIGINT AUTO_INCREMENT PRIMARY KEY,
    name VARCHAR(128) CHARSET utf8,
    KEY name (name(32))
    ) ENGINE=InnoDB DEFAULT CHARSET latin1;
    CREATE TABLE t1(
      a INT DEFAULT (1+1),
      b INT DEFAULT (a+1),
      expires DATETIME DEFAULT(NOW() + INTERVAL 1 YEAR),
      x BLOB DEFAULT USER()
    );
    MariaDB 10.2.19
    MariaDB 10.5.2
    Oracle SQL_MODE
    Oracle SQL_MODE
    Oracle SQL_MODE
    Oracle SQL_MODE
    10.5.0
    MariaDB 10.5.0
    MariaDB 10.5.2
    MariaDB 10.1.13
    Oracle SQL_MODE
    Oracle SQL mode
    10.8.0
    Oracle SQL_MODE
    Oracle SQL_MODE
    Oracle SQL_MODE
    MariaDB 10.3
    MariaDB 10.5
    Oracle mode
    MariaDB 10.2
    MariaDB 11.5
    MariaDB 11.2
    MariaDB 10.8
    MariaDB 10.8